fix(bin): skip the PR-poll mode assertion only where the filesystem cannot express modes - #2919
fix(bin): skip the PR-poll mode assertion only where the filesystem cannot express modes#29193min-lang wants to merge 3 commits into
Conversation
…annot express modes Git Bash mounts NTFS with `noacl`, so chmod is a silent no-op there and the mode is decided solely by the umask at creation time. `fm_pr_private_file_valid` asserts mode 600, which can therefore never hold, so `fm-pr-check.sh` always failed with `error: could not prepare PR poll`. No merge poll was ever armed on Windows: finished ship tasks went stale instead of being tracked to landing, and teardown never ran. Probe the actual directory instead of inferring capability from `uname` or mount flags, because one host can hold both mode-capable and mode-incapable filesystems. The probe checks both directions (600 then 644): callers run under `umask 077`, where a fresh mktemp file already reads 600, so a single chmod check cannot tell a working chmod from a no-op. A probe that cannot complete reports capable, so an unexplained failure keeps the strict assertion rather than silently relaxing it. The remaining three guarantees - regular file, same device, single hard link - are untouched, and they carry the substantive protection on filesystems that cannot express modes.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Reviews (2): Last reviewed commit: "style(bin): declare the probe locals wit..." | Re-trigger Greptile |
Review caught that only the mktemp failure path kept the strict assertion. Once the probe file existed, a failed chmod or an unreadable mode produced an observation that was not exactly 600/644, which the previous code classified as mode-incapable and cached, so later private files in that directory skipped mode validation. The comment claimed a fail-closed property the code did not have. Classify only complete, unambiguous observations. Capable means both requested modes were read back. Incapable means the same mode was read back twice, which is chmod demonstrably doing nothing. Every other outcome reports capable, keeps the strict assertion, and is deliberately not cached so a transient failure cannot be remembered as evidence.
|
Thanks - the security finding is correct and now fixed in You were right that the fail-closed guarantee only covered the The probe now classifies only complete, unambiguous observations:
Verified on the affected host: the noacl mount still classifies as incapable both under the default umask and under On regression coverage: I would rather add the test in your preferred shape than guess. Simulating a mode-incapable filesystem portably is the hard part. If a test that stubs 🤖 Generated with Claude Code |
Problem
Git for Windows mounts NTFS with
noacl, wherechmodis a silent no-op andthe mode is decided solely by the umask at creation time.
fm_pr_private_file_validasserts mode
600, so on that platform the assertion can never hold andfm-pr-check.shalways exits witherror: could not prepare PR poll.The consequence is not cosmetic: no merge poll is ever armed on Windows.
Finished ship tasks go stale instead of being tracked to landing, the merged-PR
wake never fires, and teardown never runs.
Fix
Probe the actual directory rather than inferring capability from
unameormount flags, since one host can hold both mode-capable and mode-incapable
filesystems.
The probe checks both directions (
600then644). A singlechmodcheck isnot sufficient:
fm_pr_poll_prepareruns underumask 077, so a freshmktempfile already reads600and a one-way check cannot distinguish aworking
chmodfrom a no-op. This was found by running the real path, not inreview.
A probe that cannot complete reports capable, so an unexplained failure keeps
the strict assertion rather than silently relaxing it. The other three
guarantees in
fm_pr_private_file_valid(regular file and not a symlink, samedevice, single hard link) are untouched, and they carry the substantive
protection where modes cannot be expressed.
This is not the only mode assertion affected
fm_backend_herdr_presentation_lock_namespace_validrequires mode700on/tmp/firstmate-herdr-presentation. Git Bash mounts/tmpwithnoacltoo, somkdir -m 700is a no-op there and the directory reads755, which is whyherdr presentation focus lock unavailableis reported on every spawn on thishost. That one is out of scope here, but it suggests the pattern is worth a
shared helper if you would prefer that shape.
Testing
bin/fm-lint.sh bin/fm-pr-lib.shclean.fm-pr-check.shnow arms the poll, the pollreported
mergedfor a real PR, and the artifacts retired.does not match is still rejected, and a matching one is still accepted, so
behaviour on mode-capable filesystems is unchanged.
tests/fm-pr-check-security.test.shfails on this host withnot ok - parser accepted a rejected raw-byte URL class. That failurereproduces identically on unpatched
mainhere, so it is pre-existing andunrelated to this change, not introduced by it.
I did not add a test, because simulating a mode-incapable filesystem portably
is not obvious and a misleading test seemed worse than none. Happy to add one
in whatever shape you prefer.
🤖 Generated with Claude Code