| 1 | package hostops |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "errors" |
| 6 | "testing" |
| 7 | ) |
| 8 | |
| 9 | func TestReviewedStorageFamiliesRefuseLookalikes(t *testing.T) { |
| 10 | 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"} |
| 11 | for _, key := range keys { |
| 12 | t.Run(key, func(t *testing.T) { |
| 13 | if _, check := deploymentFamily(key); check == nil { |
| 14 | t.Fatalf("family not recognized: %s", key) |
| 15 | } |
| 16 | for _, bad := range []string{key + "/apps/bab/demo", key + ".extra", "unknown/" + key} { |
| 17 | if _, check := deploymentFamily(bad); check != nil { |
| 18 | t.Fatalf("lookalike admitted: %s", bad) |
| 19 | } |
| 20 | } |
| 21 | if _, _, err := classifyDeploymentFamily(nil, MutationTarget{Method: "Delete", Key: key}); !errors.Is(err, ErrUnclassified) { |
| 22 | t.Fatalf("delete allowed: %v", err) |
| 23 | } |
| 24 | if _, _, err := classifyDeploymentFamily(nil, MutationTarget{Method: "Put", Key: key, After: []byte(`{"app":"demo","unknown":true}`)}); err == nil && key != "bootstrap/router/66587fa/carlos-linux-arm64" { |
| 25 | t.Fatal("unknown body allowed") |
| 26 | } |
| 27 | }) |
| 28 | } |
| 29 | 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"} { |
| 30 | if _, err := ClassifyMutation(context.Background(), nil, nil, MutationTarget{Method: "Put", Key: key, After: []byte(`{}`)}); err == nil { |
| 31 | t.Fatalf("unknown family admitted: %s", key) |
| 32 | } |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | func TestReviewedStorageBodiesBindIdentityAndScope(t *testing.T) { |
| 37 | for _, tc := range []struct { |
| 38 | key, body string |
| 39 | ok bool |
| 40 | }{ |
| 41 | {"accounts/bab/telemetry.json", `{"analytics":{"count":"edge","door":"on"},"errors":{"log_level":"warn"}}`, true}, |
| 42 | {"accounts/bab/telemetry.json", `{"app":"demo","analytics":{"count":"edge"}}`, false}, |
| 43 | {"accounts/bab/telemetry.json", `{"analytics":{"count":"unknown"}}`, false}, |
| 44 | {"usage/census/2026-10-07.json", `{"v":1,"date":"2026-10-08"}`, false}, |
| 45 | {"usage/storage/2026-10-07.json", `{"v":99,"date":"2026-10-07"}`, false}, |
| 46 | {"usage/scan/2026-10-07.json", `{"v":1,"date":"2026-10-07","accounts":{"bab":{"objects":2,"bytes":30}}}`, true}, |
| 47 | {"usage/scan/2026-10-07.json", `{"v":1,"date":"2026-10-07","accounts":null}`, true}, |
| 48 | {"usage/scan/2026-10-07.json", `{"v":1,"date":"2026-10-08","accounts":{}}`, false}, |
| 49 | {"usage/scan/2026-10-07.json", `{"v":2,"date":"2026-10-07","accounts":{}}`, false}, |
| 50 | {"usage/scan/2026-10-07.json", `{"v":1,"date":"2026-10-07","accounts":{"bab":{"objects":2,"bytes":30,"app":"demo"}}}`, false}, |
| 51 | {"usage/scan/2026-10-07.json", `{"v":1,"date":"2026-10-07","accounts":{}} {}`, false}, |
| 52 | {"usage/scan/2026-10-07.json", `not json`, false}, |
| 53 | {"usage/accounts/bab/2026-10.json", `{"v":1,"account":"cac","month":"2026-10"}`, false}, |
| 54 | {"status/consoles/console-a.json", `{"component":"console","actor":"console-b","instance_id":"console-b"}`, false}, |
| 55 | {"control/moves-console.json", `{"v":99,"protocol":1}`, false}, |
| 56 | {"economics/bills/2026-10.json", `{"schema":1,"month":"2026-09","source":"manual"}`, false}, |
| 57 | } { |
| 58 | t.Run(tc.key+tc.body, func(t *testing.T) { |
| 59 | _, _, err := classifyDeploymentFamily(nil, MutationTarget{Method: "Put", Key: tc.key, After: []byte(tc.body)}) |
| 60 | if (err == nil) != tc.ok { |
| 61 | t.Fatalf("err=%v want ok=%v", err, tc.ok) |
| 62 | } |
| 63 | }) |
| 64 | } |
| 65 | for _, key := range []string{"usage/census/2026-10-07.json", "usage/storage/2026-10-07.json", "bootstrap/router/66587fa/carlos-linux-arm64"} { |
| 66 | if _, _, err := classifyDeploymentFamily(nil, MutationTarget{Method: "Put", Key: key, ETag: "existing", After: []byte(`{}`)}); err == nil { |
| 67 | t.Fatalf("immutable overwrite admitted: %s", key) |
| 68 | } |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | // The scan day is folded per drain tick with a compare-and-swap, so unlike the |
| 73 | // census and storage days a rewrite of an existing key is its ordinary write. |
| 74 | // The rewrite is still the exact shape: the same day under its own key, a |
| 75 | // Put, and never a delete. |
| 76 | func TestScanDayIsRewrittenByCASNotCreateOnly(t *testing.T) { |
| 77 | key := "usage/scan/2026-10-07.json" |
| 78 | body := []byte(`{"v":1,"date":"2026-10-07","accounts":{"bab":{"objects":3,"bytes":37}}}`) |
| 79 | before := []byte(`{"v":1,"date":"2026-10-07","accounts":{"bab":{"objects":1,"bytes":7}}}`) |
| 80 | c, ok, err := classifyDeploymentFamily(nil, MutationTarget{Method: "Put", Key: key, ETag: "existing", Before: before, After: body}) |
| 81 | if !ok || err != nil { |
| 82 | t.Fatalf("a CAS rewrite of the scan day was refused: ok=%v err=%v", ok, err) |
| 83 | } |
| 84 | if c.Family != "usage-scan" || c.NonApp == "" || len(c.Scopes) != 0 { |
| 85 | t.Fatalf("classification = %+v, want the deployment-scoped usage-scan family with no app scope", c) |
| 86 | } |
| 87 | 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) { |
| 88 | t.Fatalf("a rewrite naming another day was admitted: %v", err) |
| 89 | } |
| 90 | for _, method := range []string{"Delete", "DeleteIfMatch"} { |
| 91 | if _, _, err := classifyDeploymentFamily(nil, MutationTarget{Method: method, Key: key, ETag: "existing", Before: before}); !errors.Is(err, ErrUnclassified) { |
| 92 | t.Fatalf("%s of the scan day: err = %v, want ErrUnclassified", method, err) |
| 93 | } |
| 94 | } |
| 95 | // Through the production entry point too, with no admission, no permit |
| 96 | // and no control writer: the family needs none of them. |
| 97 | c, err = ClassifyMutation(context.Background(), nil, nil, MutationTarget{Method: "Put", Key: key, ETag: "existing", Before: before, After: body}) |
| 98 | if err != nil || c.Family != "usage-scan" || len(c.Scopes) != 0 { |
| 99 | t.Fatalf("ClassifyMutation = %+v, %v", c, err) |
| 100 | } |
| 101 | } |
| 102 | |