Skip to content

feat: replace legacy exec approvals with V2#1051

Draft
bkudiess wants to merge 4 commits into
openclaw:mainfrom
bkudiess:bkudiess-v2-exec-approvals-pr
Draft

feat: replace legacy exec approvals with V2#1051
bkudiess wants to merge 4 commits into
openclaw:mainfrom
bkudiess:bkudiess-v2-exec-approvals-pr

Conversation

@bkudiess

@bkudiess bkudiess commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Replace the legacy Windows exec-approval policy and prompt path with the V2 coordinator, store, and hardened dialog introduced by feat: add exec approval prompt dialog for system.run on the Windows node #1045.
  • Make low-level system.run and system.run.prepare canonical argv-only, matching the upstream gateway contract.
  • Execute canonical argv through Local and MXC runners, including cmd-aware serialization for cmd.exe /d /s /c.
  • Port macOS parity hardening for secret redaction, display bounds, bypass detection, one-shot decisions, policy currency, audit-suppression approval, path display, and attended-desktop detection.
  • Align fresh effective policy with macOS: empty allowlist, prompt on miss when attended, deny fallback when unattended. Malformed, untrusted, and migration-failed paths remain hard deny.
  • Make the Windows V1 cutover explicit: legacy command-text rules are left untouched but are not evaluated or converted; prior allows require attended V2 reapproval and unattended calls deny.
  • Move Permissions policy editing onto the App-owned V2 store with single-read hashing, CAS, explicit UI deltas, alternate-state path support, and remote grant restrictions.
  • Remove the legacy V1 policy, prompt service, settings flag, tests, and runtime fallback.

Architecture ownership

  • Old owner: SystemCapability, ExecApprovalPolicy, and ExecApprovalPromptService split approval text matching, prompting, and shell execution across parallel paths.
  • New owner: ExecApprovalsCoordinator owns authorization; ExecApprovalsStore owns policy persistence/CAS; ExecApprovalV2UiPromptHandler and ExecApprovalDialog own presentation; runners receive only the approved execution payload.
  • Preserved invariant: the resolved canonical argv approved by V2 is the argv executed by the selected runner. Missing resolution, changed policy, unsupported transport, unsafe persistence, or presentation failure denies execution.

Behavior changes

  • Low-level callers must send command as string[] argv. The normal gateway exec host=node path already wraps Windows command strings as ["cmd.exe","/d","/s","/c",command].
  • A fresh valid policy defaults to 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 to security=deny.
  • Non-empty custom env is rejected until environment values can be identity-bound and displayed safely.
  • Shells and script/code interpreters can be approved once, but cannot receive reusable executable-only grants.
  • Remote system.execApprovals.set may preserve or remove existing grants, but cannot add/change grants or set full access.
  • The active V2 store defaults to %APPDATA%\OpenClawTray\exec-approvals.json; OPENCLAW_STATE_DIR overrides it.

Upgrade contract

Windows V1 exec-policy.json command-text globs are intentionally retired without migration.

  • V1 files remain byte-for-byte untouched during normal runtime.
  • No V1 allow or deny rule is imported into V2.
  • A fresh valid V2 policy uses an empty allowlist with prompt-on-miss and deny fallback.
  • Prior V1 allows require attended V2 reapproval; unattended calls deny.
  • Prior V1 denies are not imported and may be explicitly superseded by an attended V2 approval.
  • Existing valid V2 state wins; invalid V2 state remains hard deny and is never replaced from V1.

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.ps1
  • dotnet test .\tests\OpenClaw.Shared.Tests\OpenClaw.Shared.Tests.csproj --no-restore
    • 3,241 passed, 32 skipped, 0 failed
  • dotnet test .\tests\OpenClaw.Tray.Tests\OpenClaw.Tray.Tests.csproj --no-restore
    • 1,953 passed, 0 failed
  • dotnet test .\tests\OpenClaw.WinNode.Cli.Tests\OpenClaw.WinNode.Cli.Tests.csproj --no-restore
    • 126 passed, 0 failed
  • dotnet test .\tests\OpenClaw.SetupEngine.Tests\OpenClaw.SetupEngine.Tests.csproj --no-restore
    • 697 passed, 0 failed
  • dotnet test .\tests\OpenClaw.Tray.IntegrationTests\OpenClaw.Tray.IntegrationTests.csproj --no-restore
    • 19 passed, 0 failed
  • .\scripts\validate-mxc-e2e.ps1
    • 2 passed, 0 failed, 0 skipped
  • PowerShell parser validation passed for both modified uninstall scripts.

Real behavior proof

Gateway to Windows node to MXC

Canonical argv:

["cmd.exe","/d","/s","/c","echo OPENCLAW_GATEWAY_SYSTEM_RUN_MXC_SOURCE_READY && echo OPENCLAW_GATEWAY_SYSTEM_RUN_MXC_DENIED_PAYLOAD > \"C:\\Users\\...\\AppData\\Roaming\\OpenClawE2E\\...\\mxc-denied-write-....txt\""]

Observed:

SOURCE_READY: present
stderr: Access is denied.
exitCode: 1
fileExists: False
executor: mxc-direct-appc
contained: True
containment: mxc

The companion execution proof returned the expected marker with exit code 0 through the same contained path.

Local MCP

winnode --list-tools advertised:

system.run: command (string[] argv, required)

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, and containment=mxc.

Upgrade characterization

Automated upgrade tests cover:

  • V1 allow rule with no V2: V1 unchanged, unattended deny, attended prompt/Allow once.
  • V1 deny rule with no V2: V1 unchanged, unattended deny, attended decision explicitly owns any override.
  • Malformed V1: never parsed, remains unchanged, fresh V2 behavior applies.
  • Existing valid V2 plus V1: V2 wins unchanged.
  • Invalid V2 plus V1: hard deny; neither file is overwritten.

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.

  • Final Opus confidence: 95/100
  • Final Sol confidence: 95/100
  • Unresolved HIGH/MEDIUM findings: none
  • Remaining actionable findings: none

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P1 Urgent regression or broken agent/channel workflow affecting real users now. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jul 24, 2026
@clawsweeper

clawsweeper Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codex review: found issues before merge. Reviewed July 24, 2026, 2:47 PM ET / 18:47 UTC.

ClawSweeper review

What this changes

The PR replaces Windows node legacy command approvals with a V2 coordinator, persistence store, hardened local dialog, canonical argv-only system.run contract, and direct-argv support in local and MXC runners.

Merge readiness

Blocked by patch quality or review findings - 8 items remain

Keep this collaborator-authored PR open. The V2 execution path and its stated MXC/MCP proof are substantial, but the branch removes the legacy approval policy without a demonstrated upgrade path for existing nodes, so a previously working system.run setup can become default-deny immediately after upgrade.

Priority: P1
Reviewed head: 44c7a9651db43adf3285525dab12dc14dfb1c891
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🦪 silver shellfish (2/6) The reported runtime proof is useful, but the unaddressed existing-policy upgrade break is a merge-blocking compatibility flaw.
Proof confidence 🐚 platinum hermit (4/6) Sufficient (live_output): The PR body supplies after-fix live gateway-to-MXC containment output and local MCP canonical-argv output, both directly relevant to the changed execution path; it should additionally demonstrate upgrade behavior before merge.
Patch quality 🦪 silver shellfish (2/6) 1 actionable review finding remain.

Verification

Check Result Evidence
Real behavior Verified Sufficient (live_output): The PR body supplies after-fix live gateway-to-MXC containment output and local MCP canonical-argv output, both directly relevant to the changed execution path; it should additionally demonstrate upgrade behavior before merge.
Evidence reviewed 5 items Legacy-policy compatibility gap: The PR deletes the legacy ExecApprovalPolicy and changes the active store to exec-approvals.json; the displayed store path logic only treats an old exec-approvals.json location as legacy, not the retired exec-policy.json. An existing V1 policy therefore has no demonstrated migration or compatibility read path.
Existing policy surface is removed: The branch removes the legacy policy implementation and the runtime V1 fallback while the PR body states that V2 defaults to a different persisted file and a default-deny policy. This is an upgrade-visible behavior change, not only an internal refactor.
Merged V2 dialog baseline: The V2 dialog baseline appears to date to the merged approval-dialog change, which this PR extends into the active authorization and execution path.
Findings 1 actionable finding [P1] Preserve configured approvals across upgrades
Security None None.

How this fits together

Gateway and local MCP clients invoke system.run on the Windows node, which authorizes the request before handing its canonical argv to a local or MXC runner. The approval store and dialog determine whether an operator can safely permit that launch and how the decision persists across future invocations.

flowchart LR
  A[Gateway or local MCP call] --> B[Windows node tool bridge]
  B --> C[V2 approval coordinator]
  C --> D[Policy store and local dialog]
  C --> E[Approved canonical argv]
  E --> F[Local runner or MXC sandbox]
  F --> G[Command result and diagnostics]
Loading

Decision needed

Question Recommendation
Should existing Windows nodes retain their legacy exec-policy.json behavior until an operator explicitly migrates, or is breaking those configured approvals acceptable for this release? Stage an explicit migration: Keep legacy policy behavior for existing installations until a backed-up, operator-visible V2 conversion is completed, with upgrade tests for allowed and denied commands.

Why: The policy formats authorize different things, full command text versus resolved executable paths, so code review cannot safely choose a migration semantic or an intentional breaking security boundary without maintainer direction.

Before merge

  • Preserve configured approvals across upgrades (P1) - Existing installations persist V1 rules in exec-policy.json, but this branch removes that reader and makes V2 read exec-approvals.json; without a migration or retained compatibility path, an upgrade with no new file defaults to deny and breaks previously allowed system.run calls. The V1 command-pattern model also cannot be silently mapped to V2 executable-path grants without an explicit contract.
  • Resolve merge risk (P1) - Existing installations that rely on %LOCALAPPDATA%\OpenClawTray\exec-policy.json can lose their configured allows after upgrade and have system.run default-deny instead.
  • Resolve merge risk (P1) - The V1 full-command rule model and V2 resolved-executable allowlist model are not semantically identical, so a silent mechanical conversion could also widen or narrow approval scope unexpectedly.
  • Complete next step (P2) - A maintainer must choose the upgrade and security contract before a repair can safely preserve or replace existing V1 approval semantics.
  • Improve patch quality - Obtain maintainer direction for the V1-to-V2 upgrade contract.
  • Improve patch quality - Add fresh-install and existing-V1-policy upgrade coverage for both an allowed and a denied command.
  • Improve patch quality - Add redacted runtime evidence of the selected migration or recovery flow; a terminal transcript is suitable.

Findings

  • [P1] Preserve configured approvals across upgrades — src/OpenClaw.Shared/ExecApprovals/ExecApprovalsStore.cs:69-75
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Execution-policy surface 79 files affected; 5,179 added, 6,866 removed The patch simultaneously changes authorization, persistence, WinUI policy editing, MCP documentation, and MXC execution, making upgrade behavior a merge-critical review axis.
Runtime proof paths 2 stated real paths The PR supplies one gateway-to-MXC containment path and one local MCP argv path, but neither demonstrates an existing V1-policy upgrade.

Root-cause cluster

Relationship: canonical
Canonical: #1051
Summary: This PR is the active implementation candidate for moving the merged V2 dialog baseline into the Windows node authorization and execution path.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge-risk options

Maintainer options:

  1. Add an explicit upgrade path (recommended)
    Preserve or explicitly migrate existing V1 policy state with backup and coverage before enabling V2 as the only runtime path.
  2. Approve a deliberate reset
    Accept that existing configured approvals become default-deny only after a maintainer explicitly approves the compatibility and recovery tradeoff.

Technical review

Best possible solution:

Define and implement an explicit V1-to-V2 upgrade contract: preserve the old policy until the owner completes a reviewed conversion, or provide a narrow backed-up migration that fails closed and is covered by fresh-install and upgrade tests.

Do we have a high-confidence way to reproduce the issue?

Yes, from source: start with an existing node whose %LOCALAPPDATA%\OpenClawTray\exec-policy.json permits a command, upgrade to this branch without creating exec-approvals.json, then invoke that command. The V2-only path has no demonstrated reader or converter for the former file and defaults to deny.

Is this the best way to solve the issue?

No. Replacing V1 with V2 may be the intended architecture, but removing the old runtime path without an explicit migration or retained compatibility contract is not the safest solution for existing operators.

Full review comments:

  • [P1] Preserve configured approvals across upgrades — src/OpenClaw.Shared/ExecApprovals/ExecApprovalsStore.cs:69-75
    Existing installations persist V1 rules in exec-policy.json, but this branch removes that reader and makes V2 read exec-approvals.json; without a migration or retained compatibility path, an upgrade with no new file defaults to deny and breaks previously allowed system.run calls. The V1 command-pattern model also cannot be silently mapped to V2 executable-path grants without an explicit contract.
    Confidence: 0.94

Overall correctness: patch is incorrect
Overall confidence: 0.88

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against d2638ddbef57.

Labels

Label changes:

  • add P1: A normal upgrade can break a real existing node-command workflow by discarding the active approval configuration.
  • add merge-risk: 🚨 compatibility: The PR removes the persisted V1 policy path and replaces its rule semantics without demonstrated migration or backward compatibility.
  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body supplies after-fix live gateway-to-MXC containment output and local MCP canonical-argv output, both directly relevant to the changed execution path; it should additionally demonstrate upgrade behavior before merge.
  • add rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🐚 platinum hermit and patch quality is 🦪 silver shellfish.
  • add status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): The PR body supplies after-fix live gateway-to-MXC containment output and local MCP canonical-argv output, both directly relevant to the changed execution path; it should additionally demonstrate upgrade behavior before merge.

Label justifications:

  • P1: A normal upgrade can break a real existing node-command workflow by discarding the active approval configuration.
  • merge-risk: 🚨 compatibility: The PR removes the persisted V1 policy path and replaces its rule semantics without demonstrated migration or backward compatibility.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🐚 platinum hermit and patch quality is 🦪 silver shellfish.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): The PR body supplies after-fix live gateway-to-MXC containment output and local MCP canonical-argv output, both directly relevant to the changed execution path; it should additionally demonstrate upgrade behavior before merge.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body supplies after-fix live gateway-to-MXC containment output and local MCP canonical-argv output, both directly relevant to the changed execution path; it should additionally demonstrate upgrade behavior before merge.

Evidence

What I checked:

  • Legacy-policy compatibility gap: The PR deletes the legacy ExecApprovalPolicy and changes the active store to exec-approvals.json; the displayed store path logic only treats an old exec-approvals.json location as legacy, not the retired exec-policy.json. An existing V1 policy therefore has no demonstrated migration or compatibility read path. (src/OpenClaw.Shared/ExecApprovals/ExecApprovalsStore.cs:69, 44c7a9651db4)
  • Existing policy surface is removed: The branch removes the legacy policy implementation and the runtime V1 fallback while the PR body states that V2 defaults to a different persisted file and a default-deny policy. This is an upgrade-visible behavior change, not only an internal refactor. (src/OpenClaw.Shared/ExecApprovalPolicy.cs:1, 44c7a9651db4)
  • Merged V2 dialog baseline: The V2 dialog baseline appears to date to the merged approval-dialog change, which this PR extends into the active authorization and execution path. (src/OpenClaw.Tray.WinUI/Dialogs/ExecApprovalDialog.cs:50, 76f4d52c3b5e)
  • Contributor-provided real runtime evidence: The PR body reports a gateway-to-node MXC containment run that rejected a write to the protected data directory and a local MCP canonical-argv invocation that returned the expected marker. This is relevant after-fix runtime evidence, but it does not demonstrate an upgrade from an existing V1 policy file. (44c7a9651db4)
  • Repository policy applied: The supplied repository policy requires MXC validation, MCP discovery/invocation proof, architecture review for the App/Permissions surfaces, and a dedicated proof pass for node-command and permissions work. The PR body supplies the named validation categories, while the missing upgrade proof remains material. (AGENTS.md:1, d2638ddbef57)

Likely related people:

  • AlexAlves87: The merged V2 approval-dialog change established the dialog and prompt-handler baseline that this PR promotes into the active authorization path. (role: V2 approval-dialog feature introducer; confidence: medium; commits: 76f4d52c3b5e; files: src/OpenClaw.Tray.WinUI/Dialogs/ExecApprovalDialog.cs, src/OpenClaw.Shared/ExecApprovals/ExecApprovalV2UiPromptHandler.cs)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

bkudiess added 3 commits July 24, 2026 12:49
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@bkudiess

Copy link
Copy Markdown
Collaborator Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 24, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

@clawsweeper

clawsweeper Bot commented Jul 24, 2026

Copy link
Copy Markdown

ClawSweeper status: review started.

I am starting a fresh review of this pull request: feat: replace legacy exec approvals with V2 This is item 1/1 in the current shard. Shard 0/1.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P1 Urgent regression or broken agent/channel workflow affecting real users now. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant