feat: replace legacy exec approvals with V2 - #1051
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 29, 2026, 1:56 PM ET / 17:56 UTC. ClawSweeper reviewWhat this changesThis PR makes Windows node command execution use a V2 approval system that authorizes canonical argv, stores executable-path rules, prompts locally, and runs approved argv through local or MXC runners. Merge readinessKeep this PR open for maintainer approval rather than automated cleanup. The latest head appears to address the prior concrete redaction and remote-policy findings, but it deliberately changes the external Priority: P1 Review scores
Verification
How this fits togetherWindows-node flowchart LR
A[Gateway, MCP, CLI, plugins] --> B[system.run canonical argv request]
B --> C[V2 input and executable resolution]
C --> D[Local approval policy and prompt]
D --> E{Approved and still current?}
E -->|No| F[Typed deny result]
E -->|Yes| G[Local or MXC runner]
G --> H[Command result and audit telemetry]
Decision needed
Why: The implementation intentionally avoids unsafe conversion and dual evaluators, but accepting the resulting upgrade behavior is a product and release-contract choice rather than a mechanical code-review decision. Before merge
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Land a single authoritative argv-based approval path only after a maintainer explicitly accepts the documented API and V1-policy cutover, with release-facing migration guidance for affected low-level callers and unattended deployments. Do we have a high-confidence way to reproduce the issue? Not applicable as a standalone bug report. The PR body provides concrete live gateway-to-Windows-node MXC and local MCP execution evidence, while the remaining question is product acceptance of the upgrade contract. Is this the best way to solve the issue? Unclear. A single canonical-argv authorization path is maintainable and avoids unsafe V1 command-text conversion, but maintainers must decide whether the intentional caller and upgrade break is acceptable for this release. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 80f35d074876. LabelsLabel 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 (5 earlier review cycles)
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
f7e2ae0 to
c444067
Compare
|
I am holding this below the repository's 90% merge-confidence bar after independent Opus and Codex reviews of the current head
The first two may be deliberate product decisions, but they need explicit release handling. The third is a concrete authorization-policy gap that should be fixed before merge. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
@shanselman Thanks for the review. The concrete remote-policy weakening gap is fixed on the updated head:
Explicit product/release decision for the other two items:
Current validation: build green; Shared 3,249 passed / 32 skipped; Tray 1,954; CLI 126; SetupEngine 697; Tray Integration 19; MXC E2E 2/2 with true contained Access denied proof. Opus and Sol found no remaining actionable issues at 95% / 96% confidence. Please reconsider the merge-confidence gate on the updated head. |
|
@clawsweeper re-review |
|
🦞👀 Command router queued. I will update this comment with the next step. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
I re-reviewed current head Two new blockers remain:
Validation on the current-main merged state:
Recommendation: hold until both blockers have focused regression tests. Confidence: 96% on the numeric bypass and 93% on the redaction exploit path. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Re-review at I am still holding this head because the replacement PEM pattern introduces two verified secret-display regressions:
The pattern currently requires literal line breaks and at least four non-padding base64 characters on every line. It should accept literal or escaped line separators where those serialized forms are supported, and allow a valid short padded final line. Please add regressions for both cases. There is also a concrete behavior regression in the new Focused exec-approval tests pass: 273/273. Independent Codex review found the original blockers closed; Opus found the cases above, and I reproduced all four inputs against the current-main merge. Hold confidence: 95%. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Summary
system.runandsystem.run.preparecanonical argv-only, matching the upstream gateway contract.cmd.exe /d /s /c.Architecture ownership
SystemCapability,ExecApprovalPolicy, andExecApprovalPromptServicesplit approval text matching, prompting, and shell execution across parallel paths.ExecApprovalsCoordinatorowns authorization;ExecApprovalsStoreowns policy persistence/CAS;ExecApprovalV2UiPromptHandlerandExecApprovalDialogown presentation; runners receive only the approved execution payload.Behavior changes
commandasstring[]argv. The normal gatewayexec host=nodepath already wraps Windows command strings as["cmd.exe","/d","/s","/c",command].node.invoke, plugin, andwinnodecallers migrate from{"command":"echo hello","shell":"cmd"}to{"command":["cmd.exe","/d","/s","/c","echo hello"],"rawCommand":"echo hello"}. String requests returncommand-array-required.security=allowlist,ask=on-miss,askFallback=deny, and an empty allowlist. Only truly missing trustworthy state gets this default; invalid or unreadable active/legacy paths fail closed tosecurity=deny.envis rejected until environment values can be identity-bound and displayed safely.system.execApprovals.setmay preserve/remove existing grants and preserve/tighten effective policy, but cannot add/change grants or weakensecurity,ask,askFallback, orautoAllowSkills.%APPDATA%\OpenClawTray\exec-approvals.json;OPENCLAW_STATE_DIRoverrides it.Upgrade contract
Windows V1
exec-policy.jsoncommand-text globs are intentionally retired without migration.Mechanical conversion and V1 runtime fallback were rejected because V1 authorized shell command text while V2 binds resolved executable identity and canonical argv. Conversion could widen narrow text rules into broad command-host grants, while dual evaluators would preserve parallel authorization paths.
Validation
.\build.ps1dotnet 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.WinNode.Cli.Tests\OpenClaw.WinNode.Cli.Tests.csproj --no-restoredotnet test .\tests\OpenClaw.SetupEngine.Tests\OpenClaw.SetupEngine.Tests.csproj --no-restoredotnet test .\tests\OpenClaw.Tray.IntegrationTests\OpenClaw.Tray.IntegrationTests.csproj --no-restore.\scripts\validate-mxc-e2e.ps1Real behavior proof
Gateway to Windows node to MXC
Canonical argv:
Observed:
The companion execution proof returned the expected marker with exit code 0 through the same contained path.
Local MCP
winnode --list-toolsadvertised:Canonical invocation returned:
{ "stdout": "OPENCLAW_LOCAL_MCP_CANONICAL_ARGV_OK", "stderr": "", "exitCode": 0, "timedOut": false, "success": true }Runtime logs confirmed
path=v2,decision=Allow,contained=True, andcontainment=mxc.Upgrade characterization
Automated upgrade tests cover:
Adversarial review
Claude Opus 4.8 and GPT-5.6 Sol independently reviewed the complete diff through three rounds with cross-model challenge and re-review after fixes.