R-414: the fallback scratch must also be DELETABLE - caught by live validation
gates / gates (push) Successful in 12s

The system-data fallback resolved a scratch fine and removeProofScratch then refused to
delete it: its accepted-roots list is built from REGISTERED drives, and a driveless box has
none. Observed on demo-felhom: 'refusing to remove ... it is not inside a proof root', with
the copy still on disk. Every nightly proof would have left one behind, growing forever, on
exactly the boxes the fallback exists for.

My defect, introduced with the fallback in the same session. The unit tests missed it
because every one of them registers a drive; the new pair deliberately does not, and the
second asserts the guard still REFUSES a path outside every proof root, so the fix is not a
widening into uselessness.
This commit is contained in:
2026-09-01 10:29:08 +02:00
parent fcef8e069c
commit 8b55de734c
2 changed files with 58 additions and 1 deletions
+14 -1
View File
@@ -338,7 +338,20 @@ func (m *Manager) restoreUnitReadOnly(ctx context.Context, stack, id, unitPath,
// out-of-sandbox path means a helper above is wrong and a best-effort skip would hide that.
func (m *Manager) removeProofScratch(stack, scratch string) {
clean := filepath.Clean(scratch)
for _, drive := range m.offsiteRestoreDriveRoots() {
// R-414: the accepted roots must include the SYSTEM DATA PATH, because that is now where a
// unit-only scratch lands on a box with no registered drive.
//
// CAUGHT BY LIVE VALIDATION ON demo-felhom, 2026-09-01, and it was a leak I introduced with the
// fallback itself: `offsiteRestoreDriveRoots` is built from registered drives and schedulable
// paths, so on a driveless box it is EMPTY — the scratch resolved fine and then this refused to
// delete it ("refusing to remove … it is not inside a proof root"). Every nightly proof would have
// left a copy behind, growing forever, on exactly the boxes the fallback exists for. The unit
// tests did not see it because they register a drive.
roots := append(m.offsiteRestoreDriveRoots(), strings.TrimSpace(m.cfg.Paths.SystemDataPath))
for _, drive := range roots {
if strings.TrimSpace(drive) == "" {
continue
}
root := filepath.Clean(m.offsiteProofRootFor(drive)) + string(filepath.Separator)
if strings.HasPrefix(clean+string(filepath.Separator), root) {
if err := os.RemoveAll(clean); err != nil {