Skip to content

fix(fleet): publish without a two-link window on Linux and macOS - #6431

Merged
Hmbown merged 3 commits into
Hmbown:mainfrom
Lstarsky0:fix/fleet-publish-exclusive-rename
Sep 24, 2026
Merged

Hmbown merged 3 commits into
Hmbown:mainfrom
Lstarsky0:fix/fleet-publish-exclusive-rename

Conversation

@Lstarsky0

Copy link
Copy Markdown
Contributor

Summary

On Unix, WorkspaceFile::publish wrote a temporary, linkated it into place, then unlinked the temporary. Between those two calls the published file has two links, and open_file rejects any link count other than 1, so a reader racing the publication gets InvalidData ("Fleet file must be a regular, non-hard-linked file").

Two identical tool-image replays hit exactly that: the loser reads the winner's evidence back while it is still double-linked and gives up on the preview. That is the tool_media_publication_is_immutable_and_replay_preserves_manifest failure on macOS in this run (line 239: one of the two concurrent projections came back without tool_media). The previous attempt on the same commit passed.

Linux now publishes with renameat2(RENAME_NOREPLACE) and macOS with renameatx_np(RENAME_EXCL), the Unix side of the no-replace rename the Windows path already uses. Linux goes through the raw syscall so musl and OHOS don't depend on a libc wrapper. Any refusal other than an existing target falls back to the old linkat, so an old kernel, a filesystem that doesn't take the flag, or a seccomp filter is no worse off than today. The link-count check is unchanged.

No-Issue: flaky macOS test; the cause and a repro are above and in the new test.

Testing

  • New a_racing_reader_never_sees_a_publication_half_done spins a reader on open_file while each file is published. With the exclusive rename switched off it fails on round 0 in 10 of 10 runs here (macOS); with it, 0 of 20.
  • tool_media_publication_is_immutable_and_replay_preserves_manifest — 50 of 50 locally.
  • cargo fmt --all -- --check — clean
  • cargo clippy -p codewhale-tui --all-targets --all-features --locked with the CI allow list — clean
  • cargo nextest run -p codewhale-tui --all-features --profile ci — 13474 passed, 4 failed. The same 4 fail on untouched main here (a local HTTP proxy, and three doctor sealed-HOME tests that trip on this machine); all four passed on CI's macOS leg.

Linux isn't built locally; the Ubuntu leg and the OHOS check cover it.

Checklist

  • This PR adds a new layer/module/abstraction — n/a
  • Updated docs or comments as needed
  • Added or updated tests where relevant
  • Verified TUI behavior manually if UI changes — n/a
  • Harvested/co-authored credit uses a GitHub numeric noreply address

WorkspaceFile::publish linked the temporary into place and then unlinked
it. In between, the file has two links, and open_file rejects any link
count other than 1, so a reader racing the publication got InvalidData.
The loser of two identical tool-image replays reads the winner's
evidence back exactly then, which is how
tool_media_publication_is_immutable_and_replay_preserves_manifest failed
on macOS CI.

Linux now uses renameat2(RENAME_NOREPLACE) and macOS
renameatx_np(RENAME_EXCL), the Unix side of the no-replace rename the
Windows path already does. Any refusal other than an existing target
falls back to linkat, so no platform is worse off than before.

Signed-off-by: Lstarsky0 <59827030+Lstarsky0@users.noreply.github.com>
@Lstarsky0
Lstarsky0 requested a review from Hmbown as a code owner September 23, 2026 15:04
@github-actions github-actions Bot added the contribution-gate Author not yet in .github/APPROVED_CONTRIBUTORS; a maintainer grants access with /lgtm label Sep 23, 2026
@Hmbown
Hmbown merged commit 3b19044 into Hmbown:main Sep 24, 2026
40 of 41 checks passed
timothybrush pushed a commit to timothybrush/DeepSeek-TUI that referenced this pull request Sep 24, 2026
The RSS budget and offline eval ran inside Test for every trusted event,
assuming the warm self-hosted Mac. With CW_SELF_HOSTED_MAC off, a trusted
PR's macOS leg is a cold GitHub-hosted Mac, where Test alone took 77-80
minutes on 2026-09-23 (Hmbown#6431, Hmbown#6417) and the two extra steps would pass
the 90-minute limit. Route both steps by runner, not trust: inside Test
only on the self-hosted Mac, otherwise in the parallel macos-budget job.
Raise Test's timeout to 120 minutes for cold hosted Macs.

This makes the existing kill switch safe to use: the single self-hosted
runner had 14 queued runs and dropped jobs with "lost communication".

Verification: actionlint with CI's flags (-ignore SC2129/SC2221/SC2222)
clean. No tests run; workflow-only change, CI is the proof.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Hmbown pushed a commit to gaord/CodeWhale that referenced this pull request Sep 24, 2026
Version drift failed on Hmbown#6431, Hmbown#6443 and Hmbown#6456 with
`rm: cannot remove '/tmp/tmp.*/checkout': Directory not empty` right after
"require-release-tag-checkout tests passed": every assertion held, and only
the EXIT trap failed. The fixture commits and pushes, which can spawn a
detached `git maintenance run --auto` still writing into .git while the
trap deletes it. Disable auto maintenance/gc for every git process in the
fixture via GIT_CONFIG_COUNT, and retry the removal once.

Verification: the fixture passes locally; shellcheck clean. The race was
never reproduced locally, so the root cause is inferred from the log; CI
reruns are the proof.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution-gate Author not yet in .github/APPROVED_CONTRIBUTORS; a maintainer grants access with /lgtm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants