Skip to content

Commit 8b2551a

Browse files
authored
fix(deps): move @cipherstash/auth to 0.42.0, lockstep with its bindings (#679)
The rc.2 skilltester run found every project-local npm install of the CLI/SDK dying at startup with "Failed to load native binding" (B1, reproduced 5/5 surfaces). Root cause: Dependabot bumped the six @cipherstash/auth-* catalog entries to 0.42.0 while @cipherstash/auth — individually ignored in dependabot.yml — stayed 0.41.0. auth pins its bindings as exact-version optional peerDependencies, so the skew makes npm nest per-consumer binding copies that the hoisted auth package cannot resolve. Reproduced against the published rc.2 and verified fixed with aligned versions (npm dedupes to one hoisted binding; auth loads): npm i @cipherstash/stack@1.0.0-rc.2 @cipherstash/stack-supabase@1.0.0-rc.2 npm i -D stash@1.0.0-rc.2 node -e "require('@cipherstash/auth')" # fatal before, loads after Three changes so it can't recur: - catalog: all seven @cipherstash/auth* entries at 0.42.0, with the lockstep invariant documented as load-bearing - dependabot: ignore @cipherstash/auth-* alongside @cipherstash/auth — partial bumps of this set are never safe - supply-chain e2e: a test that fails on any version skew across the seven entries (verified red against the exact rc.2 skew) auth 0.42.0 compatibility verified: stack 828/828 (incl. live ZeroKMS auth), cli 513/513, wizard 145/145. Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
1 parent 3a86939 commit 8b2551a

5 files changed

Lines changed: 91 additions & 20 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@cipherstash/stack': patch
3+
'stash': patch
4+
'@cipherstash/wizard': patch
5+
---
6+
7+
Fix "Failed to load native binding" on project-local installs of the CLI/SDK
8+
(npm). `@cipherstash/auth` was pinned at 0.41.0 while the six
9+
`@cipherstash/auth-*` platform bindings declared in stack/stash/wizard's
10+
optionalDependencies were pinned at 0.42.0. Because auth pins its bindings as
11+
exact-version optional peer dependencies, the skew made npm nest per-consumer
12+
binding copies that the hoisted `auth` package could not resolve — any command
13+
or import touching auth then died at startup. All seven packages now move in
14+
lockstep at 0.42.0, Dependabot is barred from bumping any of them
15+
independently, and a supply-chain CI test fails on any future skew.

.github/dependabot.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ updates:
3737
ignore:
3838
# Catalog-managed; bump manually via pnpm-workspace.yaml + changeset.
3939
- dependency-name: "@cipherstash/auth"
40+
# The platform bindings MUST move in lockstep with @cipherstash/auth:
41+
# auth pins them as exact-version optional peer deps, so a skewed set
42+
# makes npm nest per-consumer binding copies the hoisted auth package
43+
# cannot resolve, and every project-local install of the CLI/SDK dies
44+
# with "Failed to load native binding". Dependabot once bumped these
45+
# six to 0.42.0 while the ignored auth stayed 0.41.0 (the rc.2 B1
46+
# bug). Bump all seven catalog entries together, manually. Lockstep is
47+
# enforced by e2e/tests/supply-chain.e2e.test.ts.
48+
- dependency-name: "@cipherstash/auth-*"
4049
# Release-managed manually alongside stack releases. Grouped bumps are
4150
# actively harmful here: Dependabot's "group consistency" once upgraded
4251
# the sunsetting packages/protect off its 0.23.0 pin (0.24+ renames the

e2e/tests/supply-chain.e2e.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,39 @@ describe('supply chain — pnpm configuration', () => {
8787
}
8888
})
8989

90+
it('@cipherstash/auth and its six platform bindings are catalog-pinned in lockstep', () => {
91+
// Not tidiness — a load-bearing invariant. @cipherstash/auth pins its
92+
// bindings as EXACT-version optional peerDependencies, while stash /
93+
// stack / wizard declare the bindings in their own optionalDependencies
94+
// (pnpm doesn't auto-install optional peer deps). If the seven catalog
95+
// entries skew, npm nests per-consumer binding copies that the hoisted
96+
// auth package cannot resolve, and every project-local install of the
97+
// CLI/SDK dies at startup with "Failed to load native binding". That is
98+
// exactly what happened in 1.0.0-rc.2: Dependabot bumped the six
99+
// bindings to 0.42.0 while the ignored @cipherstash/auth stayed 0.41.0.
100+
// Dependabot now ignores all seven names; this test catches every other
101+
// way the set can drift.
102+
const ws = readYaml('pnpm-workspace.yaml') as {
103+
catalogs?: Record<string, Record<string, string>>
104+
}
105+
const repo = ws.catalogs?.repo ?? {}
106+
const authEntries = Object.entries(repo).filter(
107+
([name]) =>
108+
name === '@cipherstash/auth' || name.startsWith('@cipherstash/auth-'),
109+
)
110+
// The wrapper + the six platform bindings. A count change means a
111+
// binding was added/removed upstream — update the consumers' package
112+
// JSONs and this expectation together.
113+
expect(authEntries.length).toBe(7)
114+
const versions = new Set(authEntries.map(([, v]) => v))
115+
expect(
116+
versions.size,
117+
`@cipherstash/auth* catalog entries have skewed versions: ${authEntries
118+
.map(([n, v]) => `${n}@${v}`)
119+
.join(', ')}`,
120+
).toBe(1)
121+
})
122+
90123
it('security overrides stay range-scoped and remain a small allowlist (≤12 entries)', () => {
91124
// Every override must be scoped to the advisory's vulnerable range
92125
// (`pkg@<range>`), never a blanket `pkg` pin — a blanket pin silently

pnpm-lock.yaml

Lines changed: 23 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,17 @@ catalogs:
77
repo:
88
# @cipherstash/auth ships per-platform native bindings as optional
99
# peerDependencies. pnpm does not auto-install platform-matched
10-
# optional peer deps, so the consuming packages (wizard, cli)
11-
# declare them as `optionalDependencies` via `catalog:repo`. Keep
12-
# all seven entries on the same version so a single bump here moves
13-
# everything in lockstep.
14-
'@cipherstash/auth': 0.41.0
10+
# optional peer deps, so the consuming packages (stack, cli, wizard)
11+
# declare them as `optionalDependencies` via `catalog:repo`.
12+
#
13+
# LOCKSTEP IS LOAD-BEARING, not tidiness: auth pins its bindings as
14+
# EXACT-version optional peer deps, so a skewed set makes npm nest
15+
# per-consumer binding copies that the hoisted auth package cannot
16+
# resolve — every project-local install of the CLI/SDK then dies with
17+
# "Failed to load native binding" (the 1.0.0-rc.2 B1 bug). Enforced by
18+
# e2e/tests/supply-chain.e2e.test.ts; Dependabot ignores all seven
19+
# names — bump them together, manually.
20+
'@cipherstash/auth': 0.42.0
1521
'@cipherstash/auth-darwin-arm64': 0.42.0
1622
'@cipherstash/auth-darwin-x64': 0.42.0
1723
'@cipherstash/auth-linux-arm64-gnu': 0.42.0

0 commit comments

Comments
 (0)