package status_test import ( "context" "encoding/json" "strings" "testing" "time" "github.com/carlosframework/platform/internal/registry" "github.com/carlosframework/platform/internal/status" ) // ---- Task 5: Contract tests — allowlist + digit scan ---- // The allowlist IS the schema. Adding a field to the structs without adding // it here fails the build — that friction is the point: every new field is a // deliberate publication decision. This file guards the public JSON contract // that the fleet status page publishes, ensuring no accidental leaks of // hostnames, IDs, or other sensitive data slip into the output. // allowedBoxKeys are THE schema for Box's JSON output. Any new field in Box // must be explicitly added here to pass the test — design friction that makes // the publication decision deliberate, never accidental. The map keys are path // strings ("" for root, "fieldname" for nested, "fieldname[]" for array // elements); values are the allowed field names at that path. var allowedBoxKeys = map[string][]string{ // "adoption_running" is a deliberate publication (pipelines spec §5): it // says whether the platform's own release-adoption timer is armed on this // box. It carries no tenant, hostname or machine identity — only whether // an opaquely-labelled box is picking up its own releases. // // "expired_canaries" is likewise deliberate (pipelines spec §5 "Canaries // expire"): a COUNT of this box's own canary/* routes past their TTL, // never which ones — no hostname, no channel name, no tenant identity. // // "config_path_running" is the issue #44 sibling of adoption_running: it // says whether this box's config-sync trigger unit (carlos-adopt.path) is // armed, i.e. whether config reaches unit-backed routes in seconds or only // on the hourly floor. Same publication argument — a platform-own unit's // liveness on an opaquely-labelled box, no tenant in it anywhere. // // "restart_path_running" is the issue #113 sibling of both: whether this // box's restart trigger unit (carlos-restart.path) is armed, i.e. whether a // member's `carlos restart` reaches its units in seconds or waits out the // hourly floor. Identical publication argument — one platform-own unit's // liveness on an opaquely-labelled box, and no tenant anywhere in it (it // says nothing about WHICH app was restarted, or that any was). // // "metrics" is the one key in this allowlist that is EXEMPT from the // band-word-not-a-number rule every other Box field follows (Task 5, // internal/status/snapshot.go's package doc): it carries raw byte // counts, a load average, a release sha, and tunnel state, unbanded. // That's safe only because Box (and this "metrics" key with it) never // leaves the bucket — status/boxes/