feat(stack): protect-ffi 0.26.0 + auth 0.39 OidcFederationStrategy (stacked on #496)#497
feat(stack): protect-ffi 0.26.0 + auth 0.39 OidcFederationStrategy (stacked on #496)#497coderdan wants to merge 6 commits into
Conversation
protect-ffi 0.25.0 is a breaking release for both entries: WASM (@cipherstash/stack/wasm-inline): - newClient(strategy, opts) -> newClient(opts) with strategy nested. - Config takes a workspaceCrn instead of region; the AccessKeyStrategy region is derived from the CRN (crn:<region>:<workspace-id>). CS_REGION is no longer consulted; set CS_WORKSPACE_CRN. Node: - serviceToken removed from the encrypt/decrypt/query option types (and the CtsToken export). The per-operation CTS token is no longer forwarded; lock contexts still travel as lockContext.identityClaim. Public LockContext/identify() API is unchanged. Adds offline lock-context wiring tests (mock protect-ffi) asserting every operation forwards identityClaim and never sends serviceToken, plus extractRegionFromCrn unit tests. Updates the Deno e2e test, Supabase example, and wasm-e2e CI job to CS_WORKSPACE_CRN.
protect-ffi 0.25 lets newClient take an AuthStrategy (any
{ getToken(): Promise<{ token }> } object). Expose it on the Node
Encryption client via config.strategy: when supplied, getToken() is
invoked on every ZeroKMS request, taking precedence over the
credentials-derived default (clientKey is still used for encryption).
Omitting it preserves existing credentials/env behaviour.
Kept on init (rather than a separate initWithStrategy) so a future
keyProvider option can land in the same config. AuthStrategy is
re-exported from @cipherstash/stack for consumers to type their own.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
🦋 Changeset detectedLatest commit: 1efdd03 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…lace lock-context ceremony
Supersedes the 0.25.0 bump with protect-ffi 0.26.0 (API-identical; internal
fixes only) and @cipherstash/auth 0.39.0, and uses the new
OidcFederationStrategy to replace the lock-context token ceremony with a
strategy-based approach for identity-bound encryption.
- bump @cipherstash/protect-ffi 0.25.0 -> 0.26.0; @cipherstash/auth catalog
(and platform entries) 0.38.0 -> 0.39.0; e2e/wasm/deno.json pins; lockfile
- .withLockContext() now accepts a plain { identityClaim } (or a LockContext)
and resolves the claim synchronously — no CTS token, no identify() call
- deprecate LockContext.identify() / getLockContext(); the client strategy
(OidcFederationStrategy) now handles user token acquisition
- re-export OidcFederationStrategy/AccessKeyStrategy/AutoStrategy/
DeviceSessionStrategy from @cipherstash/stack, and the strategies from
@cipherstash/stack/wasm-inline
- broaden the wasm-inline config strategy type to accept OidcFederationStrategy
- declare @cipherstash/auth platform optionalDependencies (auth ships them as
optional peer deps, not auto-installed) so the re-exported Node strategies
resolve their native binding for consumers
- update wiring/init/live tests, JSDoc, AGENTS.md, README, changeset
…Dependencies The optionalDependencies block added to packages/stack/package.json was not reflected in pnpm-lock.yaml, breaking `pnpm install --frozen-lockfile` in CI.
@cipherstash/auth 0.39 changed AccessKeyStrategy.create(region, accessKey) to AccessKeyStrategy.create(workspaceCrn, accessKey) — it derives the region from the CRN itself. The wasm-inline resolveStrategy still passed a derived region, so the Deno WASM e2e failed with 'Invalid CRN: <region>'. Pass the CRN directly and drop the now-obsolete extractRegionFromCrn helper + tests. (OidcFederationStrategy.create still takes region + workspaceId.)
…ext tests
- index.ts: @cipherstash/auth's Node entry is CJS with `module.exports =
{ ...native }`; the spread defeats cjs-module-lexer so a static
`export { AccessKeyStrategy } from` throws 'Named export not found' under
real Node ESM (the E2E cli failure). Default-import the module (which is
module.exports at runtime, all names present) and re-export each binding
explicitly, with instance types for the strategy classes.
- encrypt-query / encrypt-query-searchable-json tests + fixtures: the ops no
longer call getLockContext(); .withLockContext() takes a plain
{ identityClaim }. createMockLockContext() now returns that shape; dropped
the getLockContext spy assertions and the obsolete failure / null-context
cases (resolveLockContext is synchronous and cannot fail).
There was a problem hiding this comment.
Pull request overview
This PR upgrades Stack’s Protect/Auth dependencies and updates the identity-bound encryption flow to match protect-ffi ≥0.25’s removal of per-operation serviceToken, moving authentication to a client-level config.strategy (notably via OidcFederationStrategy) while keeping lock context as a pure { identityClaim } value.
Changes:
- Bump
@cipherstash/protect-ffito0.26.0and@cipherstash/authto0.39.0, updating workspace config to useworkspaceCrnconsistently (including/wasm-inline). - Replace the lock-context “token ceremony” with a synchronous lock-context resolution (
.withLockContext({ identityClaim })orLockContext), and stop forwardingserviceTokenin all operations. - Re-export auth strategies from
@cipherstash/stack(and selected ones from/wasm-inline), add wiring tests to ensureidentityClaimis forwarded andserviceTokenis never sent.
Reviewed changes
Copilot reviewed 34 out of 35 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| README.md | Updates identity-aware encryption docs to the strategy-based approach. |
| pnpm-workspace.yaml | Bumps @cipherstash/auth* catalog versions to 0.39.0. |
| pnpm-lock.yaml | Regenerated lockfile reflecting new auth/protect versions and optional deps. |
| packages/stack/src/wasm-inline.ts | Switches WASM config to workspaceCrn, supports OIDC strategy, updates protect-ffi wasm newClient call shape, and re-exports strategies. |
| packages/stack/src/types.ts | Re-exports protect-ffi AuthStrategy type and adds ClientConfig.strategy. |
| packages/stack/src/types-public.ts | Exposes AuthStrategy in public type surface. |
| packages/stack/src/index.ts | Re-exports auth strategies from @cipherstash/auth in an ESM-compatible way. |
| packages/stack/src/identity/index.ts | Adds LockContextInput + resolveLockContext, deprecates old token ceremony methods, makes CTS token optional in response type. |
| packages/stack/src/encryption/operations/encrypt.ts | Uses synchronous lock-context resolution; removes serviceToken forwarding. |
| packages/stack/src/encryption/operations/encrypt-query.ts | Uses synchronous lock-context resolution; removes serviceToken forwarding. |
| packages/stack/src/encryption/operations/encrypt-model.ts | Uses synchronous lock-context resolution and passes Context through model helpers. |
| packages/stack/src/encryption/operations/decrypt.ts | Uses synchronous lock-context resolution; removes serviceToken forwarding. |
| packages/stack/src/encryption/operations/decrypt-model.ts | Uses synchronous lock-context resolution and passes Context through model helpers. |
| packages/stack/src/encryption/operations/bulk-encrypt.ts | Uses synchronous lock-context resolution; removes serviceToken forwarding. |
| packages/stack/src/encryption/operations/bulk-encrypt-models.ts | Uses synchronous lock-context resolution and passes Context through model helpers. |
| packages/stack/src/encryption/operations/bulk-decrypt.ts | Uses synchronous lock-context resolution; removes serviceToken forwarding. |
| packages/stack/src/encryption/operations/bulk-decrypt-models.ts | Uses synchronous lock-context resolution and passes Context through model helpers. |
| packages/stack/src/encryption/operations/batch-encrypt-query.ts | Uses synchronous lock-context resolution; removes serviceToken forwarding. |
| packages/stack/src/encryption/index.ts | Plumbs optional config.strategy into protect-ffi newClient and documents identity-bound usage. |
| packages/stack/src/encryption/helpers/model-helpers.ts | Removes CTS token plumbing from model bulk encrypt/decrypt helpers. |
| packages/stack/package.json | Bumps protect-ffi and adds optionalDependencies for auth platform binaries. |
| packages/stack/tests/lock-context.test.ts | Rewrites live identity-bound tests to use OidcFederationStrategy + { identityClaim }. |
| packages/stack/tests/lock-context-wiring.test.ts | Adds offline mocks ensuring identityClaim is forwarded and serviceToken is never sent. |
| packages/stack/tests/init-strategy.test.ts | Adds tests verifying config.strategy is forwarded to protect-ffi newClient. |
| packages/stack/tests/fixtures/index.ts | Simplifies lock-context fixtures to a plain { identityClaim } input. |
| packages/stack/tests/encrypt-query.test.ts | Updates lock-context tests to use plain { identityClaim } input and removes CTS-token-failure cases. |
| packages/stack/tests/encrypt-query-searchable-json.test.ts | Updates lock-context tests to use plain { identityClaim } input and removes CTS-token-failure cases. |
| examples/supabase-worker/supabase/functions/cipherstash-roundtrip/index.ts | Updates example config to use CS_WORKSPACE_CRN (no CS_REGION). |
| examples/supabase-worker/README.md | Updates env setup instructions to include CS_WORKSPACE_CRN. |
| examples/supabase-worker/.env.example | Updates example env file to use CS_WORKSPACE_CRN and remove CS_REGION. |
| e2e/wasm/roundtrip.test.ts | Updates WASM e2e to require/use CS_WORKSPACE_CRN and drop explicit region. |
| e2e/wasm/deno.json | Pins protect/auth wasm-inline imports to 0.26.0 / 0.39.0. |
| AGENTS.md | Updates guidance to the strategy-based identity-aware encryption flow. |
| .github/workflows/tests.yml | Exposes CS_WORKSPACE_CRN to wasm e2e job and asserts it’s present. |
| .changeset/stack-protect-ffi-0-26-oidc-strategy.md | Adds release notes for the dependency bumps and new identity-bound strategy flow. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)
packages/stack/tests/lock-context.test.ts:145
- This test tries to assert that decrypting without the lock context fails, but
decryptModel()returns a Result (it doesn’t throw). As written, the try/catch never runs and the test will pass without asserting anything. Assert on the returned Result’sfailureinstead.
try {
await protectClient.decryptModel(encryptedModel.data)
} catch (error) {
const e = error as Error
expect(e.message.startsWith('Failed to retrieve key')).toEqual(true)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * "ap-southeast-2.aws", workspaceId, () => getClerkSessionToken(req), | ||
| * { store: cookieStore({ request: req, responseHeaders }) }, | ||
| * ) | ||
| * const client = await Encryption({ schemas, config: { strategy, clientId, clientKey } }) |
Stacked on top of #496 (
feat/stack-wasm-inline) — review/merge that first; this PR's base is the #496 branch, notmain.Supersedes the earlier 0.25.0 work: bumps to
@cipherstash/protect-ffi@0.26.0and@cipherstash/auth@0.39.0, and uses the newOidcFederationStrategyto replace the lock-context token ceremony with a simpler, strategy-based approach for identity-bound encryption.1. Version bumps
@cipherstash/protect-ffi0.25.0→0.26.0. The public TypeScript API is identical to0.25.0(verified by diffing the publishedlib/index.d.cts);0.26.0is internal fixes only (per-isolate NeonChannelcleanup,try_catcharound the JSgetToken).@cipherstash/authcatalog (and the six platform entries)0.38.0→0.39.0, which addsOidcFederationStrategy.e2e/wasm/deno.jsonpins +pnpm-lock.yamlregenerated.2. Strategy-based, identity-bound encryption (replaces the ceremony)
protect-ffi 0.25 removed the per-operation
serviceToken, which left the oldLockContextceremony half-broken:identify()fetched a CTS token the operations no longer sent, so the request authenticated as the service whileidentityClaimasked ZeroKMS to bind to a user it couldn't verify.OidcFederationStrategyandidentityClaimcompose: the strategy federates the end user's OIDC JWT into a CTS token at the client level (so requests authenticate as the user), andidentityClaimstill selects which claim ZeroKMS bakes into the data-key tag..withLockContext()now accepts a plain{ identityClaim }(or aLockContext) and resolves the claim synchronously — no CTS token, noidentify()call.LockContext.identify()/getLockContext()are deprecated (kept for back-compat); the client strategy handles token acquisition.config.strategyand existing credential/env behaviour is unchanged; existing.withLockContext(lockContext)call sites still compile.3. Strategy re-exports
OidcFederationStrategy,AccessKeyStrategy,AutoStrategy,DeviceSessionStrategyre-exported from@cipherstash/stack;OidcFederationStrategy/AccessKeyStrategyfrom@cipherstash/stack/wasm-inline(+ the wasmconfig.strategytype broadened to accept either). Integrators no longer need a separate@cipherstash/authinstall.@cipherstash/stacknow declares the@cipherstash/auth-<platform>packages asoptionalDependencies—@cipherstash/authships them as optional peer deps (not auto-installed), so this is required for the re-exported Node strategies to resolve their native binding for consumers.Also updated
lock-context-wiring.test.ts— asserts both aLockContextand a plain{ identityClaim }forwardidentityClaim, andserviceTokenis still never sent.init-strategy.test.ts— adds anOidcFederationStrategy-shaped forwarding case.lock-context.test.ts— live (USER_JWT-gated) round-trip rewritten to useOidcFederationStrategy+.withLockContext({ identityClaim }), confirming per-user binding.Encryption(),LockContext,ClientConfig.strategy),AGENTS.md,README.md, changeset.