Repository navigation
fix(sandbox): close the sweep's two windows with a tombstone and a guarded open (#446) - #457
Merged
Merged
Conversation
edgehero
force-pushed
the
fix/446-sandbox-sweep-windows
branch
from
September 27, 2026 20:05
f871020 to
3260f27
Compare
edgehero
force-pushed
the
fix/446-sandbox-sweep-windows
branch
from
September 28, 2026 05:48
167c3cd to
ec223a8
Compare
…arded open (#446) Two windows could delete a retained run under an operator: an unpinned open of a run past its window while the sweep was asking its runtime, and a pin that landed while a large directory was already being deleted (a 200k-file clone takes seconds). Sweep. After the fresh read matches, the sweep re-asks the run's own runtime, renames the directory to a dot-prefixed tombstone (.reap-<pid>-<now>-<n>, never the job id), reads it once more through the tombstone (a pin that landed in between puts it back, displacing only an empty directory), and only then deletes it. A tombstone with a live pin is never deleted; it is restored only under its own id's name. Leftover tombstones are cleared at the start of every pass, a young foreign one only while its pid lives; every reader of the root skips them. Open. A run past its deadline, or within SANDBOX_OPEN_GRACE_MS of it, is refused unless --pin; the pin is written right after resolving the run, before any runtime call, and a failed pin refuses. Once the container is listed the manifest and the directory's inode are read again: a run lost at launch stops the container (podman with --time=0), one lost later is reported when the shell exits, and only a never-listed container that exits 125 is read as a refused mount. Deadline. retainJobDir writes retainUntil from the worker's window; an unpinned run's deadline is the earlier of retainUntil and createdAt plus the reader's window, so an opener with a longer window agrees with the worker and lowering or turning retention off still cleans runs retained earlier. Also: a job id with a leading dot or underscore is escaped, runs retained before the escape stay openable, a directory holding another job's run is refused; doctor names stuck and pin-held tombstones with their exact path and never classifies by pid; --list says when a run needs --pin; one worker per retention root and one runtime endpoint are the supported configuration; and a new check fails CI on any merge-conflict marker in a tracked file. Specs: INT-SANDBOX-CONTRACT, REQ-RESURRECTABLE-SANDBOX, OQ-007, OQ-038. Signed-off-by: Rob Boerman <robboerman@live.nl>
…ause (#446) Signed-off-by: Rob Boerman <robboerman@live.nl>
edgehero
force-pushed
the
fix/446-sandbox-sweep-windows
branch
from
September 28, 2026 06:25
329c645 to
c26742e
Compare
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.
Closes #446.
Two windows could delete a retained run under an operator:
sandbox <id>on a run past its window while the sweep was asking its runtime.Sweep: a tombstone
After the fresh read matches, the directory is renamed to
.reap-<pid>-<now>-<n>in the same root. The name never carries the job id, so no ENAMETOOLONG. The directory is then read once more through the tombstone, and only then deleted:manifest-changed.rename-failed, in the samesandbox_reaper_skippedfamily (OQ-007).listSandboxes, the runtime watch, the network sweep's keep set, doctor's count andretainJobDir.Open: refuse late, pin first, check after launch
SANDBOX_OPEN_GRACE_MS(5 min) of it, is refused unless--pinis given, and the refusal names the command.--pin, the pin is written right after the run is resolved, before any runtime call. A failed pin now refuses; it used to only warn, and the launch then bound an auto-created empty directory.swept-at-launch. The check is aborted as soon as the shell returns.bfor such a run, and its refusal points at the CLI's--pin.Deadline
retainJobDirwritesretainUntilfrom the worker's window. An unpinned run's deadline is the earlier ofretainUntilandcreatedAtplus the reader's current window. So:The one residual is written down in
INT-SANDBOX-CONTRACT: a worker window lowered below both the opener's window and the run'sretainUntil, with an unpinned open racing that sweep. The post-launch check reports it.Also
.,..,.reap-...) is re-mapped, so it can never name the root's parent or a tombstone.Specs
INT-SANDBOX-CONTRACT,REQ-RESURRECTABLE-SANDBOX,OQ-007,OQ-038;docs/sandbox.md.