carlos / platform Public

Merge branch 'console-ux-11-status-check' into main

paul@keymail.dev f773b13f51950f402cd541acea504376e72b9dc0 parent 64972fdparent 9c707fd
2 files changed, +72 −8
  • internal/status/dryrun.go +45 −8
  • internal/status/dryrun_internal_test.go +27 −0

CI passed — run details

diff --git a/internal/status/dryrun.go b/internal/status/dryrun.go
index 557002f3d..bf1f99eea 100644
--- a/internal/status/dryrun.go
+++ b/internal/status/dryrun.go
@@ -32,20 +32,23 @@ const dryRunOptInApp = "demoapp"
// registry and probes. None of these substrings may appear in ANY object
// DryRun publishes. "prod-secret" is listed both whole and as a bare prefix
// so a leak that only carries part of the hostname (e.g. truncated in some
-// future summary field) still trips the scan. "0.73"/"0.95" are the exact
-// literal fractions fed into the probes — if either ever showed up verbatim
-// in published JSON, a raw ratio escaped banding somewhere upstream of the
-// digit-in-band-fields check below (which catches band words carrying ANY
-// digit, not just these two).
+// future summary field) still trips the scan. The fixture fractions are
+// checked as JSON numbers separately: timestamps can legitimately contain
+// the same digits in their fractional seconds.
var dryRunNeedles = []string{
"prod-secret.example.com", // fixture hostname
"prod-secret", // hostname's leak-prone substring on its own
"example.com", // the fixture domain generally
"ip-10-0-0-7", // fixture machine id
- "0.73", // fixture MemFrac, verbatim
- "0.95", // fixture DiskFrac, verbatim
}
+const (
+ dryRunMemFrac = 0.73
+ dryRunDiskFrac = 0.95
+)
+
+var dryRunFractionNeedles = []float64{dryRunMemFrac, dryRunDiskFrac}
+
// dryRunMetricsNeedles are the distinctive raw values Task 5's BoxMetrics
// carries — real numbers and strings that Box.Metrics is the ONE deliberate
// exception privileged to publish (see snapshot.go's package doc), and which
@@ -153,7 +156,7 @@ func dryRunFixtures() ([]registry.Route, Probes) {
},
}
- memFrac, diskFrac := 0.73, 0.95
+ memFrac, diskFrac := dryRunMemFrac, dryRunDiskFrac
lag := int64(120)
adopting := true // a known reading, so adoption_running publishes non-null and gets scanned
configPath := true // ditto for config_path_running (issue #44)
@@ -251,6 +254,37 @@ func scanBandFieldsForDigits(v interface{}) []string {
return bad
}
+func scanForNumericLeaks(v interface{}, banned []float64) []string {
+ seen := map[float64]bool{}
+ var walk func(interface{})
+ walk = func(v interface{}) {
+ switch t := v.(type) {
+ case map[string]interface{}:
+ for _, value := range t {
+ walk(value)
+ }
+ case []interface{}:
+ for _, value := range t {
+ walk(value)
+ }
+ case float64:
+ for _, needle := range banned {
+ if t == needle {
+ seen[needle] = true
+ }
+ }
+ }
+ }
+ walk(v)
+ var found []string
+ for _, needle := range banned {
+ if seen[needle] {
+ found = append(found, fmt.Sprintf("%g", needle))
+ }
+ }
+ return found
+}
+
// DryRun runs the real publish pipeline into a DirStore rooted at dir, then
// reads back everything it just published and fails on any leaked needle —
// see the package doc comment above for why. Progress (each published key)
@@ -372,6 +406,9 @@ func DryRun(dir string, out io.Writer) error {
// fields.
var decoded interface{}
if err := json.Unmarshal(body, &decoded); err == nil {
+ if leaks := scanForNumericLeaks(decoded, dryRunFractionNeedles); len(leaks) > 0 {
+ return fmt.Errorf("dry run: %s leaked %v", key, leaks)
+ }
if bad := scanBandFieldsForDigits(decoded); len(bad) > 0 {
return fmt.Errorf("dry run: %s: band field carries a digit: %v", key, bad)
}
diff --git a/internal/status/dryrun_internal_test.go b/internal/status/dryrun_internal_test.go
new file mode 100644
index 000000000..142552f28
--- /dev/null
+++ b/internal/status/dryrun_internal_test.go
@@ -0,0 +1,27 @@
+package status
+
+import (
+ "encoding/json"
+ "reflect"
+ "testing"
+)
+
+func TestScanForNumericLeaksFindsNestedFixtureFractions(t *testing.T) {
+ var decoded interface{}
+ if err := json.Unmarshal([]byte(`{"object":{"ratio":0.95},"list":[{"ratio":0.73}]}`), &decoded); err != nil {
+ t.Fatal(err)
+ }
+ if got, want := scanForNumericLeaks(decoded, dryRunFractionNeedles), []string{"0.73", "0.95"}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("numeric leaks = %v, want %v", got, want)
+ }
+}
+
+func TestScanForNumericLeaksIgnoresTimestampText(t *testing.T) {
+ var decoded interface{}
+ if err := json.Unmarshal([]byte(`{"generated_at":"2026-09-09T16:15:10.950730Z"}`), &decoded); err != nil {
+ t.Fatal(err)
+ }
+ if got := scanForNumericLeaks(decoded, dryRunFractionNeedles); len(got) != 0 {
+ t.Fatalf("timestamp text reported as numeric leak: %v", got)
+ }
+}