Documentation
¶
Overview ¶
Command fsguard mechanically enforces the leverage-cross-platform-fs-helpers lesson: filesystem MUTATIONS in this module must route through internal/fsops (MkdirAll / Mkdir / WriteFile / Remove / RemoveAll / Rename), which carry the Windows PowerShell fallbacks and security hardening that raw os.* calls do not. A raw os.* fs-mutator outside internal/fsops is exactly the class of bug that produced #148: agentslock acquired its sidecar lock with os.Mkdir against a not-yet-created parent, which fails on Windows with ERROR_FILE_NOT_FOUND. The compiler cannot catch that; this AST lint does.
Scope: only the six WRITE primitives are policed — os.Mkdir, os.MkdirAll, os.Remove, os.RemoveAll, os.Rename, os.WriteFile. Reads (os.Open, os.ReadFile, os.Stat) are already portable and are not flagged.
Ratchet model: the module has pre-existing raw-mutator call sites that predate this guard. Migrating all of them at once is out of scope, so each is grandfathered through the allowlist (allowlist.go) with a documented reason. What the guard buys immediately is a one-way ratchet: a NEW raw os.* mutator in a package that is not already grandfathered fails CI, forcing the author to either route through fsops or add a deliberate, reasoned allowlist entry. As packages migrate to fsops, their grandfather entries are deleted, tightening the gate.
Usage: fsguard [packages...] Defaults to "./..." when no package patterns are supplied. Exits non-zero (and prints every offending call site) the moment a non-allowlisted raw mutator is found, which is what the CI job in .github/workflows/test.yml keys off.