hub R-435: each clean-up window explains one fall only; a window stuck open past its deadline explains nothing (security review)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -117,6 +117,38 @@ func TestR435_LyingWindowExplainsOnlyItsCap(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Security review 2026-10-08: one window explains ONE fall. A window that removed 9 explains 69 → 60; a
|
||||
// second fall 60 → 55 in the next report (inside the 2-h slack, no new window) alarms.
|
||||
// RED-PROOF: stop marking windows as spent (usedWindows) → the second fall is explained again → 0 alarms → FAILS.
|
||||
func TestR435_OneWindowExplainsOneFall(t *testing.T) {
|
||||
st := newDiskStore(t)
|
||||
cust := "p10"
|
||||
if err := st.RecordOffsiteKeyInstalled(cust, "fp-1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ok, err := st.RecordOffsiteKeyConfirmed(cust, "fp-1"); err != nil || !ok {
|
||||
t.Fatalf("confirm: %v %v", ok, err)
|
||||
}
|
||||
var msgs []string
|
||||
saveOffsiteReport(t, st, cust, dropJSON(69, true, "", "ok"))
|
||||
oc := NewOffsiteChecker(st, 48*time.Hour, func(_, et, _, msg, _, _ string) {
|
||||
if et == "offsite_snapshots_dropped" {
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
}, quietLog())
|
||||
closedWindow(t, cust, 69, 60)(st)
|
||||
saveOffsiteReport(t, st, cust, dropJSON(60, true, "", "ok"))
|
||||
oc.Check()
|
||||
if len(msgs) != 0 {
|
||||
t.Fatalf("the window explains 69 -> 60; got %d alarm(s)", len(msgs))
|
||||
}
|
||||
saveOffsiteReport(t, st, cust, dropJSON(55, true, "", "ok"))
|
||||
oc.Check()
|
||||
if len(msgs) != 1 {
|
||||
t.Fatalf("a spent window must not explain the next fall 60 -> 55; got %d alarm(s)", len(msgs))
|
||||
}
|
||||
}
|
||||
|
||||
// Controls: the half-rule still governs a non-pinned tier, and an installed-but-unconfirmed key.
|
||||
func TestR435_NotPinnedKeepsHalfRule(t *testing.T) {
|
||||
if msgs := r435Run(t, "n1", r435Setup{next: dropJSON(60, true, "", "ok")}); len(msgs) != 0 {
|
||||
|
||||
Reference in New Issue
Block a user