Skip to content

Version Packages - #859

Open
github-actions[bot] wants to merge 1 commit into
mainfrom
changeset-release/main
Open

Version Packages#859
github-actions[bot] wants to merge 1 commit into
mainfrom
changeset-release/main

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@cipherstash/stack@2.0.0

Major Changes

  • 6c211f5: Adopt protect-ffi 0.31.0.

    major, not minor, because of the first item below: a credential encoding
    that worked on 1.x stops working at client construction, and @cipherstash/stack
    pins @cipherstash/protect-ffi exactly — so upgrading stack forces the new FFI
    and there is no version of this a caller opts into separately. That hex was
    always the documented encoding describes intent, not the behaviour anyone was
    running against. The fixed group takes stash, wizard and the three adapters
    to 2.0.0 with it; that is a release-management cost, not an argument about what
    the version number means.

    clientKey must now be hex-encoded. This is the change to check before
    upgrading. The client key used to be decoded by a function that accepted both
    hex and standard padded base64 — the encoding ~/.cipherstash/secretkey.json
    stores on disk — so a base64 value in config.clientKey or CS_CLIENT_KEY
    worked even though the documented encoding is hex. It is now rejected at client
    construction with invalid clientKey: expected a hex-encoded key.

    The message deliberately says nothing more, because the underlying decode error
    names the offending character and its offset and would put part of a live key
    into your logs. So if every operation starts failing at construction after this
    upgrade, check the encoding of your key first. Re-encode it as hex, or drop the
    explicit key and let the client read it from the profile store.

    Reading the key from ~/.cipherstash/secretkey.json is unaffected — that path
    still uses base64, and only an explicitly supplied key is now hex-only.

    DynamoDB errors no longer report foreign error codes as encryption codes.
    handleError accepted any string-valued code on a caught error and passed it
    through as a ProtectErrorCode, so a Node or AWS SDK failure — ECONNRESET,
    say — surfaced as though it were an encryption error code. Codes are now checked
    against the set the encryption layer actually emits, and anything else becomes
    DYNAMODB_ENCRYPTION_ERROR. If you branch on error.code for DynamoDB
    operations, a branch that was matching transport errors will stop.

    Also in this release, with no action needed: the WASM entry passes credentials
    under the option shape 0.31 expects and no longer pre-normalises cast_as
    (the native layer does it on both bindings now), and bulk operations no longer
    forward their internal correlation id across the FFI boundary, which 0.31
    rejects rather than ignores.

Minor Changes

  • 93d62c2: Add EncryptionClient.getSchemas() — the tables passed to
    Encryption({ schemas }), returned by reference.

    This is the domain-bearing view of your schema. getEncryptConfig() returns
    what the FFI consumes: each column builds to { cast_as, indexes }, and the
    concrete EQL v3 domain name is dropped. That makes cast_as: 'number' with an
    ope index ambiguous across eql_v3_integer_ord, smallint_ord, real_ord,
    double_ord and numeric_ord — so tooling that has to reason about the
    declared domain (schema linting, drift-checking a live database's
    information_schema.columns.domain_name) could not recover it from a client
    alone.

    getSchemas() closes that gap. Read a column's domain with
    column.getEqlType(), its capabilities with column.getQueryCapabilities(),
    and its DB name with column.getName():

    for (const table of client.getSchemas()) {
      for (const column of Object.values(table.columnBuilders)) {
        console.log(table.tableName, column.getName(), column.getEqlType());
      }
    }

    stash eql validate is the first consumer.

stash@2.0.0

Minor Changes

  • d473745: Rewrite db validate as eql validate, for the EQL v3 domain-type vocabulary.

    Fixes a false finding on the most ordinary v3 columns. The old rule set
    checked for ore / unique / match / ste_vec indexes and never learned
    about ope. EQL v3's default ordering domains emit ope, so
    types.IntegerOrd('age') and types.TimestampOrd('created_at') were both
    reported as "Column is encrypted but has no indexes — it will not be
    searchable". They are now silent.

    The command reads your tables through the new
    EncryptionClient.getSchemas(), so it sees each column's concrete domain
    rather than the lossy encrypt config, and gains a database pass when one is
    reachable.

    Schema checks (no database needed):

    Rule Severity
    An _ord_ore domain is declared — its ORE operator class needs superuser Warning
    Storage-only column: encrypts and decrypts, carries no query terms Info
    Searchable boolean column Error
    Free-text match index on a non-text domain Error
    Encrypted-JSONB (ste_vec) index without types.Json Error

    Database checks (skipped with a notice, not a failure, when no database is
    reachable):

    Rule Severity
    EQL v3 is not installed — reported once, remaining database checks skipped Error
    A declared table lives in a different schema than the one searched Warning
    A declared table is in the searched schema but invisible to the connected role Warning
    A declared table name carries a schema qualifier (schema.table) — not checked Warning
    A declared table exists in no schema at all Error
    A declared column is missing from a table that was found Error
    The database column's domain differs from the declared one Error
    The database column is still plain (no EQL domain) Error
    An _ord_ore domain where the EQL install could not create the ORE operator class Error
    A queryable column with no functional index over its term extractor Info
    A declared table name that resolved in the searched schema also exists in another one Info

    --exclude-operator-family is removed: it warned that an ore index would not
    support ORDER BY without operator families, and the pinned EQL v3 bundle
    self-adapts. eql install / eql upgrade had already rejected the flag;
    validate was its last consumer.

    The database pass inspects current_schema() only, and distinguishes four
    reasons a declared table can be missing from it, so that only the last fails
    the command. In another schema (Prisma multiSchema, a tenant schema): a
    Warning naming that schema. Present but invisible to the connected role: a
    Warning carrying the GRANT SELECT to run — information_schema reports only
    what the role holds a privilege on, so a missing grant is not a missing
    migration. Declared as schema.table: a Warning saying it was not checked,
    because validate matches table names unqualified. Absent everywhere: an Error.
    Reported once per table rather than once per column.

    The relation lookup that answers those questions excludes pg_* and
    information_schema. Unscoped it matched the system views named columns,
    domains, parameters, routines, sequences, tables and triggers — all
    ordinary application table names — so a project declaring one of them that had
    not run its migration was told the table "exists in schema information_schema",
    as a Warning, and the command exited 0 on a genuinely unapplied migration.

    An unqualified name found in more than one schema is now reported as an Info
    naming the relation that was actually checked ("public"."users") and the
    other schemas holding that name. A bare name resolves through search_path, so
    users in both public and Supabase's auth left it ambiguous which relation
    every other finding described. Info, not Warning: it must not fail or
    de-clean an ordinary Supabase project.

    Two of those used to exit 1 and no longer do: a privilege-invisible table and
    a schema-qualified declaration were both reported as "does not exist in any
    schema", which sent people to re-run a migration that had already run.

    Against a project whose @cipherstash/stack predates getSchemas(), validate
    says so and falls back to the encrypt config, running the index-derived rules
    and skipping the domain ones.

    stash db validate keeps working as a deprecated alias, like db install /
    db upgrade / db status. Exits 1 on errors only.

  • 1d10003: Add stash eql migration --supabase, so an EQL v3 install survives supabase db reset (No Supabase-native EQL v3 migration file: a v3 install does not survive supabase db reset #613).

    Supabase projects previously had only stash eql install --supabase, which applies the SQL directly to a running database. supabase db reset — the ordinary local development loop — drops that database and replays supabase/migrations/, so the install was wiped and the next query failed with type "eql_v3_encrypted" does not exist. There was no supported way to get EQL into the migrations directory.

    stash eql migration --supabase now writes supabase/migrations/<timestamp>_cipherstash_eql.sql, carrying the EQL v3 bundle, the anon / authenticated / service_role grants, and the cipherstash.cs_migrations tracking schema — so one supabase db reset provisions everything stash encrypt needs. The file is timestamped at generation time, so it sorts after everything already applied and pushes without --include-all. A second run exits rather than adding a duplicate install; --force regenerates the existing one in place.

    The command now warns when the migrations directory already holds EQL-referencing migrations that sort before the install it is about to write. A project that ran stash eql install directly and then added public.eql_v3_* columns against the live database gets an install stamped today — after those migrations — and supabase db reset, which replays in version order with no dependency awareness, then fails with type "eql_v3_text_search" does not exist. The warning names the specific files and the remedy (rename the install below the earliest of them, then reconcile each remote — see below). It fires on --dry-run too, and nothing is renamed automatically — the ordering of someone else's deployed history is not ours to change silently.

    That warning's remote guidance now requires you to verify the remote before writing to its ledger. It splits by whether the remote already has EQL: one where it does needs only the ledger row (supabase migration repair --status applied <version>, which runs no SQL — pushing the file instead re-runs a bundle opening with DROP SCHEMA IF EXISTS eql_v3 CASCADE), and one where it does not needs the SQL genuinely applied (supabase db push --include-all, the back-dated version being a gap in the middle of that history). Previously the first branch was recommended on an assumption the user was never asked to check, and it is the one operation here with no self-correcting failure: mark a version applied on a remote that never ran the SQL and EQL is permanently absent and permanently marked applied, so no future push installs it and the first migration referencing eql_v3 fails with nothing pointing at the cause. The warning now prints the check first — psql "$REMOTE_DATABASE_URL" -Atc "select eql_v3.version()" — and says never to mark applied when it errors. It asks for eql_v3.version() rather than the eql_v3 schema deliberately: that function is created by the bundle's closing statements, so it cannot resolve on an install that aborted partway, while the schema is created by its opening ones and survives one. The same correction lands in the stash-cli and stash-supabase skills and the CLI README, and a guard test now fails the build if a shipped skill recommends the ledger-only repair without that check above it.

    --force's follow-up guidance was wrong and is now correct. It said to re-apply with supabase db reset (local) or supabase db push (remote), but a push never re-applies a rewritten migration: the Supabase CLI decides what is pending by comparing versions, never file content, so an in-place rewrite keeping its version is skipped and push reports Remote database is up to date. The remote recipe is now supabase migration repair --status reverted <version> (tracking table only — it applies no SQL) followed by supabase db push, with --include-all called out as a conditional: it is needed only when migrations sort after the install, which leaves the reverted version as a gap in the middle of remote history. Reverting the newest version leaves it at the tail, where a plain push applies it — and the flag applies every out-of-order migration you have, so recommending it unconditionally was itself a hazard. The warning also names the hazard it never mentioned: the EQL bundle opens with DROP SCHEMA IF EXISTS eql_v3 CASCADE, so re-applying drops every index, constraint, and RLS policy that references eql_v3 / eql_v3_internal — free on a fresh db reset, destructive on a populated remote.

    --out on a bare --supabase now warns. The Supabase CLI's migrations directory is not configurable — supabase db reset and supabase db push read <project>/supabase/migrations and nothing else, config.toml has no key for it, and --workdir relocates the whole supabase/ directory rather than this subdirectory — so an install written elsewhere is never applied, which is the original bug relocated. The flag still writes the file (a project may apply that directory through its own tooling) but names the consequence, on --dry-run too. --out alongside --drizzle --supabase is unaffected: there it is drizzle-kit's output directory.

    --supabase keeps its existing meaning alongside --drizzle (append the role grants to the Drizzle migration); only a bare --supabase selects the new emitter.

    stash init --supabase now generates that migration instead of installing directly, when the project has local supabase/ scaffolding — a hosted project without it still installs directly. Re-running init over a project that already has an install migration reports it and moves on, rather than treating the duplicate refusal as a failed setup. Its next steps no longer tell you to run eql install --supabase and then supabase db reset, which was the exact sequence that destroyed the install.

    stash init's EQL summary line now distinguishes the migration it wrote from one it merely found. A re-run over an existing install migration says "EQL migration already present" instead of "EQL migration generated" — same apply guidance, same successful exit, but no claim about work the run did not do.

    stash init's EQL prompt now names the action for the route it is actually on. On the migration-first routes it asks whether to generate a migration (naming supabase/migrations/ or your Drizzle migrations folder) rather than whether to install into your database, which described the wrong action on both. Declining is fixed the same way: the retry hint is now stash eql migration --supabase / --drizzle on those routes instead of stash eql install, which on Supabase would reinstate the very bug above.

    stash init now routes on the integration flags themselves rather than on the provider's display name, so combining them works. stash init --drizzle --supabase is accepted — and is the natural invocation for a Drizzle project on Supabase — but init joined the matched flags into a single provider name (drizzle-supabase) for referrer tracking and then compared that name against 'drizzle' and 'supabase' everywhere it had a decision to make. Every comparison went false. A local Supabase stack answers on 127.0.0.1:54322, so host detection reports plain Postgres and the flags are the only signal left: the run installed EQL directly instead of writing a migration — nothing in supabase/migrations/, no anon / authenticated / service_role grants — which is the No Supabase-native EQL v3 migration file: a v3 install does not survive supabase db reset #613 failure this release exists to fix, reached through a flag combination the CLI accepts. The same fall-through dropped the supabase status hint when resolving DATABASE_URL (the one lookup that finds a local stack's URL), lost the Prisma Next branch for --prisma --supabase — scaffolding a client Prisma Next never uses and running a duplicate EQL install that races prisma-next migrate's journal — and installed no integration adapter at all, where a combined run needs both @cipherstash/stack-drizzle and @cipherstash/stack-supabase. The provider now carries the matched flags alongside its name and every step reads those; the combined name is still exactly what gets recorded as the referrer, it is simply no longer what the CLI branches on. Drizzle still wins the migration route when both flags fire — it owns the migration history, and --supabase is the grants modifier there. Single-flag runs behave exactly as before.

    Also corrects the remote apply command across the Supabase guidance: a bare supabase migration up targets the local database, so the instructions now say supabase db push.

    Also corrects the eql install --migration removal message, which pointed every Supabase user at --drizzle.

    The Supabase CLI behaviour all of the above depends on is now pinned by a live test rather than by reading the CLI's source. supabase-push.live.test.ts drives the real binary against a real Postgres — db push --db-url needs neither Docker nor a linked project — and covers: the generated install applying with no --include-all; anon reaching eql_v3 via SET ROLE through the grants carried in the emitted file (not just the ones eql install --direct applies); an out-of-order version aborting the whole push rather than being skipped; a --force-replaced file never re-applying; --include-all being needed only for the gap case; and a leaked .tmp file being ignored. Gated on STASH_TEST_SUPABASE_DB_URL + STASH_TEST_SUPABASE_CLI, so the default suite is unchanged.

Patch Changes

  • a1b53af: Correct the Dependabot section of the bundled stash-supply-chain-security
    skill. It described two monitored ecosystems (npm, github-actions); there
    are now three, because the in-tree Rust workspace at packages/protect-ffi
    brought a Cargo.lock that nothing proposed updates for. The skill now names
    the cargo entry, its non-root directory, its monthly cadence, and the
    exact-pinned CipherStash crates it ignores.

    Two things the section previously got wrong are also fixed. Major bumps do not
    "stay un-grouped — one PR each": every entry ignores
    version-update:semver-major, so Dependabot proposes no major bumps at all and
    they are applied by hand. And ignore conditions suppress Dependabot security
    PRs as well as version updates — the skill now says so, and points at
    osv-scanner.yml (which scans every lockfile in the tree, Cargo.lock
    included) as the compensating control.

  • 66ba41a: Document in the bundled stash-auth skill that CS_CLIENT_KEY must be
    hex-encoded. Hex is what stash env emits and what the skill's variable table
    already stated, but older client versions also accepted the base64 spelling
    stored in ~/.cipherstash/secretkey.json, so a key copied out of that file
    used to work. It is now rejected at client construction, with a message that
    deliberately withholds detail — so the skill names the symptom and the fix.

    The recovery advice is split by entry point: falling back to the profile store
    works on the native entry, but not on @cipherstash/stack/wasm-inline, where
    clientId and clientKey are required config and the target runtimes have no
    profile store to read. Re-encoding as hex is the fix that works on both.

  • 05f84bc: Correct the release-workflow section of the bundled stash-supply-chain-security
    skill. It described the no-Actions-cache rule as a property of one file — "no
    cache:, package-manager-cache: false, pnpm/action-setup with
    cache: false" — which is no longer the whole rule.

    The gate now follows any local composite action or reusable workflow the job
    reaches, so the constraint is on the whole call tree rather than the workflow
    file. And every published uses: must appear in the script's AUDITED_ACTIONS
    allowlist: the check cannot open a published action to prove it does not cache,
    and caching actions are not reliably named — a setup-<tool> action that caches
    by default has no cache: input and nothing in its name to match. The list is
    therefore what is permitted, not what is forbidden, and adding a step to
    release.yml or tests-supply-chain.yml means auditing the action and adding
    it there in the same PR.

  • 41c4531: Correct two inaccuracies in the bundled stash-cli skill. The stash init overview said the Supabase flow always generates an EQL migration; it now says local Supabase, matching resolveMigrationRoute — only a project with local supabase/ CLI scaffolding takes the migration-first route, while a hosted Supabase project with no supabase/ directory falls through to a direct stash eql install. And the guidance for back-dating the Supabase install migration no longer recommends supabase db push --include-all unconditionally: on a remote where stash eql install has already run, pushing the file re-runs a bundle that opens with DROP SCHEMA IF EXISTS eql_v3 CASCADE, dropping every index, constraint, and RLS policy on those schemas. That case is now supabase migration repair --status applied <version> (ledger only, no SQL) — after confirming EQL is genuinely installed on that remote with psql "$REMOTE_DATABASE_URL" -Atc "select eql_v3.version()"; --include-all stays for a remote that still needs the SQL applied.

    The same correction lands in the CLI itself, and in the two other places that repeated the old advice — the stash-supabase skill and the CLI README. stash eql migration --supabase warns when the project already has EQL-referencing migrations that sort before the install it is about to write, and that warning carried the identical blanket --include-all advice. Since this warning only fires on projects that ran stash eql install directly — so the remote usually already has the bundle and is missing only the ledger row — it now names supabase migration repair --status applied <version> as the remedy, spells out the DROP SCHEMA IF EXISTS eql_v3 CASCADE hazard of pushing the file instead, and keeps --include-all for the remote that has not had the SQL applied.

  • d348f84: Document the Dependabot major-version policy in skills/stash-supply-chain-security: no entry configures a semver-major-days cooldown, because every entry ignores version-update:semver-major and cooldown applies to version updates only. The supply-chain e2e suite now pins both halves of that relationship.

    • @cipherstash/migrate@1.0.0

@cipherstash/stack-drizzle@2.0.0

Patch Changes

  • Updated dependencies [93d62c2]
  • Updated dependencies [6c211f5]
    • @cipherstash/stack@2.0.0

@cipherstash/stack-prisma@2.0.0

Patch Changes

  • Updated dependencies [93d62c2]
  • Updated dependencies [6c211f5]
    • @cipherstash/stack@2.0.0

@cipherstash/stack-supabase@2.0.0

Patch Changes

  • Updated dependencies [93d62c2]
  • Updated dependencies [6c211f5]
    • @cipherstash/stack@2.0.0

@cipherstash/wizard@2.0.0

@cipherstash/e2e@0.0.4

Patch Changes

  • Updated dependencies [a1b53af]
  • Updated dependencies [66ba41a]
  • Updated dependencies [05f84bc]
  • Updated dependencies [93d62c2]
  • Updated dependencies [6c211f5]
  • Updated dependencies [41c4531]
  • Updated dependencies [d473745]
  • Updated dependencies [d348f84]
  • Updated dependencies [1d10003]
    • stash@2.0.0
    • @cipherstash/stack@2.0.0
    • @cipherstash/wizard@2.0.0

@cipherstash/basic-example@1.2.15

Patch Changes

  • Updated dependencies [93d62c2]
  • Updated dependencies [6c211f5]
    • @cipherstash/stack@2.0.0
    • @cipherstash/stack-drizzle@2.0.0

@cipherstash/prisma-example@0.1.1

Patch Changes

  • Updated dependencies [93d62c2]
  • Updated dependencies [6c211f5]
    • @cipherstash/stack@2.0.0
    • @cipherstash/stack-prisma@2.0.0

@cipherstash/bench@0.0.6

Patch Changes

  • Updated dependencies [93d62c2]
  • Updated dependencies [6c211f5]
    • @cipherstash/stack@2.0.0
    • @cipherstash/stack-drizzle@2.0.0

@cipherstash/test-kit@0.0.2

Patch Changes

  • Updated dependencies [93d62c2]
  • Updated dependencies [6c211f5]
    • @cipherstash/stack@2.0.0

@github-actions
github-actions Bot requested a review from a team as a code owner August 5, 2026 02:18
@github-actions
github-actions Bot force-pushed the changeset-release/main branch 4 times, most recently from 1598064 to d6abef2 Compare August 6, 2026 04:20
@github-actions
github-actions Bot force-pushed the changeset-release/main branch from d6abef2 to aa4e33b Compare August 6, 2026 08:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants