Skip to content

test(server): isolate the keychain in the connections-route suite - #91

Merged
jack-champagne merged 1 commit into
local/amicodefrom
jack/test-keychain-isolation
Jul 28, 2026
Merged

jack-champagne merged 1 commit into
local/amicodefrom
jack/test-keychain-isolation

Conversation

@jack-champagne

Copy link
Copy Markdown
Member

Makes unit (linux) interpretable again. It has been dying with exit code 137 and reporting nothing.

Not an OOM

Turbo labels any signal-killed child "likely due to running out of memory." That label is boilerplate and it is wrong here. Bun's own report:

Elapsed: 1498ms | RSS: 0.15GB | Peak: 0.37GB | Faults: 0 | Machine: 32.38GB
panic(main thread): Segmentation fault at address 0x0

0.37 GB peak on a 32 GB machine, zero faults, dead in 1.5 s. A larger runner would not have helped (and is unavailable — the org is plan=free; GET /orgs/harmoniqs/actions/hosted-runners returns 404).

What it actually was

One test — amicode-connections-routes.test.ts:335, "full lifecycle: submit(valid) → …" — segfaults at connections.ts:1005:

pasqalSecretStore().write(PASQAL_SECRET_ACCOUNT, { username, password })

which reaches @napi-rs/keyring's native Entry.setPassword(). Traced with instrumentation: [T3] before keychain prints, [T4] after keychain write never does.

That write sits only on the valid && token !== null branch, which explains the pass/fail pattern exactly:

test branch keychain write result
full lifecycle (valid + token) valid + token yes crash
null token → session-only valid, null token no pass
failure classes (exit 2/4/1) config / invalid no pass

Bisected to 467fb15cf ("two-step Pasqal auth", #194), which introduced that write per the ADR 0001 addendum. The test passed at 3e4b37298, the commit immediately before.

Production is not affected

Verified end-to-end, not assumed. Real Pasqal login, real pasqal_validate.py, real pasqal-cloud SDK, real keychain, against bun run … serve:

POST /amicode/connections/credential
  ok=True  state=connected  devices=[{'name':'FRESNEL'},{'name':'FRESNEL_CAN1'}]
server: ALIVE

And it demonstrably reached the crash site — the keychain slot was written and the token persisted (token_len: 1278).

context keychain write runs result
bun test + Effect route yes segfault
bun run … serve + Effect route yes survives
bun test, keyring alone yes survives
bun run, keyring alone yes survives

Only the first combination crashes. It is a Bun-test-runner/NAPI interaction, not a product fault, and 467fb15cf is not shipping a crash to users.

The fix

Install the in-memory secret store in beforeEach — exactly what the sibling amicode-connections.test.ts already does, which is why that file passes:

restoreSecretStore = setPasqalSecretStore(inMemorySecretStore())

Also adds AMICO_PASQAL_KEYCHAIN_SERVICE to ENV_KEYS. pasqal-secret.ts documents it as existing so "an isolated sandbox / test run gets its own slot and never shares the real connection's secret"; it was unused here. Belt and braces, so a leak cannot reach the real slot even if the seam is ever removed.

Worth noting independently of the crash: this suite was driving the developer's real OS keyring.

Stub validator: bun → python3

stageStubValidator() set AMICO_PYTHON = process.execPath, i.e. bun standing in as the Python interpreter. In production amicode provisions <opsDir>/venvs/pasqal-connector and passes it as AMICO_PYTHON (harmoniqs/amicode#189, the bundled-Julia pattern), so the interpreter is always a real python. The old stub tested a configuration that never ships.

Now a python3-executed .py with the same record/scenario contract, plus actions/setup-python in the unit job. The stub needs an interpreter, not the SDK — integration against the real pasqal-cloud SDK stays where it belongs, in amicode's assert_provisioned_python.mjs gate.

The env assertion now filters interpreter-owned locale vars, because CPython injects LC_CTYPE into its own environ under PEP 538 C-locale coercion. It still asserts the real thing: that the spawner declared nothing beyond PASQAL_USERNAME/PASSWORD/PROJECT_ID + PATH.

Windows unit lane dropped

opencode.lock.json ships darwin-arm64 and linux-x64 only, so a windows unit lane gates a platform this fork does not distribute — and at ~50 min it is the long pole on every run. It was also red on arrival for a reason unrelated to anything under test: POSIX path separators hardcoded in amicode-vaults.test.ts (#76). e2e still runs both platforms.

Verification

amicode-connections-routes.test.ts     13 pass / 0 fail      (was: segfault)
test/server/  (63 files)              554 pass / 2 skip / 0 fail
bun turbo typecheck                    23 successful, 23 total

Before this, the full packages/opencode suite could not complete at all. It now runs 3234 tests to completion, leaving a readable list: the stale LLM fixtures (#80) and a umask-dependent permissions assertion in tool.write (0o644 vs 0o664 — passes on CI's umask 0022, fails on a developer umask 0002).

Refs #82, #76

The unit job died with exit 137 and reported nothing. Not an OOM (peak
0.37GB of 32GB, zero faults) — a segfault inside @napi-rs/keyring's
native setPassword(), reached from the pasqal submit success path.

Install the in-memory secret store, as the sibling
amicode-connections.test.ts already does. Production is unaffected: the
same write succeeds under `bun run … serve`, verified end-to-end against
Pasqal with real credentials.

Also swap the stub validator from a bun-executed .mjs to a
python3-executed .py. amicode provisions <opsDir>/venvs/pasqal-connector
and passes it as AMICO_PYTHON (harmoniqs/amicode#189), so the production
interpreter is always a real python; bun-as-interpreter tested a
configuration that never ships.

Drop the windows unit lane: opencode.lock.json ships darwin-arm64 and
linux-x64 only, and it was the ~50min long pole while red for an
unrelated reason (#76).

Refs #82, #76
@jack-champagne
jack-champagne force-pushed the jack/test-keychain-isolation branch from 4875a0c to 1e83e32 Compare July 28, 2026 22:06
@jack-champagne
jack-champagne merged commit 6f21665 into local/amicode Jul 28, 2026
1 of 4 checks passed
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.

1 participant