fix: atomically swap cached native binary#591
Conversation
|
Hey @mturac — I checked out this branch and ran the empirical side of the contract you're adding. Sharing the result because it's directly relevant to one missing piece. Verified
Then I built a small filesystem-level repro to check the race itself. macOS
So the atomicity guarantee is real — readers only see one of the two stable inodes, never an in-flight one. On macOS the same fs window is what leaves the codesign signature invalid during What's missingThe PR doesn't ship a test that fails when the patch is reverted. Both A cheap deterministic addition would be a codesign-failure rollback test, which exercises the two things this PR uniquely guarantees: test("cache hit: codesign failure rolls back and cleans up staging file", async () => {
// loadEnsureNativeCompat with a codesignBinary stub that throws
const ensureNativeCompat = await loadEnsureNativeCompat({ codesignThrows: true });
createFakeBinary(abiCachePath(), "new-cached-content");
createFakeBinary(binaryPath, "old-active-content");
expect(() => ensureNativeCompat(tempDir)).toThrow();
// (1) active binary unchanged — never observable in inconsistent state
expect(readFileSync(binaryPath, "utf-8")).toBe("old-active-content");
// (2) staging tempfile cleaned up on the error path
expect(readdirSync(releaseDir).filter(f => f.includes(".staging-"))).toHaveLength(0);
});The existing Otherwise the conservative scope here is exactly right (atomic rename only, no (Minor: the |
|
@mturac resolve conflicts and comments please |
# Conflicts: # stats.json
Summary
Fixes #587
Tests
git diff --checkpnpm exec vitest run tests/core/cli.test.ts -t "ABI-aware native binary caching|cache hit"pnpm exec tsc --noEmit