bdcbd50b42
gates / gates (push) Successful in 13s
R-486 (P1): removing an app with its backups KEPT keeps its Tier-2 record, so the second-drive restore is no longer refused over an intact mirror. R-484: postgis/pgvector/timescaledb images are Postgres (logical dumps). R-485: the backup card sizes the recovery unit and the mirror(s). R-480: a held update's sentence leaves the card once the hold is lifted. R-477: the update's off-site lookup is one snapshots call, no stats. R-478: a copy older than this install's deploy does not count. R-474: "delete backups" deletes the unit, the mirror(s) and the prefs. Tests and red-proofs per row; evidence in felhom.eu documentation/audits/v0240-2026-09-13/ and nightly-2026-09-13-adventurelog/.
63 lines
1.9 KiB
Go
63 lines
1.9 KiB
Go
package api
|
|
|
|
import (
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// R-474 — the remove handler really deletes the whole unit, the Tier-2 mirror and the prefs.
|
|
func TestR474_RemoveHandlerDeletesUnitMirrorAndPrefs(t *testing.T) {
|
|
fset := token.NewFileSet()
|
|
f, err := parser.ParseFile(fset, "router.go", nil, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var sel []string
|
|
for _, d := range f.Decls {
|
|
fn, ok := d.(*ast.FuncDecl)
|
|
if !ok || fn.Name.Name != "removeStack" || fn.Body == nil {
|
|
continue
|
|
}
|
|
ast.Inspect(fn.Body, func(n ast.Node) bool {
|
|
if s, ok := n.(*ast.SelectorExpr); ok {
|
|
sel = append(sel, s.Sel.Name)
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
joined := " " + strings.Join(sel, " ") + " "
|
|
for _, want := range []string{"RecoveryUnitPath", "Tier2MirrorDirsForApp", "RemoveTier2Mirrors", "DeleteAppBackupPrefs"} {
|
|
if !strings.Contains(joined, " "+want+" ") {
|
|
t.Errorf("removeStack must call %s", want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// R-486 — removing an app with its backups KEPT keeps its Tier-2 record. The only call that may
|
|
// forget the record is DeleteAppBackupPrefs, which the R-474 branch guards on remove_backups.
|
|
//
|
|
// COMPANION RED-PROOF (REPORT.md): put `r.sett.SetCrossDriveConfig(name, nil)` back into
|
|
// removeStack unconditionally — this fails.
|
|
func TestR486_RemovalKeepsTheTier2RecordUnlessBackupsGo(t *testing.T) {
|
|
fset := token.NewFileSet()
|
|
f, err := parser.ParseFile(fset, "router.go", nil, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, d := range f.Decls {
|
|
fn, ok := d.(*ast.FuncDecl)
|
|
if !ok || fn.Name.Name != "removeStack" || fn.Body == nil {
|
|
continue
|
|
}
|
|
ast.Inspect(fn.Body, func(n ast.Node) bool {
|
|
if s, ok := n.(*ast.SelectorExpr); ok && s.Sel.Name == "SetCrossDriveConfig" {
|
|
t.Errorf("removeStack calls SetCrossDriveConfig at line %d — a removal with backups kept would forget the mirror it kept (R-486)", fset.Position(s.Pos()).Line)
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
}
|