Skip to content

Fix Codex trust gates after session restore - #8783

Closed
lawrencecchen wants to merge 135 commits into
mainfrom
task-codex-resume-trust-gates
Closed

lawrencecchen wants to merge 135 commits into
mainfrom
task-codex-resume-trust-gates

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • route saved bare and absolute Codex resume commands through the cmux wrapper while preserving the captured binary
  • bypass hook review for the restored invocation and append an undecided project decision after the resume arguments
  • preserve explicit project trust decisions and canonicalize worktree and filesystem paths like Codex
  • rebind a resumed process after an interrupted turn so repeated app crashes remain restorable

Verification

  • 256 CMUXAgentLaunch tests pass
  • 5 wrapper regressions pass
  • cloud build https://github.com/manaflow-ai/cmux/actions/runs/30061149431 passes on commit 48f0768d98
  • Codex session 019f91b7-f454-7221-b3f2-d278b218a154 in /private/tmp/cxrsm-final-head.0s8npF/nested/work restored through PIDs 36225 → 90191 → 27996 across two consecutive hard app crashes
  • both restores kept --dangerously-bypass-hook-trust before resume and projects={"/private/tmp/cxrsm-final-head.0s8npF/nested/work"={trust_level="untrusted"}} after resume
  • neither restore showed a hook-review or directory-trust picker; the composer remained interactive and no project trust was persisted
  • tagged identify and read-screen preflight checks pass

Security

Restored invocations use Codex hook trust bypass, so enabled user or project hooks can run outside the sandbox without another review prompt.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Keeps Codex auto‑resume non‑interactive and safe after session restore without persisting project trust or changing the captured Codex binary. All resumes and forks route back through cmux-codex-wrapper; we inject a resume‑scoped untrusted override only when Codex has no decision and fire a best‑effort session‑start for named resumes.

  • Bug Fixes

    • Trust resolution: read Codex’s effective config via a bounded JSONL helper isolated from model refresh; canonicalize cwd/repo like Codex (worktrees, split Git); encode override as a TOML table and inject after resume/before -- only when undecided; discard partial/malformed/oversized output; coalesce concurrent probes with a process‑shared on‑disk cache and per‑invocation freshness.
    • Wrapper routing and safety: route bare/absolute/bundled Codex (and forks) through the wrapper while pinning the captured binary via CMUX_CUSTOM_CODEX_PATH (honors CMUX_CODEX_WRAPPER_SHIM); preserve symlink identity; accept VAR=value/env prefixes and -C/--cd; robust argv parsing for -- and attached‑image flags; preserve argument order, fork tag order, and explicit update‑check settings; keep custom env portable.
    • Execution and lifecycle: preserve user PATH for Codex while resolving wrapper helpers from system paths; reject executables inside the active project before trust; allow home and custom installs outside project roots; use /bin/bash and emit NUL‑separated args; rebind repeated restores using start‑time identity plus process leases and a hidden process‑identity helper; authenticate delayed stop/teardown; treat fork as a session start; clear interrupted turn state; bound app‑server reaping.
  • Refactors

    • Added CodexResumeTrustPolicy, CodexResumeTrustProbeCache, a JSONL runner, emitCodexWrapperResumeArgs, and a hidden process‑identity helper; portable resume commands now route captured executables through the wrapper.
    • Expanded tests with a Swift Testing harness and a Python regression covering resume‑scoped trust placement, wrapper routing, env prefixes, probe coalescing/freshness, process leases/rebinds (including legacy stores), executable identity, and ordering invariants.

Written for commit 60dcafa. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Improved Codex resume handling, including project-trust overrides for unattended sessions.
    • Preserved captured Codex executables across resume and fork commands, with safer wrapper fallback behavior.
    • Added support for Codex fork hooks and resume argument restoration.
    • Improved handling of linked worktrees, custom profiles, working directories, and repository paths.
    • Added resilient probing and caching for Codex configuration decisions.
  • Bug Fixes

    • Prevented stale or mismatched Codex processes from replacing active sessions.
    • Hardened executable and environment resolution against unsafe project-controlled paths.
    • Improved parsing of complex resume arguments and failure-safe fallback behavior.
  • Tests

    • Added comprehensive coverage for trust overrides, executable routing, caching, process identity, and resume command reconstruction.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Codex resume flows now evaluate project trust, inject validated overrides, preserve captured executables, harden wrapper execution, and rebind sessions using process-generation identity. Supporting async process handling, probe caching, shell parsing, and regression tests were added.

Changes

Codex resume trust evaluation

Layer / File(s) Summary
Trust policy, probing, and caching
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/..., CLI/CMUXCLI+CodexFireAndForgetHooks.swift, CLI/CMUXCLI+Process.swift, Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/...
Resume arguments, effective directories, project decisions, app-server JSONL responses, Git roots, and cached probes are processed with fail-closed behavior and covered by policy and cache tests.

Resume argument injection

Layer / File(s) Summary
Wrapper-to-CLI resume argument exchange
Resources/bin/cmux-codex-wrapper, CLI/CMUXCLI+CodexFireAndForgetHooks.swift, CLI/cmux.swift, tests/test_codex_wrapper_resume_trust.py
The wrapper requests NUL-separated resume arguments, validates the response, inserts trust overrides around resume delimiters, and marks resumed hook events for rebinding.

Captured executable routing

Layer / File(s) Summary
Codex wrapper rendering and fallback
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift, Sources/SurfaceResumeCommandCanonicalizer+PortableAgentExecutable.swift, Sources/RestorableAgentSession.swift, cmuxTests/..., Packages/macOS/CMUXAgentLaunch/Tests/...
Codex resume and fork commands recognize wrapper tokens, preserve absolute captured executables through CMUX_CUSTOM_CODEX_PATH, and fall back safely when the wrapper is unavailable.

Resume session rebinding

Layer / File(s) Summary
Process-generation freshness and stale-event handling
CLI/cmux.swift
Codex session records persist lease identity and process-generation data; resumed replacement uses generation comparisons, and stale Codex hook events are rejected across lifecycle handlers.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

  • manaflow-ai/cmux-dev-artifacts#6023 — Covers Codex resume trust evaluation, effective-config probing, Git-root handling, and concurrent probe caching implemented here.
  • manaflow-ai/cmux-dev-artifacts#6018 — Covers the added trust policy, effective-config probing, Git metadata decisions, and probe coalescing.

Suggested reviewers: azooz2003-bit, austinywang


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (6 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error New production Swift adds flock-based waiting plus ContinuousClock.sleep in CodexResumeTrustProbeCache, and CMUXCLI+Process adds semaphores/timeouts. Refactor cache coalescing to actor/async-signal coordination and avoid semaphore/lock-based waits in the JSONL runner; keep such sync only in tests.
Cmux Cache Substitution Correctness ❌ Error The resume-trust cache reuses config/read results, but its key omits trust-config identity (e.g. config.toml), so stale decisions can survive within the 5s cache window. Include the authoritative Codex trust-config file(s) in the cache key or use a freshness-checked/event-driven invalidation so resumed trust reads cannot go stale.
Cmux Algorithmic Complexity ❌ Error CLI/CMUXCLI+Process.swift:760-835 reads JSONL stdout/stderr one byte at a time from up to 8MB streams in a hot process path, with no benchmarked bound. Switch to chunked reads (e.g. read(upToCount:) or buffered chunks) and scan newlines per chunk; keep the same output cap.
Cmux Swift Package Boundaries ❌ Error SurfaceResumeCommandCanonicalizer+PortableAgentExecutable.swift adds pure, reusable Codex resume-routing logic in app Sources/ instead of a SwiftPM package. Move the Codex executable-routing/canonicalization helpers into Packages/macOS/CMUXAgentLaunch (e.g. a small CodexResumeArgv/routing type) and keep app code as glue.
Cmux User-Facing Error Privacy ❌ Error Production wrapper error output at Resources/bin/cmux-codex-wrapper:675 tells users to set CMUX_CUSTOM_CODEX_PATH, exposing an internal env var name. Change the error to a generic missing-binary message and avoid naming CMUX_CUSTOM_CODEX_PATH in user-facing output; keep any hint in logs/docs.
Cmux Architecture Rethink ❌ Error CodexResumeTrustProbeCache adds a filesystem side channel with flock, shard files, and a DispatchSource wait loop to coalesce probes, which the rule forbids. Move probe dedup into one explicit async owner (e.g. a single actor or caller-side cache) and remove the cross-process lock/observer handoff files.
Docstring Coverage ⚠️ Warning Docstring coverage is 15.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (18 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed PASS: The new Sendable types are value-only or use an immutable FileManager with documented safety; no new MainActor-bound UI access or protocol isolation regressions.
Cmux Browser Automation Off-Main ✅ Passed The PR doesn’t touch the browser-automation routing files, and the patch shows no browser.* wait/mainActor routing changes.
Cmux Expensive Synchronous Load ✅ Passed No new heavy sync agent-history load was added; the new Codex trust probe is async/off-main via runJSONLinesProcess and CodexResumeTrustProbeCache.
Cmux No Hacky Sleeps ✅ Passed No changed production non-Swift runtime files use fixed sleeps/timers/polling; the only sleep found is a test helper in tests/test_codex_wrapper_resume_trust.py, which is out of scope.
Cmux Swift Concurrency ✅ Passed PR adds async/await and scoped withTaskGroup work; the only DispatchSource is a filesystem watcher boundary, with no new fire-and-forget Tasks or callback APIs.
Cmux Swift @Concurrent ✅ Passed PASS: the new async helpers are CLI-only and I found no new @concurrent, nonisolated async, or @MainActor misuse in the changed Swift code.
Cmux Swiftpm Lockfiles ✅ Passed Only Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CodexResumeTrustProbeCache.swift changed; no Package.swift, Package.resolved, .gitignore, workflow, or Xcode project edits.
Cmux Swift Logging ✅ Passed No added production Swift logging was found; diff adds no print/debugPrint/dump/NSLog/Logger statements outside allowed CLI/test output paths.
Cmux Full Internationalization ✅ Passed The only production diff is cache/probe logic with internal path tokens; no user-facing Swift, catalog, web, or metadata text was added or changed.
Cmux Swiftui State Layout ✅ Passed The only changed file is a non-UI cache helper; no SwiftUI views, ObservableObject/@published, GeometryReader, or render-time state mutation patterns are present.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed No touched file adds or changes standalone window code; no NSWindow/WindowGroup or cmuxAuxiliaryWindowIdentifiers changes were found.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source/test/config/script files; none are under artifact, temp, cache, or build-output paths.
Cmux No Test Or Debug Seam In Production Source ✅ Passed No new DEBUG/test-only seams appear in touched Sources files, and the widened Codex APIs are invoked by production callers, not just tests.
Cmux No Ambient Global State ✅ Passed New stateful behavior lives in injectable structs; added file-scope helpers are private, and no new mutable globals or singletons appear.
Title check ✅ Passed The title is concise and accurately reflects the main change: fixing Codex trust behavior after session restore.
Description check ✅ Passed The description covers the summary and verification well, but it does not follow the template exactly and omits demo video, review trigger, and checklist sections.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task-codex-resume-trust-gates

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes Codex trust-gate and rebinding behavior after session restore. It routes all Codex resume/fork commands through the cmux-codex-wrapper, injects an invocation-only untrusted project override after the resume subcommand (only when Codex has no persisted decision), and prevents stale PIDs from replacing active sessions by introducing processLeaseId and resumedProcessGenerationRelation.

  • Wrapper overhaul: PATH is split into a system-only search path for wrapper utilities and the user's original cmux_codex_lookup_path for Codex itself; project-boundary validation rejects project-controlled Codex and cmux binaries; resume/fork subcommand parsers are image-flag-safe and conservatively fail-closed on unknown options.
  • Trust probe: CodexResumeTrustPolicy + CodexResumeTrustProbeCache coalesce concurrent per-pane config/read probes behind sharded file locks and DispatchSource directory-change events (replacing the previous sleep-based retry); results expire after 5 seconds.
  • Rebind hardening: prepareCodexProcessEventIfFresh promotes the newer-generation wrapper PID before UserPromptSubmit/Stop hooks can race with the async SessionStart rebind; processLeaseId (UUID generated per wrapper invocation) disambiguates same-PID reuse across OS recycles.

Confidence Score: 4/5

Safe to merge with one fix: the new codexRepositoryDecisionRoots function calls a semaphore-blocking git subprocess from async code and should be made async before landing in a multi-pane restore path.

The trust-probe pipeline routes the git worktree lookup (codexRepositoryDecisionRoots) through the synchronous CLIProcessRunner.runProcess, which uses DispatchSemaphore.wait for up to 1 second per call. This runs inside the async codexResumeTrustOverride chain that fires on every concurrent pane restore, blocking a Swift cooperative thread each time. Everything else — the wrapper PATH split, project-boundary validation, CodexResumeTrustProbeCache async redesign, processLeaseId rebinding, and parser hardening — is well-structured and conservatively fail-closed.

Files Needing Attention: CLI/CMUXCLI+CodexFireAndForgetHooks.swift — codexRepositoryDecisionRoots needs an async subprocess call instead of CLIProcessRunner.runProcess.

Important Files Changed

Filename Overview
CLI/CMUXCLI+CodexFireAndForgetHooks.swift Adds emitCodexWrapperResumeArgs / codexResumeTrustOverride to fetch effective Codex project decisions and emit an invocation-only untrusted override. codexRepositoryDecisionRoots calls the synchronous (semaphore-blocking) CLIProcessRunner.runProcess from an async context, violating the blocking-runtime rule.
Resources/bin/cmux-codex-wrapper Major expansion: proper PATH isolation, project-boundary validation for codex and cmux binaries, process-lease-ID generation, resume/fork subcommand parsing with image-flag guards, and trust-override injection after resume arguments. Logic is thorough and conservatively fail-closed.
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CodexResumeTrustPolicy.swift Stateless policy struct for resume detection and trust override computation. Conservative unknown-option fail-closed parser, image-flag guard, TOML escaping, and canonicalProjectPath via realpath for /tmp → /private/tmp resolution all look correct.
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CodexResumeTrustProbeCache.swift Cross-process coalescing cache for concurrent resume probes. Previous sleep-based lock retry replaced with async DispatchSource directory-change events and ContinuousClock.sleep timeout; design is now cooperative-runtime-safe. Entry count and record size bounds are enforced.
CLI/CMUXCLI+Process.swift Adds async runJSONLinesProcess with structured task groups, cooperative timeout, and proper SIGKILL escalation without busy-sleep. Clean implementation; reap uses ContinuousClock.sleep not usleep.
CLI/cmux.swift Adds processLeaseId, prepareCodexProcessEventIfFresh, resumedProcessGenerationRelation, and allowResumedProcessReplacement to guard against stale PID rebinds and race conditions between wrapper-asynchronous SessionStart and earlier same-process Stop/UserPromptSubmit hooks.
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift Extends codex wrapper shell executable token generation with proper env grammar parsing, generatedSystemEnvPrefix flag, and VAR=value environment assignment handling; conservative and correct.
tests/test_codex_wrapper_resume_trust.py Comprehensive Python regression suite covering trust placement, image-flag guards, --cd scoping, wrapper routing, and executable resolution; good coverage of the shell wrapper's new behaviors.

Sequence Diagram

sequenceDiagram
    participant W as cmux-codex-wrapper
    participant C as cmux CLI (inject-resume-args)
    participant AS as Codex app-server
    participant CX as Codex (resumed)
    participant S as ClaudeHookSessionStore

    W->>W: find_real_codex() – project-boundary validated
    W->>W: cmux_codex_read_inject_args() – hook prefix args
    W->>C: hooks codex inject-resume-args
    C->>C: codexResumeTrustOverride()
    C->>AS: config/read (via runJSONLinesProcess, async)
    AS-->>C: effective projects map
    C->>C: CodexResumeTrustProbeCache.resolve()
    C-->>W: "NUL-separated [-c, projects={cwd={trust_level=untrusted}}]"
    W->>CX: exec codex [hook-args] resume id [-c trust-override] [--]
    CX->>S: "SessionStart (cmux_resume_rebind=true, processLeaseId)"
    S->>S: prepareCodexProcessEventIfFresh()
    S->>S: resumedProcessGenerationRelation → promote newer PID
    CX->>S: UserPromptSubmit / Stop (processLeaseId)
    S->>S: preparedMappedSession() → accept only same lease
Loading

Reviews (28): Last reviewed commit: "fix Codex resume race test harness" | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
CLI/cmux.swift (1)

1011-1037: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Require prior-PID liveness before accepting wrapper rebind

In CLI/cmux.swift:1022-1025, cmux_resume_rebind: true with incomingPID != record.pid bypasses activePromptDepth/activePromptTurnIds staleness checks before updating record.pid. The wrapper emits this flag directly from CMUX_CODEX_PID=$$ without checking whether the previously recorded record.pid has exited, so another live codex resume <same-session-id> invocation can silently steal ownership from the still-running pane. Grant this bypass only when the prior PID is absent or has exited (using an existing processExists-style check), or fail closed when the prior process is still alive.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CLI/cmux.swift` around lines 1011 - 1037, Update codexSessionStartIsStale so
allowResumedProcessReplacement can bypass active-turn staleness only when
record.pid is absent or no longer running; check the prior PID with the existing
processExists-style helper before returning false. If the prior process is still
alive, retain the normal staleness checks and fail closed against replacing its
ownership.

Source: Coding guidelines

Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift (1)

308-344: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a direct unit case for absolute codex path with no env prefix.

The new assertions cover bare codex and an absolute path with an existing env prefix, but not an absolute path with no prefix at all (e.g. parts: ["/opt/bin/codex", "resume", "SID"]). That exact shape is exercised indirectly via cmuxTests/SessionPersistenceTests.swift's testCodexResumeCommandDropsStartupImagesAndPlacesSessionBeforeFlags (environment: nil), which confirms the renderer correctly synthesizes a new env CMUX_CUSTOM_CODEX_PATH=... prefix. Adding it here too would isolate regressions in renderedPortableCodexResumeShellCommand itself without relying on the higher-level snapshot test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift`
around lines 308 - 344, The test renderedPortableCodexResumeShellCommand lacks
direct coverage for an absolute Codex executable without an existing env prefix.
Add an assertion using parts ["/opt/bin/codex", "resume", "SID"] that verifies
the renderer synthesizes the CMUX_CUSTOM_CODEX_PATH env assignment, routes the
executable through codexWrapperShellExecutableToken, and preserves the /bin/sh
-c quoting.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift`:
- Around line 1784-1842: Update
testCodexWrapperResumeSessionStartRebindsInterruptedActivePrompt to read the
session record from the codex-hook-sessions.json state file in context.root
instead of using readClaudeHookSession, which targets the Claude state file.
Preserve the existing assertions so they validate the session-start rebind
updates the written Codex record.

In
`@Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CodexResumeTrustPolicy.swift`:
- Around line 143-156: Add a guard in projectPathFromEffectiveCLITrustKey after
computing start and end to require start <= end before slicing, returning nil
for malformed or empty project segments. Preserve valid project-path parsing and
add a regression test in CodexResumeTrustPolicyTests for the
projects.trust_level override through undecidedProjectOverride.

In `@Resources/bin/cmux-codex-wrapper`:
- Line 307: Update the resume-session handling around cmux_codex_resume_payload
and the final exec_real_codex_passthrough path so unavailable hook injection
fails closed: either add the required resume hook arguments explicitly or
delegate to Codex’s trust picker. Ensure codex resume never launches with
missing hook args and an unhandled trust prompt when CMUX_CODEX_HOOK_CMUX_BIN or
CMUX_INJECT_CLI is unavailable.

---

Outside diff comments:
In `@CLI/cmux.swift`:
- Around line 1011-1037: Update codexSessionStartIsStale so
allowResumedProcessReplacement can bypass active-turn staleness only when
record.pid is absent or no longer running; check the prior PID with the existing
processExists-style helper before returning false. If the prior process is still
alive, retain the normal staleness checks and fail closed against replacing its
ownership.

In
`@Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift`:
- Around line 308-344: The test renderedPortableCodexResumeShellCommand lacks
direct coverage for an absolute Codex executable without an existing env prefix.
Add an assertion using parts ["/opt/bin/codex", "resume", "SID"] that verifies
the renderer synthesizes the CMUX_CUSTOM_CODEX_PATH env assignment, routes the
executable through codexWrapperShellExecutableToken, and preserves the /bin/sh
-c quoting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3df9e430-3b3d-4a76-9cc7-2436497e0e20

📥 Commits

Reviewing files that changed from the base of the PR and between 2c38c06 and 9ae21bf.

📒 Files selected for processing (14)
  • CLI/CMUXCLI+CodexFireAndForgetHooks.swift
  • CLI/cmux.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CodexResumeTrustPolicy.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/CodexResumeTrustPolicyTests.swift
  • Resources/bin/cmux-codex-wrapper
  • Sources/RestorableAgentSession.swift
  • Sources/SurfaceResumeCommandCanonicalizer+PortableAgentExecutable.swift
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
  • cmuxTests/SessionPersistenceResumeBindingTests.swift
  • cmuxTests/SessionPersistenceTests.swift
  • cmuxTests/SurfaceResumeBindingCodexUpdateCheckTests.swift
  • tests/test_codex_wrapper_resume_trust.py

Comment thread cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift Outdated
Comment thread Resources/bin/cmux-codex-wrapper
@cursor

cursor Bot commented Jul 24, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Resources/bin/cmux-codex-wrapper (1)

356-387: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve the resume-helper exit status before appending its output.

The consumer status from the process substitution is different from the subprocess status, so cmux_codex_read_resume_args can return success after capturing partial output. Use a status-preserving capture, such as mapfile -td '' cmux_codex_resume_args < <(...) || return $?, and reset the array on failure before appending ${cmux_codex_resume_args[@]}.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Resources/bin/cmux-codex-wrapper` around lines 356 - 387, The function
cmux_codex_read_resume_args must preserve the helper subprocess exit status
instead of relying on the process-substitution read loop. Replace both capture
loops with status-preserving array capture, such as mapfile, and return the
captured failure status; clear cmux_codex_resume_args when the capture fails so
the caller never appends partial output. Keep the existing socket/non-socket
command selection and success validation intact.
♻️ Duplicate comments (1)
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CodexResumeTrustPolicy.swift (1)

211-246: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Unresolved: Range crash on malformed projects.<key>.trust_level CLI override.

This is the same defect flagged on a previous commit of this PR and it is still present, unfixed. projectPathFromEffectiveCLITrustKey (lines 232-245) slices key[start..<end] using fixed offsets from the string's start/end without checking start <= end. When key == "projects.trust_level" (no path segment — e.g. a resume-scoped -c 'projects.trust_level="trusted"'), the literals "projects." and ".trust_level" overlap on the shared ., giving start == 9 > end == 8. Forming key[9..<8] traps at runtime.

This is reachable from production code: undecidedProjectOverride → argumentsContainProjectTrustDecision (line 37, scanning resume-scoped args) → projectTrustOverrideMatches (line 222-223) → this function — and is invoked from CMUXCLI+CodexFireAndForgetHooks.swift's codexResumeTrustOverride() on every Codex resume, for any -c/--config argument in the captured launch argv. A resume invocation like ["codex", "resume", "SID", "-c", "projects.trust_level=\"trusted\""] would crash the wrapper's hook-injection step this PR is meant to make unattended-safe.

No regression test for this scenario was added in CodexResumeTrustPolicyTests.swift either.

💥 Proposed fix: bound-check before slicing
     private func projectPathFromEffectiveCLITrustKey(_ key: String) -> String? {
-        guard key.hasPrefix("projects."),
-              key.hasSuffix(".trust_level") else {
+        let prefix = "projects."
+        let suffix = ".trust_level"
+        guard key.hasPrefix(prefix),
+              key.hasSuffix(suffix),
+              key.count >= prefix.count + suffix.count else {
             return nil
         }
-        let start = key.index(key.startIndex, offsetBy: "projects.".count)
-        let end = key.index(key.endIndex, offsetBy: -".trust_level".count)
+        let start = key.index(key.startIndex, offsetBy: prefix.count)
+        let end = key.index(key.endIndex, offsetBy: -suffix.count)
+        guard start <= end else { return nil }
         let path = String(key[start..<end])
         guard path.hasPrefix("/"),
               !path.contains(".") else {
             return nil
         }
         return path
     }

Consider adding a regression test in CodexResumeTrustPolicyTests.swift for arguments: ["codex", "resume", "SID", "-c", #"projects.trust_level="trusted""#] to lock in the fix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CodexResumeTrustPolicy.swift`
around lines 211 - 246, Prevent projectPathFromEffectiveCLITrustKey from forming
an invalid range when the projects prefix and trust_level suffix overlap or
leave no path segment; validate the computed boundaries before slicing and
return nil for malformed keys such as projects.trust_level. Add a regression
test in CodexResumeTrustPolicyTests.swift covering this resume argument and
verifying it does not crash and is not treated as a project override.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLI/cmux.swift`:
- Around line 1042-1056: Update resumedProcessGenerationIsNewer to corroborate
the start-time comparison with a process identity check using the existing
processName(for:) helper, accepting only incoming PIDs whose executable still
identifies them as codex; otherwise return false. Preserve the current timestamp
ordering logic after identity validation so unrelated PID reuse cannot authorize
resumed-process replacement.

In `@tests/test_codex_wrapper_resume_trust.py`:
- Around line 101-138: Extend the resume-wrapper tests around inject-resume-args
to cover helper failures after no output and after partial output, asserting the
original arguments remain unchanged without a malformed trust suffix. Add cases
for persisted explicit trust and command-line explicit trust decisions,
asserting neither path appends TRUST_OVERRIDE; reuse the existing run_wrapper
setup and argument assertions.

---

Outside diff comments:
In `@Resources/bin/cmux-codex-wrapper`:
- Around line 356-387: The function cmux_codex_read_resume_args must preserve
the helper subprocess exit status instead of relying on the process-substitution
read loop. Replace both capture loops with status-preserving array capture, such
as mapfile, and return the captured failure status; clear cmux_codex_resume_args
when the capture fails so the caller never appends partial output. Keep the
existing socket/non-socket command selection and success validation intact.

---

Duplicate comments:
In
`@Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CodexResumeTrustPolicy.swift`:
- Around line 211-246: Prevent projectPathFromEffectiveCLITrustKey from forming
an invalid range when the projects prefix and trust_level suffix overlap or
leave no path segment; validate the computed boundaries before slicing and
return nil for malformed keys such as projects.trust_level. Add a regression
test in CodexResumeTrustPolicyTests.swift covering this resume argument and
verifying it does not crash and is not treated as a project override.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2c141b86-6dbb-4f84-bd8c-9b9c7f7eca73

📥 Commits

Reviewing files that changed from the base of the PR and between 9ae21bf and b57d689.

📒 Files selected for processing (11)
  • CLI/CMUXCLI+CodexFireAndForgetHooks.swift
  • CLI/cmux.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CodexResumeTrustPolicy.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/CodexResumeTrustPolicyTests.swift
  • Resources/bin/cmux-codex-wrapper
  • Sources/RestorableAgentSession.swift
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
  • cmuxTests/RestorableCodexForkTagTests.swift
  • tests/test_codex_wrapper_resume_trust.py

Comment thread CLI/cmux.swift Outdated
Comment thread tests/test_codex_wrapper_resume_trust.py
Comment thread CLI/CMUXCLI+CodexFireAndForgetHooks.swift
@cursor

cursor Bot commented Jul 28, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Jul 28, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants