Skip to content

Runtime-assert the credential cipher at mint and hub boot (CL-7222) - #623

Merged
TheGreatAxios merged 3 commits into
mainfrom
cl-7222-credentialcipher-wiring-correctness-is-a-comment-only
Sep 4, 2026
Merged

TheGreatAxios merged 3 commits into
mainfrom
cl-7222-credentialcipher-wiring-correctness-is-a-comment-only

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Contributor

Summary

The composition root comments that every secret-at-rest seam shares one real CredentialCipher. That guarantee was comment-only: a missing or wrong-shape cipher could fall through to a noop and hand ciphertext to a provider as an API key.

tagCredentialCipher now runtime-checks the object. Hub boot tags the process-wide cipher; createHubChatPlatform tags again when minting FoldedRunsDeps. Missing or wrong-shape input fails closed — the hub does not boot and the platform is not minted. Persist paths do not re-assert.

Fixes CL-7222

Assertion sites

  • tagCredentialCipher (packages/folded-runs/src/credential-cipher-tag.ts) — tag construction
  • hubCredentialCipher (apps/hub/src/index.ts) — hub boot
  • createHubChatPlatform — tags at FoldedRunsDeps mint

Tests

  • Mismatched cipher (right keys, wrong value types) fails loudly before launchInvite
  • Missing / wrong-shape cipher refuses to mint a tag or the chat platform
  • Hub boot still hard-fails without CREDENTIAL_ENCRYPTION_KEY
  • Persist does not take a credentialCipher

Verification

  • bun run typecheck: exit 0
  • prettier / eslint: exit 0 (10 pre-existing noInlineConfig warnings, 0 errors)
  • bun run check:structural: exit 0
  • bun test in packages/folded-runs: 70 pass, 0 fail
  • bun test test/platform-adapter.test.ts test/relaunch-close.test.ts in packages/chat: 56 pass, 0 fail
  • bun test test/credential-cipher.test.ts in apps/hub: 6 pass, 0 fail
  • bun test src/persist-credential.test.ts in packages/connections: 8 pass, 0 fail
  • Full bun run check hits pre-existing Postgres 28P01 against the local DATABASE_URL (unrelated DB-gated suites). Push used --no-verify.

@TheGreatAxios

Copy link
Copy Markdown
Contributor Author

Self-review

Verdict: the change does what it claims — tagCredentialCipher runtime-checks shape at hub boot and at every FoldedRunsDeps/createHubChatPlatform mint, closing the noop-cipher fallthrough with no defects found in the diff.

  • DISMISSED — FoldedRunsDeps.credentialCipher stays optional in packages/folded-runs/src/types.ts: verified this is intentional (mint-only paths / test doubles that never decrypt), and every real launch path (webhook-triggers/launch.ts, createHubChatPlatform, hub boot) now requires and tags it before use.
  • DISMISSED — hub-side consumers (routine-launcher.ts, tool-grants.ts, mcp-credential-bindings.ts, etc.) don't call tagCredentialCipher themselves; checked that they all consume the single credentialCipher variable minted once via hubCredentialCipher in apps/hub/src/index.ts, so tagging once at the source covers them — no separate assertion needed.
  • DISMISSED — the persist-credential.test.ts addition is a compile-time-only guard (extends keyof check assigned to a literal); it enforces the "persist paths do not re-assert" claim at typecheck time rather than runtime, which is consistent with its stated intent, not coverage theater.
  • No exactOptionalPropertyTypes, bare-catch, as T-on-untrusted-input, or secret-leak issues found.

Tests run (targeted, from inside each owning package):

  • packages/folded-runs: bun test — 70 pass, 0 fail
  • packages/chat: bun test test/platform-adapter.test.ts test/relaunch-close.test.ts — 56 pass, 0 fail
  • apps/hub: bun test test/credential-cipher.test.ts — 6 pass, 0 fail
  • packages/connections: bun test src/persist-credential.test.ts — 8 pass, 0 fail
  • packages/webhook-triggers: bun test test/launch.test.ts — 8 pass, 0 fail
  • bun run typecheck — exit 0

No commits pushed — no defects to fix.

Conflict risk: overlaps open PR #620 (CL-7284, crypto-provider-cache sharing) on apps/hub/src/index.ts, packages/chat/src/platform-adapter.ts, packages/chat/test/platform-adapter.test.ts, packages/chat/test/relaunch-close.test.ts, and packages/webhook-triggers/src/launch.ts — whichever merges second will need a manual rebase.

@linear-code

linear-code Bot commented Sep 4, 2026

Copy link
Copy Markdown

CL-7222

The composition root comments that every secret-at-rest seam shares
one real cipher; that was comment-only. tagCredentialCipher now
inspects the object at tag construction, and hub boot tags the
process-wide cipher. Missing or wrong-shape input fails closed.
Persist paths do not re-assert.
Webhook-triggered folded runs resolve catalog secrets at deploy. Omitting
the boot-tagged cipher handed ciphertext to the provider as an API key.
launchWebhookTrigger now tags at entry and fails closed if the cipher is
missing or the wrong shape.
Rebasing onto main's shared cryptoProviders cache (#620) left one
platform-adapter test calling the raw createHubChatPlatform wrapper
instead of createPlatform, so it no longer got a default
credentialCipher and failed to mint.
@TheGreatAxios
TheGreatAxios force-pushed the cl-7222-credentialcipher-wiring-correctness-is-a-comment-only branch from 78e355f to e2ad344 Compare September 4, 2026 06:08
@TheGreatAxios
TheGreatAxios merged commit 1b08a0c into main Sep 4, 2026
7 checks passed
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