Skip to content

ci: platform-prod-secrets mints a fresh link keyset and drops the JWT copy - #32593

Merged
teamleaderleo merged 3 commits into
feat-cmux-nextfrom
lane/platform-prod-link-keyset
Nov 2, 2026
Merged

teamleaderleo merged 3 commits into
feat-cmux-nextfrom
lane/platform-prod-link-keyset

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

What. .github/workflows/platform-prod-secrets.yml (dispatch-only, environment cmux-next-production) now puts two secrets on the cmux-platform-production Worker instead of three:

  • CLOUD_LINK_SIGNING_KEYS: when the Worker lacks it, the job mints a fresh value with the new scripts/cmux-next/release/mint-link-keyset.mjs and pipes it into wrangler secret put. The environment's secrets.CLOUD_LINK_SIGNING_KEYS is no longer read.
  • CLOUD_FREESTYLE_API_KEY: unchanged (from the environment's FREESTYLE_API_KEY, only when missing).
  • JWT_PRIVATE_JWK: dropped from env and the loop.

Why. The platform takes over NEXT Cloud's CloudDO with a fresh namespace. Production has never issued a Cloud link token, and link tokens are verified only by Cloud VMs, against the keyset the platform itself serves (the bind answer and GET /v1/cloud/keyset, both forwarded to the platform). Nothing verifies a link across Workers, so a fresh keyset minted for the platform is correct and cmux-api's copy (a Worker secret only) is not needed. The platform verifies cmux-api's install tokens against cmux-api's public JWKS (a separate cmux-platform change), so it needs no JWT_PRIVATE_JWK copy.

Format. {"active":"<kid>","keys":{"<kid>":{"kty":"OKP","crv":"Ed25519","x":...,"d":...,"kid":"<kid>"}}}, kid production-<YYYY-MM-DD> (UTC), matching /^[A-Za-z0-9._-]{1,64}$/. This is what parseSigningKeys accepts in backend/apps/api/src/link-token.ts (and the identical cmux-platform parser). One kid with no published_at signs at once (signingKid), which is what we want since no production VM holds an older keyset.

Guarantees.

  • Never prints or writes the value: the script writes only to stdout; the job holds it in a shell variable and pipes it to wrangler's stdin. No echo, no file, no set -x.
  • Never overwrites: each name is put only when wrangler secret list does not show it.
  • Fails closed: set -euo pipefail, the mint is a command substitution (a failed mint stops the job), and an empty value is refused before anything is put. The script itself exits non-zero, printing nothing, on a bad kid or an unexpected JWK shape.
  • runs-on is unchanged. The checkout is sparse (just the mint script) with persist-credentials: false.

Tests.

  • New backend/apps/api/test-node/link-keyset-mint.test.ts (Node vitest, runs in the backend workflow's test:node step; the mint script was added to that workflow's paths): parseSigningKeys accepts the output, exactly one kid, it is the active kid, signingKid(keys, Date.now()) returns it, publicKeyset has no d, two runs differ, and a bad prefix exits 2 with empty stdout. Passed locally (3/3).
  • python3 tests/test_ci_linux_single_size.py, tests/test_ci_fork_runner_routing.py, tests/test_ci_no_single_size_pins.py, tests/test_ci_checkout_network_diagnostics.py, tests/test_ci_actionlint_covers_every_workflow.py: all pass.

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

Reworks platform-prod-secrets.yml so cmux-platform-production gets a freshly minted Cloud link signing keyset instead of a copy from cmux-next-production, and drops JWT_PRIVATE_JWK from the workflow.

Production never issued a link token, and link tokens are verified only by Cloud VMs against the keyset the platform itself serves. The platform verifies cmux-api's install tokens against cmux-api's public JWKS, so it needs no private JWK copy.

  • scripts/cmux-next/release/mint-link-keyset.mjs mints a single Ed25519 kid (production-<UTC date>) that signs immediately; the workflow pipes its stdout into wrangler secret put only when the Worker lacks the secret.
  • The minted value is never printed or written to disk, and a failed or empty mint exits the job before anything is put. Existing secrets are never overwritten. CLOUD_FREESTYLE_API_KEY is unchanged.
  • The secret list is re-read right before each put, and a failed or unreadable list stops the job instead of reading as "absent", narrowing the race window to the seconds of one put.
  • New link-keyset-mint.test.ts runs in the backend test:node step and validates the keyset against parseSigningKeys, signingKid, and publicKeyset; the mint script was added to that workflow's trigger paths.
  • The workflow is dispatch-only, so the change applies on the next dispatch from feat-cmux-next.

Written for commit 6cab35d. Summary will update on new commits.

View guided diff Turn on auto-fix

… copy

cmux-platform-production takes over NEXT Cloud's CloudDO with a fresh namespace.
Production never issued a link token and only Cloud VMs verify them, against the
keyset the platform itself serves, so the job mints a fresh CLOUD_LINK_SIGNING_KEYS
(scripts/cmux-next/release/mint-link-keyset.mjs) and pipes it into wrangler when the
Worker lacks it. JWT_PRIVATE_JWK is dropped: the platform verifies cmux-api's install
tokens against cmux-api's public JWKS. test-node/link-keyset-mint.test.ts checks the
minted value against parseSigningKeys, signingKid and publicKeyset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-006ebbba01a09f9367e7
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 6cab35d: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr32593 -f ref=lane/platform-prod-link-keyset -f platform=macos -f backend_mode=local

Shipped in:

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
…put, failing closed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-006ebbba01a09f9367e7
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol high, sweep, via the review router; full diff from merge base ddcaf92 to this head): BLOCK at 77d9d50

[P2] [blocking] .github/workflows/platform-prod-secrets.yml:59 - The initial secret listing is stale when the workflow reaches secret put; a concurrent writer can add either secret after the check, causing this job to overwrite it, potentially invalidating active link tokens or replacing the production API key. - Re-read the Worker secret list immediately before each put and skip when the name now exists.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol high): SHIP at e2abf03

First pass at 77d9d50 blocked on the non-atomic list-then-put; the delta re-reads the list right before each put and makes that check fail closed (Cloudflare offers no create-if-absent). Re-review of the delta: narrowed race acceptable for this dispatch-only one-off; mint format matches parseSigningKeys, no value reaches logs or disk, empty or failed mint puts nothing, runs-on unchanged, test wired into backend.yml test:node.

Follow-ups: none

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol high): SHIP at 6cab35d

Carried from the SHIP at e2abf03: the new head only changes how the test resolves the mint script path (tsc fix); same reviewer confirmed the delta.

Follow-ups: none

@teamleaderleo
teamleaderleo merged commit c9120df into feat-cmux-next Nov 2, 2026
167 of 171 checks passed
@teamleaderleo
teamleaderleo deleted the lane/platform-prod-link-keyset branch November 2, 2026 22:01

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 6cab35dc Deployed Nov 2, 2026 by teamleaderleo via cmux-tui tree preflight #102707
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant