feat(mosaic): durable pre-update snapshot + verify net + restore CLI (#791 PR2) #811
Reference in New Issue
Block a user
Delete Branch "feat/791-pr2-snapshot-restore"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Part of #791. Adds the third, independent recovery layer for keep-mode framework upgrades under
~/.config/mosaic.PR1 (#802) gave keep-mode two protections: the manifest (a keep-sync only ever writes framework-owned paths — operator config is structurally untouched) and an ephemeral
/tmpsnapshot that rolls the whole target back if the sync crashes mid-write. This PR adds the case neither covers: a "successful" upgrade that a manifest/logic bug silently let touch an operator file.What lands
install.shmake_durable_snapshot): before any mutation, copy exactly the operator-owned surface that exists into${XDG_STATE_HOME:-~/.local/state}/mosaic/backups/pre-update-<UTC-ts>/— outside~/.config/mosaicand any repo.0700dirs /0600files (umask 077scoped and restored). Fail-open (a backup failure never aborts the upgrade it protects). RetentionMOSAIC_BACKUP_RETENTION(default 5).install.shverify_operator_surface):cmpevery snapshot file against its target counterpart; restore any operator file the upgrade diverged/removed and warn loudly (a divergence = manifest bug). Honors intentional migration removals; refuses to restore through a symlink; guardsmkdirunderset -e.mosaic restore(restore.ts):--list(default, dry-run) enumerates snapshots by timestamp;--from <ts>restores over the operator surface, confirmation-gated (--yes/MOSAIC_ASSUME_YES),--dry-run. Reports counts and relative paths only — never emits file contents (secrev).Security (both classes fixed with regression tests)
secure-file.tshelpers (assertCanonicalContainment+ensureManagedDirectory) and opens the leafO_NOFOLLOW|O_CREAT|O_TRUNC0600(ELOOP = fail-closed).--fromis validated against^\d{8}T\d{6}Z(?:-\d+)?$and resolves to exactlyjoin(root, 'pre-update-'+ts)(lstat, reject symlinked snap dir).Review round 1
Codex code-review (request-changes: 1 blocker + 3 should-fix) and security-review (high: 1 high + 1 medium) both ran on the diff. All 5 deduped defects were fixed forward, each with a red-first regression test whose control neuters exactly the guard under test (verify-net migration skip, symlink leaf guard, umask restore). Independent (author ≠ reviewer) review + a durable Gitea Reviewer-of-Record comment are still required before merge — codex self-review does not satisfy that gate.
Gates
CI runs the new
test-upgrade-durable-snapshot.shin theupgrade-guardstep.Reviewer-of-Record (RoR) — exact head
d12c5f7808VERDICT: APPROVE — secure & mergeable on security/correctness grounds. (Durable PR comment: Gitea blocks a formal APPROVE review by the PR author account under the single-account setup, so this comment is the durable exact-head RoR artifact.)
Author lane: ms-791 · Reviewer lane: independent Opus adversarial/security reviewer (dispatched by MS Team Lead).
Attestation: author != reviewer is PROCESS/LANE-attested — all Gitea activity under single account jason.woltje; separation is by work lane, not provider account.
CI: Woodpecker #1882 = terminal SUCCESS at this exact head (Gitea combined commit-status = success); all 8 steps green.
Scope: CLEAN — git diff --stat 32a0ffba..d12c5f78 = exactly the 8 ratified files; no stray committed secret/snapshot/session.lock.
Findings (all info-level; no blocker/high/med)
Part 7 busybox-portability change (test-harness only)
Gate status -> mergeable
exact-head terminal-green CI OK · fresh independent exact-head RoR APPROVE OK · scope clean OK · based on current main OK · durable RoR persisted to Gitea before queue guard OK.