{{ message }}
Repository navigation
Keep the cli tests out of the home directory, and give the fence a release path - #183
Merged
Merged
Conversation
…lease path
Two cli tests built their deps by hand with a bare `env: {}`, so the real trust
gate ran and persisted first-run.json into the developer's own ~/.backthread on
every `npm test`. One of them also landed on the no-auth path with the real
ensureAuth still wired, which on any home without a token — CI — opened a login
session against the production app. Both now point the config dir at a temp
dir and stub the login. A new guard re-runs the cli suite under a fresh empty
home, fails if `.backthread/` appears there or the real one changes, and proves
on a probe that does write that it would have said so; it has its own CI job.
@backthread/redact sat at 0.1.6 in package.json while npm served 0.1.2: four
rounds of fence hardening shipped inlined in the CLI bundle, stamped on every
request as `x-backthread-redact-version`, with no tarball anyone could read.
The fence now has a release workflow on `redact-v*` tags (same OIDC shape as
the extractor), a changelog that ships in the tarball, and the CLI release
refuses to publish while the redact version it stamps is not on npm — a guard
that is self-tested against a stub registry in the same run.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PeY7VEztPfBPEWeXwkLhdP
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.

What
1. The cli test suite no longer writes into the home directory — and CI now checks that it doesn't.
Measured on
mainby running every test file under a fresh$HOME: two tests created~/.backthread/first-run.json—capture.test.ts("runCapture never throws even when a dep throws synchronously") andcaptureCommand.test.ts("end-to-end: manual capture drives the real runCapture with all seams mocked"). Both build their deps by hand with a bareenv: {}, so the real trust gate ran and persisted its flag into the developer's own state dir.backfill.test.tsandsweep.test.tswere already isolated (#178) and are clean.Worse, the
capture.test.tscase lands on the no-auth path with the realensureAuthstill wired: on any home without a token — CI, every run — it opened a login session against the production app and tried to launch a browser (the run printed a livecli-auth?session=…URL). On a developer machine the existing token short-circuited it, which is why nobody saw it.Both tests now point
BACKTHREAD_CONFIG_DIRat a temp dir and the first also stubsensureAuthImpl.scripts/check-home-isolation.mjsre-runs the cli suite under a fresh empty home withBACKTHREAD_CONFIG_DIRcleared, then fails if.backthread/appeared under it or the real~/.backthreadchanged (entries, sizes, mtimes).--self-testruns a probe that does write~/.backthread/probe.jsonthrough the same harness and requires the check to report it, and a probe that writes nothing and requires a pass. Its own CI job (home-isolation) — the test-matrix guard rightly refuses anif:step insidetest.Mutation-proven locally: reverting either test fix turns the guard red naming
.backthread/first-run.json; with both fixes it is green and the self-test passes.2.
@backthread/redactgets a release path, and the CLI release refuses to ship a fence npm doesn't serve.packages/redact/package.jsonsays0.1.6; npm serves0.1.2(npm view @backthread/redact versions). The CLI bundle inlines the local version and stamps it on every request asx-backthread-redact-version— so the published CLI has been telling every server "the fence that redacted this was redact@0.1.6", naming four rounds of hardening (#174, #175, #178, #179, #180) that nobody outside this repo can read. The package is public precisely so that claim is auditable..github/workflows/release-redact.yml— on aredact-v*tag, same OIDC trusted-publishing shape as the extractor. Needs a one-time Trusted Publisher on npm (documented inRELEASING.md).packages/redact/CHANGELOG.md— 0.1.0 → 0.1.6 reconstructed from the PR history; ships in the tarball (files).scripts/check-published-version.mjs <workspace>— asks npm for the served versions and fails closed when the local version is not among them (or npm cannot answer). Wired intorelease.ymlbeforenpm publish, with a--self-testthat re-runs the guard against a stubnpmonPATH: a list without the version must be red, a list with it must be green, an unparseable answer must be red.0.1.6vs0.1.2— the real defect, which is the point.Why
.backthread/.doctor.test.tsandnpm.test.tsspawn the realnpmbinary, which writes~/.npmunder whatever home it is given; that is a network seam, reported as a note, not a fail — so a red here always means the cli itself wrote state.~/.backthreadmid-run; it is load-bearing in CI, where no such directory exists.Other unisolated seams found (enumerated, not fixed)
doctor.test.ts— two tests reach the realrunNpm(['view','backthread','version'])(registry network call +~/.npmcache/log writes).npm.test.ts— spawns the realnpmwith a bogus subcommand (no network, but~/.npm/_logsis written).capture.test.ts(fixed here, but the shape recurs): any hand-builtCaptureDepsthat omitsensureAuthImplreaches the real login on a token-less home. Onlydeps()-built cases are safe by construction.~/.backthread/config.jsonwheneverenvlacksBACKTHREAD_CONFIG_DIRandreadConfigImplis not injected — which is what masked the login on a developer machine.Gate
npm run typecheckclean;npm test— backthread 954 / extractor 2201 / ci 363 passing, floors held; committed bundle in sync;check-no-internal-refs,check-test-matrix,check-provenanceall OK;check-home-isolation+ self-test OK;check-published-version --self-testOK.🤖 Generated with Claude Code
https://claude.ai/code/session_01PeY7VEztPfBPEWeXwkLhdP