package hostops import ( "context" "errors" "testing" ) func TestReviewedStorageFamiliesRefuseLookalikes(t *testing.T) { keys := []string{"economics/active.json", "economics/bills/2026-10.json", "economics/scenarios/test.json", "infra/inventory.json", "usage/census/2026-10-07.json", "usage/storage/2026-10-07.json", "usage/scan/2026-10-07.json", "usage/accounts/bab/2026-10.json", "status/consoles/console-a.json", "control/moves-console.json", "accounts/bab/telemetry.json", "system/antivirus.json", "bootstrap/router/66587fa/carlos-linux-arm64", "control/system/router/canary.json"} for _, key := range keys { t.Run(key, func(t *testing.T) { if _, check := deploymentFamily(key); check == nil { t.Fatalf("family not recognized: %s", key) } for _, bad := range []string{key + "/apps/bab/demo", key + ".extra", "unknown/" + key} { if _, check := deploymentFamily(bad); check != nil { t.Fatalf("lookalike admitted: %s", bad) } } if _, _, err := classifyDeploymentFamily(nil, MutationTarget{Method: "Delete", Key: key}); !errors.Is(err, ErrUnclassified) { t.Fatalf("delete allowed: %v", err) } if _, _, err := classifyDeploymentFamily(nil, MutationTarget{Method: "Put", Key: key, After: []byte(`{"app":"demo","unknown":true}`)}); err == nil && key != "bootstrap/router/66587fa/carlos-linux-arm64" { t.Fatal("unknown body allowed") } }) } for _, key := range []string{"usage/apps/bab/demo.json", "economics/apps/bab/demo.json", "accounts/bab/telemetry/demo.json", "bootstrap/router/../carlos-linux-arm64", "usage/accounts/bab/not-a-month.json", "usage/census/2026-99-99.json", "usage/scan/2026-99-99.json", "usage/scan/bab/2026-10-07.json", "control/system/router/other.json"} { if _, err := ClassifyMutation(context.Background(), nil, nil, MutationTarget{Method: "Put", Key: key, After: []byte(`{}`)}); err == nil { t.Fatalf("unknown family admitted: %s", key) } } } func TestReviewedStorageBodiesBindIdentityAndScope(t *testing.T) { for _, tc := range []struct { key, body string ok bool }{ {"accounts/bab/telemetry.json", `{"analytics":{"count":"edge","door":"on"},"errors":{"log_level":"warn"}}`, true}, {"accounts/bab/telemetry.json", `{"app":"demo","analytics":{"count":"edge"}}`, false}, {"accounts/bab/telemetry.json", `{"analytics":{"count":"unknown"}}`, false}, {"usage/census/2026-10-07.json", `{"v":1,"date":"2026-10-08"}`, false}, {"usage/storage/2026-10-07.json", `{"v":99,"date":"2026-10-07"}`, false}, {"usage/scan/2026-10-07.json", `{"v":1,"date":"2026-10-07","accounts":{"bab":{"objects":2,"bytes":30}}}`, true}, {"usage/scan/2026-10-07.json", `{"v":1,"date":"2026-10-07","accounts":null}`, true}, {"usage/scan/2026-10-07.json", `{"v":1,"date":"2026-10-08","accounts":{}}`, false}, {"usage/scan/2026-10-07.json", `{"v":2,"date":"2026-10-07","accounts":{}}`, false}, {"usage/scan/2026-10-07.json", `{"v":1,"date":"2026-10-07","accounts":{"bab":{"objects":2,"bytes":30,"app":"demo"}}}`, false}, {"usage/scan/2026-10-07.json", `{"v":1,"date":"2026-10-07","accounts":{}} {}`, false}, {"usage/scan/2026-10-07.json", `not json`, false}, {"usage/accounts/bab/2026-10.json", `{"v":1,"account":"cac","month":"2026-10"}`, false}, {"status/consoles/console-a.json", `{"component":"console","actor":"console-b","instance_id":"console-b"}`, false}, {"control/moves-console.json", `{"v":99,"protocol":1}`, false}, {"economics/bills/2026-10.json", `{"schema":1,"month":"2026-09","source":"manual"}`, false}, } { t.Run(tc.key+tc.body, func(t *testing.T) { _, _, err := classifyDeploymentFamily(nil, MutationTarget{Method: "Put", Key: tc.key, After: []byte(tc.body)}) if (err == nil) != tc.ok { t.Fatalf("err=%v want ok=%v", err, tc.ok) } }) } for _, key := range []string{"usage/census/2026-10-07.json", "usage/storage/2026-10-07.json", "bootstrap/router/66587fa/carlos-linux-arm64"} { if _, _, err := classifyDeploymentFamily(nil, MutationTarget{Method: "Put", Key: key, ETag: "existing", After: []byte(`{}`)}); err == nil { t.Fatalf("immutable overwrite admitted: %s", key) } } } // The scan day is folded per drain tick with a compare-and-swap, so unlike the // census and storage days a rewrite of an existing key is its ordinary write. // The rewrite is still the exact shape: the same day under its own key, a // Put, and never a delete. func TestScanDayIsRewrittenByCASNotCreateOnly(t *testing.T) { key := "usage/scan/2026-10-07.json" body := []byte(`{"v":1,"date":"2026-10-07","accounts":{"bab":{"objects":3,"bytes":37}}}`) before := []byte(`{"v":1,"date":"2026-10-07","accounts":{"bab":{"objects":1,"bytes":7}}}`) c, ok, err := classifyDeploymentFamily(nil, MutationTarget{Method: "Put", Key: key, ETag: "existing", Before: before, After: body}) if !ok || err != nil { t.Fatalf("a CAS rewrite of the scan day was refused: ok=%v err=%v", ok, err) } if c.Family != "usage-scan" || c.NonApp == "" || len(c.Scopes) != 0 { t.Fatalf("classification = %+v, want the deployment-scoped usage-scan family with no app scope", c) } if _, _, err := classifyDeploymentFamily(nil, MutationTarget{Method: "Put", Key: key, ETag: "existing", Before: before, After: []byte(`{"v":1,"date":"2026-10-08","accounts":{}}`)}); !errors.Is(err, ErrIdentity) { t.Fatalf("a rewrite naming another day was admitted: %v", err) } for _, method := range []string{"Delete", "DeleteIfMatch"} { if _, _, err := classifyDeploymentFamily(nil, MutationTarget{Method: method, Key: key, ETag: "existing", Before: before}); !errors.Is(err, ErrUnclassified) { t.Fatalf("%s of the scan day: err = %v, want ErrUnclassified", method, err) } } // Through the production entry point too, with no admission, no permit // and no control writer: the family needs none of them. c, err = ClassifyMutation(context.Background(), nil, nil, MutationTarget{Method: "Put", Key: key, ETag: "existing", Before: before, After: body}) if err != nil || c.Family != "usage-scan" || len(c.Scopes) != 0 { t.Fatalf("ClassifyMutation = %+v, %v", c, err) } }