Files
felhom.eu/hub/internal/web/offsite_integrity_line_test.go
T
admin 655f5f66f8
gates / gates (push) Successful in 6m0s
hub v0.147.0 (code): the operator's answers S4, S6, S10, S29, S30, S32, S33
- S4 / R-242: GoldenVouchChecker - a published golden unvouched for 2 h raises golden_not_vouched (operator only)
- S6 / R-244: the delete cascade de-references app_log_issues; one-time sweep flag -sweep-app-log-residue=count|apply
- S10 / R-266: read_failed storage entry shows "read failed", not 0 %
- S29 / R-250: host-key scan IPv4 first, ~2 min ladder, "safe to press Save again" error
- S30 / R-246: stale_at retired (reader, setter, badge)
- S32 / R-521: storage_reconnected ends the storage_disconnected cooldown on both channels
- S33 / R-402: host page "Last full check (off-site)" line; two wire-gate allowlist entries removed
Each with a test seen failing first. Not built or deployed yet (operator-attended deploy).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-12 14:54:14 +02:00

47 lines
2.4 KiB
Go

package web
import (
"strings"
"testing"
)
// R-402 (operator ruling 2026-10-12, S33, `09` §3 decision 228): the host page shows ONE line about
// the off-site integrity check — „Last full check: OK/FAILED, depth N, date" — from the fields the
// controller has sent since v0.227.0/v0.228.0. The verdict is never shown without its depth, and an
// absent timestamp means NEVER CHECKED, not FAILED (the R-331 lesson: a card that rendered a verdict
// from fields nothing wrote).
func TestOffsiteIntegrityLine(t *testing.T) {
cases := []struct{ name, report, want string }{
{"ok, full depth", `{"offsite":{"last_integrity_check":"2026-10-12T01:14:00Z","last_integrity_ok":true,"last_integrity_depth":"100%"}}`,
"OK, depth 100%, 2026-10-12 01:14 UTC"},
{"failed (bool absent), structure", `{"offsite":{"last_integrity_check":"2026-10-11T01:00:00Z","last_integrity_depth":"structure"}}`,
"FAILED, depth structure, 2026-10-11 01:00 UTC"},
{"old controller: no depth", `{"offsite":{"last_integrity_check":"2026-10-11T01:00:00Z","last_integrity_ok":true}}`,
"OK, depth unknown (controller older than v0.228.0), 2026-10-11 01:00 UTC"},
{"never checked", `{"offsite":{"repo_size_bytes":5}}`, "never checked"},
{"no off-site object", `{"version":"0.307.0"}`, "not reported (no off-site status in the box's report)"},
{"no report", ``, "not reported (no off-site status in the box's report)"},
}
for _, c := range cases {
if got := offsiteIntegrityLine(c.report); got != c.want {
t.Errorf("%s: got %q, want %q", c.name, got, c.want)
}
}
}
// The line reaches the host page (both branches of the template gate: a host with a customer renders
// it, with the verdict from the newest controller report). RED-PROOF: delete the "OffsiteIntegrity"
// key from hostDetailData → the id and the verdict are missing.
func TestHostPageShowsOffsiteIntegrityLine(t *testing.T) {
s, st, _ := newRevealServer(t)
cookie, _ := newRevealSession(t, s)
seedNetHost(t, st, "r402-host", "0.150.0", liveReportJSON, "")
if err := st.SaveReport("c-r402-host", []byte(`{"offsite":{"last_integrity_check":"2026-10-12T01:14:00Z","last_integrity_ok":true,"last_integrity_depth":"100%"}}`)); err != nil {
t.Fatal(err)
}
body := getHostPage(t, s, cookie, "r402-host")
if !strings.Contains(body, `id="offsite-integrity"`) || !strings.Contains(body, "OK, depth 100%, 2026-10-12 01:14 UTC") {
t.Fatal("the host page does not show the off-site integrity line")
}
}