Skip to content

feat(skills): stash-zerokms and stash-auth — canonical keyset and authentication skills - #834

Merged
coderdan merged 13 commits into
mainfrom
docs/stash-zerokms-auth-skills
Jul 30, 2026
Merged

feat(skills): stash-zerokms and stash-auth — canonical keyset and authentication skills#834
coderdan merged 13 commits into
mainfrom
docs/stash-zerokms-auth-skills

Conversation

@coderdan

@coderdan coderdan commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Adds two new agent skills — stash-zerokms and stash-auth — as the canonical sources for the ZeroKMS access model and the authentication model, installed for every integration, plus a verified accuracy pass over the existing skills. Closes #794. Closes #756.

stash-zerokms — keysets, clients, and key management

The keyset/client model had no canonical home, and several shipped skills describe it incorrectly (the "credential-identity rule" — index terms deriving from the client key so mismatched credentials "decrypt but silently miss queries"). This skill is the verified model, checked against the ZeroKMS server implementation and the whitepaper:

  • The four-level key hierarchy (root → per-keyset authority key → per-client client key → per-value data key), proxy re-encryption, and why revoking a client is immediate and complete.
  • The scoping rule: every encrypt, decrypt, and query is scoped to a keyset, and a client without a grant fails all three loudly (ZeroKMS 404) — there is no silent decrypt-works-search-misses failure mode; every granted client derives the same per-keyset index key.
  • Workspace default keyset vs each client's own default keyset (what a keyset-less operation actually resolves to), grants per (client, keyset), the device client that stash auth login provisions (a standard client key, differently encapsulated in the profile), per-payload decrypt routing, the disabled-keyset kill-switch, the ZeroKMS management API with scopes, failure surfaces, and a diagnostic runbook separating the keyset gate from the lock-context gate.

The skill sites that carried the wrong model are corrected in this PR: stash-edge's "Credential-Identity Rule" section (the canonical wrong one — replaced with the keyset model plus a short retrospective naming the old rule), the backfill precondition and stash env warning in stash-cli, the writer/reader notes in stash-postgres and stash-supabase, and stash-encryption's claim that edge identity-binding is "configured via config.authStrategy" (the #794 evidence item — the edge entry simply lacks lock context, #797). Each now states the keyset / retrieval-binding model and defers to stash-zerokms / stash-auth as canonical. Covered by its own stash patch changeset.

stash-auth — credentials, auth strategies, and lock context (#794)

  • The service-token model: every request to a CipherStash service carries a short-lived CTS-minted JWT; access keys and IdP JWTs are exchanged at CTS, never sent to ZeroKMS. The token carries a service-discovery mechanism — the one user-facing fact being that a token is only valid for services in the region it was issued for. Current regions listed, with stash auth regions as the live source.
  • The three separable concerns (client credentials / end-user identity / key binding) and the corrected lock-context model: a claim from the encrypting caller's service token is bound to the data key, and retrieval requires presenting the same claim — orthogonal to keysets, and it gates key retrieval, not key derivation.
  • The @cipherstash/auth strategies, including: auto's requirement of both CS_CLIENT_ACCESS_KEY and CS_WORKSPACE_CRN (missing CRN with the key set fails MISSING_WORKSPACE_CRN rather than silently falling back to the profile), the Result trap (create() returns Result<Strategy, AuthFailure> — unwrap before config.authStrategy), the AuthFailure codes, and the OIDC federation prerequisite (the JWT's issuer must be registered with the workspace; Clerk, Supabase, Auth0, Okta; multiple providers per workspace subject to plan).
  • Credential discovery vs the WASM entry's explicit config (mutual exclusion of authStrategy + accessKey enforced on the WASM entry), the four CS_* variables and stash env, and the client-lifetime hazard stated mechanically: the strategy caches one federated CTS token, so a shared client rides whichever user's token is cached — one client per request/user.
  • The explicit rule that agents never read ~/.cipherstash, and a note that Proxy authentication is a different path (dedicated skill to come).

Accompanying source fixes (@cipherstash/stack, patch)

  • config.keyset doc comments: omitting the option resolves to the client's default keyset (the keyset the client was created against), not "the workspace's default keyset" per se.
  • The native entry's authStrategy JSDoc examples passed create()'s Result straight into config.authStrategy — the exact mistake Add a stash-auth skill covering credentials, auth strategies, and lock context #794 calls out; they now unwrap, matching the wasm-inline docs and integration tests.
  • The WasmEncryptionClient doc comment's lock-context wording corrected to the retrieval-binding model.

stash-prisma-next verified against main (#756)

The skill was verified line-by-line against @cipherstash/prisma-next on main (constructors, domains, operator surface, rawSql shape, EQL function names against the pinned @cipherstash/eql 3.0.2 bundle, CLI commands). Fixes, targeting the forthcoming release:

On #756's other two points: migration apply was already fixed on main (#765), and the extensionPacks:extensions: claim doesn't hold at @prisma-next/cli 0.16.0 — extensionPacks is the CLI config field, extensions is the postgres() runtime option; the skill uses both correctly.

Wiring

Both SKILL_MAPs (CLI + wizard, order-identical for the parity test), BASE_SKILLS, SKILL_PURPOSES, the AGENTS doctrine, AGENTS.md (skills list + two new canonical-source rows in the check table), and the test expectation lists. Changesets: stash minor ×2, @cipherstash/wizard patch ×2, @cipherstash/stack patch ×2.

Verification

  • CLI suite: 873 passed. Wizard suite: 333 passed. skill-map-parity e2e: passed. Biome: no errors on touched files (pre-existing warnings only). @cipherstash/stack builds (DTS regenerates).
  • Model claims verified against: the ZeroKMS server handlers and persistence layer, the shipped cipherstash-client 0.42.0 and @cipherstash/auth 0.42.0, protect-ffi 0.31.0, the CTS authorize endpoint, and stack-auth's strategy/refresher sources (including the token-caching tests behind the client-lifetime section).

Related: #832 (per-operation keysets, filed from this investigation).

Summary by CodeRabbit

  • New Features
    • Added authentication, deployment, and ZeroKMS guidance as installable integration skills.
    • Expanded CLI and wizard setup to include these skills across supported integrations.
    • Added clearer prompts describing each newly available skill.
  • Documentation
    • Clarified authentication strategy setup, result handling, lock context behavior, and keyset defaults.
    • Documented staged encryption deployments, rollback considerations, credential handling, and ZeroKMS access rules.
    • Updated repository guidance and integration references.
  • Tests
    • Updated setup coverage for expanded skill installation and failure reporting.

Summary by CodeRabbit

  • New Features

    • Added canonical guidance for authentication, ZeroKMS keysets, grants, lock contexts, and deployment workflows.
    • stash init and integration setup now include authentication, deployment, and ZeroKMS skills.
  • Enhancements

    • Stack now uses EQL v3 exclusively with clearer keyset and authentication configuration.
    • Prisma Next guidance now reflects its native migration workflow and expanded column-type support.
  • Documentation

    • Clarified keyset defaults, credential behavior, edge encryption limitations, and identity-bound decryption.
    • Updated CLI, integration, and agent documentation with corrected troubleshooting and setup instructions.

@coderdan
coderdan requested a review from a team as a code owner July 29, 2026 09:38
@changeset-bot

changeset-bot Bot commented Jul 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 0325015

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 11 packages
Name Type
@cipherstash/stack Minor
stash Minor
@cipherstash/wizard Minor
@cipherstash/bench Patch
@cipherstash/prisma-next Minor
@cipherstash/stack-drizzle Minor
@cipherstash/stack-supabase Minor
@cipherstash/test-kit Patch
@cipherstash/basic-example Patch
@cipherstash/prisma-next-example Patch
@cipherstash/e2e Patch

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

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@coderdan, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 5 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7234965f-deab-41af-b65e-e8eeba0aeb1c

📥 Commits

Reviewing files that changed from the base of the PR and between 33d2958 and 0325015.

📒 Files selected for processing (11)
  • .changeset/skills-keyset-auth-wording-pass.md
  • .changeset/stash-zerokms-skill.md
  • packages/cli/src/commands/eql/__tests__/migration.test.ts
  • packages/cli/src/commands/eql/migration.ts
  • packages/cli/src/messages.ts
  • skills/stash-cli/SKILL.md
  • skills/stash-deployment/SKILL.md
  • skills/stash-edge/SKILL.md
  • skills/stash-postgres/SKILL.md
  • skills/stash-supabase/SKILL.md
  • skills/stash-zerokms/SKILL.md
📝 Walkthrough

Walkthrough

The PR adds canonical authentication and ZeroKMS skills, updates EQL v3 Stack contracts and documentation, corrects Prisma Next migration and adapter guidance, and distributes the new skills through CLI and wizard installation flows.

Changes

Stack contracts and authentication

Layer / File(s) Summary
EQL v3 client contracts
packages/stack/src/encryption/index.ts, packages/stack/src/types.ts
Removes legacy EQL version selection, pins initialization to EQL v3, and updates the generic non-empty schema contract.
Authentication and keyset semantics
packages/stack/src/encryption/index.ts, packages/stack/src/types.ts, packages/stack/src/wasm-inline.ts, .changeset/*
Corrects auth-strategy Result handling and documents client-default keysets and lock-context retrieval behavior.

Canonical authentication and ZeroKMS skills

Layer / File(s) Summary
Canonical authentication guidance
skills/stash-auth/SKILL.md, skills/stash-encryption/SKILL.md, skills/stash-edge/SKILL.md, skills/stash-supabase/SKILL.md, .changeset/*
Adds stash-auth and aligns authentication, credential discovery, lock-context, and WASM guidance.
ZeroKMS keyset guidance
skills/stash-zerokms/SKILL.md, skills/stash-cli/SKILL.md, skills/stash-edge/SKILL.md, skills/stash-postgres/SKILL.md, skills/stash-supabase/SKILL.md, .changeset/*
Documents keyset-scoped access, grants, defaults, failure behavior, and canonical cross-references.

Skill distribution through integration tooling

Layer / File(s) Summary
CLI and wizard skill mappings
packages/cli/src/commands/init/lib/install-skills.ts, packages/wizard/src/lib/install-skills.ts, AGENTS.md, packages/cli/src/commands/init/doctrine/AGENTS-doctrine.md
Adds deployment, ZeroKMS, and authentication skills to integration and fallback installation sets.
Prompt wiring and installation validation
packages/cli/src/commands/init/lib/setup-prompt.ts, packages/cli/src/commands/init/lib/__tests__/*, packages/wizard/src/__tests__/*
Adds skill purpose labels and updates installation expectations for the expanded skill sets.

Prisma Next migration and adapter guidance

Layer / File(s) Summary
Prisma Next migration messaging
packages/cli/src/cli/registry.ts, packages/cli/src/commands/eql/migration.ts, packages/cli/src/messages.ts, .changeset/*
Updates Prisma Next migration descriptions and routes users to Prisma Next’s migration framework.
Prisma Next adapter and schema documentation
skills/stash-prisma-next/SKILL.md, packages/cli/src/commands/init/providers/prisma-next.ts, examples/prisma/prisma/schema.prisma, .changeset/*
Corrects constructor examples, expands the column-type catalog, documents native runtime requirements, and adds the column-types subpath.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

  • cipherstash/stack#756 — The Prisma Next skill now includes the complete constructor catalog and corrected adapter guidance.
  • cipherstash/stack#764 — The documentation updates replace credential-identity semantics with keyset-based behavior.
  • cipherstash/stack#757 — The new stash-zerokms skill documents keysets, grants, defaults, and cross-client access.
  • cipherstash/stack#794 — The new stash-auth skill centralizes authentication and lock-context guidance.
  • cipherstash/stack#637 — Stack client configuration and generic encryption client contracts are revised.
  • cipherstash/stack#793 — WASM auth-strategy and lock-context semantics are corrected.

Possibly related PRs

Suggested reviewers: tobyhede, calvinbrewer, auxesis

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the PR’s main change: adding the canonical stash-zerokms and stash-auth skills.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/stash-zerokms-auth-skills

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/stash-auth-skill.md:
- Around line 22-25: Update the lock-context description in the changeset to
match the corrected model: describe it as governing claim-bound retrieval of a
value’s data key, not selecting which encryption key the value uses. Preserve
the distinction between auth strategy identity and lock-context behavior, using
skills/stash-auth/SKILL.md and packages/stack/src/wasm-inline.ts as the
authoritative wording.

In @.changeset/stash-zerokms-skill.md:
- Around line 15-17: Qualify the revocation description to state that it blocks
future access or seed issuance without re-encryption, rather than claiming
immediate and complete revocation of already-derived keys or plaintext. Apply
this wording to the hierarchy explanation in .changeset/stash-zerokms-skill.md
(lines 15-17) and the corresponding explanation in skills/stash-zerokms/SKILL.md
(lines 79-82).

In `@packages/stack/src/types.ts`:
- Around line 135-138: The client documentation is inconsistent about its
default keyset and multi-keyset behavior. In packages/stack/src/types.ts lines
135-138, qualify the one-client-per-tenant guidance so it applies to
encrypt/query or keyset-less operations; in skills/stash-zerokms/SKILL.md lines
178-193, describe the client as having one default keyset while explicitly
preserving decryption across granted keysets.

In `@skills/stash-auth/SKILL.md`:
- Line 161: Update every copied npx command in SKILL.md, including the command
near NOT_AUTHENTICATED and the locations around the other referenced sections,
to invoke stash with the repository-supported pinned version instead of
resolving the mutable package. Keep the surrounding authentication and
credential-operation instructions unchanged.

In `@skills/stash-deployment/SKILL.md`:
- Around line 58-70: Add an explicit text/plaintext language tag to the fenced
blocks containing the deployment diagram and error output in the documentation,
including the second block around the additional referenced section. Leave the
block contents unchanged.
- Around line 299-308: Update the executable production database migration
examples to avoid mutable latest CLI resolution: replace the unversioned `npx
`@prisma/cli`` and `npx prisma-next` invocations with exact-version commands or
the repository’s pinned pnpm invocations, while preserving the existing
connection creation, migration update, and removal sequence.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d56f719d-39be-485e-a328-ff0401890a54

📥 Commits

Reviewing files that changed from the base of the PR and between a3987e0 and c67caa2.

📒 Files selected for processing (18)
  • .changeset/auth-strategy-jsdoc-unwrap.md
  • .changeset/keyset-default-doc-precision.md
  • .changeset/stash-auth-skill.md
  • .changeset/stash-deployment-skill.md
  • .changeset/stash-zerokms-skill.md
  • AGENTS.md
  • packages/cli/src/commands/init/doctrine/AGENTS-doctrine.md
  • packages/cli/src/commands/init/lib/__tests__/install-skills.test.ts
  • packages/cli/src/commands/init/lib/install-skills.ts
  • packages/cli/src/commands/init/lib/setup-prompt.ts
  • packages/stack/src/encryption/index.ts
  • packages/stack/src/types.ts
  • packages/stack/src/wasm-inline.ts
  • packages/wizard/src/__tests__/install-skills.test.ts
  • packages/wizard/src/lib/install-skills.ts
  • skills/stash-auth/SKILL.md
  • skills/stash-deployment/SKILL.md
  • skills/stash-zerokms/SKILL.md

Comment thread .changeset/stash-auth-skill.md Outdated
Comment thread .changeset/stash-zerokms-skill.md Outdated
Comment thread packages/stack/src/types.ts Outdated
Comment thread skills/stash-auth/SKILL.md
Comment thread skills/stash-deployment/SKILL.md Outdated
Comment thread skills/stash-deployment/SKILL.md
@coderdan
coderdan changed the base branch from main to docs/stash-deployment-skill July 29, 2026 09:57

@freshtonic freshtonic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve

Reviewed the full diff at 4379e7a7 (11 commits on docs/stash-deployment-skill). Since skills ship into the stash tarball and get copied into customer repos, I focused on accuracy: I read both new skills and all five corrected ones myself, and fact-checked every code-checkable claim against the actual repo + dependency source. No skill teaches anything the code refutes, wiring/parity is fully correct, and all 14 CI checks pass. This is a careful, well-sourced correction of a previously-wrong customer-facing model.

Verified against the code (clean)

Source doc-fixes. The native authStrategy JSDoc now unwraps create()'s Result (if (strategy.failure) throw …; authStrategy: strategy.data) — matching @cipherstash/auth 0.42.0's Result<Strategy, AuthFailure> return type and the WASM docs. config.keyset and the WasmEncryptionClient lock-context wording are corrected to the client-default-keyset and retrieval-binding models.

Auth-strategy claims (stash-auth). Confirmed against @cipherstash/auth types: the Result trap, all eight enumerated AuthFailure codes exist (no fictional code), auto selecting the access-key arm on access-key presence so access-key-set + CRN-missing yields MISSING_WORKSPACE_CRN, and the WASM entry's authStrategy/accessKey mutual exclusion — enforced both at the type level (?: never) and at runtime (throws).

prisma-next catalog (stash-prisma-next). The headline #756 fix — the full 31-constructor catalog — is exact against packages/prisma-next/src/v3/catalog.ts: 41 eql_v3_* domains minus the 10 *_ord_ore variants the adapter deliberately doesn't expose = 31 constructors, every name matching (including the IntegerOrd=number vs BigIntOrd=bigint distinction that the integer-cents trap turned on). defineConfig genuinely comes from @prisma-next/cli/config-types (no bare prisma-next package exists), and extensionPacks (CLI config) vs extensions (postgres() runtime) are each used correctly.

--prisma retirement. Registry summary, flag description, the migrationPrismaUnavailable message, and the init next-steps are all updated consistently to "not needed → run prisma-next migrate" with no leftover "#690"/"soon"; the command still fails cleanly via CliExit(1). schema.prisma comment renames match the real constructor names.

Skill consistency + wiring. stash-edge honestly names the old "credential-identity rule" as wrong and rewrites it (anchor link updated to match the new heading); all five corrected sites replace "index terms derive from the client key / decrypt-but-never-match" with the per-keyset model and defer to the canonical skills. Both new skills carry valid frontmatter with name: matching the directory, no Linear IDs. SKILL_MAPs are order-identical across CLI + wizard (guarded by an order-sensitive parity test), and BASE_SKILLS / SKILL_PURPOSES / both test suites / AGENTS.md list + check table / the doctrine are all updated in lockstep. Changesets are accurate and appropriately scoped (two stash minor for the new skills, @cipherstash/stack patch for the doc-fixes).

Scope note on the cryptographic model

The ZeroKMS server-side claims — the four-level key hierarchy, proxy re-encryption, per-keyset (not per-client) index-term derivation, and the retrieval-binding lock-context mechanism — live in the ZeroKMS server + native client, not this repo, so I couldn't independently re-derive them here. What I could check is consistent: the FFI types corroborate that encrypt/query use the client's bound keyset (no per-operation keyset on EncryptOptions/EncryptQueryOptions), and nothing in the repo contradicts the decrypt-follows-payload split. These claims rest on the PR's stated verification against the ZeroKMS server implementation and whitepaper. Two things lower the risk: the lock-context correction is observationally equivalent (decrypt requires the same context under either description), and the keyset correction moves the diagnostic in the safer fail-loud direction (a keyset mismatch surfaces as total failure, not a silent search miss).

Non-blocking

  • Stale internal comments. Two JSDoc comments still say the Prisma emitter is "not yet available (#690)", now contradicting the shipped "not needed" message: packages/cli/src/commands/eql/migration.ts:61 and the doc block at packages/cli/src/messages.ts:75-78. Internal only — not user-facing, not in any skill — but worth sweeping since the rest of that surface was updated.
  • The messages.ts constant is still named migrationPrismaUnavailable though the message now says "not needed" rather than "unavailable" — a slightly misleading internal name.

Excellent, rigorous work — correcting a wrong model that had already propagated across five shipped skills, with the replacement checked against the server implementation and the client libraries, is exactly the right treatment for artifacts that land in customers' repos. LGTM.

Base automatically changed from docs/stash-deployment-skill to main July 30, 2026 01:32
coderdan added 11 commits July 30, 2026 11:35
…skill

Install it for every integration (both SKILL_MAPs + BASE_SKILLS). The skill
is the single source of truth for the ZeroKMS access model: the four-level
key hierarchy, keysets scoping every encrypt/decrypt/query, clients and
grants, the workspace vs client default keyset distinction, per-payload
decrypt routing, failure surfaces, and a diagnostic runbook.

Also corrects the config.keyset doc comments in @cipherstash/stack: omitting
the option resolves to the client's default keyset (the keyset the client
was created against), not the workspace default per se.

Refs #832 (per-operation keysets, filed while verifying the FFI surface).
The service-token model (all CipherStash requests carry a CTS-minted JWT;
the token's services claim names the regional ZeroKMS endpoint), the three
separable auth concerns, the @cipherstash/auth strategies and the
create()-returns-Result trap, credential discovery vs the WASM entry's
explicit config, the four CS_* variables and stash env, client lifetime
with user-scoped strategies, lock context and its deprecations, and the
never-read-~/.cipherstash rule. Installed for every integration.

stash-zerokms gains the companion section: ZeroKMS accepts only CTS service
tokens, runs in multiple regions, and its endpoint is determined by CTS —
bulk deferred to stash-auth.

Also fixes the native entry's authStrategy JSDoc examples, which passed
create()'s Result straight into config.authStrategy — the exact mistake
#794 calls out. They now unwrap, matching the wasm-inline docs and the
integration tests.

Closes #794.
…nline lock-context wording

stash-zerokms now covers the device client: stash auth login generates a
device identity, provisions a client on the workspace default keyset (one
per device per workspace), and persists a standard client key to the
profile's secretkey.json — same key, different encapsulation than the hex
CS_CLIENT_KEY form. Profile files stay CLI-only.

stash-auth now states the OIDC federation prerequisite: the JWT's issuer
must be registered with the workspace (Clerk, Supabase, Auth0, or Okta, via
the dashboard's OIDC providers page); an unregistered issuer fails with 'No
OIDC provider found for issuer'. Multiple providers per workspace, subject
to billing/plan.

The WasmEncryptionClient doc comment said a lock context decides 'which key
the value is encrypted under' — key material is identical either way; the
binding gates retrieval of the data key by the claim in the caller's
service token. Reworded to match stash-auth's canonical model.
… regions

CipherStash runs in multiple regions and the set is subject to change —
stash-auth now carries the current seven (matching the CLI's picker) plus
the instruction to retrieve the live list with `stash auth regions`
(--json for machines), deferring command details to stash-cli. stash-zerokms
points at both.
…ound

The token exchange section now frames the services claim as a built-in
service-discovery mechanism the user never configures, with the one fact
that matters surfaced: a CipherStash-issued service token is only valid for
services in the region it was issued for.
The shared-client hazard isn't 'whoever arrived first' — the strategy
caches one federated CTS token and returns it until expiry (getJwt is not
consulted while the cache is warm; pinned by
test_caches_token_after_initial_federation), so a shared client rides
whichever user's token is currently cached, flipping identity at each
re-federation. States the design fact (the strategy is one-user-scoped) and
the mitigation (one client per request/user).
…non-retroactivity, keyset-binding qualifier

- The stash-auth changeset still carried the pre-correction 'which key a
  value is encrypted under' framing; now states the retrieval-binding model.
- Revocation claims bounded: blocks all future key operations immediately
  and without re-encryption, but is not retroactive — with the per-value
  granularity point that the blast radius is exactly what the revoked
  client already accessed.
- types.ts keyset JSDoc: 'bound to one keyset for its lifetime' qualified —
  encrypt/query always use it, decrypt follows each payload's own keyset
  subject to grants — matching the skill.
…, defer to canonical sources

The 'credential-identity rule' (index terms derive from the client key;
mismatched credentials decrypt but silently never match a query) was wrong
in stash-edge (the canonical section), stash-cli (backfill precondition +
stash env warning), stash-postgres, and stash-supabase. All now state the
keyset model — per-keyset index key, loud total failure without a grant —
and defer to stash-zerokms / stash-auth.

stash-encryption's edge note claimed identity-bound encryption is
'configured via config.authStrategy' (the #794 conflation); it now states
the lock-context gap (#797) and the retrieval-binding model, and its auth,
lock-context, and keysets sections point at the canonical skills.
stash-prisma-next's auth section points at stash-auth. stash-edge keeps a
short retrospective naming the old wrong rule so agents who saw it in older
copies aren't left guessing.
…mport, bundling claim, stale constructor names

Line-by-line verification against @cipherstash/prisma-next confirmed the
skill's constructors, domain table, operator surface, rawSql shape, EQL v3
function names (checked against the pinned @cipherstash/eql 3.0.2 bundle),
and CLI commands are all current. Two real errors fixed:

- defineConfig comes from @prisma-next/cli/config-types, not a nonexistent
  'prisma-next' package (verified against examples/prisma).
- The bundling section pointed edge runtimes at wasm-inline; the adapter is
  native-only, so it now says that instead of sending agents down a dead end.

Adds the column-types subpath (TS-authored contracts) to the exports table.
Drive-bys surfaced by the same review: stash init --prisma-next's next steps
still said cipherstash.Encrypted*() (pre-rename constructor names), and the
example schema's header comment did too.
Prisma Next installs the EQL bundle through its own migration framework
(the extension pack's migrations/cipherstash/ contract space), so the
promised Prisma emitter (#690, closed) is not coming and was never needed.
The registry copy, code comment, error message, and stash-cli skill now
state the mechanism and route to prisma-next migrate.
…og (#756)

The column-type table was a six-row sample presented as the catalog —
IntegerOrd wasn't mentioned once, and the missing plaintext-type column is
exactly what distinguishes IntegerOrd (number) from BigIntOrd (bigint) in
the integer-cents case #756 reports. The table is now the complete exposed
surface (plaintext type x capability tier), derived from DOMAIN_REGISTRY,
with the capability semantics spelled out (*Ord includes equality;
TextMatch is free-text only; *OrdOre deliberately unexposed) and the
envelope pairing restated per family.

Of #756's other two points against rc.4: 'migration apply' was already
fixed on main (#765), and the extensionPacks-vs-extensions claim does not
hold at @prisma-next/cli 0.16.0 — extensionPacks is the CLI config field
(types-DnpnkEgM.d.mts) and extensions is the postgres() runtime option; the
skill uses both correctly.

Closes #756.
@coderdan
coderdan force-pushed the docs/stash-zerokms-auth-skills branch from 4379e7a to 33d2958 Compare July 30, 2026 01:37
…tionPrismaUnavailable

The --prisma path now reports 'not needed' (Prisma Next installs EQL through
its own migration framework), but two internal JSDoc blocks still described
the emitter as a pending follow-up, and the messages.ts constant was still
named migrationPrismaUnavailable. Comments now describe the routing behaviour;
the constant is migrationPrismaNotNeeded. Internal only — no user-facing
change.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
packages/cli/src/messages.ts (1)

82-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep Prisma Next migration comments synchronized with the new routing contract.

The implementation now routes Prisma Next through its own migration framework, but nearby comments still describe obsolete or inconsistent commands.

  • packages/cli/src/messages.ts#L82-L82: Replace the “emitter isn't built yet” comment with the current “emitter not needed; route to Prisma Next migrations” behavior.
  • packages/cli/src/commands/init/providers/prisma-next.ts#L17-L17: Update migration plan|apply to match the emitted migration plan && migrate guidance, or verify and use the canonical command in both places.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/messages.ts` at line 82, Synchronize Prisma Next migration
guidance across packages/cli/src/messages.ts at line 82 and
packages/cli/src/commands/init/providers/prisma-next.ts at line 17: replace the
obsolete “emitter isn't built yet” explanation with the behavior that the
emitter is unnecessary and migrations route through Prisma Next, and make both
comments use the canonical “migration plan && migrate” command guidance
consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/stash-cli/SKILL.md`:
- Line 443: Update the keyset precondition documentation to state that backfill
may use native auto-authentication and fall back to the local development
profile when access-key environment variables are absent. Refer to the
credentials as “resolved credentials,” and separately recommend explicitly
exporting the target environment’s CS_* variables for CI and production.

In `@skills/stash-postgres/SKILL.md`:
- Around line 410-416: Update the same-keyset requirement in the paragraph
beginning “Every writer and reader” to apply specifically to every writer and
query reader, or explicitly scope it to encrypted search. Preserve the existing
keyset behavior and guidance for decrypt operations.

In `@skills/stash-zerokms/SKILL.md`:
- Around line 43-61: Update the canonical keyset guidance around config.keyset
to distinguish inaccessible or disabled keysets, which fail loudly, from
reachable-but-different query keyspaces, which may return zero rows while
decrypt still succeeds via the payload’s keyset; when omitted, use each client’s
default keyset. Propagate this distinction to
.changeset/stash-zerokms-skill.md:20-26,
.changeset/skills-keyset-auth-wording-pass.md:8-17,
skills/stash-edge/SKILL.md:163-191, skills/stash-supabase/SKILL.md:59-64,
skills/stash-cli/SKILL.md:443 and 488-496, and
skills/stash-postgres/SKILL.md:410-416, preserving the reachable-keyset mismatch
diagnostic and scoping same-keyset requirements to encrypted-search readers.

---

Nitpick comments:
In `@packages/cli/src/messages.ts`:
- Line 82: Synchronize Prisma Next migration guidance across
packages/cli/src/messages.ts at line 82 and
packages/cli/src/commands/init/providers/prisma-next.ts at line 17: replace the
obsolete “emitter isn't built yet” explanation with the behavior that the
emitter is unnecessary and migrations route through Prisma Next, and make both
comments use the canonical “migration plan && migrate” command guidance
consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ebb512a2-0e3d-49a9-8025-04c7a7b30773

📥 Commits

Reviewing files that changed from the base of the PR and between c67caa2 and 33d2958.

📒 Files selected for processing (30)
  • .changeset/auth-strategy-jsdoc-unwrap.md
  • .changeset/eql-migration-prisma-not-needed.md
  • .changeset/keyset-default-doc-precision.md
  • .changeset/prisma-next-skill-accuracy.md
  • .changeset/skills-keyset-auth-wording-pass.md
  • .changeset/stash-auth-skill.md
  • .changeset/stash-zerokms-skill.md
  • AGENTS.md
  • examples/prisma/prisma/schema.prisma
  • packages/cli/src/cli/registry.ts
  • packages/cli/src/commands/eql/migration.ts
  • packages/cli/src/commands/init/doctrine/AGENTS-doctrine.md
  • packages/cli/src/commands/init/lib/__tests__/install-skills.test.ts
  • packages/cli/src/commands/init/lib/install-skills.ts
  • packages/cli/src/commands/init/lib/setup-prompt.ts
  • packages/cli/src/commands/init/providers/prisma-next.ts
  • packages/cli/src/messages.ts
  • packages/stack/src/encryption/index.ts
  • packages/stack/src/types.ts
  • packages/stack/src/wasm-inline.ts
  • packages/wizard/src/__tests__/install-skills.test.ts
  • packages/wizard/src/lib/install-skills.ts
  • skills/stash-auth/SKILL.md
  • skills/stash-cli/SKILL.md
  • skills/stash-edge/SKILL.md
  • skills/stash-encryption/SKILL.md
  • skills/stash-postgres/SKILL.md
  • skills/stash-prisma-next/SKILL.md
  • skills/stash-supabase/SKILL.md
  • skills/stash-zerokms/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/cli/src/commands/init/doctrine/AGENTS-doctrine.md
  • packages/wizard/src/tests/install-skills.test.ts
  • packages/stack/src/wasm-inline.ts
  • AGENTS.md

Comment thread skills/stash-cli/SKILL.md Outdated
Comment thread skills/stash-postgres/SKILL.md Outdated
Comment thread skills/stash-zerokms/SKILL.md Outdated
…und keyset, decrypt follows the payload's

Corrects the claim (made canonical yesterday in stash-zerokms and echoed in
stash-edge, stash-supabase, stash-cli, stash-postgres, stash-deployment and
two changesets) that a keyset mismatch always fails loudly and that
'decrypt works but search returns zero rows' can never be key-related.

Per the runtime contract (packages/stack/src/types.ts): a client is bound
to one keyset — encrypt and encryptQuery always use it — while decrypt
follows each payload's keyset, subject to grants. So one silent case
exists: a reader granted the writer's keyset but bound to a different one
decrypts fine while its query terms derive under its own keyspace and
return zero rows with no error. All sites now distinguish unreachable
keysets (loud) from reachable-but-different bound keysets (silent search
miss), scope the same-keyset rule to writers and query readers, and put
the bound-keyset check first in the zero-rows diagnostic.

Also documents the backfill credential resolution order in stash-cli:
CS_* variables when present, else the ~/.cipherstash profile via native
auto auth (CodeRabbit's third finding).

Addresses CodeRabbit review on #834.
@coderdan
coderdan merged commit 8817cfb into main Jul 30, 2026
18 checks passed
@coderdan
coderdan deleted the docs/stash-zerokms-auth-skills branch July 30, 2026 01:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants