fix: bind SSH credential handoffs to owned listeners - #1126
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4f13b1ca-b8e7-404c-9712-e470a47a53ec
|
Codex review: needs maintainer review before merge. Reviewed August 14, 2026, 5:53 PM ET / 21:53 UTC. ClawSweeper reviewWhat this changesThis PR makes SSH tunnel restart and operator/node gateway handoffs verify the active registry record, tunnel owner generation, listener, and WebSocket generation before credentials are sent. Merge readinessKeep open for maintainer review. Current main does not contain this SSH ownership hardening, and the current head has no discrete correctness finding; its intentional fail-closed credential and restart behavior needs security and availability acceptance after the in-progress exact-head checks finish. Priority: P1 Review scores
Verification
How this fits togetherThe tray sends gateway and Windows-node connections through the connection manager, which may first establish an SSH loopback tunnel. This change binds listener verification and credential-bearing handshakes to that manager-owned tunnel before the gateway session becomes connected. flowchart LR
A[Restart tunnel action] --> B[Connection manager]
B --> C[Owned SSH listener check]
C --> D[Gateway WebSocket]
D --> E[Credential handoff]
E --> F[Connected operator and node sessions]
C --> G[Fail-closed connection error]
Decision needed
Why: This is an intentional security-versus-availability boundary, not a mechanical defect that automated repair can safely decide. Before merge
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Retain the manager-owned, generation-bound restart path and land it once current-head validation is green and a security owner accepts the intentional fail-closed recovery behavior. Do we have a high-confidence way to reproduce the issue? Yes. The current head contains focused manager tests and three ownership E2Es covering listener replacement and withheld credential frames; this read-only review did not execute them. Is this the best way to solve the issue? Yes. Binding the checks at the connection-manager and generation-bound transport boundary is narrower and safer than allowing UI code or a stale socket to decide listener trust. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against f02e0562b16a. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (6 earlier review cycles)
|
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4f13b1ca-b8e7-404c-9712-e470a47a53ec
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4f13b1ca-b8e7-404c-9712-e470a47a53ec
…ned-handoffs-followup # Conflicts: # docs/ARCHITECTURE.md
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8d3c2a8c-1e78-47ee-aa3d-bb4bee89b1b1
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ned-handoffs-followup # Conflicts: # src/OpenClaw.Shared/OpenClawGatewayClient.cs # src/OpenClaw.Shared/WindowsNodeClient.cs # tests/OpenClaw.Shared.Tests/OpenClawGatewayClientTests.cs
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8d3c2a8c-1e78-47ee-aa3d-bb4bee89b1b1
…ned-handoffs-followup
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8d3c2a8c-1e78-47ee-aa3d-bb4bee89b1b1
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ned-handoffs-followup
Summary
Narrow current-main follow-up that binds SSH restart and credential handoffs to the exact manager, registry record, tunnel generation, and WebSocket generation that authorized them.
Current-main scope comparison
c4b4f90bvs old basebafdc49evs current mainThe one additional test file is
ConnectEnvelopeBuilderTests.cs, required to adapt the signer-failure proof to current main's authoritativeConnectEnvelopeBuilderand handshake gate.Why every product file remains
docs/ARCHITECTURE.mdGatewayConnectionManagerwithout restoring any current-main App or ConnectionPage responsibility.GatewayConnectionManager.csIGatewayConnectionManager.csISshTunnelManager.csSshTunnelService.csOpenClawGatewayClient.csSshTunnelCommandLine.cs-FSSH config injection surface.WebSocketClientBase.csWindowsNodeClient.csApp.xaml.csConnectionPage.xaml.csNo direct-connect extraction, DeviceIdentity change, WSL repair, browser UI, setup-token precedence, MXC behavior, or workflow change is present in the PR diff.
Validation
Exact product head before the final workflow-only main merge, with identical product binaries to
bafdc49e:.\build.ps1: passedAGENTS.mdbecause this PR does not change MXC orsystem.runbafdc49e: rerun pending after workflow-only current-main mergeReal behavior proof
Authorized real-profile proof against SSH host
192.168.1.10:127.0.0.1:18789and[::1]:18789tools/listsucceeded and benignsystem.whichresolvedgitopenclaw nodes invoke ... system.whichsucceeded against the connected Windows nodegateways.jsonchanged, solely the expectedlastConnectedtimestamp.10SSH host, SSH/local/remote ports, shared/bootstrap token values, settings file, and per-gateway identity file remained unchangedIntended retained profile state before merge: the authorized
.10realm, its existing active gateway ID, and its per-gateway device identity remain; this proof introduced no structural profile or credential change.