Conversation
Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs real behavior proof before merge. Reviewed September 25, 2026, 9:08 PM ET / September 26, 2026, 01:08 UTC (Revision 10). ClawSweeper reviewWhat this changesThe setup engine selects pending operator and node pairing requests by device identity, approves exact request IDs, and limits later approval drains to matching requests. Merge readiness⛔ Blocked before merge - 13 items remain This PR addresses a real pairing approval risk, but its missing-ID selector can still choose an older request with the same identity. The maintainer replacement at #1523 covers that case, but remains open without the required adversarial Gateway proof, so it is not yet a safe superseding landing path. Priority: P0 Review scores
Verification
How this fits togetherWindows setup opens operator and node connections to a Gateway running in WSL. When pairing is required, the setup engine reads pending Gateway requests and sends an approval command before continuing setup. flowchart LR
A[Setup connection] --> B[Pairing request ID]
B --> C{ID supplied?}
C -->|Yes| D[Approve exact request]
C -->|No| E[Read pending requests]
E --> F[Select by setup identity]
F --> D
D --> G[Gateway pairing state]
Decision needed
Why: The replacement is technically more complete but has not met the security-boundary and repository proof gates, so choosing a landing branch requires maintainer ownership. Before merge
Findings
Agent review detailsSecurityNeeds attention: The identity-only fallback does not prove that the selected approval request belongs to the current setup socket. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Land one identity-bound setup path that excludes requests pending before each socket opens, checks list results before deciding a queue is empty, preserves WSL stdin transport, and has current-head Gateway and required MXC proof. Do we have a high-confidence way to reproduce the issue? Yes, at source level: current main invokes approve --latest for a missing operator request ID, and the PR's focused tests demonstrate selection among pending requests. I did not execute a live reproduction in this read-only review. Is this the best way to solve the issue? No. Exact request IDs are the right direction, but identity alone does not establish that a pending request belongs to the socket opened by this setup run; the replacement adds a pre-connect baseline. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 5a59535216ee. LabelsLabel changes: No label changes. Label justifications:
EvidenceSecurity concerns:
What I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (9 earlier review cycles; latest 8 shown)
|
When setup uses the separate wizard identity, load that identity even if context still holds an older operator id. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
Thanks, Seb. The request/device binding and the follow-up wizard-identity correction are good changes. Reviewed head: The end-to-end setup claim still has a bypass: after the new selector leaves an unrelated request pending, Please remove the broad drain or limit it to the identities/request IDs captured by this setup run. Unknown pending requests should remain untouched. A full-setup regression with our intended request plus an unrelated concurrent request should prove the unrelated request is still pending at completion, not only immediately after There is also a concrete integration detail with #1476 (fix(setup): keep WSL PATH scripts off the wsl.exe argv path), which I am validating first:
I want to keep these changes on your PRs and land the small fixes in a coordinated order. |
|
Global triage: HOLD_FOR_AUTHOR. Take confidence 35%; recommendation confidence 90%; effort moderate; risk high. Reviewed exact head |
The end-to-end and node drains were still approving every pending request after the wizard selector. They now approve only the setup device request. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
Thanks, the There is one remaining fallback in the same setup flow: Please use the identity-bound selector there too, against the actual full setup-node identity, with This is a remaining pre-existing path, not a defect in the new bound drains. The earlier PATH/stdin integration note still applies when the relevant branches are combined. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 50e2dd32-b79f-4654-9231-5766c9e5316d
Reuse the existing identity-bound selector when the node socket has no request ID. Keep exact socket requests unchanged and cover foreign, missing, short, ambiguous, and unsafe requests through the actual approval path. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 50e2dd32-b79f-4654-9231-5766c9e5316d
Use an explicit review-safe synthetic credential in the new fixture; no production behavior changes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 50e2dd32-b79f-4654-9231-5766c9e5316d
|
The fallback on edb0832 selects the pending node with TrySelectPendingRequestForDevice(ctx.OperatorDeviceId, matchNodeId: true). NodeDeviceId is display-only and is not the selector. A sole foreign node fails, and a missing OperatorDeviceId fails before approve. Local setup-engine filter AutoApproveNodePairing_WithoutRequestId: 12 passed. |
|
Maintainer-owned replacement #1523 carries this fix on current It preserves the exact socket-request-ID behavior and hardens missing-ID fallback with a pre-connect request snapshot, so stale same-identity requests are excluded before uniqueness is enforced. Current replacement head: Local build and required Shared, Tray, SetupEngine, and 46 focused pairing tests pass. The PR records two honest blockers: no current-head live WSL Gateway proof, and no no-skip MXC run because this host is |
|
Final maintainer handoff: replacement #1523 is at The replacement preserves exact socket request IDs and binds missing-ID fallback to one post-baseline request matching the full setup identity. Baseline and both drain parsers now check exit status and parse JSON before exact legacy empty-list fallback. Final local validation: build passed; Shared 4,107 passed / 32 skipped; Tray 3,115 passed; SetupEngine 1,228 passed / 1 skipped; focused pairing suite 50 passed. GitHub No force-push to the contributor fork and no merge were performed. Active maintainer ownership is ending; the remaining proof blockers are recorded on #1523. |
|
Closing in favor of #1523 (fix(setup): approve only the pairing request setup just opened). The maintainer replacement preserves the exact request-ID behavior and hardens missing-ID fallback with the pre-connect request baseline and full identity matching. The original contributor branch remains untouched. |
What Problem
AutoApprovePairing with no request id ran openclaw devices approve --latest before checking an id. That approves whichever pending request is newest.
Why
A local process can submit a newer loopback pairing request during setup.
User Impact
Setup now lists pending requests, keeps the operator row for the socket it just opened, and approves only that id. approve --latest is not used on this path.
Evidence
Red: AutoApprovePairing_WithoutRequestId_ApprovesOnlyTheRequestForTheOpenedSocket approved attacker-latest-req. Green: that test passed. Setup-engine suite 1192 passed. The host wsl --version UTF-16 test failed and does not touch this change. .\build.ps1 passed.
The paragraph above preserves the original author evidence. The current-head results below supersede those historical counts and the previous lack of live Gateway proof.
Bounded maintainer follow-up
Preserves SebTardif's operator, wizard-identity, and late-drain fixes. The remaining
PairNodeStep.AutoApproveNodePairingfallback now reusesTrySelectPendingRequestForDevice(..., ctx.OperatorDeviceId, matchNodeId: true)instead of approving the sole pending node. The operator and node setup sockets use the same per-gateway full identity;NodeDeviceIdis a shortened display value and is not approval authority. Socket-provided request IDs, unsafe-ID rejection, and plugin/list failure handling are unchanged.Current head:
edb08328e5e051c30d4604ab5527e765a0ce16ad. Integrated current main42c562f91a42ae0251ac971c44f6ce0f8028e88dwith an ordinary merge, preserving contributor history. The repair adds 14 actual approval-path regression cases and a short architecture-reference note. A second maintainer commit only replaces the fake test credential with an established explicit placeholder for review scanning.Required proof pools
windows-wsl-gateway-e2e: setup operator/node pairing approval changed. Native official Gateway contract proof is recorded below; full WSL setup remains Not verified / blocked.windows-wsl-mxc: repository-required gateway-to-Windows-node containment closeout remains Not verified / blocked. No MXC behavior changed and no containment claim is made.Validation
Final-head native Windows ARM64 validation used the private .NET SDK 10.0.400,
OPENCLAW_REPO_ROOTset to this isolated worktree, unique tray data/AppData directories, and E2E flags disabled. Fresh test-project builds preceded--no-restoreruns. The complete floor was repeated after the fixture-only follow-up..\build.ps1dotnet build .\tests\OpenClaw.Shared.Tests\OpenClaw.Shared.Tests.csprojdotnet build .\tests\OpenClaw.Tray.Tests\OpenClaw.Tray.Tests.csprojdotnet test .\tests\OpenClaw.Shared.Tests\OpenClaw.Shared.Tests.csproj --no-restoredotnet test .\tests\OpenClaw.Tray.Tests\OpenClaw.Tray.Tests.csproj --no-restoredotnet test .\tests\OpenClaw.SetupEngine.Tests\OpenClaw.SetupEngine.Tests.csproj --no-restoredotnet test .\tests\OpenClaw.SetupEngine.Tests\OpenClaw.SetupEngine.Tests.csproj --no-restore --filter FullyQualifiedName~AutoApproveNodePairingAll test runs emitted TRX results. Before the production repair, the same focused subset produced 9 failures and 9 passes: eight behavioral failures and one changed diagnostic assertion. Afterward all 18 passed, including sole foreign pending, full
nodeId/deviceIdselection among foreign requests, missing/short identities, ambiguous matches, unsafe IDs, exact socket-ID routing, and existing plugin error cases. No new regression test executes a distro.Focused rubber-duck review found no blockers. Structured autoreview used Codex 0.156.1,
gpt-5.6-sol, high reasoning, withpython .\.agents\skills\autoreview\scripts\autoreview --mode branch --base f613578ac17afc136d8a4da0b371309d0e59f6b3 --engine codexand the verified native Codex executable. This exact repair range excludes unchanged author/main commits. Result: no accepted/actionable findings. Dead-helper cleanup was deliberately left outside this bounded repair.Real behavior proof
One isolated native official Gateway 2026.9.5 case ran against the current-head production assemblies. Real
WindowsNodeClienthandshakes created two task-owned synthetic identities and pending node surfaces by advertisingsystem.which; no node command was invoked. Device bootstrap approval used only exact request IDs matched to those synthetic full identities. The actualopenclaw nodes list --jsonoutput exposedpending[].requestIdand a 64-characterpending[].nodeId.The harness called production
AutoApproveNodePairingwith a missing socket request ID. A constrained nativeICommandRunneradapter translated only its list/approve transport to the pinned official CLI. It did not fabricate pending JSON or replace the production selector.Executed
OpenClaw.SetupEngine.dllSHA-256:CAB04539C0A611D6AF5E954734DED4582384AEFD09D9EDE561E5B12358538664. ProductionPairNodeStep.csblob:b9eb59d2289ad233130ca95b82f10f1c9eff094e. The harness and final-head test output DLL hashes match. The owned Gateway and harness processes were stopped, port 22480 had no remaining listener, and synthetic identity/profile directories were removed. No tokens, identity files, or normal user state are published.Not verified / blocked: native CLI transport is not
wsl.exeargument/environment propagation, full WSL setup, GUI/MCP smoke, or Gateway-to-node MXC containment proof. Shared-host safety rules prohibited distro startup, services, GUI, and probes. The sole allowed WSL operation was the existingwsl.exe --versiondecoder unit test. These limits do not convert the outstanding custom proof pools into passes. Merge and proof-pool disposition remain with the coordinating maintainer.