R-263 writer invariant pinned by an AST test; R-368 IsDefault comment exact (no binary change; burn-down)
gates / gates (push) Successful in 32s
gates / gates (push) Successful in 32s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// R-263: "SetBackupTarget is the only writer that GRANTS StoragePath.BackupTarget" — a drive never acquires the
|
||||
// whole-guest backup-target role by appearing (E-2 §3). This scans EVERY non-test Go file under controller/internal and
|
||||
// cmd for a write of a field named BackupTarget — an assignment `x.BackupTarget = v` or a composite-literal key
|
||||
// `BackupTarget: v` — and fails on any that is not the literal `false`, unless it sits inside SetBackupTarget.
|
||||
// RED-PROOF: plant `s.StoragePaths[0].BackupTarget = true` in any other function → this test fails.
|
||||
func TestR263_OnlySetBackupTargetGrantsTheRole(t *testing.T) {
|
||||
var roots []string
|
||||
for _, r := range []string{"..", "../../cmd"} { // internal/ (this package's parent) and cmd/
|
||||
if _, err := os.Stat(r); err == nil {
|
||||
roots = append(roots, r)
|
||||
}
|
||||
}
|
||||
files, writes := 0, 0
|
||||
var bad []string
|
||||
for _, root := range roots {
|
||||
_ = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil || info.IsDir() || !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") {
|
||||
return nil
|
||||
}
|
||||
fset := token.NewFileSet()
|
||||
f, perr := parser.ParseFile(fset, path, nil, 0)
|
||||
if perr != nil {
|
||||
t.Fatalf("parse %s: %v", path, perr)
|
||||
}
|
||||
files++
|
||||
for _, decl := range f.Decls {
|
||||
fn, _ := decl.(*ast.FuncDecl)
|
||||
inSetter := fn != nil && fn.Name.Name == "SetBackupTarget"
|
||||
ast.Inspect(decl, func(n ast.Node) bool {
|
||||
check := func(val ast.Expr, pos token.Pos) {
|
||||
writes++
|
||||
if id, ok := val.(*ast.Ident); ok && id.Name == "false" {
|
||||
return
|
||||
}
|
||||
if !inSetter {
|
||||
bad = append(bad, fset.Position(pos).String())
|
||||
}
|
||||
}
|
||||
switch x := n.(type) {
|
||||
case *ast.AssignStmt:
|
||||
for i, lhs := range x.Lhs {
|
||||
if sel, ok := lhs.(*ast.SelectorExpr); ok && sel.Sel.Name == "BackupTarget" && i < len(x.Rhs) {
|
||||
check(x.Rhs[i], x.Pos())
|
||||
}
|
||||
}
|
||||
case *ast.KeyValueExpr:
|
||||
if k, ok := x.Key.(*ast.Ident); ok && k.Name == "BackupTarget" {
|
||||
check(x.Value, x.Pos())
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if files < 100 || writes < 2 {
|
||||
t.Fatalf("scan too small to mean anything: %d files, %d BackupTarget writes (want the two in settings.go)", files, writes)
|
||||
}
|
||||
if len(bad) > 0 {
|
||||
t.Fatalf("BackupTarget may be granted outside SetBackupTarget at: %v", bad)
|
||||
}
|
||||
}
|
||||
@@ -569,7 +569,7 @@ const NetworkMountRoot = "/mnt/felhom-drives"
|
||||
type StoragePath struct {
|
||||
Path string `json:"path"` // e.g., "/mnt/hdd_1" (drive) or "/mnt/felhom-drives/<name>" (network)
|
||||
Label string `json:"label,omitempty"` // e.g., "Külső HDD 1TB"
|
||||
IsDefault bool `json:"is_default,omitempty"` // new apps use this by default
|
||||
IsDefault bool `json:"is_default,omitempty"` // the deploy FORM pre-selects it (templates/deploy.html); the deploy API applies no default (R-368)
|
||||
Schedulable bool `json:"schedulable"` // whether new apps can be deployed here
|
||||
AddedAt string `json:"added_at"` // RFC3339
|
||||
Disconnected bool `json:"disconnected,omitempty"` // true when drive detected as disconnected
|
||||
@@ -1652,8 +1652,9 @@ func (s *Settings) SetSchedulable(path string, schedulable bool) error {
|
||||
}
|
||||
|
||||
// SetBackupTarget assigns the whole-guest backup-target role to exactly one storage path, clearing it
|
||||
// from every other. This is the ONLY writer of StoragePath.BackupTarget — registration must never set
|
||||
// it (E-2 §3: a drive never acquires a role by appearing).
|
||||
// from every other. This is the ONLY writer that GRANTS StoragePath.BackupTarget (ClearBackupTarget also writes
|
||||
// the field, only ever false) — registration must never set it (E-2 §3: a drive never acquires a role by
|
||||
// appearing). Pinned by TestR263_OnlySetBackupTargetGrantsTheRole (a scan of every non-test file).
|
||||
//
|
||||
// Refusals, both structural rather than advisory:
|
||||
// - a NETWORK share can never be the target. vzdump writes a multi-GB archive through the host, and
|
||||
|
||||
Reference in New Issue
Block a user