Skip to content

fix(secrets): stop the test suite writing into the real vault on Windows - #6

Merged
dirtysouthalpha merged 1 commit into
mainfrom
fix/keyring-env-fallback
Aug 5, 2026
Merged

dirtysouthalpha merged 1 commit into
mainfrom
fix/keyring-env-fallback

Conversation

@dirtysouthalpha

Copy link
Copy Markdown
Owner

The bug

The secrets tests sandboxed themselves by setting HOME. homedir() reads USERPROFILE on Windows and ignores HOME, so on this platform the isolation silently failed and the suite operated on the user's actual ~/.config/sentinel.

Measured 2026-08-05 on Windows: a plain npm test created secrets.dpapi.json in the live vault.

This repo treats Windows/PowerShell as a first-class target, so a test-isolation mechanism that only works on POSIX is a real defect, not a cosmetic one.

The fix

Both file-backed backends (file-backend.ts, windows-backend.ts) now honour SENTINEL_CONFIG_DIR.

Deliberately not keyed off HOME. Git Bash sets HOME on Windows, often as /c/Users/..., which join() resolves against the current drive — that would quietly relocate a real user's vault to C:\c\Users\.... An explicit variable cannot be tripped by accident.

tests/secrets-real-keyring.test.ts was the actual leak. It does a deliberately unmocked round-trip through whichever backend the platform picks, and its comment assumed Linux + Secret Service; on Windows it picks DPAPI, whose store is a sidecar file. It is now sandboxed too — only the sidecar's location moves, DPAPI still encrypts and decrypts through PowerShell, so the test still proves exactly what it claims to. The sandbox is applied in beforeEach with vi.resetModules(), because the backends read the path at module load.

Verification

Not a mock assertion — the real filesystem state, before and after:

content before removal: {}
removed. exists? NO
Test Files  106 passed (106)
     Tests  844 passed | 11 skipped (855)
did the suite recreate the real vault? NO - sandbox holds

Two POSIX-only tests now skipped on win32

Rather than asserting a shape Windows cannot produce:

  • chmodSync(dir, 0o500) does not make a directory read-only on Windows — POSIX mode bits are ignored, so the write succeeds and nothing throws. Provoking it there needs an ACL denial via icacls, far heavier than the behaviour under test warrants.
  • buildBwrapArgs is a Linux sandbox argv builder, never invoked on Windows, and its path round-trip cannot hold where resolve("/home/u/proj") yields C:\home\u\proj.

In both cases the guarantee itself (a failed write leaves the original intact; the argv builder binds the project root) is platform-independent — only these ways of provoking it are POSIX-specific.

Also

Regenerates package-lock.json, which was stale at 1.1.0 against a 3.3.0 package.json.

Unrelated thing worth a look

package.json lists puppeteer in both optionalDependencies and devDependencies. Left alone here since it changes packaging behaviour and is outside this change's scope.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XAEEDpd383FpE3maq5Y8Bv

The secrets tests sandboxed themselves by setting HOME. `homedir()` reads
USERPROFILE on Windows and ignores HOME, so on this platform the isolation
silently failed and the suite operated on the user's actual
~/.config/sentinel. Measured 2026-08-05: a plain `npm test` created
secrets.dpapi.json in the live vault.

Both file-backed backends now honour SENTINEL_CONFIG_DIR. Deliberately not
keyed off HOME: Git Bash sets HOME on Windows, often as /c/Users/..., which
join() resolves against the current drive and would quietly relocate a real
user's vault to C:\c\Users\... An explicit variable cannot be tripped by
accident.

tests/secrets-real-keyring.test.ts was the actual leak. It does a
deliberately unmocked round-trip through whichever backend the platform
picks, and its comment assumed Linux + Secret Service; on Windows it picks
DPAPI, whose sidecar is a file. It is now sandboxed too. Only the sidecar's
location moves — DPAPI still encrypts and decrypts through PowerShell — so
the test still proves what it claims. The sandbox is applied in beforeEach
with vi.resetModules(), because the backends read the path at module load.

Verified by removing the stray real-vault file and re-running: 844 passing,
106 files, and the real vault is not recreated.

Two POSIX-only tests are now skipped on win32 rather than asserting a shape
that platform cannot produce: chmodSync(dir, 0o500) does not make a
directory read-only on Windows (POSIX mode bits are ignored, so the write
succeeds and nothing throws), and buildBwrapArgs is a Linux sandbox builder
whose path round-trip cannot hold where resolve("/home/u/proj") yields
"C:\home\u\proj". Both guarantees are platform-independent; only these ways
of provoking them are POSIX-specific.

Also regenerates package-lock.json, which was stale at 1.1.0 against a
3.3.0 package.json.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAEEDpd383FpE3maq5Y8Bv
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@dirtysouthalpha
dirtysouthalpha merged commit 271e86f into main Aug 5, 2026
1 check passed
@dirtysouthalpha
dirtysouthalpha deleted the fix/keyring-env-fallback branch August 5, 2026 20:35
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