feat: add shellctl home snapshot save/restore endpoints - #40975
Closed
GareArc wants to merge 16 commits into
Closed
Conversation
An empty Home now streams an ordinary 16-byte archive with no entries instead of a 204. Callers no longer need a branch for it: the snapshot is stored, resolved, and restored through the same path as any other, and a consumer cannot mistake an absent snapshot for an empty one.
Workspace content is not logically part of a Home Snapshot, per the agent backend's HomeSnapshotBackend protocol. Enforcing that through the default value of SHELLCTL_HOME_SNAPSHOT_EXCLUDES let any deployment silently opt out of it by setting the variable to something else. SaveHome now always skips the top-level workspace directory. The env var becomes a purely additive list of further excludes and defaults to empty.
GareArc
force-pushed
the
feat/shellctl-snapshot-endpoints
branch
2 times, most recently
from
August 19, 2026 23:13
8728f41 to
259cda8
Compare
SnapshotTimeout was hardcoded to 600s, so tuning it for slow networks, large Home directories, or loaded nodes meant rebuilding the image. SHELLCTL_SNAPSHOT_TIMEOUT now overrides it with a Go duration string. An unparseable or non-positive value fails startup rather than falling back to the default. A non-positive deadline is the dangerous case: it expires before the first write, and since the deadline is what releases the single-operation gate when a peer stalls, every save and restore would return 409 from then on. Both snapshot env vars are parsed and checked in DefaultConfig, which returns an error, so an unusable value yields no config at all and the caller has a single gate. That absorbs Config.Validate, a one-line pass-through to snapshot.ValidateExcludes, and ValidateExcludes itself: exported for this one consumer and called by nothing in its own package, its rule is about the shape of an env value, not about snapshotting. A malformed exclude is already inert in excluded(), which only matches top-level names.
GareArc
force-pushed
the
feat/shellctl-snapshot-endpoints
branch
from
August 19, 2026 23:22
259cda8 to
c68ed66
Compare
Removed comments explaining the parseHomeSnapshotExcludes function.
This deadline is the runtime defending its own liveness, not a budget for the operation. It exists because the save/restore gate is held for the whole call: if the caller stops reading, the write blocks, the gate is never released, and every later save and restore on that sandbox answers 409 snapshot_busy until the deadline fires. At 600s that wedge lasted nearly ten minutes. 45s puts it just above the 30s its caller now allows, which is the ordering that matters. Above, and the caller aborts first and reports its own timeout while this gate frees shortly after. Equal or below, and the runtime aborts first, the caller reads a stream that ends without an ok trailer, and a slow snapshot is reported as a corrupt archive. SHELLCTL_SNAPSHOT_TIMEOUT still overrides it; only the shipped default moves.
5 tasks
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
Adds
POST /v1/snapshot/saveandPOST /v1/snapshot/restoreto shellctl.204when Home is empty, integrity trailers (X-Snapshot-Status/X-Snapshot-Sha256/X-Snapshot-Bytes). A mid-stream failure aborts the connection, so a truncated stream can never be read as success.os.Root(openat2/RESOLVE_BENEATHon Linux),400 archive_malformedvs500 restore_failed, setuid/setgid/sticky stripped, ownership never applied.409 snapshot_busysingle-flight across both endpoints; I/O deadlines bound how long a stalled peer can hold the gate.Excludes are configurable via
SHELLCTL_HOME_SNAPSHOT_EXCLUDES(defaultworkspace).Notes for review
github.com/klauspost/compress— the module's first compression dependency.os.Rootkernel path is untested on darwin; worth a linux/amd64 CI run.