Skip to content

fix: prevent exec approval revocation races#103515

Merged
steipete merged 41 commits into
mainfrom
codex/fix-exec-approval-races-78226
Jul 10, 2026
Merged

fix: prevent exec approval revocation races#103515
steipete merged 41 commits into
mainfrom
codex/fix-exec-approval-races-78226

Conversation

@steipete

@steipete steipete commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Exec-approval mutations could save stale state after an administrator revoked or tightened policy. That could restore a revoked allowlist entry, execute after a late policy change, or lose one of two concurrent allow-always grants. The macOS approval socket also used a Foundation read API that can wait for a full buffer instead of returning a short JSONL frame, deadlocking both ends on valid requests.

This is the reviewed maintainer replacement for #78226 because the contributor fork could not be updated from the secured execution environment. It preserves Coy Geek's authorship credit in the repaired commit history.

Closes #78225.
Closes #44749.

Why This Change Was Made

  • Serialize Node, Gateway, CLI, and macOS approval mutations through a shared lock boundary.
  • Re-read and validate current policy inside the same locked transaction that records usage or persists a grant.
  • Bind execution to the authorization basis actually consumed, including durable exact-command trust and Windows wrapper policy.
  • Keep concurrent operator-approved grants additive while revocation, source downgrade, and policy tightening fail closed.
  • Preserve the shipped synchronous compatibility APIs as synchronous durable writes.

User Impact

Revoked approvals remain revoked under concurrent runtime and settings updates. Late authorization changes prevent execution instead of being overwritten. Independent simultaneous allow-always approvals are both retained. macOS approval requests now return short JSONL responses promptly and idle peers are bounded by kernel socket timeouts.

Change Type

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Root Cause

Execution-time helpers mutated approval data derived from an earlier evaluation snapshot and wrote it outside the complete cross-process serialization boundary. Authorization and persistence were separate operations, so a policy change could occur between them. macOS settings also replaced whole allowlist arrays from UI snapshots.

Implementation

  • Centralize read-modify-write transactions in src/infra/exec-approvals.ts and the matching macOS store.
  • Carry a closed authorization provenance through Gateway, Node, and Mac execution paths.
  • Revalidate scalar policy plus the exact snapshotted rule set under lock before any grant or usage mutation.
  • Treat additional current rules as safe concurrent grants; require every expected rule, including its exact source and argPattern bytes, to remain present.
  • Revalidate approval-bound Node cwd and script identities after the commit checkpoint and immediately before spawn.
  • Persist generated macOS allowlist IDs before entry-scoped UI edits.
  • Fail closed for malformed, ownerless, reused-PID, or otherwise unverifiable lock ownership.
  • Validate every directory and symlink in the macOS prompt-socket resolution chain and reject mutating ACL grants to untrusted principals.
  • Read macOS approval JSONL frames with bounded POSIX recv calls and receive/send timeouts instead of Foundation full-count reads.

Evidence

  • Exact published head: 7cc44c2a5fad0ebd44e6e32957d79eb524a269c3.
  • Fresh whole-diff autoreview on the production tree: clean, no accepted or actionable findings, confidence 0.92; exact compiler-only follow-up review clean at 0.99; final socket/fixture bundle review clean at 0.90.
  • Independent focused Darwin security review of nested symlinks, path normalization, ACL qualifiers, and alias handling: clean.
  • git diff --check, strict SwiftFormat, targeted SwiftLint, Swift frontend parsing, and standalone Swift typecheck: passed; the final Swift socket/fixture bundle also passes strict formatting and frontend parsing.
  • Standalone macOS runtime smoke: safe . alias accepted; nested unsafe alias rejected; mutating group/everyone ACL rejected; current-user ACL accepted.
  • Sanitized public-network AWS Crabbox run run_783fefc61664: security-equivalent parent verified, instance profile empty, Tailscale absent, native i18n unchanged at 2,923 entries, and 404 focused tests passed across six Vitest shards.
  • Static SSH macOS proof on clawmac: 88 tests across ExecApprovalsPromptServerTests, ExecApprovalsSocketPathGuardTests, and ExecApprovalsStoreRefactorTests passed twice; an independent prompt-server rerun passed 5/5 in 0.125 seconds.
  • All 41 branch commits remain GitHub-verified after the native rebase; GitHub reports the exact head mergeable.
  • Independent rebase proof: git merge-tree --write-tree 8cc75e285b 99e1a6081b produced the exact 7cc44c2a5f tree; all 11 incorporated-main blobs match current main byte-for-byte, and the residual binary patch hash is unchanged at 78629da716139bacb60af4138cf02ddcc33ddc35efd278f7b774a07c2f6bf38f.
  • Exact-head hosted run 29121165105: 54 successful and 4 skipped source jobs with workflow success. Full PR rollup settled at 86 successful, 20 skipped, 1 neutral, 1 routine auto-response cancellation, 0 failures, and 0 pending checks.

Security Impact

  • New permissions/capabilities? No.
  • Secrets/tokens handling changed? No.
  • New/changed network calls? Yes: existing local Unix-domain JSONL reads now use bounded POSIX recv plus socket receive/send timeouts; no remote endpoint or permission changed.
  • Command/tool execution surface changed? Yes: authorization persistence now linearizes with current policy and fails closed under unsafe concurrency.
  • Data access scope changed? No.

Compatibility / Migration

  • Backward compatible: Yes.
  • Config/env changes: No.
  • Migration needed: No.
  • Existing synchronous approval helper contracts remain synchronous and durable.

Risks and Mitigations

  • Risk: unverifiable lock ownership can temporarily block approval mutation.
    • Mitigation: bounded retry for verifiable live contention; fail-closed errors preserve policy integrity.
  • Risk: the transaction boundary spans Node and macOS implementations.
    • Mitigation: mirrored invariants and focused regression coverage in both languages.
  • Risk: additive snapshot validation could accidentally tolerate a revoked rule.
    • Mitigation: every snapshotted rule key includes exact pattern, source, command text, and argPattern; removal or source change fails validation.
  • Risk: custom macOS socket paths can traverse aliases or ACL-managed directories.
    • Mitigation: validate each resolved component and accept mutating ACL entries only for root or the current user.

Human Verification

  • Verified by review: every execution path carries explicit authorization provenance into the locked commit.
  • Verified by review: concurrent grants are additive; revocation and source downgrade remain fail closed.
  • Verified remotely: the security-equivalent parent native inventory and all 404 focused regressions pass in a secretless public-network sandbox.
  • Verified on macOS: final socket-path and short-frame behavior passes 88 focused tests in three suites on clawmac, including a clean independent prompt-server rerun.
  • Verified on exact-head hosted CI after rebasing onto fix(gateway): restore cooperative suspension validation #103925: lint, topology, macos-swift, Android, security, Gateway, Node, iOS, type, and focused quality lanes all passed.

Review Conversations

  • I replied to or resolved every review conversation addressed by this replacement.
  • No unresolved conversation is being hidden by the replacement.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation app: macos App: macos gateway Gateway runtime cli CLI command changes scripts Repository scripts commands Command implementations agents Agent runtime and tooling size: XL maintainer Maintainer-authored PR labels Jul 10, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels Jul 10, 2026
@clawsweeper

clawsweeper Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 10, 2026, 4:32 PM ET / 20:32 UTC.

Summary
The branch serializes exec-approval mutations and revalidates authorization across Gateway, Node, CLI, plugin-locking, and macOS paths while hardening native approval sockets and settings updates.

Reproducibility: yes. The exact-head source gives deterministic paths for policy tightening or file deletion between evaluation and final commit/CAS, plus a direct inherited-entry deletion no-op; focused live execution was not repeated during this read-only review.

Review metrics: 1 noteworthy metric.

  • Blocking invariants: 5 defects remain. Four security-critical authorization or stale-save defects and one persisted-trust UI defect must be resolved before merge.

Stored data model
Persistent data-model change detected: migration/backfill/repair: src/commands/doctor-security.test.ts, persistent cache schema: apps/macos/Tests/OpenClawIPCTests/ExecApprovalsSocketAuthTests.swift, serialized state: apps/macos/Sources/OpenClaw/SystemRunSettingsView.swift, serialized state: apps/macos/Tests/OpenClawIPCTests/ExecApprovalsPromptServerTests.swift, serialized state: apps/macos/Tests/OpenClawIPCTests/ExecApprovalsUIRollbackTests.swift, serialized state: src/commands/doctor-security.test.ts, and 1 more. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: canonical
Canonical: #103515
Summary: This is the maintained replacement candidate for two linked approval-race issues; several nearby maintainer issues intentionally track distinct remaining layers.

Members:

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

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🐚 platinum hermit
Patch quality: 🦪 silver shellfish
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Repair the five findings across TypeScript and macOS.
  • Post redacted exact-head focused and native proof for the repaired interleavings; updating the PR body should trigger review, or a maintainer can request @clawsweeper re-review.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR provides strong Crabbox, native macOS, and runtime evidence, but the cited runs do not demonstrate the five remaining interleavings on final exact head 7cc44c2a; after repair, update the PR body with redacted exact-head logs or terminal output to trigger re-review.

Risk before merge

  • [P1] Merging the current head can still execute commands after some persisted-policy tightening and can mutate approval state while rejecting stale saves.
  • [P1] The new fail-closed lock ownership, filesystem, and socket checks can temporarily block approval reads or mutations, so availability and operator recovery behavior remain merge-relevant.
  • [P1] The branch is behind current main; it needs a review refresh after rebasing, although GitHub currently reports it mergeable and stale-base status alone is not evidence of lost current-main behavior.

Maintainer options:

  1. Repair the remaining races (recommended)
    Fix all five authorization, CAS, and inherited-entry defects and rerun exact-head focused and native proof before merge.
  2. Pause the broad replacement
    Pause the PR if the cross-platform authorization and storage invariants cannot be repaired and reviewed coherently on this branch.

Next step before merge

  • [P1] The PR carries the protected maintainer label, so ClawSweeper should surface the concrete blockers but not queue an autonomous repair job.

Security
Needs attention: Five exact-head defects remain in the command-authorization and persisted-approval boundary.

Review findings

  • [P1] Require snapshots for every explicit approval — src/node-host/invoke-system-run.ts:995
  • [P1] Reject auto-review whenever evaluated policy tightens — src/infra/exec-approvals.ts:2136-2140
  • [P1] Validate local CAS before creating approval state — src/gateway/server-methods/exec-approvals.ts:181-182
Review details

Best possible solution:

Use a mandatory persisted-policy snapshot contract for every delayed explicit and automatic authorization, make every set/CAS path non-mutating until freshness is accepted, preserve allowlist entry ownership in resolved UI rows, and then prove tightening, deletion, inherited-edit, and concurrent-add cases on one exact repaired head.

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

Yes. The exact-head source gives deterministic paths for policy tightening or file deletion between evaluation and final commit/CAS, plus a direct inherited-entry deletion no-op; focused live execution was not repeated during this read-only review.

Is this the best way to solve the issue?

No, not on this head. A shared locked transaction is the right owner boundary, but optional snapshots, partial automatic-policy checks, pre-CAS mutation, and lost entry ownership leave the intended revocation invariant incomplete.

Full review comments:

  • [P1] Require snapshots for every explicit approval — src/node-host/invoke-system-run.ts:995
    policySnapshot is attached only when an allow-always decision persists a durable grant, so an allow-once approval can still commit after policy tightens from full to allowlist or matching rules change. Carry the evaluation snapshot for every explicit approval and require it at the final locked commit.
    Confidence: 0.99
  • [P1] Reject auto-review whenever evaluated policy tightens — src/infra/exec-approvals.ts:2136-2140
    This branch rejects only deny and ask=always; changing full to allowlist or off to on-miss still executes without deriving a current allowlist basis. Compare the evaluated policy snapshot or re-authorize the exact command against current policy.
    Confidence: 0.99
  • [P1] Validate local CAS before creating approval state — src/gateway/server-methods/exec-approvals.ts:181-182
    ensureExecApprovalsSnapshot() may create a missing approvals file before baseHash is checked, so a stale save can return conflict after recreating defaults and socket state. Use a non-mutating read for freshness and let the accepted locked update be the first write.
    Confidence: 0.99
  • [P1] Validate native CAS before ensuring the approvals file — apps/macos/Sources/OpenClaw/ExecApprovalsStore.swift:617-618
    saveFile calls ensureFileUnlocked() before checking the base hash; if the file was deleted, a rejected stale save recreates it before returning conflict. Read without persistence, validate CAS, then create or normalize only for an accepted write.
    Confidence: 0.99
  • [P2] Reject deletes that cannot mutate an inherited entry — apps/macos/Sources/OpenClaw/ExecApprovalsStore.swift:1121-1128
    The settings model lists wildcard-inherited entries for an agent, but this removal filters only that agent's owned list and reports success when the id is absent, leaving the inherited trust active while the row disappears locally. Track the owning scope or return a conflict/not-found.
    Confidence: 0.98

Overall correctness: patch is incorrect
Overall confidence: 0.99

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add merge-risk: 🚨 compatibility: The patch changes shipped synchronous approval APIs, save semantics, request fields, and macOS settings behavior across existing installations.
  • add merge-risk: 🚨 security-boundary: The exact head can preserve stale execution authority or recreate approval state during a rejected write.
  • add merge-risk: 🚨 availability: The new fail-closed ownership and socket checks can block approval operations under unverifiable filesystem or lock state.
  • add rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🐚 platinum hermit and patch quality is 🦪 silver shellfish.

Label justifications:

  • P1: The exact head still has high-impact defects in the exec authorization and persisted approval boundary.
  • merge-risk: 🚨 compatibility: The patch changes shipped synchronous approval APIs, save semantics, request fields, and macOS settings behavior across existing installations.
  • merge-risk: 🚨 security-boundary: The exact head can preserve stale execution authority or recreate approval state during a rejected write.
  • merge-risk: 🚨 availability: The new fail-closed ownership and socket checks can block approval operations under unverifiable filesystem or lock state.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🐚 platinum hermit and patch quality is 🦪 silver shellfish.
Evidence reviewed

Security concerns:

  • [high] Stale delayed authorization — src/infra/exec-approvals.ts:2123
    Explicit one-shot and automatic approvals can survive some persisted-policy tightening before spawn.
    Confidence: 0.99
  • [high] Rejected writes mutate policy state — src/gateway/server-methods/exec-approvals.ts:181
    Local and native set paths can create or normalize the approvals store before rejecting a stale base hash.
    Confidence: 0.99
  • [medium] Inherited trust cannot be removed from the shown scope — apps/macos/Sources/OpenClaw/ExecApprovalsStore.swift:1121
    The macOS settings UI may report a successful removal while an inherited wildcard allowlist rule remains active.
    Confidence: 0.98

What I checked:

  • Explicit approval snapshot remains optional: The final Node commit attaches policySnapshot only when an allow-always decision persists a durable grant; an explicit allow-once therefore reaches the validator without the evaluated persisted-policy snapshot. (src/node-host/invoke-system-run.ts:995, 7cc44c2a5fad)
  • Auto-review validates only extreme tightening: The locked validator rejects automatic authorization when policy becomes deny or ask-always, but returns after full-to-allowlist or off-to-on-miss tightening without deriving a current allowlist basis. (src/infra/exec-approvals.ts:2136, 7cc44c2a5fad)
  • Local rejected save can create state: The local Gateway set handler calls the ensuring snapshot helper before checking baseHash, so deleting the approvals file before a stale save can cause the rejected request to recreate defaults and socket state. (src/gateway/server-methods/exec-approvals.ts:181, 7cc44c2a5fad)
  • Native rejected save can create state: The macOS conditional save invokes ensureFileUnlocked() before validating the caller's base hash; a deleted file is recreated or normalized before the method returns conflict. (apps/macos/Sources/OpenClaw/ExecApprovalsStore.swift:617, 7cc44c2a5fad)
  • Inherited delete remains a successful no-op: The settings model displays resolved wildcard entries for an agent, but removal filters only that agent's owned list and returns success when the inherited id is absent, leaving the rule trusted. (apps/macos/Sources/OpenClaw/ExecApprovalsStore.swift:1121, 7cc44c2a5fad)
  • Re-review continuity: The current behavior matches the unresolved findings recorded in six earlier ClawSweeper cycles; these blockers were not newly invented after the final rebase. (src/infra/exec-approvals.ts:2123, 7cc44c2a5fad)

Likely related people:

  • steipete: Authored the replacement branch and the commits introducing the cross-platform transaction, authorization snapshot, socket, and UI mutation model. (role: recent area contributor; confidence: high; commits: 660ac1e6acf1, 876ff15a9824, 8a6ea2e429ab; files: src/infra/exec-approvals.ts, src/gateway/server-methods/exec-approvals.ts, apps/macos/Sources/OpenClaw/ExecApprovalsStore.swift)
  • coygeek: Reported the stale node writeback vulnerability and contributed the source work and co-authored commits that this maintained replacement preserves. (role: introduced reported behavior and source repair; confidence: high; commits: 85a1865401de, 660ac1e6acf1, 876ff15a9824; files: src/infra/exec-approvals.ts, src/node-host/invoke-system-run.ts, apps/macos/Sources/OpenClaw/ExecApprovalsStore.swift)
  • vincentkoc: Merged the current-main Gateway contract repair that the final branch rebased onto; relevant for separating baseline cron/import fixes from this PR's exec-approval changes. (role: adjacent merger; confidence: medium; commits: 99e1a6081bca; files: src/gateway/server-cron-contract.ts, src/gateway/local-request-context.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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.

How this review workflow works
  • 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.
Review history (6 earlier review cycles)
  • reviewed 2026-07-10T11:13:18.743Z sha 5eaceae :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-10T16:11:23.692Z sha f242a14 :: needs real behavior proof before merge. :: [P1] Require a snapshot for every explicit approval | [P1] Validate the policy snapshot for macOS allow-once
  • reviewed 2026-07-10T17:31:38.615Z sha 26cc13b :: needs real behavior proof before merge. :: [P1] Reject auto-review when exec policy tightens | [P1] Bind native auto-review to the evaluated policy
  • reviewed 2026-07-10T18:02:13.754Z sha ee15f1b :: needs real behavior proof before merge. :: [P1] Require a snapshot for every explicit approval | [P1] Reject auto-review when policy tightens | [P1] Bind native explicit-once to the evaluated policy | [P1] Reject native auto-review after policy tightening | [P1] Check local CAS before creating the approvals file | [P1] Check node CAS before ensuring approval state
  • reviewed 2026-07-10T18:12:13.041Z sha ee15f1b :: needs real behavior proof before merge. :: [P1] Require a policy snapshot for every explicit approval | [P1] Reject auto-review when the evaluated policy tightens | [P1] Bind native auto-review to the evaluated policy | [P1] Require native explicit-once snapshot validation | [P1] Check local CAS before creating approval state | [P1] Check native CAS before ensuring the approvals file
  • reviewed 2026-07-10T19:31:13.178Z sha a632790 :: needs real behavior proof before merge. :: [P1] Require a snapshot for every explicit approval | [P1] Reject auto-review when the evaluated policy tightens | [P1] Bind native auto-review to the evaluated policy | [P1] Validate the base hash before creating local state | [P1] Check native CAS before ensuring the approvals file | [P2] Reject deletes that cannot mutate an inherited entry

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2be0b5d7d6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2100 to +2101
expectedPolicy &&
!execApprovalPolicySnapshotIsCurrent(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Require snapshots for all explicit approvals

When source is explicit-approval but no policySnapshot is supplied, this branch skips the policy comparison and returns. The new node/gateway callers only attach policySnapshot when an allow-always grant is being persisted, so an allow-once prompt created under full/ask=always can still execute after the operator tightens the approvals file to allowlist/ask=off or removes the matching rule, as long as the new security is not deny. Require a snapshot for explicit approvals or have the callers always pass the snapshot captured before prompting.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f242a146ff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1257 to +1261
case let .explicitOnce(security):
guard ExecSecurity.narrower(security, current.agent.security) != .deny else {
throw self.executionAuthorizationChangedError()
}
return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Require snapshots for macOS allow-once approvals

Fresh evidence beyond the existing TypeScript comment: the new macOS commit path added here has the same gap for .explicitOnce. If a prompt was approved with allow-once, then before commitExecution takes the lock an operator changes ask to .always, changes security to .allowlist, or removes/downgrades the matching allowlist rule, this branch only rejects a new .deny policy and still executes the stale approval. The .explicitAlways branch immediately below compares the captured policySnapshot; .explicitOnce needs equivalent snapshot validation so one-shot human approvals cannot survive policy tightening or revocation.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 10, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 26cc13b1b2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2136 to +2140
if (params.authorization.source === "auto-review") {
if (ask === "always") {
throw new Error("Exec approval changed before execution");
}
return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Recheck tightened policy for auto-review approvals

With source: "auto-review", this branch only rejects deny and ask=always. If an auto-reviewed command is waiting to commit and the approvals file tightens from full to allowlist (or from ask=off to on-miss) before the lock is taken, the changed security/ask is ignored and the stale automatic approval still executes, while the current-policy path below rejects the same drift. Please require the evaluated security/ask to remain current, or re-derive a current allowlist basis, for auto-review commits.

Useful? React with 👍 / 👎.

Comment on lines +945 to +947
case let .autoReview(security):
guard ExecSecurity.narrower(security, current.agent.security) != .deny,
current.agent.ask != .always

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject auto-review after security tightening

For forwarded .autoReview, this guard only fails for deny or ask == .always. If the upstream auto-review was made under a broader policy and the store is tightened to .allowlist before this locked commit, the branch returns without checking for a current allowlist basis, so the stale automatic approval can still execute. Mirror the current-policy validation here by rejecting evaluated security/ask drift or requiring a current basis.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jul 10, 2026
@steipete
steipete requested a review from a team as a code owner July 10, 2026 17:33
@github-actions github-actions Bot added the dependencies-changed PR changes dependency-related files label Jul 10, 2026
@openclaw-barnacle openclaw-barnacle Bot added channel: nextcloud-talk Channel integration: nextcloud-talk and removed dependencies-changed PR changes dependency-related files labels Jul 10, 2026
@steipete
steipete force-pushed the codex/fix-exec-approval-races-78226 branch from a632790 to b363012 Compare July 10, 2026 19:51
@steipete

steipete commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Land-ready review completed on exact head 76da8d6a3f78a15337e5b3a4a6d9074cfbd93fda.

The policy-owner transaction now linearizes current-policy validation, optional durable grants, and execution usage before spawn across CLI, Gateway, Node, and macOS. Revocation, tightening, source downgrade, malformed state, and persistence failure remain fail closed; independent grants and the exact nil-to-allow-always promotion remain additive. The final Darwin repair also replaces Foundation full-count reads with bounded short-frame POSIX socket reads.

Proof:

  • Sanitized public-network AWS Crabbox run_783fefc61664: 404 focused tests passed across six shards; native i18n unchanged at 2,923 entries.
  • clawmac static SSH proof: 88 focused Swift tests passed twice; independent prompt-server rerun 5/5 in 0.125 seconds.
  • git diff --check, strict SwiftFormat, targeted SwiftLint, Swift frontend parse, standalone Swift typecheck, and focused runtime smoke passed.
  • Whole-diff autoreview clean at 0.92, compiler follow-up clean at 0.99, final socket bundle clean at 0.90, and focused Darwin security review clean.
  • Hosted run 29119435632: 84 successful, 21 skipped, 1 neutral, 2 failed, 0 pending. macos-swift job 86450937912 and Android job 86450937932 passed.
  • The only two failures are inherited unchanged from exact base 1bcc4c5e706: base lint job 86446192688 has the same five errors in untouched tests as PR job 86450937974; base architecture job 86446192773 has the identical 560-module Madge SCC as PR job 86450938150.

No remaining code finding or proof gap. Proceeding through the native guarded landing workflow.

Update: the native guard correctly required the root changelog entry to remain release-owned. The two inherited baseline failures then landed fixed in #103925. Exact head 7cc44c2a5fad0ebd44e6e32957d79eb524a269c3 is rebased onto that clean baseline, all 41 commits are verified, and hosted run 29121165105 is fully green: 54 successful and 4 skipped source jobs, with no failures or pending work.

@clawsweeper clawsweeper Bot removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jul 10, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7cc44c2a5f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +78 to +82
if (params.authority === "auto-review") {
if (current.hostAsk === "always") {
throw new Error("exec denied: host=node ask=always requires human approval");
}
return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Recheck host allowlist for node auto-review

Fresh node-host evidence beyond the existing auto-review comments: this auto-review branch only rejects security=deny or ask=always before forwarding the approved node.invoke. If the command was auto-reviewed under a broader host policy and the exec approvals file tightens to allowlist/ask=off or removes the relevant rule before dispatch, this still returns and the node only enforces its own local policy, so the Gateway-owned host revocation no longer applies. Re-derive the current host allowlist basis (or require the evaluated security/ask/allowlist snapshot to remain valid) before returning here.

Useful? React with 👍 / 👎.

Comment on lines +902 to +904
switch ExecHostRequestEvaluator.validateCommand(
command: params.command,
rawCommand: params.rawCommand)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve shell-preview rawCommand for Mac node runs

This new validation path rejects normal Gateway-dispatched Mac node commands such as command: ["/bin/sh", "-lc", "echo hi"] with rawCommand: "echo hi": ExecSystemRunCommandValidator only accepts the shell preview when hasTrailingPositionalArgvAfterInlineCommand is false, but that helper currently counts the inline command token itself as trailing positional argv. Mac nodes do not advertise system.run.prepare, so buildLocalPreparedNodeRun intentionally sends transportRawCommand as the preview for these legacy/native nodes; adding this validator makes ordinary host=node exec calls fail with INVALID_REQUEST: rawCommand does not match command.

Useful? React with 👍 / 👎.

@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

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

Labels

agents Agent runtime and tooling app: macos App: macos cli CLI command changes commands Command implementations docs Improvements or additions to documentation gateway Gateway runtime maintainer Maintainer-authored PR P1 High-priority user-facing bug, regression, or broken workflow. scripts Repository scripts size: XL

Projects

None yet

1 participant