diff --git a/.changeset/cli-install-sql-digest.md b/.changeset/cli-install-sql-digest.md deleted file mode 100644 index 197c7f958..000000000 --- a/.changeset/cli-install-sql-digest.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'stash': patch ---- - -Verify the EQL install SQL against its release digest before running it. - -`stash eql install` reads the EQL v3 bundle from the resolved -`@cipherstash/eql` in your `node_modules` and executes it against your -database. That read was a bare `readFileSync` — nothing checked that the bytes -on disk were the bundle the resolved release actually ships. A corrupt, -partially-updated, or tampered package installed silently: the database ended -up carrying SQL the version it reports does not define, and the CLI printed -"EQL extensions installed." - -The CLI now hashes the bundle and compares it to `installSqlSha256` from the -release manifest that ships alongside it, and **refuses** on a mismatch. The -error names the expected digest, the actual digest, the resolved file path and -the EQL version, so the remedy is visible rather than inferred. Verification -happens before any database connection is opened, so a refusal means nothing -was attempted — not that something was rolled back. - -The check covers all three paths that read the bundle: `stash eql install`, -the SQL embedded by `stash eql migration --drizzle` / `--supabase`, and the -expected-surface baseline `stash eql verify` compares your database against. -`@cipherstash/stack-prisma` has verified against this same digest since its v3 -migrations landed; this brings the CLI in line. - -No healthy install is affected — the SQL and its manifest are produced by the -same build of `@cipherstash/eql`, so a mismatch only ever means a broken -dependency tree. - -`skills/stash-cli` documents the new pre-flight alongside the existing -post-install surface check, so an agent reading it does not report a digest -refusal as a failed install. diff --git a/.changeset/doctor-optional-absent-is-not-a-pass.md b/.changeset/doctor-optional-absent-is-not-a-pass.md deleted file mode 100644 index 43af18459..000000000 --- a/.changeset/doctor-optional-absent-is-not-a-pass.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'stash': patch ---- - -`stash doctor` no longer reports "All checks passed." when `@cipherstash/stack` -is absent. The package is an optional peer, so running `doctor` before `stash -init` skips the encryption check entirely — the row already said so, but the -outro claimed a pass for a check that never ran. It now ends with "stash doctor -could not run every check.", the same line an unprobeable install gets, and -still exits 0: an absent optional package is recoverable, not a failure. diff --git a/.changeset/eql-3-0-5-migration.md b/.changeset/eql-3-0-5-migration.md deleted file mode 100644 index 49e195b93..000000000 --- a/.changeset/eql-3-0-5-migration.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -'@cipherstash/stack-prisma': minor ---- - -Move the bundled EQL v3 migrations to **eql-3.0.5**, which renames the SQL -function `eql_v3.ste_vec_contains` to `eql_v3.jsonb_document_contains`. - -**The blast radius is narrower than a renamed public function suggests.** The -`@>` / `<@` operators on `public.eql_v3_json_search` behave exactly as before, -and so do the two function-form entry points that exist for platforms without -operator support — `eql_v3.jsonb_contains(jsonb, jsonb)` and -`eql_v3.jsonb_contained_by(jsonb, jsonb)` are byte-identical to 3.0.4. Those -are what a PostgREST caller invokes, so PostgREST callers on the documented -surface are **not** affected. The renamed function is the typed implementation -those operators dispatch into. - -**And the old name still works.** eql-3.0.5 ships `eql_v3.ste_vec_contains` as -a deprecated delegating alias for both overloads, so hand-written SQL naming it -— an application query, a view, an RLS policy, or a per-function -`GRANT EXECUTE ON FUNCTION eql_v3.ste_vec_contains(…)` — keeps resolving. The -typed overload stays inlinable, so a function-form query through the alias -still matches the same functional GIN index. Migrate to -`jsonb_document_contains` when convenient; nothing forces it at upgrade time. - -**Separately — and true of every EQL upgrade, not just this one:** the install -bundle opens with `DROP SCHEMA IF EXISTS eql_v3 CASCADE`, so applying it drops -every object in `eql_v3` / `eql_v3_internal` and everything that depended on -them. **Encrypted data and column types are not affected** — the storage -domains are `public.eql_v3_*`, deliberately outside both dropped schemas, and -their CHECK functions are re-created rather than dropped. What does not survive -is everything else pointing into the schema, which is two actions, neither of -them to do with the rename: - -1. **Re-run your grant script.** Every grant on every `eql_v3` / - `eql_v3_internal` object is gone. The schema-wide form EQL documents — - `GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA eql_v3 TO app_role` — picks up - both the new name and the alias on its own. -2. **Recreate your functional indexes, then `ANALYZE`.** Indexes over - `eql_v3.eq_term(…)` / `ord_term` / `match_term` / `to_ste_vec_query(…)` - depend on the dropped schema and go with it. Nothing errors afterwards: - encrypted predicates keep working and silently fall back to sequential - scans. A migration runner will not redo an already-applied migration, so - this has to be a *new* one. The `stash-indexing` skill documents the - mechanism ("These indexes do not survive an EQL reinstall or upgrade") and - the `EXPLAIN` check that confirms recovery; capturing and restoring them - automatically is tracked in - [cipherstash/stack#918](https://github.com/cipherstash/stack/issues/918). - -Any RLS policy, view, or constraint that calls an `eql_v3` function is dropped -by the same CASCADE and needs recreating too. **The rename itself needs no -action — the alias makes it non-breaking.** - -Two artefacts carry the new bundle: - -- A new upgrade edge, `20260814T0000_upgrade_eql_v3_3_0_5`, carrying the - invariant `cipherstash:upgrade-eql-v3-bundle-3.0.5-v1`. Databases already - running an earlier bundle re-install through this edge on the next - `prisma-next migration plan` followed by `prisma-next migrate`, exactly as - they did for 3.0.2 and 3.0.4. **`migrate` alone is not enough** — the seed - phase that copies a new migration package into your repo runs only from - `migration plan`, so without it the 3.0.5 directory never reaches disk and - `migrate` is a silent no-op that leaves the database on the older bundle. -- The baseline install migration `20260601T0100_install_eql_v3_bundle`, whose - baked bundle moves to 3.0.5 and which gains a fourth no-SQL carrier op for - the new invariant. Fresh databases therefore land on 3.0.5 from the single - all-additive genesis edge, keeping `db init` (additive-only policy) working. - -**Action required.** The baseline's bytes — and so its `migrationHash` — have -changed. If your project already has a `migrations/cipherstash/` directory -generated against `@cipherstash/stack-prisma@1.0.0` or `@1.1.0`, delete that -directory and re-run `prisma-next migration plan` (or `migrate`); the 1.1.0 -Prisma Next 0.17 upgrade re-anchored the same artefacts, so a space vendored -against either release is stale here. The seed phase regenerates -it byte-identical to the shipped artefacts. Your database keeps its markers, so -already-applied invariants are not re-run — the only new work is the 3.0.5 -upgrade edge. - -If you skip the delete, nothing warns you: a vendored baseline is stale but -internally intact, so it passes every integrity check. On an existing database -the upgrade still applies correctly; on a **fresh** one, `db init` refuses with -`Operation cipherstash.upgrade-eql-v3-bundle-3.0.5 has class "data" which is -not allowed by policy.` — an error that names neither the directory nor the -remedy. See "Upgrading from 1.0.0" in the package README. - -**Why the baseline was re-emitted rather than left frozen.** These artefacts are -content-addressed and normally append-only: an EQL bump ships as a new upgrade -directory and published directories are never rewritten. That rule cannot be -followed here without a second `from: null` genesis edge, because no upgrade -edge can ever be walked by `db init` — every upgrade edge is a self-edge, and -the integrity checker requires a self-edge to carry a `data`-class op, which -`db init`'s additive-only policy refuses. A fresh database must therefore -collect every head-ref invariant from the genesis edge it walks. The -append-only alternative would duplicate the full ~2.6 MB bundle into a new -genesis edge on every EQL release, permanently; re-emitting was taken instead -while 1.0.0 was two weeks old with negligible adoption, and is a decision to be -re-argued on adoption numbers rather than repeated by default. diff --git a/.changeset/eql-exact-runtime-pin.md b/.changeset/eql-exact-runtime-pin.md deleted file mode 100644 index 00b4eef9f..000000000 --- a/.changeset/eql-exact-runtime-pin.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -'@cipherstash/stack-prisma': patch -'stash': patch ---- - -Pin the packed `@cipherstash/eql` dependency to an exact version, closing a -route by which an installed EQL bundle could drift ahead of the code built -against it. - -Both packages declared `"@cipherstash/eql": "workspace:^"` under -`dependencies`. In this workspace that resolves in-tree either way, so nothing -in development or CI could see a difference — but the two specifiers do not -pack the same. pnpm rewrites the protocol when it builds the tarball a customer -actually installs: - - "workspace:^" packs as "^3.0.5" - "workspace:*" packs as "3.0.5" - -The caret is the problem. `@cipherstash/eql` is still published from -`cipherstash/encrypt-query-language` until the publisher repoint, so a 3.0.x can -reach npm without passing through this repository at all — and `^3.0.5` accepts -it. A customer installing `stash` or `@cipherstash/stack-prisma` would then get -SQL that STORES and queries encrypted payloads at one version, while -`@cipherstash/stack`'s v3 domain types (which EMIT those payloads) and -`stack-prisma`'s baked migrations stayed frozen at the version this repo built -and tested against. The two halves of EQL are released in lockstep precisely -because that skew does not fail at install or in CI — it fails in a database. - -`workspace:*` is the only form that closes it. A literal `"3.0.5"` would be an -exact pin too, but it is a registry pin: `pnpm run lint:eql-pins` rejects it, -because resolving EQL from a registry rather than from this repo is the same -drift one layer up. - -No API, behaviour or SQL changes. What changes is the dependency range in the -published tarballs, and only in the narrowing direction — the version resolved -today is the version that was already being resolved. Nothing needs to be done -on upgrade. - -`@cipherstash/stack` declares the same dependency under `devDependencies` and -is deliberately left alone: pnpm rewrites that range too, but no consumer of the -package ever resolves it. diff --git a/.changeset/eql-repoint-manifests-to-stack.md b/.changeset/eql-repoint-manifests-to-stack.md deleted file mode 100644 index 903621653..000000000 --- a/.changeset/eql-repoint-manifests-to-stack.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@cipherstash/eql': patch ---- - -Point `repository`, `repository.directory`, and `bugs.url` at `cipherstash/stack` instead of the archived `cipherstash/encrypt-query-language`. Purely metadata — no behaviour change — but required before npm's trusted publishing (already repointed at `cipherstash/stack`) can accept a release: npm rejects a publish whose manifest `repository.url` doesn't match the publishing repository. diff --git a/.changeset/lucky-poems-repeat.md b/.changeset/lucky-poems-repeat.md deleted file mode 100644 index b7f49eaf4..000000000 --- a/.changeset/lucky-poems-repeat.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@cipherstash/stack-supabase': patch ---- - -Correct the runtime story in the TSDoc that ships as `.d.ts`. - -Three claims a user sees on hover were wrong: - -- `makeEncryptedSupabase` said "Declare your schemas and it runs anywhere; omit - them and we discover them for you, which needs a database connection and is - therefore Node-only." Declaring `schemas` does skip introspection entirely — - no Postgres connection, no `pg`, no `databaseUrl` — but it does not make the - default entry edge-capable. **The entry point decides where the wrapper runs; - `schemas` decides only whether Postgres is involved.** -- The default entry's doc named `@cipherstash/protect-ffi` as the Node-API - binary loaded on import. It is the one package in that graph that - deliberately does not load on import; the module-evaluation-time load belongs - to `@cipherstash/auth`. -- `./wasm-inline`'s doc called introspection "half of what made the default - entry Node-only". The engine is what makes it Node-only, and its emitted - bundle also carries an `import("pg")` specifier a bundler resolves at build - time. Introspection is a separate axis. - -Documentation only — no runtime behaviour changes. diff --git a/.changeset/nextjs-cts-refusal-diagnostics.md b/.changeset/nextjs-cts-refusal-diagnostics.md deleted file mode 100644 index 004cbb71d..000000000 --- a/.changeset/nextjs-cts-refusal-diagnostics.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@cipherstash/nextjs': minor ---- - -Report what the CipherStash token service actually said when it refuses a token. - -`getCtsToken()` reported a non-2xx response as `Failed to fetch CTS token: ` and -nothing else. It read `statusText`, which is the empty string over HTTP/2 — so -the message ended at the colon — and it discarded the response body, taking any -refusal code with it. A billing refusal was indistinguishable from a bad token, -and the accompanying log said "contact support", which is the wrong advice for -an organisation that needs to upgrade a plan. - -The failure now names the status and quotes what the service returned, and the -refusal code is surfaced on a new optional `authCode` field of -`GetCtsTokenResponse` — `USAGE_LIMIT_EXCEEDED` for an organisation over its -allowance, `ORG_NOT_PROVISIONED` for one not registered with the usage system. -Both are terminal: retrying cannot clear either. Unknown `402` codes are -declined so a future payment-required response does not inherit the wrong -classification. - -The body is read as text exactly once and then parsed defensively, never with -`response.json()`. The two shapes are not the same shape: a `402` is JSON, while -every other failure from this endpoint is `text/plain` (a `401` is the bare -string `Authorization failed: InvalidToken`), and `.json()` on one of those -throws a `SyntaxError` that replaces the real failure with a parse error. A -response that is not a recognisable CipherStash refusal — a gateway or WAF -answering in front of the service — still reports its status and body rather -than being reported as a billing problem it is not. - -This package does not depend on `@cipherstash/stack`, so it carries the code -rather than a copy of that package's remedy text — look the remedy up from -`authCode` if you need to render one. diff --git a/.changeset/prisma-skill-upgrade-replan.md b/.changeset/prisma-skill-upgrade-replan.md deleted file mode 100644 index 19d93f919..000000000 --- a/.changeset/prisma-skill-upgrade-replan.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'stash': patch ---- - -`skills/stash-prisma` now documents the re-plan step that follows an -`@cipherstash/stack-prisma` upgrade: `rm -rf migrations/cipherstash && npx -prisma-next migration plan`, why only `migration plan` vendors new migration -packages, and the exact `db init` refusal a stale vendored directory produces on -a fresh database (`Operation cipherstash.upgrade-eql-v3-bundle-3.0.5 has class -"data" which is not allowed by policy.`). - -The package README already carried this; the skill did not — and the skill is -what ships inside the `stash` tarball and gets copied into a user's -`.claude/skills/`, so an agent driving the upgrade hit the refusal with no route -out of it. `packages/stack-prisma/test/v3/stale-vendored-space.test.ts` now pins -both files to the planner's real message so they cannot drift apart again. diff --git a/.changeset/protect-ffi-auth-error-code.md b/.changeset/protect-ffi-auth-error-code.md deleted file mode 100644 index 4dd3439af..000000000 --- a/.changeset/protect-ffi-auth-error-code.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@cipherstash/protect-ffi': minor ---- - -Carry `stack-auth` diagnostics across the JavaScript boundary. Errors that -originate in `stack-auth` now expose `authCode`, `help`, and `url` on both the -native and WASM bindings, alongside protect-ffi's existing `code` field. - -The boundary remains deliberately thin: `Error::Auth` and `Error::ZeroKMS` are -transparent miette diagnostics, so stack-auth continues to own the message, -instructions, and destination URL. Protect-ffi only serializes those fields and -reads the stable auth code from the typed `AuthError`; it does not classify the -message or maintain its own remedy taxonomy. - -`getAuthErrorCode(err)` reads the new field and `ProtectAuthErrorCode` types it. -The auth taxonomy is separate from protect-ffi's closed `ProtectErrorCode` set. diff --git a/.changeset/protect-ffi-client-0-42-3.md b/.changeset/protect-ffi-client-0-42-3.md deleted file mode 100644 index 3584a789d..000000000 --- a/.changeset/protect-ffi-client-0-42-3.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@cipherstash/protect-ffi': patch ---- - -Move the CipherStash client crates to `0.42.3` — `cipherstash-client`, -`cts-common`, `stack-auth` and `stack-profile`, which release in lockstep. - -This is the release that raises the usage-denial taxonomy. `stack-auth` gained -typed `UsageLimitExceeded` / `OrgNotProvisioned` errors with a `help` and a -`url` on each, a shared classifier for a `402` from any credential-issuance -path, and a 60-second sticky cache so a refused organisation stops re-issuing -the same doomed request at its own request rate. Together they are what makes -`authCode` on a failure report a billing refusal as one, rather than as a -generic server error a retry loop will hammer. - -It also carries a ZeroKMS change requiring `org_id` on every token. The client -side decodes claims without requiring it, so this is transparent here. diff --git a/.changeset/protect-ffi-eql-bindings-in-tree.md b/.changeset/protect-ffi-eql-bindings-in-tree.md deleted file mode 100644 index 894015531..000000000 --- a/.changeset/protect-ffi-eql-bindings-in-tree.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -'@cipherstash/protect-ffi': patch ---- - -Compile `eql-bindings` from this repository rather than from crates.io. - -The native binding pinned `eql-bindings = "=3.0.2"` from the registry. It now -resolves by path from `packages/eql/crates/eql-bindings`, which ships at 3.0.5 -alongside the `@cipherstash/eql` SQL bundle. - -**No behaviour change.** `eql-bindings` is the Rust half of EQL — it EMITS the -encrypted payloads that the SQL half STORES and queries — and its Rust source is -byte-identical across 3.0.2, 3.0.4 and 3.0.5 (`src/`, `bindings/` and `schema/` -compared directly). What 3.0.3 through 3.0.5 changed was SQL, carried on the -shared lockstep version number. So the payloads this binding produces are the -same bytes before and after; what moves is the version stamped on the crate -compiled into `index.node`, from 3.0.2 to 3.0.5. - -**Why it is worth a release anyway.** A registry pin let the two halves of EQL -drift apart silently. Nothing asserted they agreed: a mismatched pair compiles, -passes every suite, and fails in a database — because the failure is a payload -the installed SQL cannot read, which no unit test holds both sides of. Resolving -from the tree makes the skew unrepresentable: the emitter and the SQL are now -the same commit, and `pnpm run lint:eql-pins` fails any change that reintroduces -a registry pin on either. - -The flip was taken while it was a no-op deliberately. Waiting for the first -release where the two halves genuinely diverge would have turned a provenance -change into a behaviour change that had to be argued under credentialed test. - -Verified without credentials: `cargo build -p protect-ffi` clean, the crate test -suite green (310 passed) with `cargo fmt --check` clean, and a -`wasm32-unknown-unknown` build clean — the last of those being the target where a -cross-workspace path dependency would break first, since the EQL workspace never -otherwise builds for wasm32. diff --git a/.changeset/protect-ffi-jsonwebtoken-cve.md b/.changeset/protect-ffi-jsonwebtoken-cve.md deleted file mode 100644 index 8693f8e97..000000000 --- a/.changeset/protect-ffi-jsonwebtoken-cve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@cipherstash/protect-ffi': patch ---- - -Bump `cipherstash-client`, `cts-common`, `stack-auth`, and `stack-profile` to 0.42.2, which moves the transitive `jsonwebtoken` dependency from 9.3.1 to 10.4.0, resolving [CVE-2026-25537](https://github.com/advisories/GHSA-h395-gr6q-cpjc) (a JWT claim-validation type-confusion bug that could allow bypassing `nbf`/`exp` checks). No API changes. diff --git a/.changeset/skills-eql-source-and-index-cascade.md b/.changeset/skills-eql-source-and-index-cascade.md deleted file mode 100644 index 6b7c75930..000000000 --- a/.changeset/skills-eql-source-and-index-cascade.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'stash': patch ---- - -Correct two things the bundled agent skills were telling customers wrongly -about EQL. - -**`skills/stash-postgres` pointed at the wrong repository.** EQL's source now -lives in `cipherstash/stack` under `packages/eql/`, and that is where operator -gaps and domain-level bugs are filed; only *publishing* still happens from -`cipherstash/encrypt-query-language`, which the skill continues to say. The -skill also cited "the EQL skill" as a source of truth that "ships from -`encrypt-query-language` alongside the bundle" — no such skill ships from -either repository, so the reference is gone and the remaining three sources -(the generated types, the install SQL, and `SELECT eql_v3.version()`) are -renumbered. - -**And it claimed the CLI pins an exact `@cipherstash/eql` version, "so a -database is only ever on one bundle."** Neither half holds: the CLI depends on -the workspace package rather than a pinned literal, and a database is on -whatever bundle was last applied to it — the Prisma Next adapter installs and -upgrades the bundle through its own migrations without involving the CLI at -all. Replaced with the guarantee that does hold: one `stash` release carries -one resolved bundle, and the database is the authority on which bundle it has. - -**`skills/stash-prisma` hands out the functional-index recipe without saying an -EQL upgrade destroys it.** Installing a bundle begins with `DROP SCHEMA IF -EXISTS eql_v3 CASCADE`, which cascade-drops every index over an `eql_v3.*` -extractor — the PSL expression indexes Prisma Next 0.17 introduced and any -`rawSql` index DDL alike; queries keep working and silently sequential-scan. -Because an applied migration is never replayed, recovery is a NEW one: a PSL -expression index has to change its `name:` (the physical name carries a content -hash of the expression, so re-declaring the same one plans no work), and a -`rawSql` recovery op needs a new `id`. Said where the recipe is given, pointing -at `stash-indexing` for the mechanism and at -[cipherstash/stack#918](https://github.com/cipherstash/stack/issues/918) for -capturing and restoring them automatically. diff --git a/.changeset/stack-prisma-upgrade-from-1-0-0.md b/.changeset/stack-prisma-upgrade-from-1-0-0.md deleted file mode 100644 index 311ae91a5..000000000 --- a/.changeset/stack-prisma-upgrade-from-1-0-0.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@cipherstash/stack-prisma': patch ---- - -Document the 1.0.0 → 3.0.5 upgrade in the package README: why -`migrations/cipherstash/` must be deleted and regenerated, what each Prisma Next -command does if it is not, and the exact `db init` refusal -(`Operation cipherstash.upgrade-eql-v3-bundle-3.0.5 has class "data" which is -not allowed by policy.`) that a stale vendored directory produces on a fresh -database. - -The behaviour worth knowing regardless of version: only `prisma-next migration -plan` copies new migration packages into your repo. Running `migrate` or -`db init` after upgrading this package without planning first silently leaves -the database on the older EQL bundle — a stale vendored directory is internally -intact, so it passes every integrity check and nothing reports a problem. diff --git a/.changeset/supabase-skill-eql-305.md b/.changeset/supabase-skill-eql-305.md deleted file mode 100644 index 8f65699f7..000000000 --- a/.changeset/supabase-skill-eql-305.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'stash': patch ---- - -Update the bundled agent skills for eql-3.0.5. `skills/stash-supabase` -re-states the PostgREST query-domain limitations against 3.0.5 (unchanged in -substance — the typed `eql_v3.query_*` operand requirement still stands), and -`skills/stash-postgres` drops one of the two places it claimed the CLI pins -`@cipherstash/eql` to an exact version — a claim that stopped being true when -EQL moved in-tree. The second copy goes in the same release, with the rest of -that skill's EQL source and issue pointers. diff --git a/.changeset/usage-limit-refusal-guidance.md b/.changeset/usage-limit-refusal-guidance.md deleted file mode 100644 index 31eb32531..000000000 --- a/.changeset/usage-limit-refusal-guidance.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@cipherstash/stack': minor -'stash': minor ---- - -Surface CipherStash token-service refusals as typed diagnostics. - -`@cipherstash/stack` operation and initialization failures now carry -`authCode`, `help`, and `url` from stack-auth. The message remains stack-auth's -original diagnostic message; Stack does not copy or rewrite its instructions. -Callers can branch on `USAGE_LIMIT_EXCEEDED` or `ORG_NOT_PROVISIONED`, render -`help`, and link to `url`. - -`LockContext.identify()` also recognizes those two codes on a genuine CTS -`402`, while declining malformed or unknown responses. Legacy valid JSON -responses without `cs_code` retain the historical usage-limit classification. - -`stash auth login` and `stash env` now consume `@cipherstash/auth` 0.44.0's -typed failures. They print the upstream diagnostic guidance, preserve its URL, -avoid suggesting another login for terminal account refusals, and expose -terminal codes on the JSON stream. The JSON error envelope gains an optional -`hint` for the upstream guidance. diff --git a/.changeset/wasm-inline-client-key-not-browser-safe.md b/.changeset/wasm-inline-client-key-not-browser-safe.md deleted file mode 100644 index 995bc5937..000000000 --- a/.changeset/wasm-inline-client-key-not-browser-safe.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@cipherstash/stack': patch -'stash': patch ---- - -Document that `@cipherstash/stack/wasm-inline` is server-side only, and pin the -reason against the core. - -`WasmClientConfig` requires `clientId` and `clientKey` on every auth arm, -including the `authStrategy` (OIDC federation) arm. That read like an -over-declaration the SDK could relax — if federation alone sufficed, a browser -could hold a client without a workspace secret. It cannot. The core requires -both fields regardless of strategy, and loads `clientKey` as encryption key -material *before* it ever calls the auth strategy. Since `clientKey` is a -workspace secret, no configuration of this entry belongs in a browser bundle — -which is why this entry has no `browser` export condition, and will not get one -until the core changes. - -No behaviour change. The types and runtime are unchanged; what changes is that -the constraint is now stated where callers meet it — `WasmClientConfig`, the -`stash-edge` skill, the `stash-encryption` entry-point table, and, where this -entry had been described as browser-capable, the `stash-supabase` skill and -the `supabase-worker` example — and enforced by contract tests that run -against the real WASM core instead of the mocks and stubs the rest of the wasm -suite uses. diff --git a/e2e/CHANGELOG.md b/e2e/CHANGELOG.md index 099fe996c..9e958f2c4 100644 --- a/e2e/CHANGELOG.md +++ b/e2e/CHANGELOG.md @@ -1,5 +1,21 @@ # @cipherstash/e2e +## 0.0.6 + +### Patch Changes + +- Updated dependencies [801868d] +- Updated dependencies [ac46a5a] +- Updated dependencies [4422d5c] +- Updated dependencies [ad033df] +- Updated dependencies [4422d5c] +- Updated dependencies [ba37039] +- Updated dependencies [b04ea2f] +- Updated dependencies [518abfd] + - stash@1.2.0 + - @cipherstash/stack@1.2.0 + - @cipherstash/wizard@1.2.0 + ## 0.0.5 ### Patch Changes diff --git a/e2e/package.json b/e2e/package.json index 03d3bf485..d8717521e 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/e2e", - "version": "0.0.5", + "version": "0.0.6", "private": true, "description": "End-to-end tests that exercise built CipherStash binaries and cross-package behaviour.", "type": "module", diff --git a/examples/basic/CHANGELOG.md b/examples/basic/CHANGELOG.md index 0f978233b..f989f1cad 100644 --- a/examples/basic/CHANGELOG.md +++ b/examples/basic/CHANGELOG.md @@ -1,5 +1,14 @@ # @cipherstash/basic-example +## 1.2.17 + +### Patch Changes + +- Updated dependencies [b04ea2f] +- Updated dependencies [518abfd] + - @cipherstash/stack@1.2.0 + - @cipherstash/stack-drizzle@1.2.0 + ## 1.2.16 ### Patch Changes diff --git a/examples/basic/package.json b/examples/basic/package.json index f2975b41f..38056359b 100644 --- a/examples/basic/package.json +++ b/examples/basic/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/basic-example", "private": true, - "version": "1.2.16", + "version": "1.2.17", "type": "module", "scripts": { "start": "tsx index.ts", diff --git a/examples/prisma/CHANGELOG.md b/examples/prisma/CHANGELOG.md index e1f8a9ca6..8829870de 100644 --- a/examples/prisma/CHANGELOG.md +++ b/examples/prisma/CHANGELOG.md @@ -1,5 +1,17 @@ # @cipherstash/prisma-next-example +## 0.1.3 + +### Patch Changes + +- Updated dependencies [ba37039] +- Updated dependencies [4422d5c] +- Updated dependencies [c604028] +- Updated dependencies [b04ea2f] +- Updated dependencies [518abfd] + - @cipherstash/stack-prisma@1.2.0 + - @cipherstash/stack@1.2.0 + ## 0.1.2 ### Patch Changes diff --git a/examples/prisma/package.json b/examples/prisma/package.json index 53e28833b..6c0f96e9a 100644 --- a/examples/prisma/package.json +++ b/examples/prisma/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/prisma-example", "private": true, - "version": "0.1.2", + "version": "0.1.3", "description": "End-to-end example of @cipherstash/stack-prisma: searchable application-layer encryption for Postgres with Prisma Next, using @cipherstash/stack as the SDK.", "type": "module", "scripts": { diff --git a/packages/bench/CHANGELOG.md b/packages/bench/CHANGELOG.md index 87d5b7a4b..d341d7166 100644 --- a/packages/bench/CHANGELOG.md +++ b/packages/bench/CHANGELOG.md @@ -1,5 +1,14 @@ # @cipherstash/bench +## 0.0.8 + +### Patch Changes + +- Updated dependencies [b04ea2f] +- Updated dependencies [518abfd] + - @cipherstash/stack@1.2.0 + - @cipherstash/stack-drizzle@1.2.0 + ## 0.0.7 ### Patch Changes diff --git a/packages/bench/package.json b/packages/bench/package.json index 56068c2ef..809e21efa 100644 --- a/packages/bench/package.json +++ b/packages/bench/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/bench", - "version": "0.0.7", + "version": "0.0.8", "private": true, "description": "Performance / index-engagement benchmarks for stack integrations (Drizzle, encryptedSupabase, Prisma).", "type": "module", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 1401bdda2..c9bdb74b8 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,182 @@ # stash +## 1.2.0 + +### Minor Changes + +- b04ea2f: Surface CipherStash token-service refusals as typed diagnostics. + + `@cipherstash/stack` operation and initialization failures now carry + `authCode`, `help`, and `url` from stack-auth. The message remains stack-auth's + original diagnostic message; Stack does not copy or rewrite its instructions. + Callers can branch on `USAGE_LIMIT_EXCEEDED` or `ORG_NOT_PROVISIONED`, render + `help`, and link to `url`. + + `LockContext.identify()` also recognizes those two codes on a genuine CTS + `402`, while declining malformed or unknown responses. Legacy valid JSON + responses without `cs_code` retain the historical usage-limit classification. + + `stash auth login` and `stash env` now consume `@cipherstash/auth` 0.44.0's + typed failures. They print the upstream diagnostic guidance, preserve its URL, + avoid suggesting another login for terminal account refusals, and expose + terminal codes on the JSON stream. The JSON error envelope gains an optional + `hint` for the upstream guidance. + +### Patch Changes + +- 801868d: Verify the EQL install SQL against its release digest before running it. + + `stash eql install` reads the EQL v3 bundle from the resolved + `@cipherstash/eql` in your `node_modules` and executes it against your + database. That read was a bare `readFileSync` — nothing checked that the bytes + on disk were the bundle the resolved release actually ships. A corrupt, + partially-updated, or tampered package installed silently: the database ended + up carrying SQL the version it reports does not define, and the CLI printed + "EQL extensions installed." + + The CLI now hashes the bundle and compares it to `installSqlSha256` from the + release manifest that ships alongside it, and **refuses** on a mismatch. The + error names the expected digest, the actual digest, the resolved file path and + the EQL version, so the remedy is visible rather than inferred. Verification + happens before any database connection is opened, so a refusal means nothing + was attempted — not that something was rolled back. + + The check covers all three paths that read the bundle: `stash eql install`, + the SQL embedded by `stash eql migration --drizzle` / `--supabase`, and the + expected-surface baseline `stash eql verify` compares your database against. + `@cipherstash/stack-prisma` has verified against this same digest since its v3 + migrations landed; this brings the CLI in line. + + No healthy install is affected — the SQL and its manifest are produced by the + same build of `@cipherstash/eql`, so a mismatch only ever means a broken + dependency tree. + + `skills/stash-cli` documents the new pre-flight alongside the existing + post-install surface check, so an agent reading it does not report a digest + refusal as a failed install. + +- ac46a5a: `stash doctor` no longer reports "All checks passed." when `@cipherstash/stack` + is absent. The package is an optional peer, so running `doctor` before `stash +init` skips the encryption check entirely — the row already said so, but the + outro claimed a pass for a check that never ran. It now ends with "stash doctor + could not run every check.", the same line an unprobeable install gets, and + still exits 0: an absent optional package is recoverable, not a failure. +- 4422d5c: Pin the packed `@cipherstash/eql` dependency to an exact version, closing a + route by which an installed EQL bundle could drift ahead of the code built + against it. + + Both packages declared `"@cipherstash/eql": "workspace:^"` under + `dependencies`. In this workspace that resolves in-tree either way, so nothing + in development or CI could see a difference — but the two specifiers do not + pack the same. pnpm rewrites the protocol when it builds the tarball a customer + actually installs: + + "workspace:^" packs as "^3.0.5" + "workspace:*" packs as "3.0.5" + + The caret is the problem. `@cipherstash/eql` is still published from + `cipherstash/encrypt-query-language` until the publisher repoint, so a 3.0.x can + reach npm without passing through this repository at all — and `^3.0.5` accepts + it. A customer installing `stash` or `@cipherstash/stack-prisma` would then get + SQL that STORES and queries encrypted payloads at one version, while + `@cipherstash/stack`'s v3 domain types (which EMIT those payloads) and + `stack-prisma`'s baked migrations stayed frozen at the version this repo built + and tested against. The two halves of EQL are released in lockstep precisely + because that skew does not fail at install or in CI — it fails in a database. + + `workspace:*` is the only form that closes it. A literal `"3.0.5"` would be an + exact pin too, but it is a registry pin: `pnpm run lint:eql-pins` rejects it, + because resolving EQL from a registry rather than from this repo is the same + drift one layer up. + + No API, behaviour or SQL changes. What changes is the dependency range in the + published tarballs, and only in the narrowing direction — the version resolved + today is the version that was already being resolved. Nothing needs to be done + on upgrade. + + `@cipherstash/stack` declares the same dependency under `devDependencies` and + is deliberately left alone: pnpm rewrites that range too, but no consumer of the + package ever resolves it. + +- ad033df: `skills/stash-prisma` now documents the re-plan step that follows an + `@cipherstash/stack-prisma` upgrade: `rm -rf migrations/cipherstash && npx +prisma-next migration plan`, why only `migration plan` vendors new migration + packages, and the exact `db init` refusal a stale vendored directory produces on + a fresh database (`Operation cipherstash.upgrade-eql-v3-bundle-3.0.5 has class +"data" which is not allowed by policy.`). + + The package README already carried this; the skill did not — and the skill is + what ships inside the `stash` tarball and gets copied into a user's + `.claude/skills/`, so an agent driving the upgrade hit the refusal with no route + out of it. `packages/stack-prisma/test/v3/stale-vendored-space.test.ts` now pins + both files to the planner's real message so they cannot drift apart again. + +- 4422d5c: Correct two things the bundled agent skills were telling customers wrongly + about EQL. + + **`skills/stash-postgres` pointed at the wrong repository.** EQL's source now + lives in `cipherstash/stack` under `packages/eql/`, and that is where operator + gaps and domain-level bugs are filed; only _publishing_ still happens from + `cipherstash/encrypt-query-language`, which the skill continues to say. The + skill also cited "the EQL skill" as a source of truth that "ships from + `encrypt-query-language` alongside the bundle" — no such skill ships from + either repository, so the reference is gone and the remaining three sources + (the generated types, the install SQL, and `SELECT eql_v3.version()`) are + renumbered. + + **And it claimed the CLI pins an exact `@cipherstash/eql` version, "so a + database is only ever on one bundle."** Neither half holds: the CLI depends on + the workspace package rather than a pinned literal, and a database is on + whatever bundle was last applied to it — the Prisma Next adapter installs and + upgrades the bundle through its own migrations without involving the CLI at + all. Replaced with the guarantee that does hold: one `stash` release carries + one resolved bundle, and the database is the authority on which bundle it has. + + **`skills/stash-prisma` hands out the functional-index recipe without saying an + EQL upgrade destroys it.** Installing a bundle begins with `DROP SCHEMA IF +EXISTS eql_v3 CASCADE`, which cascade-drops every index over an `eql_v3.*` + extractor — the PSL expression indexes Prisma Next 0.17 introduced and any + `rawSql` index DDL alike; queries keep working and silently sequential-scan. + Because an applied migration is never replayed, recovery is a NEW one: a PSL + expression index has to change its `name:` (the physical name carries a content + hash of the expression, so re-declaring the same one plans no work), and a + `rawSql` recovery op needs a new `id`. Said where the recipe is given, pointing + at `stash-indexing` for the mechanism and at + [cipherstash/stack#918](https://github.com/cipherstash/stack/issues/918) for + capturing and restoring them automatically. + +- ba37039: Update the bundled agent skills for eql-3.0.5. `skills/stash-supabase` + re-states the PostgREST query-domain limitations against 3.0.5 (unchanged in + substance — the typed `eql_v3.query_*` operand requirement still stands), and + `skills/stash-postgres` drops one of the two places it claimed the CLI pins + `@cipherstash/eql` to an exact version — a claim that stopped being true when + EQL moved in-tree. The second copy goes in the same release, with the rest of + that skill's EQL source and issue pointers. +- 518abfd: Document that `@cipherstash/stack/wasm-inline` is server-side only, and pin the + reason against the core. + + `WasmClientConfig` requires `clientId` and `clientKey` on every auth arm, + including the `authStrategy` (OIDC federation) arm. That read like an + over-declaration the SDK could relax — if federation alone sufficed, a browser + could hold a client without a workspace secret. It cannot. The core requires + both fields regardless of strategy, and loads `clientKey` as encryption key + material _before_ it ever calls the auth strategy. Since `clientKey` is a + workspace secret, no configuration of this entry belongs in a browser bundle — + which is why this entry has no `browser` export condition, and will not get one + until the core changes. + + No behaviour change. The types and runtime are unchanged; what changes is that + the constraint is now stated where callers meet it — `WasmClientConfig`, the + `stash-edge` skill, the `stash-encryption` entry-point table, and, where this + entry had been described as browser-capable, the `stash-supabase` skill and + the `supabase-worker` example — and enforced by contract tests that run + against the real WASM core instead of the mocks and stubs the rest of the wasm + suite uses. + +- Updated dependencies [e52d331] + - @cipherstash/eql@3.0.6 + - @cipherstash/migrate@1.0.0 + ## 1.1.1 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 879cc0f09..afa98b376 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "stash", - "version": "1.1.1", + "version": "1.2.0", "description": "CipherStash CLI — the one stash command for auth, init, encryption schema, database setup, and secrets.", "repository": { "type": "git", diff --git a/packages/eql/Cargo.lock b/packages/eql/Cargo.lock index 8e6f936bb..4ebb4b70a 100644 --- a/packages/eql/Cargo.lock +++ b/packages/eql/Cargo.lock @@ -1131,7 +1131,7 @@ dependencies = [ [[package]] name = "eql-bindings" -version = "3.0.5" +version = "3.0.6" dependencies = [ "eql-domains", "schemars", diff --git a/packages/eql/crates/eql-bindings/Cargo.toml b/packages/eql/crates/eql-bindings/Cargo.toml index 5c443d5cc..dea9d5db2 100644 --- a/packages/eql/crates/eql-bindings/Cargo.toml +++ b/packages/eql/crates/eql-bindings/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eql-bindings" -version = "3.0.5" +version = "3.0.6" edition = "2021" description = "Canonical wire types for EQL payloads — single source of truth for Rust, TypeScript (ts-rs), and JSON Schema (schemars)." # crates.io metadata. `license` is REQUIRED by crates.io — publish fails without diff --git a/packages/eql/crates/eql-bindings/sql/cipherstash-encrypt.sql b/packages/eql/crates/eql-bindings/sql/cipherstash-encrypt.sql index 88c460300..4b40deee5 100644 --- a/packages/eql/crates/eql-bindings/sql/cipherstash-encrypt.sql +++ b/packages/eql/crates/eql-bindings/sql/cipherstash-encrypt.sql @@ -59469,7 +59469,7 @@ DROP FUNCTION IF EXISTS eql_v3.version(); --! @brief EQL version reporting (self-contained eql_v3 surface) --! --! This file is auto-generated from src/v3/version.template during build. ---! The 3.0.5 placeholder is replaced with the actual release +--! The 3.0.6 placeholder is replaced with the actual release --! version (bare semver, e.g. "3.0.0") supplied via `mise run build --version`, --! or "DEV" for development builds. @@ -59488,14 +59488,14 @@ CREATE FUNCTION eql_v3.version() RETURNS text IMMUTABLE STRICT PARALLEL SAFE AS $$ - SELECT '3.0.5'; + SELECT '3.0.6'; $$ LANGUAGE SQL; --! @brief Schema-level version marker for obj_description() discoverability --! --! Mirrors eql_v3.version() as a comment on the schema so the installed --! version can also be read via obj_description('eql_v3'::regnamespace). -COMMENT ON SCHEMA eql_v3 IS '3.0.5'; +COMMENT ON SCHEMA eql_v3 IS '3.0.6'; --! @file pin_search_path_v3.sql --! @brief Post-install: pin search_path on every eql_v3.* function. --! diff --git a/packages/eql/crates/eql-bindings/sql/release-manifest.json b/packages/eql/crates/eql-bindings/sql/release-manifest.json index f0203fcc7..cd386a01c 100644 --- a/packages/eql/crates/eql-bindings/sql/release-manifest.json +++ b/packages/eql/crates/eql-bindings/sql/release-manifest.json @@ -1,6 +1,6 @@ { - "eqlVersion": "3.0.5", + "eqlVersion": "3.0.6", "schemaVersion": 3, - "installSqlSha256": "accde0030b8f356af616175640635f67661d51aa900624b7fb0fb059e8115048", + "installSqlSha256": "9b6dab789248f911707f7c1c468c5d455987b47aac4a30fc421bc813073fffb1", "uninstallSqlSha256": "b1b5131b8175c5d04da9ada108d25c81c5772b15fad79a6c419ebb32d18c60a9" } diff --git a/packages/eql/packages/eql/CHANGELOG.md b/packages/eql/packages/eql/CHANGELOG.md index 1942b9676..6f0c535d2 100644 --- a/packages/eql/packages/eql/CHANGELOG.md +++ b/packages/eql/packages/eql/CHANGELOG.md @@ -1,5 +1,11 @@ # @cipherstash/eql +## 3.0.6 + +### Patch Changes + +- e52d331: Point `repository`, `repository.directory`, and `bugs.url` at `cipherstash/stack` instead of the archived `cipherstash/encrypt-query-language`. Purely metadata — no behaviour change — but required before npm's trusted publishing (already repointed at `cipherstash/stack`) can accept a release: npm rejects a publish whose manifest `repository.url` doesn't match the publishing repository. + ## 3.0.5 ### Patch Changes @@ -20,7 +26,7 @@ pressure. See [U-001](../../docs/upgrading/v3.0.5.md#u-001-the-containment-implementation-is-renamed). **The thing in this release that does have consequences is not the rename.** - The installer opens with `DROP SCHEMA IF EXISTS eql_v3 CASCADE`, so *every* EQL + The installer opens with `DROP SCHEMA IF EXISTS eql_v3 CASCADE`, so _every_ EQL install drops grants, functional indexes and dependent views — true of every release, not just this one, and now the only item here with operational weight. See [U-002](../../docs/upgrading/v3.0.5.md#u-002-grants-and-dependent-objects-do-not-survive-an-install). @@ -49,6 +55,7 @@ re-synced to that release so the bundle here is byte-identical to the published one — `installSqlSha256: accde0030…`. The generated entry below is upstream's own changeset for the same release. + - 4c2bb92: **`eql_v3.ste_vec_contains` is renamed to `eql_v3.jsonb_document_contains`.** This consolidates the last `ste_vec_*`-named public object into the `jsonb_*` family, matching the earlier renames of the SteVec entry/query surface (`jsonb_entry`, diff --git a/packages/eql/packages/eql/package.json b/packages/eql/packages/eql/package.json index 36db8bd81..ae87ef23b 100644 --- a/packages/eql/packages/eql/package.json +++ b/packages/eql/packages/eql/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/eql", - "version": "3.0.5", + "version": "3.0.6", "description": "Canonical EQL v3 wire types, JSON schemas, and SQL bundle.", "keywords": [ "eql", diff --git a/packages/eql/packages/eql/sql/cipherstash-encrypt.sql b/packages/eql/packages/eql/sql/cipherstash-encrypt.sql index 88c460300..4b40deee5 100644 --- a/packages/eql/packages/eql/sql/cipherstash-encrypt.sql +++ b/packages/eql/packages/eql/sql/cipherstash-encrypt.sql @@ -59469,7 +59469,7 @@ DROP FUNCTION IF EXISTS eql_v3.version(); --! @brief EQL version reporting (self-contained eql_v3 surface) --! --! This file is auto-generated from src/v3/version.template during build. ---! The 3.0.5 placeholder is replaced with the actual release +--! The 3.0.6 placeholder is replaced with the actual release --! version (bare semver, e.g. "3.0.0") supplied via `mise run build --version`, --! or "DEV" for development builds. @@ -59488,14 +59488,14 @@ CREATE FUNCTION eql_v3.version() RETURNS text IMMUTABLE STRICT PARALLEL SAFE AS $$ - SELECT '3.0.5'; + SELECT '3.0.6'; $$ LANGUAGE SQL; --! @brief Schema-level version marker for obj_description() discoverability --! --! Mirrors eql_v3.version() as a comment on the schema so the installed --! version can also be read via obj_description('eql_v3'::regnamespace). -COMMENT ON SCHEMA eql_v3 IS '3.0.5'; +COMMENT ON SCHEMA eql_v3 IS '3.0.6'; --! @file pin_search_path_v3.sql --! @brief Post-install: pin search_path on every eql_v3.* function. --! diff --git a/packages/eql/packages/eql/sql/release-manifest.json b/packages/eql/packages/eql/sql/release-manifest.json index f0203fcc7..cd386a01c 100644 --- a/packages/eql/packages/eql/sql/release-manifest.json +++ b/packages/eql/packages/eql/sql/release-manifest.json @@ -1,6 +1,6 @@ { - "eqlVersion": "3.0.5", + "eqlVersion": "3.0.6", "schemaVersion": 3, - "installSqlSha256": "accde0030b8f356af616175640635f67661d51aa900624b7fb0fb059e8115048", + "installSqlSha256": "9b6dab789248f911707f7c1c468c5d455987b47aac4a30fc421bc813073fffb1", "uninstallSqlSha256": "b1b5131b8175c5d04da9ada108d25c81c5772b15fad79a6c419ebb32d18c60a9" } diff --git a/packages/eql/packages/eql/src/generated/release-manifest.ts b/packages/eql/packages/eql/src/generated/release-manifest.ts index 21c403c1c..30e8cd835 100644 --- a/packages/eql/packages/eql/src/generated/release-manifest.ts +++ b/packages/eql/packages/eql/src/generated/release-manifest.ts @@ -1,6 +1,6 @@ export const releaseManifest = { - eqlVersion: '3.0.5', + eqlVersion: '3.0.6', schemaVersion: 3, - installSqlSha256: 'accde0030b8f356af616175640635f67661d51aa900624b7fb0fb059e8115048', + installSqlSha256: '9b6dab789248f911707f7c1c468c5d455987b47aac4a30fc421bc813073fffb1', uninstallSqlSha256: 'b1b5131b8175c5d04da9ada108d25c81c5772b15fad79a6c419ebb32d18c60a9', } as const diff --git a/packages/nextjs/CHANGELOG.md b/packages/nextjs/CHANGELOG.md index cf588367b..028fd5306 100644 --- a/packages/nextjs/CHANGELOG.md +++ b/packages/nextjs/CHANGELOG.md @@ -1,5 +1,39 @@ # @cipherstash/nextjs +## 4.2.0 + +### Minor Changes + +- d3efdbd: Report what the CipherStash token service actually said when it refuses a token. + + `getCtsToken()` reported a non-2xx response as `Failed to fetch CTS token: ` and + nothing else. It read `statusText`, which is the empty string over HTTP/2 — so + the message ended at the colon — and it discarded the response body, taking any + refusal code with it. A billing refusal was indistinguishable from a bad token, + and the accompanying log said "contact support", which is the wrong advice for + an organisation that needs to upgrade a plan. + + The failure now names the status and quotes what the service returned, and the + refusal code is surfaced on a new optional `authCode` field of + `GetCtsTokenResponse` — `USAGE_LIMIT_EXCEEDED` for an organisation over its + allowance, `ORG_NOT_PROVISIONED` for one not registered with the usage system. + Both are terminal: retrying cannot clear either. Unknown `402` codes are + declined so a future payment-required response does not inherit the wrong + classification. + + The body is read as text exactly once and then parsed defensively, never with + `response.json()`. The two shapes are not the same shape: a `402` is JSON, while + every other failure from this endpoint is `text/plain` (a `401` is the bare + string `Authorization failed: InvalidToken`), and `.json()` on one of those + throws a `SyntaxError` that replaces the real failure with a parse error. A + response that is not a recognisable CipherStash refusal — a gateway or WAF + answering in front of the service — still reports its status and body rather + than being reported as a billing problem it is not. + + This package does not depend on `@cipherstash/stack`, so it carries the code + rather than a copy of that package's remedy text — look the remedy up from + `authCode` if you need to render one. + ## 4.1.2 ### Patch Changes diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 948e606ad..6f6b2529c 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/nextjs", - "version": "4.1.2", + "version": "4.2.0", "description": "Nextjs package for use with @cipherstash/stack", "keywords": [ "encrypted", diff --git a/packages/protect-ffi/CHANGELOG.md b/packages/protect-ffi/CHANGELOG.md index 9129d0cc5..5cfe7a32e 100644 --- a/packages/protect-ffi/CHANGELOG.md +++ b/packages/protect-ffi/CHANGELOG.md @@ -1,5 +1,72 @@ # Changelog +## 0.33.0 + +### Minor Changes + +- 8839d5a: Carry `stack-auth` diagnostics across the JavaScript boundary. Errors that + originate in `stack-auth` now expose `authCode`, `help`, and `url` on both the + native and WASM bindings, alongside protect-ffi's existing `code` field. + + The boundary remains deliberately thin: `Error::Auth` and `Error::ZeroKMS` are + transparent miette diagnostics, so stack-auth continues to own the message, + instructions, and destination URL. Protect-ffi only serializes those fields and + reads the stable auth code from the typed `AuthError`; it does not classify the + message or maintain its own remedy taxonomy. + + `getAuthErrorCode(err)` reads the new field and `ProtectAuthErrorCode` types it. + The auth taxonomy is separate from protect-ffi's closed `ProtectErrorCode` set. + +### Patch Changes + +- 8839d5a: Move the CipherStash client crates to `0.42.3` — `cipherstash-client`, + `cts-common`, `stack-auth` and `stack-profile`, which release in lockstep. + + This is the release that raises the usage-denial taxonomy. `stack-auth` gained + typed `UsageLimitExceeded` / `OrgNotProvisioned` errors with a `help` and a + `url` on each, a shared classifier for a `402` from any credential-issuance + path, and a 60-second sticky cache so a refused organisation stops re-issuing + the same doomed request at its own request rate. Together they are what makes + `authCode` on a failure report a billing refusal as one, rather than as a + generic server error a retry loop will hammer. + + It also carries a ZeroKMS change requiring `org_id` on every token. The client + side decodes claims without requiring it, so this is transparent here. + +- 4422d5c: Compile `eql-bindings` from this repository rather than from crates.io. + + The native binding pinned `eql-bindings = "=3.0.2"` from the registry. It now + resolves by path from `packages/eql/crates/eql-bindings`, which ships at 3.0.5 + alongside the `@cipherstash/eql` SQL bundle. + + **No behaviour change.** `eql-bindings` is the Rust half of EQL — it EMITS the + encrypted payloads that the SQL half STORES and queries — and its Rust source is + byte-identical across 3.0.2, 3.0.4 and 3.0.5 (`src/`, `bindings/` and `schema/` + compared directly). What 3.0.3 through 3.0.5 changed was SQL, carried on the + shared lockstep version number. So the payloads this binding produces are the + same bytes before and after; what moves is the version stamped on the crate + compiled into `index.node`, from 3.0.2 to 3.0.5. + + **Why it is worth a release anyway.** A registry pin let the two halves of EQL + drift apart silently. Nothing asserted they agreed: a mismatched pair compiles, + passes every suite, and fails in a database — because the failure is a payload + the installed SQL cannot read, which no unit test holds both sides of. Resolving + from the tree makes the skew unrepresentable: the emitter and the SQL are now + the same commit, and `pnpm run lint:eql-pins` fails any change that reintroduces + a registry pin on either. + + The flip was taken while it was a no-op deliberately. Waiting for the first + release where the two halves genuinely diverge would have turned a provenance + change into a behaviour change that had to be argued under credentialed test. + + Verified without credentials: `cargo build -p protect-ffi` clean, the crate test + suite green (310 passed) with `cargo fmt --check` clean, and a + `wasm32-unknown-unknown` build clean — the last of those being the target where a + cross-workspace path dependency would break first, since the EQL workspace never + otherwise builds for wasm32. + +- Bump `cipherstash-client`, `cts-common`, `stack-auth`, and `stack-profile` to 0.42.2, which moves the transitive `jsonwebtoken` dependency from 9.3.1 to 10.4.0, resolving [CVE-2026-25537](https://github.com/advisories/GHSA-h395-gr6q-cpjc) (a JWT claim-validation type-confusion bug that could allow bypassing `nbf`/`exp` checks). No API changes. + ## 0.32.0 ### Minor Changes @@ -122,7 +189,7 @@ clientKey: expected a hex-encoded key`. Re-encode as hex, or read the key - **A key an options object doesn't declare is now an error, not a silent drop.** Every options struct rejects unrecognised fields, naming the - offender — `` unknown field `clientId` `` — instead of discarding them on the + offender — ``unknown field `clientId` `` — instead of discarding them on the way in. A misspelling, a stale key, or a value in the wrong place fails loudly. ([#144]) @@ -156,8 +223,8 @@ clientKey: expected a hex-encoded key`. Re-encode as hex, or read the key `Object.defineProperty({enumerable: false})` is dropped. Neon has always been `JSON.stringify`, which is own-enumerable too. - **A misspelled _required_ field now reports it as missing, not unknown.** - `encrypt(client, {plaintext, column, tabel: 'users'})` says `` missing -field `table` `` and never names `tabel`; it used to say both. Serde's + `encrypt(client, {plaintext, column, tabel: 'users'})` says ``missing +field `table` `` and never names `tabel`; it used to say both. Serde's flatten path buffers the map and reports at its closing brace, which also drops the `expected one of ...` list from every rejection. Neon-only — the wasm path had no error to lose. diff --git a/packages/protect-ffi/Cargo.lock b/packages/protect-ffi/Cargo.lock index 9ea0210c7..dc409fec6 100644 --- a/packages/protect-ffi/Cargo.lock +++ b/packages/protect-ffi/Cargo.lock @@ -1058,7 +1058,7 @@ dependencies = [ [[package]] name = "eql-bindings" -version = "3.0.5" +version = "3.0.6" dependencies = [ "schemars", "serde", @@ -1079,7 +1079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3024,7 +3024,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3369,7 +3369,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -4400,7 +4400,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] diff --git a/packages/protect-ffi/integration-tests/CHANGELOG.md b/packages/protect-ffi/integration-tests/CHANGELOG.md new file mode 100644 index 000000000..7f2deaa1c --- /dev/null +++ b/packages/protect-ffi/integration-tests/CHANGELOG.md @@ -0,0 +1,11 @@ +# @cipherstash/ffi-integration-tests + +## 1.0.1 + +### Patch Changes + +- Updated dependencies [8839d5a] +- Updated dependencies [8839d5a] +- Updated dependencies [4422d5c] +- Updated dependencies + - @cipherstash/protect-ffi@0.33.0 diff --git a/packages/protect-ffi/integration-tests/package.json b/packages/protect-ffi/integration-tests/package.json index 8ece03acd..97620d469 100644 --- a/packages/protect-ffi/integration-tests/package.json +++ b/packages/protect-ffi/integration-tests/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/ffi-integration-tests", - "version": "1.0.0", + "version": "1.0.1", "private": true, "description": "Live integration coverage for @cipherstash/protect-ffi — real ZeroKMS, real Postgres, EQL v2 and v3", "license": "MIT", diff --git a/packages/protect-ffi/package.json b/packages/protect-ffi/package.json index 0edef5ffa..7c6dccfa2 100644 --- a/packages/protect-ffi/package.json +++ b/packages/protect-ffi/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.32.0", + "version": "0.33.0", "repository": { "type": "git", "url": "git+https://github.com/cipherstash/stack.git" diff --git a/packages/protect-ffi/platforms/darwin-arm64/CHANGELOG.md b/packages/protect-ffi/platforms/darwin-arm64/CHANGELOG.md index f29e8e2a3..807ce0ec6 100644 --- a/packages/protect-ffi/platforms/darwin-arm64/CHANGELOG.md +++ b/packages/protect-ffi/platforms/darwin-arm64/CHANGELOG.md @@ -1,5 +1,7 @@ # @cipherstash/protect-ffi-darwin-arm64 +## 0.33.0 + ## 0.32.0 ### Patch Changes diff --git a/packages/protect-ffi/platforms/darwin-arm64/package.json b/packages/protect-ffi/platforms/darwin-arm64/package.json index 155b6f6bd..859494a49 100644 --- a/packages/protect-ffi/platforms/darwin-arm64/package.json +++ b/packages/protect-ffi/platforms/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-arm64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-arm64`.", - "version": "0.32.0", + "version": "0.33.0", "repository": { "type": "git", "url": "git+https://github.com/cipherstash/stack.git", diff --git a/packages/protect-ffi/platforms/darwin-x64/CHANGELOG.md b/packages/protect-ffi/platforms/darwin-x64/CHANGELOG.md index 8cc1976ff..f7067ef63 100644 --- a/packages/protect-ffi/platforms/darwin-x64/CHANGELOG.md +++ b/packages/protect-ffi/platforms/darwin-x64/CHANGELOG.md @@ -1,5 +1,7 @@ # @cipherstash/protect-ffi-darwin-x64 +## 0.33.0 + ## 0.32.0 ### Patch Changes diff --git a/packages/protect-ffi/platforms/darwin-x64/package.json b/packages/protect-ffi/platforms/darwin-x64/package.json index b0e369e85..49ee91d06 100644 --- a/packages/protect-ffi/platforms/darwin-x64/package.json +++ b/packages/protect-ffi/platforms/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-x64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-x64`.", - "version": "0.32.0", + "version": "0.33.0", "repository": { "type": "git", "url": "git+https://github.com/cipherstash/stack.git", diff --git a/packages/protect-ffi/platforms/linux-arm64-gnu/CHANGELOG.md b/packages/protect-ffi/platforms/linux-arm64-gnu/CHANGELOG.md index 75edf5eb6..8a79eab40 100644 --- a/packages/protect-ffi/platforms/linux-arm64-gnu/CHANGELOG.md +++ b/packages/protect-ffi/platforms/linux-arm64-gnu/CHANGELOG.md @@ -1,5 +1,7 @@ # @cipherstash/protect-ffi-linux-arm64-gnu +## 0.33.0 + ## 0.32.0 ### Patch Changes diff --git a/packages/protect-ffi/platforms/linux-arm64-gnu/package.json b/packages/protect-ffi/platforms/linux-arm64-gnu/package.json index dbbb71e8d..3c2a9f10c 100644 --- a/packages/protect-ffi/platforms/linux-arm64-gnu/package.json +++ b/packages/protect-ffi/platforms/linux-arm64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-arm64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-arm64-gnu`.", - "version": "0.32.0", + "version": "0.33.0", "repository": { "type": "git", "url": "git+https://github.com/cipherstash/stack.git", diff --git a/packages/protect-ffi/platforms/linux-x64-gnu/CHANGELOG.md b/packages/protect-ffi/platforms/linux-x64-gnu/CHANGELOG.md index 031fa09e5..ccaad566a 100644 --- a/packages/protect-ffi/platforms/linux-x64-gnu/CHANGELOG.md +++ b/packages/protect-ffi/platforms/linux-x64-gnu/CHANGELOG.md @@ -1,5 +1,7 @@ # @cipherstash/protect-ffi-linux-x64-gnu +## 0.33.0 + ## 0.32.0 ### Patch Changes diff --git a/packages/protect-ffi/platforms/linux-x64-gnu/package.json b/packages/protect-ffi/platforms/linux-x64-gnu/package.json index 18cafb70e..231d1de2e 100644 --- a/packages/protect-ffi/platforms/linux-x64-gnu/package.json +++ b/packages/protect-ffi/platforms/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-gnu`.", - "version": "0.32.0", + "version": "0.33.0", "repository": { "type": "git", "url": "git+https://github.com/cipherstash/stack.git", diff --git a/packages/protect-ffi/platforms/linux-x64-musl/CHANGELOG.md b/packages/protect-ffi/platforms/linux-x64-musl/CHANGELOG.md index fa4ce6b3a..8bacbdb5c 100644 --- a/packages/protect-ffi/platforms/linux-x64-musl/CHANGELOG.md +++ b/packages/protect-ffi/platforms/linux-x64-musl/CHANGELOG.md @@ -1,5 +1,7 @@ # @cipherstash/protect-ffi-linux-x64-musl +## 0.33.0 + ## 0.32.0 ### Patch Changes diff --git a/packages/protect-ffi/platforms/linux-x64-musl/package.json b/packages/protect-ffi/platforms/linux-x64-musl/package.json index 5885c934b..90ebc3350 100644 --- a/packages/protect-ffi/platforms/linux-x64-musl/package.json +++ b/packages/protect-ffi/platforms/linux-x64-musl/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-musl", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-musl`.", - "version": "0.32.0", + "version": "0.33.0", "repository": { "type": "git", "url": "git+https://github.com/cipherstash/stack.git", diff --git a/packages/protect-ffi/platforms/win32-x64-msvc/CHANGELOG.md b/packages/protect-ffi/platforms/win32-x64-msvc/CHANGELOG.md index d7bc53160..86a2feda4 100644 --- a/packages/protect-ffi/platforms/win32-x64-msvc/CHANGELOG.md +++ b/packages/protect-ffi/platforms/win32-x64-msvc/CHANGELOG.md @@ -1,5 +1,7 @@ # @cipherstash/protect-ffi-win32-x64-msvc +## 0.33.0 + ## 0.32.0 ### Patch Changes diff --git a/packages/protect-ffi/platforms/win32-x64-msvc/package.json b/packages/protect-ffi/platforms/win32-x64-msvc/package.json index 6a33f28d8..430e4e9e2 100644 --- a/packages/protect-ffi/platforms/win32-x64-msvc/package.json +++ b/packages/protect-ffi/platforms/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-win32-x64-msvc", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `win32-x64-msvc`.", - "version": "0.32.0", + "version": "0.33.0", "repository": { "type": "git", "url": "git+https://github.com/cipherstash/stack.git", diff --git a/packages/stack-drizzle/CHANGELOG.md b/packages/stack-drizzle/CHANGELOG.md index 62ccaa572..b066fcea3 100644 --- a/packages/stack-drizzle/CHANGELOG.md +++ b/packages/stack-drizzle/CHANGELOG.md @@ -1,5 +1,13 @@ # @cipherstash/stack-drizzle +## 1.2.0 + +### Patch Changes + +- Updated dependencies [b04ea2f] +- Updated dependencies [518abfd] + - @cipherstash/stack@1.2.0 + ## 1.1.1 ### Patch Changes diff --git a/packages/stack-drizzle/package.json b/packages/stack-drizzle/package.json index 738969ef2..0ba93aa84 100644 --- a/packages/stack-drizzle/package.json +++ b/packages/stack-drizzle/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/stack-drizzle", - "version": "1.1.1", + "version": "1.2.0", "description": "CipherStash Stack Drizzle ORM integration: searchable, application-layer field-level encryption for PostgreSQL.", "keywords": [ "encrypted", diff --git a/packages/stack-prisma/CHANGELOG.md b/packages/stack-prisma/CHANGELOG.md index deb7af322..8fce490df 100644 --- a/packages/stack-prisma/CHANGELOG.md +++ b/packages/stack-prisma/CHANGELOG.md @@ -1,5 +1,160 @@ # @cipherstash/stack-prisma +## 1.2.0 + +### Minor Changes + +- ba37039: Move the bundled EQL v3 migrations to **eql-3.0.5**, which renames the SQL + function `eql_v3.ste_vec_contains` to `eql_v3.jsonb_document_contains`. + + **The blast radius is narrower than a renamed public function suggests.** The + `@>` / `<@` operators on `public.eql_v3_json_search` behave exactly as before, + and so do the two function-form entry points that exist for platforms without + operator support — `eql_v3.jsonb_contains(jsonb, jsonb)` and + `eql_v3.jsonb_contained_by(jsonb, jsonb)` are byte-identical to 3.0.4. Those + are what a PostgREST caller invokes, so PostgREST callers on the documented + surface are **not** affected. The renamed function is the typed implementation + those operators dispatch into. + + **And the old name still works.** eql-3.0.5 ships `eql_v3.ste_vec_contains` as + a deprecated delegating alias for both overloads, so hand-written SQL naming it + — an application query, a view, an RLS policy, or a per-function + `GRANT EXECUTE ON FUNCTION eql_v3.ste_vec_contains(…)` — keeps resolving. The + typed overload stays inlinable, so a function-form query through the alias + still matches the same functional GIN index. Migrate to + `jsonb_document_contains` when convenient; nothing forces it at upgrade time. + + **Separately — and true of every EQL upgrade, not just this one:** the install + bundle opens with `DROP SCHEMA IF EXISTS eql_v3 CASCADE`, so applying it drops + every object in `eql_v3` / `eql_v3_internal` and everything that depended on + them. **Encrypted data and column types are not affected** — the storage + domains are `public.eql_v3_*`, deliberately outside both dropped schemas, and + their CHECK functions are re-created rather than dropped. What does not survive + is everything else pointing into the schema, which is two actions, neither of + them to do with the rename: + + 1. **Re-run your grant script.** Every grant on every `eql_v3` / + `eql_v3_internal` object is gone. The schema-wide form EQL documents — + `GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA eql_v3 TO app_role` — picks up + both the new name and the alias on its own. + 2. **Recreate your functional indexes, then `ANALYZE`.** Indexes over + `eql_v3.eq_term(…)` / `ord_term` / `match_term` / `to_ste_vec_query(…)` + depend on the dropped schema and go with it. Nothing errors afterwards: + encrypted predicates keep working and silently fall back to sequential + scans. A migration runner will not redo an already-applied migration, so + this has to be a _new_ one. The `stash-indexing` skill documents the + mechanism ("These indexes do not survive an EQL reinstall or upgrade") and + the `EXPLAIN` check that confirms recovery; capturing and restoring them + automatically is tracked in + [cipherstash/stack#918](https://github.com/cipherstash/stack/issues/918). + + Any RLS policy, view, or constraint that calls an `eql_v3` function is dropped + by the same CASCADE and needs recreating too. **The rename itself needs no + action — the alias makes it non-breaking.** + + Two artefacts carry the new bundle: + + - A new upgrade edge, `20260814T0000_upgrade_eql_v3_3_0_5`, carrying the + invariant `cipherstash:upgrade-eql-v3-bundle-3.0.5-v1`. Databases already + running an earlier bundle re-install through this edge on the next + `prisma-next migration plan` followed by `prisma-next migrate`, exactly as + they did for 3.0.2 and 3.0.4. **`migrate` alone is not enough** — the seed + phase that copies a new migration package into your repo runs only from + `migration plan`, so without it the 3.0.5 directory never reaches disk and + `migrate` is a silent no-op that leaves the database on the older bundle. + - The baseline install migration `20260601T0100_install_eql_v3_bundle`, whose + baked bundle moves to 3.0.5 and which gains a fourth no-SQL carrier op for + the new invariant. Fresh databases therefore land on 3.0.5 from the single + all-additive genesis edge, keeping `db init` (additive-only policy) working. + + **Action required.** The baseline's bytes — and so its `migrationHash` — have + changed. If your project already has a `migrations/cipherstash/` directory + generated against `@cipherstash/stack-prisma@1.0.0` or `@1.1.0`, delete that + directory and re-run `prisma-next migration plan` (or `migrate`); the 1.1.0 + Prisma Next 0.17 upgrade re-anchored the same artefacts, so a space vendored + against either release is stale here. The seed phase regenerates + it byte-identical to the shipped artefacts. Your database keeps its markers, so + already-applied invariants are not re-run — the only new work is the 3.0.5 + upgrade edge. + + If you skip the delete, nothing warns you: a vendored baseline is stale but + internally intact, so it passes every integrity check. On an existing database + the upgrade still applies correctly; on a **fresh** one, `db init` refuses with + `Operation cipherstash.upgrade-eql-v3-bundle-3.0.5 has class "data" which is +not allowed by policy.` — an error that names neither the directory nor the + remedy. See "Upgrading from 1.0.0" in the package README. + + **Why the baseline was re-emitted rather than left frozen.** These artefacts are + content-addressed and normally append-only: an EQL bump ships as a new upgrade + directory and published directories are never rewritten. That rule cannot be + followed here without a second `from: null` genesis edge, because no upgrade + edge can ever be walked by `db init` — every upgrade edge is a self-edge, and + the integrity checker requires a self-edge to carry a `data`-class op, which + `db init`'s additive-only policy refuses. A fresh database must therefore + collect every head-ref invariant from the genesis edge it walks. The + append-only alternative would duplicate the full ~2.6 MB bundle into a new + genesis edge on every EQL release, permanently; re-emitting was taken instead + while 1.0.0 was two weeks old with negligible adoption, and is a decision to be + re-argued on adoption numbers rather than repeated by default. + +### Patch Changes + +- 4422d5c: Pin the packed `@cipherstash/eql` dependency to an exact version, closing a + route by which an installed EQL bundle could drift ahead of the code built + against it. + + Both packages declared `"@cipherstash/eql": "workspace:^"` under + `dependencies`. In this workspace that resolves in-tree either way, so nothing + in development or CI could see a difference — but the two specifiers do not + pack the same. pnpm rewrites the protocol when it builds the tarball a customer + actually installs: + + "workspace:^" packs as "^3.0.5" + "workspace:*" packs as "3.0.5" + + The caret is the problem. `@cipherstash/eql` is still published from + `cipherstash/encrypt-query-language` until the publisher repoint, so a 3.0.x can + reach npm without passing through this repository at all — and `^3.0.5` accepts + it. A customer installing `stash` or `@cipherstash/stack-prisma` would then get + SQL that STORES and queries encrypted payloads at one version, while + `@cipherstash/stack`'s v3 domain types (which EMIT those payloads) and + `stack-prisma`'s baked migrations stayed frozen at the version this repo built + and tested against. The two halves of EQL are released in lockstep precisely + because that skew does not fail at install or in CI — it fails in a database. + + `workspace:*` is the only form that closes it. A literal `"3.0.5"` would be an + exact pin too, but it is a registry pin: `pnpm run lint:eql-pins` rejects it, + because resolving EQL from a registry rather than from this repo is the same + drift one layer up. + + No API, behaviour or SQL changes. What changes is the dependency range in the + published tarballs, and only in the narrowing direction — the version resolved + today is the version that was already being resolved. Nothing needs to be done + on upgrade. + + `@cipherstash/stack` declares the same dependency under `devDependencies` and + is deliberately left alone: pnpm rewrites that range too, but no consumer of the + package ever resolves it. + +- c604028: Document the 1.0.0 → 3.0.5 upgrade in the package README: why + `migrations/cipherstash/` must be deleted and regenerated, what each Prisma Next + command does if it is not, and the exact `db init` refusal + (`Operation cipherstash.upgrade-eql-v3-bundle-3.0.5 has class "data" which is +not allowed by policy.`) that a stale vendored directory produces on a fresh + database. + + The behaviour worth knowing regardless of version: only `prisma-next migration +plan` copies new migration packages into your repo. Running `migrate` or + `db init` after upgrading this package without planning first silently leaves + the database on the older EQL bundle — a stale vendored directory is internally + intact, so it passes every integrity check and nothing reports a problem. + +- Updated dependencies [e52d331] +- Updated dependencies [b04ea2f] +- Updated dependencies [518abfd] + - @cipherstash/eql@3.0.6 + - @cipherstash/stack@1.2.0 + ## 1.1.1 ### Patch Changes @@ -52,9 +207,7 @@ ```ts const cipherstash = await cipherstashFromStack({ contractJson, - encryptionConfig: { - /* credentials and auth options only */ - }, + encryptionConfig: {/* credentials and auth options only */}, }); ``` @@ -420,7 +573,7 @@ not a function`. The bundled `stash-prisma` skill documents this too. ```ts async function makeClient( - schemas: S + schemas: S, ) { return await Encryption({ schemas }); } diff --git a/packages/stack-prisma/package.json b/packages/stack-prisma/package.json index 3a855d7a0..703c38eab 100644 --- a/packages/stack-prisma/package.json +++ b/packages/stack-prisma/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/stack-prisma", - "version": "1.1.1", + "version": "1.2.0", "license": "MIT", "author": "CipherStash ", "description": "CipherStash extension for Prisma Next: searchable application-layer field-level encryption for Postgres (EQL v3), with domain-typed encrypted columns, the eql* query operators, bulk encrypt/decrypt middleware, and a baseline migration that installs the EQL v3 bundle.", diff --git a/packages/stack-supabase/CHANGELOG.md b/packages/stack-supabase/CHANGELOG.md index 5b0f13b27..35c5f3c25 100644 --- a/packages/stack-supabase/CHANGELOG.md +++ b/packages/stack-supabase/CHANGELOG.md @@ -1,5 +1,34 @@ # @cipherstash/stack-supabase +## 1.2.0 + +### Patch Changes + +- f31a202: Correct the runtime story in the TSDoc that ships as `.d.ts`. + + Three claims a user sees on hover were wrong: + + - `makeEncryptedSupabase` said "Declare your schemas and it runs anywhere; omit + them and we discover them for you, which needs a database connection and is + therefore Node-only." Declaring `schemas` does skip introspection entirely — + no Postgres connection, no `pg`, no `databaseUrl` — but it does not make the + default entry edge-capable. **The entry point decides where the wrapper runs; + `schemas` decides only whether Postgres is involved.** + - The default entry's doc named `@cipherstash/protect-ffi` as the Node-API + binary loaded on import. It is the one package in that graph that + deliberately does not load on import; the module-evaluation-time load belongs + to `@cipherstash/auth`. + - `./wasm-inline`'s doc called introspection "half of what made the default + entry Node-only". The engine is what makes it Node-only, and its emitted + bundle also carries an `import("pg")` specifier a bundler resolves at build + time. Introspection is a separate axis. + + Documentation only — no runtime behaviour changes. + +- Updated dependencies [b04ea2f] +- Updated dependencies [518abfd] + - @cipherstash/stack@1.2.0 + ## 1.1.1 ### Patch Changes diff --git a/packages/stack-supabase/package.json b/packages/stack-supabase/package.json index b6a304817..91c3d576b 100644 --- a/packages/stack-supabase/package.json +++ b/packages/stack-supabase/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/stack-supabase", - "version": "1.1.1", + "version": "1.2.0", "description": "CipherStash Stack Supabase integration: transparent, searchable field-level encryption for Supabase.", "keywords": [ "encrypted", diff --git a/packages/stack/CHANGELOG.md b/packages/stack/CHANGELOG.md index 419a7e088..8028ca1f1 100644 --- a/packages/stack/CHANGELOG.md +++ b/packages/stack/CHANGELOG.md @@ -1,5 +1,56 @@ # @cipherstash/stack +## 1.2.0 + +### Minor Changes + +- b04ea2f: Surface CipherStash token-service refusals as typed diagnostics. + + `@cipherstash/stack` operation and initialization failures now carry + `authCode`, `help`, and `url` from stack-auth. The message remains stack-auth's + original diagnostic message; Stack does not copy or rewrite its instructions. + Callers can branch on `USAGE_LIMIT_EXCEEDED` or `ORG_NOT_PROVISIONED`, render + `help`, and link to `url`. + + `LockContext.identify()` also recognizes those two codes on a genuine CTS + `402`, while declining malformed or unknown responses. Legacy valid JSON + responses without `cs_code` retain the historical usage-limit classification. + + `stash auth login` and `stash env` now consume `@cipherstash/auth` 0.44.0's + typed failures. They print the upstream diagnostic guidance, preserve its URL, + avoid suggesting another login for terminal account refusals, and expose + terminal codes on the JSON stream. The JSON error envelope gains an optional + `hint` for the upstream guidance. + +### Patch Changes + +- 518abfd: Document that `@cipherstash/stack/wasm-inline` is server-side only, and pin the + reason against the core. + + `WasmClientConfig` requires `clientId` and `clientKey` on every auth arm, + including the `authStrategy` (OIDC federation) arm. That read like an + over-declaration the SDK could relax — if federation alone sufficed, a browser + could hold a client without a workspace secret. It cannot. The core requires + both fields regardless of strategy, and loads `clientKey` as encryption key + material _before_ it ever calls the auth strategy. Since `clientKey` is a + workspace secret, no configuration of this entry belongs in a browser bundle — + which is why this entry has no `browser` export condition, and will not get one + until the core changes. + + No behaviour change. The types and runtime are unchanged; what changes is that + the constraint is now stated where callers meet it — `WasmClientConfig`, the + `stash-edge` skill, the `stash-encryption` entry-point table, and, where this + entry had been described as browser-capable, the `stash-supabase` skill and + the `supabase-worker` example — and enforced by contract tests that run + against the real WASM core instead of the mocks and stubs the rest of the wasm + suite uses. + +- Updated dependencies [8839d5a] +- Updated dependencies [8839d5a] +- Updated dependencies [4422d5c] +- Updated dependencies + - @cipherstash/protect-ffi@0.33.0 + ## 1.1.1 ## 1.1.0 @@ -415,7 +466,7 @@ ```ts async function makeClient( - schemas: S + schemas: S, ) { return await Encryption({ schemas }); } @@ -2137,7 +2188,7 @@ value)` and `selectorNe(col, path, value)` (dot-notation paths; `ne` includes schemas: [users], config: { authStrategy: OidcFederationStrategy.create(workspaceCrn, () => - getUserJwt() + getUserJwt(), ), }, }); @@ -2357,7 +2408,6 @@ value)` and `selectorNe(col, path, value)` (dot-notation paths; `ne` includes - **README**: Refreshed main repo README and Stack package readme; basic example README now uses `npm install @cipherstash/stack`, CipherStash account and dashboard credentials, and drops Stash CLI references. Added docs badge linking to cipherstash.com/docs. ### Features - - **Logging**: Logger is now used consistently across Stack client interfaces for initialization and operations. ## 0.4.0 diff --git a/packages/stack/package.json b/packages/stack/package.json index b65ba1a4f..8f3dbc7e0 100644 --- a/packages/stack/package.json +++ b/packages/stack/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/stack", - "version": "1.1.1", + "version": "1.2.0", "description": "CipherStash Stack for TypeScript and JavaScript", "keywords": [ "encrypted", diff --git a/packages/test-kit/CHANGELOG.md b/packages/test-kit/CHANGELOG.md index 5fa2eda70..170c7e0dc 100644 --- a/packages/test-kit/CHANGELOG.md +++ b/packages/test-kit/CHANGELOG.md @@ -1,5 +1,13 @@ # @cipherstash/test-kit +## 0.0.4 + +### Patch Changes + +- Updated dependencies [b04ea2f] +- Updated dependencies [518abfd] + - @cipherstash/stack@1.2.0 + ## 0.0.3 ### Patch Changes diff --git a/packages/test-kit/package.json b/packages/test-kit/package.json index 7d2fb8ac0..fa3c64375 100644 --- a/packages/test-kit/package.json +++ b/packages/test-kit/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/test-kit", - "version": "0.0.3", + "version": "0.0.4", "private": true, "description": "Shared EQL v3 test harness: the domain catalog, the plaintext oracle, and the integration-suite driver. Consumed as TypeScript source — no build step.", "type": "module", diff --git a/packages/wizard/CHANGELOG.md b/packages/wizard/CHANGELOG.md index 5793aa069..7f765495a 100644 --- a/packages/wizard/CHANGELOG.md +++ b/packages/wizard/CHANGELOG.md @@ -1,5 +1,7 @@ # @cipherstash/wizard +## 1.2.0 + ## 1.1.1 ## 1.1.0 diff --git a/packages/wizard/package.json b/packages/wizard/package.json index 46b23ec08..5bc82a125 100644 --- a/packages/wizard/package.json +++ b/packages/wizard/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/wizard", - "version": "1.1.1", + "version": "1.2.0", "description": "AI-powered encryption setup for CipherStash. Reads your codebase, picks columns to encrypt, and wires everything up.", "repository": { "type": "git",