Version Packages - #859
Open
github-actions[bot] wants to merge 1 commit into
Open
Conversation
github-actions
Bot
force-pushed
the
changeset-release/main
branch
4 times, most recently
from
August 6, 2026 04:20
1598064 to
d6abef2
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
August 6, 2026 08:25
d6abef2 to
aa4e33b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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, notminor, because of the first item below: a credential encodingthat worked on 1.x stops working at client construction, and
@cipherstash/stackpins
@cipherstash/protect-ffiexactly — so upgrading stack forces the new FFIand 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,wizardand the three adaptersto 2.0.0 with it; that is a release-management cost, not an argument about what
the version number means.
clientKeymust now be hex-encoded. This is the change to check beforeupgrading. The client key used to be decoded by a function that accepted both
hex and standard padded base64 — the encoding
~/.cipherstash/secretkey.jsonstores on disk — so a base64 value in
config.clientKeyorCS_CLIENT_KEYworked 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.jsonis unaffected — that pathstill uses base64, and only an explicitly supplied key is now hex-only.
DynamoDB errors no longer report foreign error codes as encryption codes.
handleErroraccepted any string-valuedcodeon a caught error and passed itthrough 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 onerror.codefor DynamoDBoperations, 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 toEncryption({ schemas }), returned by reference.This is the domain-bearing view of your schema.
getEncryptConfig()returnswhat the FFI consumes: each column builds to
{ cast_as, indexes }, and theconcrete EQL v3 domain name is dropped. That makes
cast_as: 'number'with anopeindex ambiguous acrosseql_v3_integer_ord,smallint_ord,real_ord,double_ordandnumeric_ord— so tooling that has to reason about thedeclared domain (schema linting, drift-checking a live database's
information_schema.columns.domain_name) could not recover it from a clientalone.
getSchemas()closes that gap. Read a column's domain withcolumn.getEqlType(), its capabilities withcolumn.getQueryCapabilities(),and its DB name with
column.getName():stash eql validateis the first consumer.stash@2.0.0
Minor Changes
d473745: Rewrite
db validateaseql 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_vecindexes and never learnedabout
ope. EQL v3's default ordering domains emitope, sotypes.IntegerOrd('age')andtypes.TimestampOrd('created_at')were bothreported 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 domainrather than the lossy encrypt config, and gains a database pass when one is
reachable.
Schema checks (no database needed):
_ord_oredomain is declared — its ORE operator class needs superuserbooleancolumnmatchindex on a non-text domainste_vec) index withouttypes.JsonDatabase checks (skipped with a notice, not a failure, when no database is
reachable):
schema.table) — not checked_ord_oredomain where the EQL install could not create the ORE operator class--exclude-operator-familyis removed: it warned that anoreindex would notsupport
ORDER BYwithout operator families, and the pinned EQL v3 bundleself-adapts.
eql install/eql upgradehad already rejected the flag;validatewas its last consumer.The database pass inspects
current_schema()only, and distinguishes fourreasons a declared table can be missing from it, so that only the last fails
the command. In another schema (Prisma
multiSchema, a tenant schema): aWarning naming that schema. Present but invisible to the connected role: a
Warning carrying the
GRANT SELECTto run —information_schemareports onlywhat 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_*andinformation_schema. Unscoped it matched the system views namedcolumns,domains,parameters,routines,sequences,tablesandtriggers— allordinary 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 theother schemas holding that name. A bare name resolves through
search_path, sousersin bothpublicand Supabase'sauthleft it ambiguous which relationevery 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/stackpredatesgetSchemas(), validatesays so and falls back to the encrypt config, running the index-derived rules
and skipping the domain ones.
stash db validatekeeps working as a deprecated alias, likedb install/db upgrade/db status. Exits 1 on errors only.1d10003: Add
stash eql migration --supabase, so an EQL v3 install survivessupabase db reset(No Supabase-native EQL v3 migration file: a v3 install does not survivesupabase 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 replayssupabase/migrations/, so the install was wiped and the next query failed withtype "eql_v3_encrypted" does not exist. There was no supported way to get EQL into the migrations directory.stash eql migration --supabasenow writessupabase/migrations/<timestamp>_cipherstash_eql.sql, carrying the EQL v3 bundle, theanon/authenticated/service_rolegrants, and thecipherstash.cs_migrationstracking schema — so onesupabase db resetprovisions everythingstash encryptneeds. 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;--forceregenerates 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 installdirectly and then addedpublic.eql_v3_*columns against the live database gets an install stamped today — after those migrations — andsupabase db reset, which replays in version order with no dependency awareness, then fails withtype "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-runtoo, 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 withDROP 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 referencingeql_v3fails 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 foreql_v3.version()rather than theeql_v3schema 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 thestash-cliandstash-supabaseskills 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 withsupabase db reset(local) orsupabase 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 reportsRemote database is up to date.The remote recipe is nowsupabase migration repair --status reverted <version>(tracking table only — it applies no SQL) followed bysupabase db push, with--include-allcalled 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 withDROP SCHEMA IF EXISTS eql_v3 CASCADE, so re-applying drops every index, constraint, and RLS policy that referenceseql_v3/eql_v3_internal— free on a freshdb reset, destructive on a populated remote.--outon a bare--supabasenow warns. The Supabase CLI's migrations directory is not configurable —supabase db resetandsupabase db pushread<project>/supabase/migrationsand nothing else,config.tomlhas no key for it, and--workdirrelocates the wholesupabase/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-runtoo.--outalongside--drizzle --supabaseis unaffected: there it is drizzle-kit's output directory.--supabasekeeps its existing meaning alongside--drizzle(append the role grants to the Drizzle migration); only a bare--supabaseselects the new emitter.stash init --supabasenow generates that migration instead of installing directly, when the project has localsupabase/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 runeql install --supabaseand thensupabase 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 (namingsupabase/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 nowstash eql migration --supabase/--drizzleon those routes instead ofstash eql install, which on Supabase would reinstate the very bug above.stash initnow routes on the integration flags themselves rather than on the provider's display name, so combining them works.stash init --drizzle --supabaseis 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 on127.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 insupabase/migrations/, noanon/authenticated/service_rolegrants — which is the No Supabase-native EQL v3 migration file: a v3 install does not survivesupabase db reset#613 failure this release exists to fix, reached through a flag combination the CLI accepts. The same fall-through dropped thesupabase statushint when resolvingDATABASE_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 racesprisma-next migrate's journal — and installed no integration adapter at all, where a combined run needs both@cipherstash/stack-drizzleand@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--supabaseis 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 uptargets the local database, so the instructions now saysupabase db push.Also corrects the
eql install --migrationremoval 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.tsdrives the real binary against a real Postgres —db push --db-urlneeds neither Docker nor a linked project — and covers: the generated install applying with no--include-all;anonreachingeql_v3viaSET ROLEthrough the grants carried in the emitted file (not just the oneseql install --directapplies); an out-of-order version aborting the whole push rather than being skipped; a--force-replaced file never re-applying;--include-allbeing needed only for the gap case; and a leaked.tmpfile being ignored. Gated onSTASH_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-securityskill. It described two monitored ecosystems (
npm,github-actions); thereare now three, because the in-tree Rust workspace at
packages/protect-ffibrought a
Cargo.lockthat nothing proposed updates for. The skill now namesthe
cargoentry, its non-rootdirectory, its monthly cadence, and theexact-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 andthey are applied by hand. And
ignoreconditions suppress Dependabot securityPRs as well as version updates — the skill now says so, and points at
osv-scanner.yml(which scans every lockfile in the tree,Cargo.lockincluded) as the compensating control.
66ba41a: Document in the bundled
stash-authskill thatCS_CLIENT_KEYmust behex-encoded. Hex is what
stash envemits and what the skill's variable tablealready stated, but older client versions also accepted the base64 spelling
stored in
~/.cipherstash/secretkey.json, so a key copied out of that fileused 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, whereclientIdandclientKeyare required config and the target runtimes have noprofile 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-securityskill. It described the no-Actions-cache rule as a property of one file — "no
cache:,package-manager-cache: false,pnpm/action-setupwithcache: 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'sAUDITED_ACTIONSallowlist: 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 cachesby default has no
cache:input and nothing in its name to match. The list istherefore what is permitted, not what is forbidden, and adding a step to
release.ymlortests-supply-chain.ymlmeans auditing the action and addingit there in the same PR.
41c4531: Correct two inaccuracies in the bundled
stash-cliskill. Thestash initoverview said the Supabase flow always generates an EQL migration; it now says local Supabase, matchingresolveMigrationRoute— only a project with localsupabase/CLI scaffolding takes the migration-first route, while a hosted Supabase project with nosupabase/directory falls through to a directstash eql install. And the guidance for back-dating the Supabase install migration no longer recommendssupabase db push --include-allunconditionally: on a remote wherestash eql installhas already run, pushing the file re-runs a bundle that opens withDROP SCHEMA IF EXISTS eql_v3 CASCADE, dropping every index, constraint, and RLS policy on those schemas. That case is nowsupabase migration repair --status applied <version>(ledger only, no SQL) — after confirming EQL is genuinely installed on that remote withpsql "$REMOTE_DATABASE_URL" -Atc "select eql_v3.version()";--include-allstays 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-supabaseskill and the CLI README.stash eql migration --supabasewarns 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-alladvice. Since this warning only fires on projects that ranstash eql installdirectly — so the remote usually already has the bundle and is missing only the ledger row — it now namessupabase migration repair --status applied <version>as the remedy, spells out theDROP SCHEMA IF EXISTS eql_v3 CASCADEhazard of pushing the file instead, and keeps--include-allfor 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 asemver-major-dayscooldown, because every entry ignoresversion-update:semver-majorand cooldown applies to version updates only. The supply-chain e2e suite now pins both halves of that relationship.@cipherstash/stack-drizzle@2.0.0
Patch Changes
@cipherstash/stack-prisma@2.0.0
Patch Changes
@cipherstash/stack-supabase@2.0.0
Patch Changes
@cipherstash/wizard@2.0.0
@cipherstash/e2e@0.0.4
Patch Changes
@cipherstash/basic-example@1.2.15
Patch Changes
@cipherstash/prisma-example@0.1.1
Patch Changes
@cipherstash/bench@0.0.6
Patch Changes
@cipherstash/test-kit@0.0.2
Patch Changes