Skip to content

fix: harden Codex auth and backend task startup#521

Draft
robinbraemer wants to merge 6 commits into
kunchenguid:mainfrom
robinbraemer:fm/codex-auth-boundary-f4
Draft

fix: harden Codex auth and backend task startup#521
robinbraemer wants to merge 6 commits into
kunchenguid:mainfrom
robinbraemer:fm/codex-auth-boundary-f4

Conversation

@robinbraemer

Copy link
Copy Markdown

Intent

Fix Firstmate's Codex CLI launch auth boundary so every Firstmate-launched Codex crewmate, scout, and secondmate preserves HOME=/Users/robin and explicitly unsets ambient CODEX_HOME at the Codex process boundary. The fix must be one-owner in fm-spawn's Codex template, leave raw launch-command escape hatches and all non-Codex harnesses unchanged, and preserve model, effort, autonomy, notify/turn-end, quoting, and secondmate behavior. Add regression coverage for hostile ambient CODEX_HOME across ship, scout, batch, and secondmate launches plus a safe fake-process smoke. Do not modify no-mistakes, Orca, CodexBar, Pi/router credentials, token files, active servers, or healthy sessions. Keep operator guidance generic with no product-specific auth or session paths.

What Changed

  • Captain, Firstmate now unsets ambient CODEX_HOME for Codex ship, scout, batch, and secondmate launches while preserving existing launch options and raw-command escape hatches.
  • Recover Zellij task tabs when creation returns no ID and wait for delayed terminal panes to become available.
  • Add regression coverage for Codex auth isolation and backend startup races, with matching Codex, Herdr, and Zellij guidance updates.

Risk Assessment

✅ Low: Captain, the change is narrowly scoped to the Codex process boundary, preserves existing launch behavior, and correctly resolves both prior findings without introducing new material risk.

Testing

The supplied full-suite baseline was successful; fresh focused spawn and secondmate suites also passed. An end-to-end fake-process smoke exercised ship, scout, two batch children, and secondmate launches, proving each preserved HOME=/Users/robin, unset hostile CODEX_HOME, and retained expected options and notification behavior, while raw-command and Claude controls remained unchanged. Evidence was retained, temporary fixtures were removed, and the worktree is clean.

Evidence: Codex auth-boundary end-to-end smoke transcript

PASS: 5 Codex child processes preserved HOME=/Users/robin and received CODEX_HOME unset; raw and Claude controls preserved the ambient variable unchanged.

Firstmate Codex auth-boundary end-to-end smoke
target_commit=ff336b23a26d166d07b6e1594c8a20d1d1d5167b
invoking_HOME=/Users/robin
ambient_CODEX_HOME=/hostile/runtime/codex-home

== ship spawn ==
spawned evidence-ship-z1 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate-evidence:fm-evidence-ship-z1 worktree=/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/worktree
captured_command=env -u CODEX_HOME codex --model 'gpt-5' -c 'model_reasoning_effort="high"' --dangerously-bypass-approvals-and-sandbox -c "notify=[\"bash\",\"-c\",\"touch '/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/state/evidence-ship-z1.turn-ended'\"]" "$(cat '/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/data/evidence-ship-z1/brief.md')"
== scout spawn ==
spawned evidence-scout-z2 harness=codex kind=scout mode=no-mistakes yolo=off window=firstmate-evidence:fm-evidence-scout-z2 worktree=/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/worktree
captured_command=env -u CODEX_HOME codex --dangerously-bypass-approvals-and-sandbox -c "notify=[\"bash\",\"-c\",\"touch '/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/state/evidence-scout-z2.turn-ended'\"]" "$(cat '/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/data/evidence-scout-z2/brief.md')"
== batch spawn ==
spawned evidence-batch-a-z3 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate-evidence:fm-evidence-batch-a-z3 worktree=/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/worktree
spawned evidence-batch-b-z4 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate-evidence:fm-evidence-batch-b-z4 worktree=/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/worktree
captured_command[1]=env -u CODEX_HOME codex --model 'gpt-5' -c 'model_reasoning_effort="high"' --dangerously-bypass-approvals-and-sandbox -c "notify=[\"bash\",\"-c\",\"touch '/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/state/evidence-batch-a-z3.turn-ended'\"]" "$(cat '/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/data/evidence-batch-a-z3/brief.md')"
captured_command[2]=env -u CODEX_HOME codex --model 'gpt-5' -c 'model_reasoning_effort="high"' --dangerously-bypass-approvals-and-sandbox -c "notify=[\"bash\",\"-c\",\"touch '/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/state/evidence-batch-b-z4.turn-ended'\"]" "$(cat '/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/data/evidence-batch-b-z4/brief.md')"
== secondmate spawn ==
spawned evidence-sm-z7 harness=codex kind=secondmate mode=secondmate yolo=off window=firstmate-evidence:fm-evidence-sm-z7 worktree=/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/secondmate-home
captured_command=FM_ROOT_OVERRIDE= FM_STATE_OVERRIDE= FM_DATA_OVERRIDE= FM_PROJECTS_OVERRIDE= FM_CONFIG_OVERRIDE= FM_HOME='/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/secondmate-home' env -u CODEX_HOME codex --model 'gpt-5' -c 'model_reasoning_effort="high"' --dangerously-bypass-approvals-and-sandbox "$(cat '/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/secondmate-home/data/charter.md')"
== raw-command control ==
spawned evidence-raw-z5 harness=custom-agent kind=ship mode=no-mistakes yolo=off window=firstmate-evidence:fm-evidence-raw-z5 worktree=/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/worktree
captured_command=custom-agent --flag
== non-Codex control ==
spawned evidence-claude-z6 harness=claude kind=ship mode=no-mistakes yolo=off window=firstmate-evidence:fm-evidence-claude-z6 worktree=/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/worktree
captured_command=CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false claude --dangerously-skip-permissions --model 'sonnet' --effort 'high' "$(cat '/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/data/evidence-claude-z6/brief.md')"

== observed child-process environments ==
role=ship
process=codex
HOME=/Users/robin
CODEX_HOME=unset
FM_HOME=unset
ARGV= <--model> <gpt-5> <-c> <model_reasoning_effort="high"> <--dangerously-bypass-approvals-and-sandbox> <-c> <notify=["bash","-c","touch '/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/state/evidence-ship-z1.turn-ended'"]> <evidence brief for evidence-ship-z1>
role=scout
process=codex
HOME=/Users/robin
CODEX_HOME=unset
FM_HOME=unset
ARGV= <--dangerously-bypass-approvals-and-sandbox> <-c> <notify=["bash","-c","touch '/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/state/evidence-scout-z2.turn-ended'"]> <evidence brief for evidence-scout-z2>
role=batch-1
process=codex
HOME=/Users/robin
CODEX_HOME=unset
FM_HOME=unset
ARGV= <--model> <gpt-5> <-c> <model_reasoning_effort="high"> <--dangerously-bypass-approvals-and-sandbox> <-c> <notify=["bash","-c","touch '/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/state/evidence-batch-a-z3.turn-ended'"]> <evidence brief for evidence-batch-a-z3>
role=batch-2
process=codex
HOME=/Users/robin
CODEX_HOME=unset
FM_HOME=unset
ARGV= <--model> <gpt-5> <-c> <model_reasoning_effort="high"> <--dangerously-bypass-approvals-and-sandbox> <-c> <notify=["bash","-c","touch '/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/home/state/evidence-batch-b-z4.turn-ended'"]> <evidence brief for evidence-batch-b-z4>
role=secondmate
process=codex
HOME=/Users/robin
CODEX_HOME=unset
FM_HOME=/private/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work/secondmate-home
ARGV= <--model> <gpt-5> <-c> <model_reasoning_effort="high"> <--dangerously-bypass-approvals-and-sandbox> <secondmate charter evidence>
role=raw
process=custom-agent
HOME=/Users/robin
CODEX_HOME=set:/hostile/runtime/codex-home
ARGV= <--flag>
role=claude
process=claude
HOME=/Users/robin
CODEX_HOME=set:/hostile/runtime/codex-home
ARGV= <--dangerously-skip-permissions> <--model> <sonnet> <--effort> <high> <evidence brief for evidence-claude-z6>

PASS: 5 Codex child processes preserved HOME=/Users/robin and received CODEX_HOME unset; raw and Claude controls preserved the ambient variable unchanged.
- Outcome: 🔧 1 issue found → auto-fixed (3) ✅ across 4 runs (1h53m0s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 2 issues found → auto-fixed ✅
  • 🚨 .agents/skills/harness-adapters/SKILL.md:156 - Shared operator guidance hard-codes HOME=/Users/robin and adds Orca/Pi credential rules. This reusable skill should instead say to preserve the invoking user's existing HOME while unsetting CODEX_HOME, without unrelated product-specific authentication guidance.
  • 🚨 .agents/skills/harness-adapters/SKILL.md:157 - The new rule requires the auth boundary for resume/recovery, but the concrete instruction at line 153 remains bare codex resume &lt;session-id&gt;. With hostile ambient CODEX_HOME, that command uses the wrong auth/session state; make the command explicitly boundary-safe, such as env -u CODEX_HOME codex resume &lt;session-id&gt;.

🔧 Fix: Captain, generalize Codex auth-boundary guidance
✅ Re-checked - no issues remain.

🔧 **Test** - 1 issue found → auto-fixed (3) ✅
  • 🚨 tests failed with exit code 1
  • command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"

🔧 Fix: Captain: fix bootstrap fixture and Zellij creation races
1 error still open:

  • 🚨 tests failed with exit code 1
  • command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"

🔧 Fix: Captain: stabilize Herdr and Zellij startup races
1 error still open:

  • 🚨 tests failed with exit code 1
  • command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"

🔧 Fix: Captain: stabilize real-Herdr fixture shell readiness
✅ Re-checked - no issues remain.

  • command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"
  • Pre-run baseline supplied by the runner: command -v tmux &gt;/dev/null || { echo &#34;tmux is required for e2e tests&#34; &gt;&amp;2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo &#34;== $t ==&#34;; bash &#34;$t&#34; || rc=1; done; exit &#34;$rc&#34;
  • bash tests/fm-spawn-dispatch-profile.test.sh
  • bash tests/fm-secondmate-harness.test.sh
  • set -o pipefail; ./.tmp-codex-auth-boundary-smoke.sh | tee /var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/codex-auth-boundary-smoke.txt
  • test -s "$artifact"; test ! -e /var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KXDB531RZJT9VR5GAA6Z7JMB/.codex-auth-smoke-work; sed -n '1,240p' "$artifact"
  • git status --short; git diff --stat; git diff --cached --stat; git rev-parse HEAD
⏭️ **Document** - skipped
  • ⚠️ bin/fm-spawn.sh:836 - Captain, production Herdr spawn sends treehouse get before proving the new pane shell is ready; fixing this runtime race requires executable changes outside the documentation-only scope.
✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@robinbraemer robinbraemer marked this pull request as draft July 13, 2026 13:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant