diff --git a/.changeset/pre.json b/.changeset/pre.json index 12a91ccef..a303b3249 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -23,8 +23,11 @@ "changesets": [ "adapter-package-split", "adapter-split-skills", + "auth-binding-lockstep", "cli-anonymous-telemetry", "cli-eql-v3-single-bundle", + "drizzle-kit-eql-v3-ddl", + "eql-migration-command", "eql-v3-adapter-type-robustness", "eql-v3-bigint-domains", "eql-v3-bundle-from-package", @@ -37,16 +40,24 @@ "eql-v3-json-selector", "eql-v3-json-skills", "eql-v3-json", + "eql-v3-prisma-next", "eql-v3-public-domains", "eql-v3-rename-contains-to-matches", "eql-v3-sole-docs", + "eql-v3-source-from-package", "eql-v3-supabase-adapter", "eql-v3-text-search", "eql-v3-typed-client", "eql-v3-typed-schema", "eql-v3-wasm-inline", + "honest-noninteractive-init", "init-pins-runtime-versions", + "migrate-eql-v3", + "plan-complete-rollout-yes", + "prisma-example-eql-v3", "prisma-next-0-14", + "prisma-next-drop-encrypted-prefix", + "prisma-next-eql-runtime-source", "prisma-next-joins-release-train", "release-train-coupling", "remove-legacy-drizzle-package", @@ -59,6 +70,8 @@ "stash-cli-eql-v3-default", "stash-cli-skill-refresh", "stash-drizzle-skill-encrypt-query", + "stash-env-mint-credentials", + "stash-prisma-next-skill", "stash-skills-contains-to-matches", "stash-supabase-contains-substrings", "supabase-encryption-error", diff --git a/e2e/CHANGELOG.md b/e2e/CHANGELOG.md index 21198d562..d8b61b3d8 100644 --- a/e2e/CHANGELOG.md +++ b/e2e/CHANGELOG.md @@ -1,5 +1,23 @@ # @cipherstash/e2e +## 0.0.3-rc.3 + +### Patch Changes + +- Updated dependencies [8b2551a] +- Updated dependencies [b8cb599] +- Updated dependencies [0811330] +- Updated dependencies [175eeb7] +- Updated dependencies [d20e48a] +- Updated dependencies [3a86939] +- Updated dependencies [b0634df] +- Updated dependencies [4923c0a] +- Updated dependencies [f188c7a] +- Updated dependencies [8872d1e] + - @cipherstash/stack@1.0.0-rc.3 + - stash@1.0.0-rc.3 + - @cipherstash/wizard@1.0.0-rc.3 + ## 0.0.3-rc.2 ### Patch Changes diff --git a/e2e/package.json b/e2e/package.json index 30073e978..72b91ba7e 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/e2e", - "version": "0.0.3-rc.2", + "version": "0.0.3-rc.3", "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 c49c345aa..8496f1897 100644 --- a/examples/basic/CHANGELOG.md +++ b/examples/basic/CHANGELOG.md @@ -1,5 +1,15 @@ # @cipherstash/basic-example +## 1.2.14-rc.3 + +### Patch Changes + +- Updated dependencies [8b2551a] +- Updated dependencies [b8cb599] + - @cipherstash/stack@1.0.0-rc.3 + - @cipherstash/stack-drizzle@1.0.0-rc.3 + - @cipherstash/stack-supabase@1.0.0-rc.3 + ## 1.2.14-rc.2 ### Patch Changes diff --git a/examples/basic/package.json b/examples/basic/package.json index 46b477089..734001f7b 100644 --- a/examples/basic/package.json +++ b/examples/basic/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/basic-example", "private": true, - "version": "1.2.14-rc.2", + "version": "1.2.14-rc.3", "type": "module", "scripts": { "start": "tsx index.ts" diff --git a/examples/prisma/CHANGELOG.md b/examples/prisma/CHANGELOG.md index 4614b5064..7360cfda5 100644 --- a/examples/prisma/CHANGELOG.md +++ b/examples/prisma/CHANGELOG.md @@ -1,5 +1,20 @@ # @cipherstash/prisma-next-example +## 0.1.0-rc.3 + +### Minor Changes + +- a75513b: Convert the example app to EQL v3. Every column is now a concrete `public.eql_v3_*` domain authored with the per-domain constructors (`EncryptedTextSearch`, `EncryptedDoubleOrd`, `EncryptedBigIntOrd`, `EncryptedDateOrd`, `EncryptedBoolean`, `EncryptedJson`), wired through `cipherstashFromStackV3({ contractJson })`. The e2e harness runs the full v3 surface against live Postgres + ZeroKMS with no skips: the `eql*` operator vocabulary (equality/range plus `eqlMatch` free-text token search), `eqlAsc`/`eqlDesc` order-term sorting, encrypted JSON containment (`eqlJsonContains` — the v2 `cipherstashJsonb*` helpers do not exist in v3), lossless `bigint` beyond `Number.MAX_SAFE_INTEGER`, and the storage-only `eql_v3_boolean` refusal (`EncryptionOperatorError`) pinned as a feature. Migrations regenerate from the v3 contract: the initial app migration creates the `users` table against the v3 domains with zero `add_search_config` ops, and the cipherstash space carries both bundle baselines (v2 + v3). + +### Patch Changes + +- Updated dependencies [8b2551a] +- Updated dependencies [a75513b] +- Updated dependencies [4923c0a] +- Updated dependencies [a2f80ea] + - @cipherstash/stack@1.0.0-rc.3 + - @cipherstash/prisma-next@1.0.0-rc.3 + ## 0.0.6-rc.2 ### Patch Changes diff --git a/examples/prisma/package.json b/examples/prisma/package.json index 4429e1a91..ea8f3843a 100644 --- a/examples/prisma/package.json +++ b/examples/prisma/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/prisma-next-example", "private": true, - "version": "0.0.6-rc.2", + "version": "0.1.0-rc.3", "description": "End-to-end example of @cipherstash/prisma-next: 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 d36464f81..f78d55b47 100644 --- a/packages/bench/CHANGELOG.md +++ b/packages/bench/CHANGELOG.md @@ -1,5 +1,14 @@ # @cipherstash/bench +## 0.0.5-rc.3 + +### Patch Changes + +- Updated dependencies [8b2551a] +- Updated dependencies [b8cb599] + - @cipherstash/stack@1.0.0-rc.3 + - @cipherstash/stack-drizzle@1.0.0-rc.3 + ## 0.0.5-rc.2 ### Patch Changes diff --git a/packages/bench/package.json b/packages/bench/package.json index b9b961ea6..4cd8be524 100644 --- a/packages/bench/package.json +++ b/packages/bench/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/bench", - "version": "0.0.5-rc.2", + "version": "0.0.5-rc.3", "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 cd5e4afe7..b723ee0a7 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,235 @@ # @cipherstash/cli +## 1.0.0-rc.3 + +### Minor Changes + +- 0811330: Add `stash eql migration` — generate an EQL **v3** install migration for your ORM + instead of running the SQL directly against the database (`stash eql install`). + Migration-first is the preferred path: the install lands in your migration history + and ships to every environment through the ORM's own migrate step. + + ```bash + stash eql migration --drizzle # Drizzle custom migration + stash eql migration --drizzle --supabase # also grants eql_v3 to anon/authenticated/service_role + ``` + + The migration carries the CLI's bundled v3 install SQL (one source of truth) plus + the `cs_migrations` tracking schema, so a single `drizzle-kit migrate` covers + everything `stash encrypt …` needs. `--supabase` appends the `eql_v3` + + `eql_v3_internal` role grants for PostgREST/RLS access. + + `--prisma` is registered but not available yet — the Prisma Next migration + emitter is a follow-up (tracked in cipherstash/stack#690) that will let + prisma-next drop its baked install baseline. It fails with a pointer for now. + +- d20e48a: `stash init` is honest non-interactively — it no longer reports success for a + setup that didn't fully complete. + + - **Fails on version skew.** A non-interactive run can't reconcile an + already-installed `@cipherstash/*` package that's _older_ than this CLI + expects (it won't mutate an install without consent), so instead of warning + and proceeding — scaffolding against mismatched packages and then claiming + success — it now refuses with a non-zero exit and the exact align command. + Interactive runs still offer to align. A _newer_ install stays a warn (the + install is likely fine; update the CLI instead). + - **No false "Setup complete".** If the EQL extension isn't installed at the + end — and the integration isn't one that installs it out-of-band — the + summary reads "Setup incomplete" and init exits non-zero, pointing at + `stash eql install`. Integrations that install EQL via a migration are + reported honestly rather than as failures: Prisma Next (installs it via + `migration apply`) and the Drizzle flow, which _generates_ an EQL migration + and now says "EQL migration generated — apply it with `drizzle-kit migrate`" + instead of claiming the extension is already installed. + - **Honest checkmarks.** The summary no longer claims "Database connection + verified" (init resolves a URL but doesn't open a connection) — it now says + "Database URL resolved" — and only shows "Encryption client scaffolded" when + a client was actually written (skipped for Prisma Next). + - **No false "skills loaded".** The agent handoff prompt only points at the + skills directory when skills were actually copied (a stripped build installs + none), instead of telling the agent to read files that aren't there. + +- 3a86939: EQL v3 support for the encryption rollout lifecycle (#648). The `stash +encrypt *` commands (and `@cipherstash/migrate` underneath) now resolve a + column's EQL version and its encrypted counterpart from the **Postgres domain + types** — the EQL v3 types are self-describing, so the `_encrypted` + naming is a convention only, never enforced or relied upon — and follow the + right lifecycle, no new flags: + + - **`encrypt backfill`** works on v3 columns unchanged (the engine was always + version-agnostic; pass an `EncryptionV3` client and real v3 envelopes land + in the concrete `eql_v3_*` domain column — verified live against a real + database, including the domain CHECK and a decrypt round-trip). The + manifest records the detected version, the encrypted column's name, and the + v3 target phase, and the command prints v3-appropriate next steps. + - **`encrypt cutover`** on a backfilled v3 column reports "not applicable" + (exit 0) with guidance: v3 has no rename cut-over — the application + switches to the encrypted column by name. Before backfill completes it + exits 1 and says to finish the backfill instead of instructing the switch. + On a database with no `eql_v2_configuration` table (a v3-only install) the + v2 path now explains that instead of surfacing a raw Postgres error. + - **`encrypt drop`** is version-aware: v3 runs from the `backfilled` phase, + **verifies live coverage** (refuses to generate the migration while any row + still has the plaintext set and the encrypted column NULL — the + `countUnencrypted` check), and drops the ORIGINAL plaintext column (there + is no `_plaintext` under v3); v2 behaviour is unchanged. The generated + v3 migration **re-verifies coverage at apply time** — it locks the table, + re-counts, and aborts without dropping if plaintext-only rows appeared + after generation. And because dropping is the one irreversible step, it + requires a positively asserted plaintext↔ciphertext pairing (the + manifest's recorded `encryptedColumn` or the naming convention): a match + found only by being the table's sole EQL column is refused with + instructions, and an ambiguous table (several EQL columns, none + identifiable) fails closed listing the candidates — as does `cutover`. + - **`encrypt status`** classifies each column from the observed domain type + (manifest as fallback), shows `v3` in the EQL column, and no longer raises + the v2-only `not-registered` / `plaintext-col-missing` drift flags for v3 + columns. `stash status`'s quest ladder and the `stash init` agent handoff + prompt teach the version-appropriate next step (no more "run cutover" on + v3 columns). + - New `@cipherstash/migrate` exports: `classifyEqlDomain`, + `resolveEncryptedColumn`, `pickEncryptedColumn`, `listEncryptedColumns` + (domain-type resolution — case-exact for quoted/mixed-case table names), + `countEncrypted` / `countUnencrypted` (coverage counts), and manifest + `eqlVersion` + `encryptedColumn` fields. `EqlVersion` is numeric (`2 | 3`), + matching the manifest and the installer. Resolved columns carry `via: +'hint' | 'convention' | 'sole'` so callers can tell a positively asserted + pairing from a by-elimination guess. + - Fixed: `encrypt cutover`/`encrypt drop` precondition failures now actually + exit 1 — the early-return guards previously skipped the exit-code path + entirely, so failed preconditions exited 0. (This also applies to v2 + preconditions: scripted pipelines that relied on the erroneous exit 0 will + now see the documented exit 1.) + + The `stash-cli` and `stash-encryption` skills and the `@cipherstash/migrate` + README document the two lifecycles (v2: backfill → cutover → drop; + v3: backfill → switch-by-name → drop). + +- b0634df: `stash plan --complete-rollout` is now automatable and has an honest exit code. + It skips the production-deploy gate, so it needs explicit consent — previously + that was an interactive prompt with no bypass, so a non-interactive run + auto-cancelled (default-no) and exited **0** without drafting a plan, leaving + automation to assume a plan existed. + + - New `--yes` flag confirms the gate-skip without a prompt (for CI/agents). + - Without `--yes`, a non-interactive `--complete-rollout` run now **refuses + with a non-zero exit** and points at `--yes`, instead of silently succeeding. + - Interactive behaviour is unchanged (default-no confirm). + +- f188c7a: `stash env` now works: it mints deployment credentials from your device-code + session and prints them as env vars — no dashboard copy-paste. The command + creates a fresh ZeroKMS client and a member-role CipherStash access key (named + via `--name`; the role is pinned in the request and verified on the response — + the CLI deliberately cannot mint admin keys), then emits `CS_WORKSPACE_CRN`, + `CS_CLIENT_ID`, `CS_CLIENT_KEY`, and `CS_CLIENT_ACCESS_KEY`. + + Output goes to stdout by default — and stdout is pipe-clean (progress UI is on + stderr), so `stash env --name x > prod.env` and pipes into secret stores are + safe. `--write [path]` writes a file instead (default `.env.production.local`, + enforced mode 0600 even when overwriting), confirming before overwriting and + refusing non-interactively — always _before_ anything is minted, so a refusal + never discards the shown-exactly-once access key. `--json` emits NDJSON; with + `--write` the confirmation event is deliberately secret-free. API responses + are schema-validated so a service change can never print `undefined` into a + credentials file. Creating access keys requires the admin role in the + workspace. + + This is also the supported credential path for WASM/edge local development + (Supabase Edge Functions, Cloudflare Workers, Deno), where the runtime cannot + read the `~/.cipherstash` device profile: mint a key and feed it via + `supabase functions serve --env-file` or the platform's secret store. + + The `STASH_EXPERIMENTAL_ENV_CMD` gate is removed. + +- 8872d1e: `stash init`, `stash plan`, and `stash impl` no longer crash on a Prisma Next + project. `SKILL_MAP` was missing a `prisma-next` entry, so the skills-install + and AGENTS.md-builder steps hit `SKILL_MAP[integration]` → `undefined` and threw + "not iterable" for any repo the CLI detected as Prisma Next. The entry is added + and both consumers now resolve skills through a `skillsFor()` helper that + degrades an unmapped integration to the base skill set instead of crashing + (`tsup` ships without type-checking, so the `Record` type alone + didn't protect the build). + + Ships a new **`stash-prisma-next`** agent skill documenting the EQL v3 Prisma + Next surface — the domain-named encrypted column types (`EncryptedTextSearch`, + `EncryptedDoubleOrd`, …), `cipherstashFromStackV3` wiring, the runtime value + envelopes, the `eql*` query operators, and EQL installation via + `prisma-next migration apply`. It is installed for Prisma Next projects and + inlined into `AGENTS.md` for editor agents. + + `stash eql install` now refuses to run in a Prisma Next project (pointing you + at `prisma-next migration apply`, which owns EQL installation) unless you pass + `--force` — closing the manual-invocation hole that `stash init --prisma-next` + already avoided. + +### Patch Changes + +- 8b2551a: Fix "Failed to load native binding" on project-local installs of the CLI/SDK + (npm). `@cipherstash/auth` was pinned at 0.41.0 while the six + `@cipherstash/auth-*` platform bindings declared in stack/stash/wizard's + optionalDependencies were pinned at 0.42.0. Because auth pins its bindings as + exact-version optional peer dependencies, the skew made npm nest per-consumer + binding copies that the hoisted `auth` package could not resolve — any command + or import touching auth then died at startup. All seven packages now move in + lockstep at 0.42.0, Dependabot is barred from bumping any of them + independently, and a supply-chain CI test fails on any future skew. +- b8cb599: Fix invalid DDL from `drizzle-kit generate`/`push` for EQL v3 encrypted columns. + A v3 column declared its SQL type as the schema-qualified domain + (`public.eql_v3_text_search`), but drizzle-kit wraps a custom type's whole name + in a single pair of double quotes — emitting `"public.eql_v3_text_search"`, which + Postgres reads as one dotted identifier and rejects with `type +"public.eql_v3_text_search" does not exist`. Generated migrations had to be + hand-repaired. + + The v3 column now emits the **unqualified** domain (`eql_v3_text_search`), which + drizzle-kit renders as the valid `"eql_v3_text_search"` and which resolves via the + search path (the domains live in `public`). This matches how the v2 + `encryptedType` surface already declares its type, and how drizzle-kit reads the + type back during a `push` introspection diff, so the two sides no longer disagree. + Builder recovery still yields the canonical `public.eql_v3_*` identity, so + operators and schema extraction are unchanged. + + The bundled `stash-drizzle` skill is updated to describe the unqualified generated + type and the search-path requirement (hence the `stash` bump — the skill ships in + its tarball). + +- 175eeb7: The EQL **v3** install SQL is now read from the `@cipherstash/eql` package at + runtime instead of a copy vendored into this repo. `@cipherstash/eql` becomes a + runtime dependency of `stash`, and a version bump now flows straight through — no + re-vendor step, no drift between the pin and the shipped bundle. + + This removes ~44k lines of generated plpgsql from the repository (which had made + GitHub classify the whole repo as plpgsql — CIP-3518) along with the + `gen:eql-v3-sql` vendor script and its CI drift-check. + + No behaviour change: v3 installs the same one-artifact bundle (which self-adapts to + non-superuser environments like Supabase), and the v2 path is unchanged. + +- 4923c0a: **Breaking (v3 authoring surface):** the EQL v3 PSL column constructors drop + the `Encrypted` prefix to line up with the stack / Drizzle `types.*` catalog — + the `cipherstash.` namespace already disambiguates. So + `cipherstash.EncryptedTextSearch()` → `cipherstash.TextSearch()`, + `cipherstash.EncryptedDoubleOrd()` → `cipherstash.DoubleOrd()`, + `cipherstash.EncryptedBoolean()` → `cipherstash.Boolean()`, etc. + + The v3 one-call setup function is renamed `cipherstashFromStackV3` → + `cipherstashFromStack` (v3 is the default), and the existing v2 setup function + becomes `cipherstashFromStackV2`. + + The camelCase TS-authoring factory exports move in lockstep: + `encryptedTextSearch` → `textSearch`, `encryptedDoubleOrd` → `doubleOrd`, etc. + (a property test enforces the PSL and TS names agree modulo first-letter case). + + Unchanged: the runtime value envelopes (`EncryptedString`, `EncryptedNumber`, + `EncryptedBoolean`, …), the `cipherstash.*V2` legacy column constructors, the + generated `contract.json` / codec ids, and the `eql*` query operators. + + The `stash-prisma-next` skill is updated to the new names (skills ship in the + `stash` tarball). + +- Updated dependencies [3a86939] + - @cipherstash/migrate@1.0.0-rc.1 + ## 1.0.0-rc.2 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index bc2eaf6ec..ecb82e00a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "stash", - "version": "1.0.0-rc.2", - "description": "CipherStash CLI \u2014 the one stash command for auth, init, encryption schema, database setup, and secrets.", + "version": "1.0.0-rc.3", + "description": "CipherStash CLI — the one stash command for auth, init, encryption schema, database setup, and secrets.", "repository": { "type": "git", "url": "git+https://github.com/cipherstash/stack.git", @@ -56,7 +56,7 @@ "posthog-node": "^5.40.0", "zod": "^3.25.76" }, - "//optionalDependencies": "@cipherstash/auth ships per-platform native bindings as optional peerDependencies. pnpm does not auto-install platform-matched optional peer deps, so we declare them here as optionalDependencies \u2014 pnpm then picks the binary matching the host's os/cpu (from each sub-package's own package.json) and ignores the rest. All seven names share a single catalog entry to keep them in lockstep.", + "//optionalDependencies": "@cipherstash/auth ships per-platform native bindings as optional peerDependencies. pnpm does not auto-install platform-matched optional peer deps, so we declare them here as optionalDependencies — pnpm then picks the binary matching the host's os/cpu (from each sub-package's own package.json) and ignores the rest. All seven names share a single catalog entry to keep them in lockstep.", "optionalDependencies": { "@cipherstash/auth-darwin-arm64": "catalog:repo", "@cipherstash/auth-darwin-x64": "catalog:repo", diff --git a/packages/migrate/CHANGELOG.md b/packages/migrate/CHANGELOG.md index 8b991d515..ebcfb9bdd 100644 --- a/packages/migrate/CHANGELOG.md +++ b/packages/migrate/CHANGELOG.md @@ -1,5 +1,65 @@ # @cipherstash/migrate +## 1.0.0-rc.1 + +### Minor Changes + +- 3a86939: EQL v3 support for the encryption rollout lifecycle (#648). The `stash +encrypt *` commands (and `@cipherstash/migrate` underneath) now resolve a + column's EQL version and its encrypted counterpart from the **Postgres domain + types** — the EQL v3 types are self-describing, so the `_encrypted` + naming is a convention only, never enforced or relied upon — and follow the + right lifecycle, no new flags: + + - **`encrypt backfill`** works on v3 columns unchanged (the engine was always + version-agnostic; pass an `EncryptionV3` client and real v3 envelopes land + in the concrete `eql_v3_*` domain column — verified live against a real + database, including the domain CHECK and a decrypt round-trip). The + manifest records the detected version, the encrypted column's name, and the + v3 target phase, and the command prints v3-appropriate next steps. + - **`encrypt cutover`** on a backfilled v3 column reports "not applicable" + (exit 0) with guidance: v3 has no rename cut-over — the application + switches to the encrypted column by name. Before backfill completes it + exits 1 and says to finish the backfill instead of instructing the switch. + On a database with no `eql_v2_configuration` table (a v3-only install) the + v2 path now explains that instead of surfacing a raw Postgres error. + - **`encrypt drop`** is version-aware: v3 runs from the `backfilled` phase, + **verifies live coverage** (refuses to generate the migration while any row + still has the plaintext set and the encrypted column NULL — the + `countUnencrypted` check), and drops the ORIGINAL plaintext column (there + is no `_plaintext` under v3); v2 behaviour is unchanged. The generated + v3 migration **re-verifies coverage at apply time** — it locks the table, + re-counts, and aborts without dropping if plaintext-only rows appeared + after generation. And because dropping is the one irreversible step, it + requires a positively asserted plaintext↔ciphertext pairing (the + manifest's recorded `encryptedColumn` or the naming convention): a match + found only by being the table's sole EQL column is refused with + instructions, and an ambiguous table (several EQL columns, none + identifiable) fails closed listing the candidates — as does `cutover`. + - **`encrypt status`** classifies each column from the observed domain type + (manifest as fallback), shows `v3` in the EQL column, and no longer raises + the v2-only `not-registered` / `plaintext-col-missing` drift flags for v3 + columns. `stash status`'s quest ladder and the `stash init` agent handoff + prompt teach the version-appropriate next step (no more "run cutover" on + v3 columns). + - New `@cipherstash/migrate` exports: `classifyEqlDomain`, + `resolveEncryptedColumn`, `pickEncryptedColumn`, `listEncryptedColumns` + (domain-type resolution — case-exact for quoted/mixed-case table names), + `countEncrypted` / `countUnencrypted` (coverage counts), and manifest + `eqlVersion` + `encryptedColumn` fields. `EqlVersion` is numeric (`2 | 3`), + matching the manifest and the installer. Resolved columns carry `via: +'hint' | 'convention' | 'sole'` so callers can tell a positively asserted + pairing from a by-elimination guess. + - Fixed: `encrypt cutover`/`encrypt drop` precondition failures now actually + exit 1 — the early-return guards previously skipped the exit-code path + entirely, so failed preconditions exited 0. (This also applies to v2 + preconditions: scripted pipelines that relied on the erroneous exit 0 will + now see the documented exit 1.) + + The `stash-cli` and `stash-encryption` skills and the `@cipherstash/migrate` + README document the two lifecycles (v2: backfill → cutover → drop; + v3: backfill → switch-by-name → drop). + ## 1.0.0-rc.0 ### Patch Changes diff --git a/packages/migrate/package.json b/packages/migrate/package.json index a302385c8..b14343caa 100644 --- a/packages/migrate/package.json +++ b/packages/migrate/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/migrate", - "version": "1.0.0-rc.0", + "version": "1.0.0-rc.1", "description": "Plaintext-to-encrypted column migration for CipherStash: resumable backfill, per-column state, and EQL lifecycle orchestration.", "repository": { "type": "git", diff --git a/packages/prisma-next/CHANGELOG.md b/packages/prisma-next/CHANGELOG.md index 3f1a33d03..8bd057d0a 100644 --- a/packages/prisma-next/CHANGELOG.md +++ b/packages/prisma-next/CHANGELOG.md @@ -1,5 +1,80 @@ # @cipherstash/prisma-next +## 1.0.0-rc.3 + +### Minor Changes + +- a75513b: **Breaking:** EQL v3 columns are now authored through **concrete per-domain constructors** — the constructor you choose _is_ the capability set. The legacy boolean-option surface (`EncryptedString({ equality, freeTextSearch, orderAndRange })`) is not carried into v3. + + - New per-domain constructors, one per exposed `public.eql_v3_*` domain: + - Text: `EncryptedText` (storage), `EncryptedTextEq`, `EncryptedTextOrd` (eq + order/range), `EncryptedTextMatch` (free-text), `EncryptedTextSearch` (eq + free-text + order/range). + - Scalars (Integer, Smallint, BigInt, Numeric, Real, Double, Date, Timestamp): `Encrypted` (storage), `EncryptedEq`, `EncryptedOrd`. + - `EncryptedBoolean` — storage-only (`public.eql_v3_boolean`); there is no boolean equality constructor. + - `EncryptedJson` — searchable encrypted JSONB (`public.eql_v3_json`, `ste_vec`), queried with `eqlJsonContains` (`@>` containment). Selector querying (comparing the value at a JSONPath) is tracked in #677. + - **Impossible capability combinations have no constructor** (e.g. text equality + free-text without order/range) — they are unrepresentable, not runtime errors. + - **BigInt is a first-class v3 family** (`EncryptedBigInt` / `EncryptedBigIntEq` / `EncryptedBigIntOrd`, JS `bigint` plaintext, backed by `public.eql_v3_bigint*`). + - Use the `*V2` constructors (`EncryptedStringV2`, `EncryptedDoubleV2`, `EncryptedBigIntV2`, `EncryptedDateV2`, `EncryptedBooleanV2`, `EncryptedJsonV2`) to keep EQL v2 columns. A client is v2 or v3 — the two runtime descriptors are never co-registered. + - New `@cipherstash/prisma-next/v3` entry point: `cipherstashFromStackV3({ contractJson })` builds the v3 runtime descriptor, bulk-encrypt middleware, and a stack `EncryptionV3` client from the emitted contract. + - Query operators use an **EQL-derived vocabulary** (`eqlEq`, `eqlNeq`, `eqlIn`, `eqlNotIn`, `eqlGt`, `eqlGte`, `eqlLt`, `eqlLte`, `eqlBetween`, `eqlNotBetween`, `eqlJsonContains`; ordering via `eqlAsc` / `eqlDesc`), lowering to the same-named `eql_v3.*` functions with operands cast to the domain's query type (`$n::eql_v3.query_`); ordering uses `eql_v3.ord_term` / `eql_v3.ord_term_ore` by the column's ordering flavour. The domains are `public.eql_v3_*`; the operator functions live in the `eql_v3` schema. (The v2 surface keeps its `cipherstash*` names.) + - Free-text search is **`eqlMatch`** — fuzzy bloom token matching (`eql_v3.contains`), deliberately NOT named after SQL `ILIKE`: matching is case-insensitive, order/multiplicity-insensitive, and one-sided (may false-positive). Two guards run before encryption: SQL wildcards are normalised (leading/trailing `%` stripped; interior `%` or any `_` rejected), and needles the column's match index cannot answer (empty / below the tokenizer length) are rejected via the shared `matchNeedleError` guard. There is **no negated match operator** — negating a may-false-positive bloom test would silently drop matching rows. + - A new baseline migration `20260601T0100_install_eql_v3_bundle` (invariant `cipherstash:install-eql-v3-bundle-v1`) installs the `public.eql_v3_*` domains and `eql_v3.*` functions from the pinned `@cipherstash/eql` release. Regenerate contracts and run migrations after changing constructors. + - **The v3 ORM surface is fully wired end-to-end** (proven by converting `examples/prisma`): + - The generated `contract.d.ts` type surface covers every v3 codec id: `CodecTypes` gains all 40 `cipherstash/eql-v3/*@1` entries (envelope outputs — `number`-castAs domains decode to the new `EncryptedNumber` — plus trait-accurate operator visibility), and `QueryOperationTypes` gains the `eql*` operator set, surfaced on v3 columns via type-level `cipherstash:v3-*` marker traits (the v2 `cipherstash*` methods never appear on v3 columns, and vice-versa). Storage-only domains (including `EncryptedBoolean`) surface no operator methods at the type level, matching the runtime gate. + - The v3 runtime descriptor now presents the **pack id** (`cipherstash`) with v3's own version, so `postgres({ extensions })` accepts contracts emitted by the cipherstash extension pack instead of failing with `RUNTIME.MISSING_EXTENSION_PACK`. + - Every v3 codec id registers a control-plane `expandNativeType` hook that strips the `public.` qualifier — `prisma-next migration plan` now renders `CREATE TABLE` columns as bare domain names (`eql_v3_bigint_ord`), matching what introspection reports, with **no `add_search_config` ops** (v3 domains carry their own index metadata). No `onFieldEvent` is registered for v3. + - The v3 bundle baseline migration op is reclassified `data` (it is a contract-shape-neutral self-edge; the aggregate integrity checker rejects self-edges without a data-class op), unblocking `prisma-next migration plan` / `migrate` in consuming apps. + +- 4923c0a: **Breaking (v3 authoring surface):** the EQL v3 PSL column constructors drop + the `Encrypted` prefix to line up with the stack / Drizzle `types.*` catalog — + the `cipherstash.` namespace already disambiguates. So + `cipherstash.EncryptedTextSearch()` → `cipherstash.TextSearch()`, + `cipherstash.EncryptedDoubleOrd()` → `cipherstash.DoubleOrd()`, + `cipherstash.EncryptedBoolean()` → `cipherstash.Boolean()`, etc. + + The v3 one-call setup function is renamed `cipherstashFromStackV3` → + `cipherstashFromStack` (v3 is the default), and the existing v2 setup function + becomes `cipherstashFromStackV2`. + + The camelCase TS-authoring factory exports move in lockstep: + `encryptedTextSearch` → `textSearch`, `encryptedDoubleOrd` → `doubleOrd`, etc. + (a property test enforces the PSL and TS names agree modulo first-letter case). + + Unchanged: the runtime value envelopes (`EncryptedString`, `EncryptedNumber`, + `EncryptedBoolean`, …), the `cipherstash.*V2` legacy column constructors, the + generated `contract.json` / codec ids, and the `eql*` query operators. + + The `stash-prisma-next` skill is updated to the new names (skills ship in the + `stash` tarball). + +- a2f80ea: Source the EQL v3 install SQL from `@cipherstash/eql` at runtime instead of + baking it into the baseline migration. + + `@cipherstash/eql` is now a runtime dependency, pinned exact (`3.0.0`) to match + the release `@cipherstash/stack` encodes its v3 domain **types** against — the + two must move together, so an EQL upgrade is a coordinated version bump, not a + float. The v3 baseline migration no longer embeds the ~1.7 MB install bundle in + its `ops.json`: the committed op carries a placeholder, and the extension + descriptor injects `readInstallSql()` from the installed `@cipherstash/eql` when + it is built, and recomputes the content-addressed migration hash from the + injected operations before Prisma Next materialises the package. + + The win over baking: bumping the pinned `@cipherstash/eql` no longer requires + re-running the maintainer emit loop to regenerate a 1.7 MB `ops.json` — it is a + one-line version bump plus a rebuild. This mirrors how the `stash` CLI already + sources the v3 SQL. + + No change to user-facing behaviour: EQL still installs as part of + `prisma-next migration apply`. Safe because the v3 baseline is an + invariant-only self-edge — the install SQL never contributes to the + contract-space hash. Injection matches the placeholder by value and fails loudly + if it is absent, so a drift between the emit source and the injector can never + silently ship an empty install. + +### Patch Changes + +- Updated dependencies [8b2551a] + - @cipherstash/stack@1.0.0-rc.3 + ## 1.0.0-rc.2 ### Patch Changes diff --git a/packages/prisma-next/package.json b/packages/prisma-next/package.json index 4ff2191f4..0f4194ede 100644 --- a/packages/prisma-next/package.json +++ b/packages/prisma-next/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/prisma-next", - "version": "1.0.0-rc.2", + "version": "1.0.0-rc.3", "license": "MIT", "author": "CipherStash ", "description": "CipherStash extension for Prisma Next: searchable application-layer field-level encryption for Postgres, with six encrypted column types, 17 query operators, bulk encrypt/decrypt middleware, and a baseline migration that installs the vendored EQL bundle SQL byte-for-byte.", diff --git a/packages/stack-drizzle/CHANGELOG.md b/packages/stack-drizzle/CHANGELOG.md index 493aca61d..46e49bba3 100644 --- a/packages/stack-drizzle/CHANGELOG.md +++ b/packages/stack-drizzle/CHANGELOG.md @@ -1,5 +1,32 @@ # @cipherstash/stack-drizzle +## 1.0.0-rc.3 + +### Patch Changes + +- b8cb599: Fix invalid DDL from `drizzle-kit generate`/`push` for EQL v3 encrypted columns. + A v3 column declared its SQL type as the schema-qualified domain + (`public.eql_v3_text_search`), but drizzle-kit wraps a custom type's whole name + in a single pair of double quotes — emitting `"public.eql_v3_text_search"`, which + Postgres reads as one dotted identifier and rejects with `type +"public.eql_v3_text_search" does not exist`. Generated migrations had to be + hand-repaired. + + The v3 column now emits the **unqualified** domain (`eql_v3_text_search`), which + drizzle-kit renders as the valid `"eql_v3_text_search"` and which resolves via the + search path (the domains live in `public`). This matches how the v2 + `encryptedType` surface already declares its type, and how drizzle-kit reads the + type back during a `push` introspection diff, so the two sides no longer disagree. + Builder recovery still yields the canonical `public.eql_v3_*` identity, so + operators and schema extraction are unchanged. + + The bundled `stash-drizzle` skill is updated to describe the unqualified generated + type and the search-path requirement (hence the `stash` bump — the skill ships in + its tarball). + +- Updated dependencies [8b2551a] + - @cipherstash/stack@1.0.0-rc.3 + ## 1.0.0-rc.2 ### Patch Changes diff --git a/packages/stack-drizzle/package.json b/packages/stack-drizzle/package.json index 1c00bc76e..b0ca4bc50 100644 --- a/packages/stack-drizzle/package.json +++ b/packages/stack-drizzle/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/stack-drizzle", - "version": "1.0.0-rc.2", + "version": "1.0.0-rc.3", "description": "CipherStash Stack Drizzle ORM integration: searchable, application-layer field-level encryption for PostgreSQL.", "keywords": [ "encrypted", diff --git a/packages/stack-supabase/CHANGELOG.md b/packages/stack-supabase/CHANGELOG.md index b9d906960..87121f008 100644 --- a/packages/stack-supabase/CHANGELOG.md +++ b/packages/stack-supabase/CHANGELOG.md @@ -1,5 +1,12 @@ # @cipherstash/stack-supabase +## 1.0.0-rc.3 + +### Patch Changes + +- Updated dependencies [8b2551a] + - @cipherstash/stack@1.0.0-rc.3 + ## 1.0.0-rc.2 ### Patch Changes diff --git a/packages/stack-supabase/package.json b/packages/stack-supabase/package.json index 47defc69b..bd55a43e0 100644 --- a/packages/stack-supabase/package.json +++ b/packages/stack-supabase/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/stack-supabase", - "version": "1.0.0-rc.2", + "version": "1.0.0-rc.3", "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 cafcead22..b5cac25f6 100644 --- a/packages/stack/CHANGELOG.md +++ b/packages/stack/CHANGELOG.md @@ -1,5 +1,19 @@ # @cipherstash/stack +## 1.0.0-rc.3 + +### Patch Changes + +- 8b2551a: Fix "Failed to load native binding" on project-local installs of the CLI/SDK + (npm). `@cipherstash/auth` was pinned at 0.41.0 while the six + `@cipherstash/auth-*` platform bindings declared in stack/stash/wizard's + optionalDependencies were pinned at 0.42.0. Because auth pins its bindings as + exact-version optional peer dependencies, the skew made npm nest per-consumer + binding copies that the hoisted `auth` package could not resolve — any command + or import touching auth then died at startup. All seven packages now move in + lockstep at 0.42.0, Dependabot is barred from bumping any of them + independently, and a supply-chain CI test fails on any future skew. + ## 1.0.0-rc.2 ### Minor Changes diff --git a/packages/stack/package.json b/packages/stack/package.json index b3436500f..3caab9025 100644 --- a/packages/stack/package.json +++ b/packages/stack/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/stack", - "version": "1.0.0-rc.2", + "version": "1.0.0-rc.3", "description": "CipherStash Stack for TypeScript and JavaScript", "keywords": [ "encrypted", diff --git a/packages/test-kit/CHANGELOG.md b/packages/test-kit/CHANGELOG.md index a38633351..afdb8935f 100644 --- a/packages/test-kit/CHANGELOG.md +++ b/packages/test-kit/CHANGELOG.md @@ -1,5 +1,12 @@ # @cipherstash/test-kit +## 0.0.1-rc.3 + +### Patch Changes + +- Updated dependencies [8b2551a] + - @cipherstash/stack@1.0.0-rc.3 + ## 0.0.1-rc.2 ### Patch Changes diff --git a/packages/test-kit/package.json b/packages/test-kit/package.json index 7636865a7..14fe49815 100644 --- a/packages/test-kit/package.json +++ b/packages/test-kit/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/test-kit", - "version": "0.0.1-rc.2", + "version": "0.0.1-rc.3", "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 e1d7dc287..9fa7bc2dd 100644 --- a/packages/wizard/CHANGELOG.md +++ b/packages/wizard/CHANGELOG.md @@ -1,5 +1,19 @@ # @cipherstash/wizard +## 1.0.0-rc.3 + +### Patch Changes + +- 8b2551a: Fix "Failed to load native binding" on project-local installs of the CLI/SDK + (npm). `@cipherstash/auth` was pinned at 0.41.0 while the six + `@cipherstash/auth-*` platform bindings declared in stack/stash/wizard's + optionalDependencies were pinned at 0.42.0. Because auth pins its bindings as + exact-version optional peer dependencies, the skew made npm nest per-consumer + binding copies that the hoisted `auth` package could not resolve — any command + or import touching auth then died at startup. All seven packages now move in + lockstep at 0.42.0, Dependabot is barred from bumping any of them + independently, and a supply-chain CI test fails on any future skew. + ## 1.0.0-rc.2 ### Patch Changes diff --git a/packages/wizard/package.json b/packages/wizard/package.json index a44cd9453..cbeadfd64 100644 --- a/packages/wizard/package.json +++ b/packages/wizard/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/wizard", - "version": "1.0.0-rc.2", + "version": "1.0.0-rc.3", "description": "AI-powered encryption setup for CipherStash. Reads your codebase, picks columns to encrypt, and wires everything up.", "repository": { "type": "git",