Repository navigation
docs: rule that filesystem access is received, never constructed - #409
Merged
Merged
Conversation
Phase 3's first call site exposed a wrong pattern and drew a ruling that inserts a phase ahead of the migration. Migrating pkg/signing by having it open its own root looked reasonable and was not: the root is set by whoever starts a starlark or graph execution, carried on the RuntimeEnvironment, and reached downstream through the activation record -- ActivationRecord.RuntimeEnvironment is documented as "always set during dispatch", and every provider already reads p.RuntimeEnvironment().Root. A provider constructing its own root bypasses the session that owns it. The signing change is reverted rather than left as precedent for 29 more sites; its generateLocalKey now carries a TODO(#405) stating plainly that the private key's 0600 is NOT enforced on Windows and why. Phase 2b, inserted before the migration: Scratch joins root on the session, communicated the same way. Scratch has the sharper hazard -- an unclosed root leaks a handle, an unclosed scratch leaks a TREE that Windows cannot remove while a handle inside it is open -- so concentrating ownership where the teardown is already proven matters more, not less. Both allocate lazily, so a planning-only session holds no confined-root handle at all, shrinking the exact surface #393 was about. Root keeps eager preflight validation: purely lazy allocation would move a bad anchor from "refused before dispatch" to "died halfway through a run", undoing the ReasonPreflightFailed terminal phase 2 just built. Root becomes an accessor that asserts on a post-validation mint failure, consistent with the repository's checksum trust boundary, keeping ~40 provider call sites as one-liners. Scratch anchors at the OS temp directory with no spec field. os.MkdirTemp("") resolves through os.TempDir(), which already honors TMPDIR on Unix and TMP/TEMP on Windows, so every configuration reason to relocate scratch is already served and a spec field would reinvent an environment variable. The one non-configuration case is cross-device staging -- a stage-then-rename is atomic only on one filesystem, and TMPDIR cannot know the target's device -- which is per-operation and belongs inside the target root. CLI root ownership ruled: internal/cli owns purpose-named roots (state, config, install prefix), lazily opened and closed at command exit, with everything downstream receiving one. That keeps the invariant whole instead of carving an exception from it -- the session owner constructs, everyone else receives, and for CLI-side work the CLI layer is the session owner. Giving the CLI a full RuntimeEnvironment was rejected as heavy machinery for writing a config file that also inverts an existing dependency (config loading precedes environment construction), and per-command construction was rejected because it makes the rule area-dependent exactly where a contributor would guess wrong. Assisted-by: Claude Signed-off-by: David Noble <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 3's first call site exposed a wrong pattern, and the ruling it drew inserts phase 2b ahead
of the 29-site migration.
Migrating
pkg/signingby having it open its own root looked reasonable and was not. The root isset by whoever starts a starlark or graph execution, carried on the
RuntimeEnvironment, andreached downstream through the activation record —
ActivationRecord.RuntimeEnvironmentisdocumented as "always set during dispatch", and every provider already reads
p.RuntimeEnvironment().Root. A provider constructing its own root bypasses the session that ownsit.
The signing change is reverted rather than left as precedent for 29 more sites. Its
generateLocalKeynow carries aTODO(#405)stating plainly that the private key's0600is notenforced on Windows, and why.
Phase 2b — session-owned filesystem access
The invariant: code never constructs filesystem access — it receives it.
a tree Windows cannot remove while a handle inside it is open.
"refused before dispatch" to "died halfway through a run".
Root()asserts on a post-validation mint failure, matching the checksum trust boundary andkeeping ~40 call sites as one-liners.
os.TempDir()already honorsTMPDIR/TMP. The one exception, cross-device staging, is per-operation.CLI root ownership
internal/cliowns purpose-named roots (state, config, install prefix), lazily opened andclosed at command exit; everything downstream receives one. That keeps the invariant whole rather
than carving an exception from it — the session owner constructs, everyone else receives, and for
CLI-side work the CLI layer is the session owner.
Rejected: a full
RuntimeEnvironmentfor the CLI (heavy machinery to write a config file, and itinverts an existing dependency — config loading precedes environment construction), and
per-command construction (makes the rule area-dependent exactly where a contributor would guess
wrong).
Docs plus one
TODOcomment; no behavior change.make testzero failures,lint-allgreen on allthree GOOS.
Assisted-by: Claude