cloud-journey: Codex in stub mode, the stub on a free port, backend.yml watches the journey inputs

Merged
TE
2d ago
+96-31

This PR does three things for the Cloud journey (scripts/cmux-next/cloud-journey.ts):

  • the two Codex review follow-ups from #35301;
  • Codex wiring for the stub mode;
  • the login copy for either provider.

What changes

  • Stub on a free port: --port 0. The journey reads the port from the stub's ready file, so a busy port can no longer fail the hourly run.
  • backend.yml path filters now include Packages/macOS/CmuxNext/Sources/CmuxNextCloudCredentials/** and tests/fixtures/model-stub/**, the journey's two other inputs.
  • --agent codex with --model stub:
    • The journey passes a made-up ChatGPT sign-in (auth.json with unsigned JWTs and a fresh last_refresh) through the same login copy the Mac uses, with provider codex.
    • It checks the sign-in with the app's own rules (CloudCredentialTransfer.validate).
    • It points a Codex model provider (requires_openai_auth = true) at the shared stub's /v1.
    • It checks that every /v1/responses request carried the forwarded access token.
    • A real Codex run takes CODEX_AUTH_JSON. No CI secret holds one, so the scheduled jobs stay Claude-only.

Observed / Not run

  • Production, Claude, stub mode (local run): every step passed through the stub check. The reply was "Stub reply a93edeb89372. The tool printed a93edeb89372-tool." It came from 4 model requests, each carrying the forwarded login, and the stub ran on a port it chose itself. connect is still red on production: link_token answers auth.forbidden "the original receiving VM has no live ready attempt". That red is not from this PR.

  • Production, Codex, stub mode (local run): pass Codex login passed, and the launcher sees the own login. Every Codex request reached the stub with the same credential hash. The turn is not green, for two reasons:

    1. Codex cannot decode the shared stub's GET /v1/models answer ("failed to decode models response"), since it expects Codex's own models schema. It then sends the turn with no tools, and the stub replies "Stub side reply.".
    2. With a ChatGPT sign-in, Codex also calls chatgpt.com plugin endpoints with that sign-in. Those calls get a 401, since the token is made up. A login-free check for Codex therefore also needs plugins off.

    Both are follow-ups, for the shared stub's owner and the Codex config.

  • One flaky run: the first Codex run failed preflight on a fresh machine. The same preflight passed on a second machine and on retry.

  • Not run here: bun test, since agents don't run tests on this Mac. The new helpers were checked with bun -e, and actionlint is clean.

Changelog

none

Agent session: agent session

🤖 Generated with Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Adds Codex support to the Cloud journey's stub mode, and fixes two follow-ups from #35301.

  • Stub on a free port: --port 0 lets the stub choose its port, which the journey reads from the stub's ready file; a busy port can no longer fail the hourly run.
  • backend.yml path filters now include Packages/macOS/CmuxNext/Sources/CmuxNextCloudCredentials/** and tests/fixtures/model-stub/**, the journey's two other inputs.
  • --agent codex with --model stub: passes a made-up ChatGPT sign-in (auth.json with unsigned JWTs) through the app's own login copy and validation, points a Codex model provider (requires_openai_auth = true) at the shared stub, and checks every /v1/responses request carried the forwarded token. A real Codex run reads CODEX_AUTH_JSON; no CI secret holds one, so scheduled jobs stay Claude-only.

Known limitations

  • Codex cannot decode the stub's GET /v1/models answer, so it sends the turn with no tools and the stub replies with its side reply.
  • With a ChatGPT sign-in, Codex calls chatgpt.com plugin endpoints, which return 401 since the token is made up; a login-free Codex check also needs plugins off.