Skip to content

Commit e78e71d

Browse files
auxesisclaude
andcommitted
build: take @cipherstash/auth from the workspace, not the registry
stack, stash, @cipherstash/wizard and the protect-ffi integration suite move the wrapper and the six platform packages from `catalog:repo` to `workspace:*`. The seven catalog entries, the two minimumReleaseAgeExclude entries and the two npm Dependabot ignores are dead config and go. The lock changes only the auth importers and entries, and `pnpm pack` still writes each range as the exact version. A workspace @cipherstash/auth ships source only, and its index.js loads the napi module on import, so every CI job that imports the SDK or runs the CLI now builds it: without a build, the stack, stash and wizard suites fail 26, 16 and 2 files with `Failed to load native binding`. .github/actions/build-auth-binding runs build:debug, and build:wasm with `wasm: 'true'`, then checks both load. It runs after each of the ten build-ffi-binding calls, with wasm where that call has it, and in tests-bench.yml, whose unit checks import the SDK and whose globalSetup runs `stash`. In tests.yml's run-tests it replaces the auth half of the binding build step. auth-binding-step-order.test.mjs holds the pairing and the filters. Every workflow that uses the action filters on it. The three integration workflows that saw auth bumps through pnpm-workspace.yaml now filter on the paths require-auth-npm-changeset.yml treats as what @cipherstash/auth ships. supply-chain.e2e.test.ts keeps the lockstep invariant in its new shape: no auth catalog entry, and `workspace:*` in every consumer. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PaY5xYydZUWhv8Nex9Sw8a
1 parent 0d12014 commit e78e71d

18 files changed

Lines changed: 457 additions & 274 deletions
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
name: Build the @cipherstash/auth binding
2+
description: >-
3+
Compile `languages/typescript/packages/auth` into what its JS consumers load
4+
at runtime — the napi module (cargo, debug) and optionally `wasm/`
5+
(wasm-pack) — then prove they load.
6+
7+
WHY THIS EXISTS: `@cipherstash/stack`, `stash`, `@cipherstash/wizard` and the
8+
protect-ffi integration suite take `@cipherstash/auth` from the workspace.
9+
It ships source only there, and its `index.js` loads the napi module on
10+
import, so every job that imports the SDK or runs the CLI builds it first.
11+
From npm, the platform package brought a prebuilt `.node`. Without this, those
12+
jobs fail with `Failed to load native binding for linux-x64`. It is the auth
13+
half of `.github/actions/build-ffi-binding`, and runs after it;
14+
scripts/__tests__/auth-binding-step-order.test.mjs holds the jobs to that.
15+
16+
DO NOT USE FROM A PUBLISHING WORKFLOW: release builds go through
17+
`_build-auth-artifacts.yml`, which compiles every platform from scratch.
18+
19+
inputs:
20+
wasm:
21+
description: >-
22+
Also build `wasm/`, which `@cipherstash/auth/wasm-inline` imports and
23+
`@cipherstash/stack/wasm-inline` re-exports. Pass it where the job passes
24+
`wasm: true` to build-ffi-binding.
25+
required: false
26+
default: 'false'
27+
28+
runs:
29+
using: composite
30+
steps:
31+
# The runner's cargo, as build-ffi-binding uses for `index.node`. Writes
32+
# the typings to the committed `native.d.ts`, so the tree stays clean.
33+
- name: Build the napi module (cargo)
34+
shell: bash
35+
run: pnpm --filter @cipherstash/auth run build:debug
36+
37+
# The root mise.toml pins wasm-pack for this build. `install_args` narrows
38+
# the install to it: the root also pins Rust, Go and golangci-lint, which
39+
# this needs none of. Same action and pin as build-ffi-binding.
40+
- name: Install wasm-pack
41+
if: inputs.wasm == 'true'
42+
uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3
43+
with:
44+
install: true
45+
install_args: aqua:wasm-bindgen/wasm-pack
46+
working_directory: .
47+
48+
- name: Add the wasm32 target
49+
if: inputs.wasm == 'true'
50+
shell: bash
51+
run: rustup target add wasm32-unknown-unknown
52+
53+
- name: Build wasm/ (wasm-pack)
54+
if: inputs.wasm == 'true'
55+
shell: bash
56+
run: pnpm --filter @cipherstash/auth run build:wasm
57+
58+
- name: Verify the binding loads
59+
shell: bash
60+
working-directory: languages/typescript/packages/auth
61+
env:
62+
WANT_WASM: ${{ inputs.wasm }}
63+
run: |
64+
set -euo pipefail
65+
66+
# index.js loads the napi module when it is required.
67+
node -e "require('./index.js')"
68+
echo "the napi module loads"
69+
70+
if [ "$WANT_WASM" = "true" ]; then
71+
node --input-type=module -e "await import('./wasm-inline.mjs')"
72+
echo "wasm/ loads"
73+
fi

‎.github/dependabot.yml‎

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,6 @@ updates:
4343
patterns:
4444
- "@types/*"
4545
ignore:
46-
# Catalog-managed; bump manually via pnpm-workspace.yaml + changeset.
47-
- dependency-name: "@cipherstash/auth"
48-
# The platform bindings MUST move in lockstep with @cipherstash/auth:
49-
# auth pins them as exact-version optional peer deps, so a skewed set
50-
# makes npm nest per-consumer binding copies the hoisted auth package
51-
# cannot resolve, and every project-local install of the CLI/SDK dies
52-
# with "Failed to load native binding". Dependabot once bumped these
53-
# six to 0.42.0 while the ignored auth stayed 0.41.0 (the rc.2 B1
54-
# bug). Bump all seven catalog entries together, manually. Lockstep is
55-
# enforced by e2e/tests/supply-chain.e2e.test.ts.
56-
- dependency-name: "@cipherstash/auth-*"
5746
# 0.x bumps ship breaking type changes (e.g. 0.2 → 0.3 tightened the
5847
# FailureOption constraint). Review and apply manually.
5948
- dependency-name: "@byteslice/result"
@@ -126,13 +115,12 @@ updates:
126115
- patch
127116
ignore:
128117
# The CipherStash crates are pinned with EXACT `=` requirements in
129-
# crates/protect-ffi/Cargo.toml and are the same release train as the
130-
# @cipherstash/auth catalog entries above — cipherstash-client,
131-
# cts-common, stack-auth and stack-profile all sit at =0.42.0, matching
132-
# the catalog's 0.42.0. Dependabot bumping a subset is the Rust version
133-
# of the rc.2 B1 bug recorded above: it would rewrite one `=` pin and
134-
# leave the rest, and the crates do not tolerate skew. Bump them
135-
# together, manually, in step with the npm catalog.
118+
# crates/protect-ffi/Cargo.toml and are one release train —
119+
# cipherstash-client, cts-common, stack-auth and stack-profile all sit at
120+
# the same `=` version. Dependabot bumping a subset would rewrite one `=`
121+
# pin and leave the rest, and the crates do not tolerate skew (a skewed
122+
# @cipherstash/auth platform set was the npm form of this, the rc.2 B1
123+
# bug). Bump them together, manually.
136124
#
137125
# Caveat worth knowing: `ignore` suppresses Dependabot SECURITY PRs too,
138126
# not just version updates. osv-scanner is the compensating control —

‎.github/workflows/integration-drizzle.yml‎

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ on:
4141
# directory, so without these two entries the only suites that would catch
4242
# it never start. They are the files a bump actually edits: exact pins
4343
# (`protect-ffi`, `@cipherstash/eql`) live in the package manifest,
44-
# `catalog:` ones (`@cipherstash/auth`, which moves in lockstep with
45-
# protect-ffi for the WASM entry) in the workspace catalog.
44+
# `catalog:` ones in the workspace catalog.
4645
#
4746
# `pnpm-lock.yaml` is deliberately NOT listed. It changes on roughly every
4847
# dependency bump in the monorepo — far more often than either file here —
4948
# and these are credentialed, database-backed jobs. Nothing is lost: a
50-
# protect-ffi or auth version change cannot reach the lockfile without
51-
# editing one of the two manifests below first.
49+
# protect-ffi version change cannot reach the lockfile without editing
50+
# one of the two manifests below first, and an auth one edits its own
51+
# manifest, under the auth paths below.
5252
- 'languages/typescript/packages/stack/package.json'
5353
- 'pnpm-workspace.yaml'
5454
- 'languages/typescript/packages/test-kit/**'
@@ -60,6 +60,15 @@ on:
6060
- '.github/actions/integration-setup/**'
6161
- '.github/actions/integration-db/**'
6262
- '.github/actions/build-ffi-binding/**'
63+
- '.github/actions/build-auth-binding/**'
64+
# `@cipherstash/auth` is a workspace package, and the SDK loads its napi
65+
# module (and, for `wasm-inline`, its wasm) on import, so a change to what
66+
# it ships arrives here rather than in `pnpm-workspace.yaml`. The paths of
67+
# require-auth-npm-changeset.yml.
68+
- 'packages/stack-auth/Cargo.toml'
69+
- 'packages/stack-auth/src/**'
70+
- 'languages/typescript/packages/auth/**'
71+
- 'languages/typescript/packages/stack-auth-wasm/**'
6372
# The Rust that produces every EQL payload these suites round-trip.
6473
# Absorbing protect-ffi put it in-tree, so a crate change can now
6574
# break them in a PR that touches no TypeScript at all.
@@ -126,14 +135,14 @@ on:
126135
# directory, so without these two entries the only suites that would catch
127136
# it never start. They are the files a bump actually edits: exact pins
128137
# (`protect-ffi`, `@cipherstash/eql`) live in the package manifest,
129-
# `catalog:` ones (`@cipherstash/auth`, which moves in lockstep with
130-
# protect-ffi for the WASM entry) in the workspace catalog.
138+
# `catalog:` ones in the workspace catalog.
131139
#
132140
# `pnpm-lock.yaml` is deliberately NOT listed. It changes on roughly every
133141
# dependency bump in the monorepo — far more often than either file here —
134142
# and these are credentialed, database-backed jobs. Nothing is lost: a
135-
# protect-ffi or auth version change cannot reach the lockfile without
136-
# editing one of the two manifests below first.
143+
# protect-ffi version change cannot reach the lockfile without editing
144+
# one of the two manifests below first, and an auth one edits its own
145+
# manifest, under the auth paths below.
137146
- 'languages/typescript/packages/stack/package.json'
138147
- 'pnpm-workspace.yaml'
139148
- 'languages/typescript/packages/test-kit/**'
@@ -145,6 +154,15 @@ on:
145154
- '.github/actions/integration-setup/**'
146155
- '.github/actions/integration-db/**'
147156
- '.github/actions/build-ffi-binding/**'
157+
- '.github/actions/build-auth-binding/**'
158+
# `@cipherstash/auth` is a workspace package, and the SDK loads its napi
159+
# module (and, for `wasm-inline`, its wasm) on import, so a change to what
160+
# it ships arrives here rather than in `pnpm-workspace.yaml`. The paths of
161+
# require-auth-npm-changeset.yml.
162+
- 'packages/stack-auth/Cargo.toml'
163+
- 'packages/stack-auth/src/**'
164+
- 'languages/typescript/packages/auth/**'
165+
- 'languages/typescript/packages/stack-auth-wasm/**'
148166
# The Rust that produces every EQL payload these suites round-trip.
149167
# Absorbing protect-ffi put it in-tree, so a crate change can now
150168
# break them in a PR that touches no TypeScript at all.
@@ -276,6 +294,11 @@ jobs:
276294
with:
277295
wasm: 'true'
278296

297+
- name: Build the @cipherstash/auth binding
298+
uses: ./.github/actions/build-auth-binding
299+
with:
300+
wasm: 'true'
301+
279302
# No pre-`up` cleanup step any more: the project name is unique per job, so
280303
# a container leaked by a hard-killed prior run cannot hold this job's
281304
# name or its (ephemeral) port. Blanket-pruning would now be actively

‎.github/workflows/integration-prisma-next.yml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ on:
3434
- '.github/actions/integration-setup/**'
3535
- '.github/actions/integration-db/**'
3636
- '.github/actions/build-ffi-binding/**'
37+
- '.github/actions/build-auth-binding/**'
3738
# The Rust that produces every EQL payload these suites round-trip.
3839
# Absorbing protect-ffi put it in-tree, so a crate change can now
3940
# break them in a PR that touches no TypeScript at all.
@@ -81,6 +82,7 @@ on:
8182
- '.github/actions/integration-setup/**'
8283
- '.github/actions/integration-db/**'
8384
- '.github/actions/build-ffi-binding/**'
85+
- '.github/actions/build-auth-binding/**'
8486
# The Rust that produces every EQL payload these suites round-trip.
8587
# Absorbing protect-ffi put it in-tree, so a crate change can now
8688
# break them in a PR that touches no TypeScript at all.
@@ -166,6 +168,9 @@ jobs:
166168
- name: Build the protect-ffi binding
167169
uses: ./.github/actions/build-ffi-binding
168170

171+
- name: Build the @cipherstash/auth binding
172+
uses: ./.github/actions/build-auth-binding
173+
169174
# No pre-`up` cleanup step any more: the project name is unique per job, so
170175
# a container leaked by a hard-killed prior run cannot hold this job's
171176
# name or its (ephemeral) port. Blanket-pruning would now be actively

‎.github/workflows/integration-protect-ffi.yml‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ name: Integration — protect-ffi (native + WASM)
2323
# queried SQL installed from the PUBLISHED EQL bundle while the payloads under
2424
# test were emitted by the in-tree `eql-bindings`, so the two halves of EQL could
2525
# disagree — and would have disagreed in a database, not in CI. `@cipherstash/eql`
26-
# now resolves `workspace:^`, and `@cipherstash/auth` and `vitest` take
26+
# now resolves `workspace:^`, `@cipherstash/auth` `workspace:*`, and `vitest`
2727
# `catalog:repo`.
2828
#
2929
# Separate from `tests.yml` on purpose, and separate from `tests-rust.yml`: this
@@ -39,7 +39,7 @@ on:
3939
# and its manifest.
4040
- 'languages/typescript/packages/protect-ffi/integration-tests/**'
4141
# The suite's dependency versions, now that it is a pnpm workspace member:
42-
# `@cipherstash/auth`, `vitest` and `typescript` reach it through
42+
# `vitest` and `typescript` reach it through
4343
# `catalog:repo`, so a catalog bump changes what this job runs while
4444
# editing no file under the suite. Same entry, same reason, as the other
4545
# integration workflows — and like them, `pnpm-lock.yaml` is deliberately
@@ -89,6 +89,15 @@ on:
8989
- 'packages/eql/Cargo.toml'
9090
- '.github/workflows/integration-protect-ffi.yml'
9191
- '.github/actions/build-ffi-binding/**'
92+
- '.github/actions/build-auth-binding/**'
93+
# `@cipherstash/auth` is a workspace package, and the SDK loads its napi
94+
# module (and, for `wasm-inline`, its wasm) on import, so a change to what
95+
# it ships arrives here rather than in `pnpm-workspace.yaml`. The paths of
96+
# require-auth-npm-changeset.yml.
97+
- 'packages/stack-auth/Cargo.toml'
98+
- 'packages/stack-auth/src/**'
99+
- 'languages/typescript/packages/auth/**'
100+
- 'languages/typescript/packages/stack-auth-wasm/**'
92101
- '.github/actions/require-cs-secrets/**'
93102
pull_request:
94103
branches: ['**']
@@ -119,6 +128,15 @@ on:
119128
- 'packages/eql/Cargo.toml'
120129
- '.github/workflows/integration-protect-ffi.yml'
121130
- '.github/actions/build-ffi-binding/**'
131+
- '.github/actions/build-auth-binding/**'
132+
# `@cipherstash/auth` is a workspace package, and the SDK loads its napi
133+
# module (and, for `wasm-inline`, its wasm) on import, so a change to what
134+
# it ships arrives here rather than in `pnpm-workspace.yaml`. The paths of
135+
# require-auth-npm-changeset.yml.
136+
- 'packages/stack-auth/Cargo.toml'
137+
- 'packages/stack-auth/src/**'
138+
- 'languages/typescript/packages/auth/**'
139+
- 'languages/typescript/packages/stack-auth-wasm/**'
122140
- '.github/actions/require-cs-secrets/**'
123141
workflow_dispatch: {}
124142

@@ -292,6 +310,11 @@ jobs:
292310
with:
293311
wasm: 'true'
294312

313+
- name: Build the @cipherstash/auth binding
314+
uses: ./.github/actions/build-auth-binding
315+
with:
316+
wasm: 'true'
317+
295318
# `working_directory` is load-bearing, not tidiness. mise reads config
296319
# from the current directory and its PARENTS, so an action running at the
297320
# repo root never sees languages/typescript/packages/protect-ffi/mise.toml — it would install

‎.github/workflows/integration-supabase.yml‎

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,15 @@ on:
3434
# payload deserialization and it touches NO source directory, so without
3535
# these two entries the only suites that would catch it never start. They
3636
# are the files a bump actually edits: exact pins (`protect-ffi`,
37-
# `@cipherstash/eql`) live in the package manifest, `catalog:` ones
38-
# (`@cipherstash/auth`) in the workspace catalog.
37+
# `@cipherstash/eql`) live in the package manifest, `catalog:` ones in
38+
# the workspace catalog.
3939
#
4040
# `pnpm-lock.yaml` is deliberately NOT listed. It changes on roughly every
4141
# dependency bump in the monorepo — far more often than either file here —
4242
# and these are credentialed, database-backed jobs. Nothing is lost: a
43-
# protect-ffi or auth version change cannot reach the lockfile without
44-
# editing one of the two manifests below first.
43+
# protect-ffi version change cannot reach the lockfile without editing
44+
# one of the two manifests below first, and an auth one edits its own
45+
# manifest, under the auth paths below.
4546
- 'languages/typescript/packages/stack/package.json'
4647
- 'pnpm-workspace.yaml'
4748
- 'languages/typescript/packages/test-kit/**'
@@ -52,6 +53,15 @@ on:
5253
- '.github/actions/integration-setup/**'
5354
- '.github/actions/integration-db/**'
5455
- '.github/actions/build-ffi-binding/**'
56+
- '.github/actions/build-auth-binding/**'
57+
# `@cipherstash/auth` is a workspace package, and the SDK loads its napi
58+
# module (and, for `wasm-inline`, its wasm) on import, so a change to what
59+
# it ships arrives here rather than in `pnpm-workspace.yaml`. The paths of
60+
# require-auth-npm-changeset.yml.
61+
- 'packages/stack-auth/Cargo.toml'
62+
- 'packages/stack-auth/src/**'
63+
- 'languages/typescript/packages/auth/**'
64+
- 'languages/typescript/packages/stack-auth-wasm/**'
5565
# The Rust that produces every EQL payload these suites round-trip.
5666
# Absorbing protect-ffi put it in-tree, so a crate change can now
5767
# break them in a PR that touches no TypeScript at all.
@@ -104,14 +114,15 @@ on:
104114
# payload deserialization and it touches NO source directory, so without
105115
# these two entries the only suites that would catch it never start. They
106116
# are the files a bump actually edits: exact pins (`protect-ffi`,
107-
# `@cipherstash/eql`) live in the package manifest, `catalog:` ones
108-
# (`@cipherstash/auth`) in the workspace catalog.
117+
# `@cipherstash/eql`) live in the package manifest, `catalog:` ones in
118+
# the workspace catalog.
109119
#
110120
# `pnpm-lock.yaml` is deliberately NOT listed. It changes on roughly every
111121
# dependency bump in the monorepo — far more often than either file here —
112122
# and these are credentialed, database-backed jobs. Nothing is lost: a
113-
# protect-ffi or auth version change cannot reach the lockfile without
114-
# editing one of the two manifests below first.
123+
# protect-ffi version change cannot reach the lockfile without editing
124+
# one of the two manifests below first, and an auth one edits its own
125+
# manifest, under the auth paths below.
115126
- 'languages/typescript/packages/stack/package.json'
116127
- 'pnpm-workspace.yaml'
117128
- 'languages/typescript/packages/test-kit/**'
@@ -122,6 +133,15 @@ on:
122133
- '.github/actions/integration-setup/**'
123134
- '.github/actions/integration-db/**'
124135
- '.github/actions/build-ffi-binding/**'
136+
- '.github/actions/build-auth-binding/**'
137+
# `@cipherstash/auth` is a workspace package, and the SDK loads its napi
138+
# module (and, for `wasm-inline`, its wasm) on import, so a change to what
139+
# it ships arrives here rather than in `pnpm-workspace.yaml`. The paths of
140+
# require-auth-npm-changeset.yml.
141+
- 'packages/stack-auth/Cargo.toml'
142+
- 'packages/stack-auth/src/**'
143+
- 'languages/typescript/packages/auth/**'
144+
- 'languages/typescript/packages/stack-auth-wasm/**'
125145
# The Rust that produces every EQL payload these suites round-trip.
126146
# Absorbing protect-ffi put it in-tree, so a crate change can now
127147
# break them in a PR that touches no TypeScript at all.
@@ -227,6 +247,9 @@ jobs:
227247
- name: Build the protect-ffi binding
228248
uses: ./.github/actions/build-ffi-binding
229249

250+
- name: Build the @cipherstash/auth binding
251+
uses: ./.github/actions/build-auth-binding
252+
230253
# No pre-`up` cleanup step any more: the project name is unique per job, so
231254
# a container leaked by a hard-killed prior run cannot hold this job's
232255
# name or its (ephemeral) port. Blanket-pruning would now be actively

‎.github/workflows/prisma-example-readme-e2e.yml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ on:
2626
# report — a PR touching any of these runs the walkthrough before the
2727
# change lands, not after.
2828
- '.github/actions/build-ffi-binding/**'
29+
- '.github/actions/build-auth-binding/**'
2930
- 'languages/typescript/packages/protect-ffi/crates/**'
3031
- 'languages/typescript/packages/protect-ffi/src/**'
3132
- 'languages/typescript/packages/protect-ffi/Cargo.toml'
@@ -58,6 +59,7 @@ on:
5859
# scripts/__tests__/workflow-paths-filter-parity.test.mjs compares the
5960
# two copies.)
6061
- '.github/actions/build-ffi-binding/**'
62+
- '.github/actions/build-auth-binding/**'
6163
- 'languages/typescript/packages/protect-ffi/crates/**'
6264
- 'languages/typescript/packages/protect-ffi/src/**'
6365
- 'languages/typescript/packages/protect-ffi/Cargo.toml'
@@ -145,6 +147,9 @@ jobs:
145147
- name: Build the protect-ffi binding
146148
uses: ./.github/actions/build-ffi-binding
147149

150+
- name: Build the @cipherstash/auth binding
151+
uses: ./.github/actions/build-auth-binding
152+
148153
# Build via turbo so `^build` on `@cipherstash/stack-prisma` and
149154
# its `@cipherstash/stack` peer is honoured. The test's
150155
# `pnpm install` subprocess inside `languages/typescript/examples/prisma/` is a no-op

0 commit comments

Comments
 (0)