Repository navigation
fix(server): a racing secret creator never reads a half-written secret - #261
Conversation
Independent review (Sol, gpt-6.1-sol) of 6d4e7c7What: no blocking findings at exact head Findings
Verified mechanism and callers
Independent proofCandidate worktree HEAD and live PR head both matched the exact SHA above; base was
Reviewer: Sol, gpt-6.1-sol through the Codex harness. |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
|
Independent review (Grok, grok-4.7) of 6d4e7c7 Verdict: no blocking findings, and no non-blocking findings. During the review the PR head moved to DiagnosisThe flake is a real race. On the parent of A local Create
Cleanup covers the paths that leave a temp name: Windows was not executed. Node CallersEach production caller still treats
Test and scope
|
create opened the secret file exclusively and then wrote it, so a creator that lost the race could read the winner's file while it was still empty and return empty bytes (#249). create now writes the complete secret to a temporary file and hard-links it into place; the link fails with AlreadyExists when another creator won. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ServerSecretStore.ts and its test are upstream files, so the carried edit needs an allowlist entry and an owner in the feature map (Fork Stack Model check). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
045489a to
5dd590e
Compare
|
Independent review round 2 (Sol, gpt-6.1-sol) of 5dd590e What: independent review passes at exact head Findings
Exact-head and rebase verificationLive PR and clean author worktree both matched the exact head above before and after proof; base is
Independent proof on this candidateFrom
No repository edits, checkout, config/remote changes, server startup, browser use, live T3 data access, or repo-wide checks. Round 1's baseline-failure proof and the author's repeat-loop/broader-suite reports were not rerun in this round. Windows was not executed. This verdict is an independent code review with focused proof, not a claim that the full CI merge gate passed. Reviewer: Sol, gpt-6.1-sol through the Codex harness. |
|
Independent review round 2 (Grok, grok-4.7) of 5dd590e Verdict: no blocking findings at exact head Rebase and carryThe code change matches round 1. The new ProofWorktree
FindingsNone. Round 1's non-blocking notes still apply. The code diff is unchanged, so they are not new defects and they do not block.
|
#261) * fix(server): a racing secret creator never reads a half-written secret create opened the secret file exclusively and then wrote it, so a creator that lost the race could read the winner's file while it was still empty and return empty bytes (#249). create now writes the complete secret to a temporary file and hard-links it into place; the link fails with AlreadyExists when another creator won. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(fork): carry the atomic secret create ServerSecretStore.ts and its test are upstream files, so the carried edit needs an allowlist entry and an owner in the feature map (Fork Stack Model check). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
What: a server secret being created is never visible until its bytes are complete, so concurrent creators always agree on the stored secret.
Why:
createopened the final secret file withwxand then wrote it; a creator that lost the race read the winner's still-empty file and returned 0 bytes. The flaky test was catching a real race.So what: after merge the race test is deterministic and the store no longer hands out empty secrets; nothing else is needed.
Closes #249
Elon record
create.lengths [ 0, 32 ]); the new test fails on the baseline and passes with the fix.Fix
createnow writes the complete value to<name>.bin.<uuid>.tmp(wx, mode 0600, fsync, chmod), thenlinks it to<name>.bin. The hard link is atomic and fails withEEXIST(mapped toAlreadyExists) when another creator won, so every existing caller (getOrCreateRandom,persistEnvironmentKeyPair,CloudLink,SecretRequests) keeps its contract. The temporary file is always removed.The changed upstream files are carried edits: listed in
scripts/fork-upstream-edits.txtand owned by thesecret-store-atomic-createentry indocs/fork-features.md(scripts/fork-check.sh: OK).Proof
writeAllinsidecreate, reads the secret mid-write, and asserts it is absent. Baseline:AssertionError: expected false to be true. With the fix: passes.vp test run src/auth/ServerSecretStore.test.ts50 times in a loop: 50 passed, 0 failed.vp test run src/auth src/cloud src/secrets: 30 files, 321 tests passed.tsc --noEmitinapps/server: no diagnostics in changed files;vp lintandvp fmt --checkclean.Not checked: Windows.
fs.linkcreates NTFS hard links, but this PR ran on Linux only.Upstream:
pingdotgg/t3codemain has the samecreate; no Issue or PR there covers this race.Model and harness: Claude Opus 5.5 in Claude Code.
🤖 Generated with Claude Code