hub v0.131.1: a scanned host pass (reboot_scanned, agent 0.141.1) clears 'reboot needed', so the 14-day alarm does not fire after a reboot; live evidence partB/partD/partG
gates / gates (push) Successful in 30s
gates / gates (push) Successful in 30s
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:
@@ -1,3 +1,14 @@
|
||||
## v0.131.1 — a reboot clears "reboot needed" (2026-10-04)
|
||||
|
||||
**Pairs with agent v0.141.1.** A patch release in the same session as v0.131.0 — a deliberate exception to "one
|
||||
release per repo": without it the 14-day `os_reboot_needed` alarm fires on a host the operator rebooted long ago.
|
||||
|
||||
- The fleet line's "reboot needed since" now also counts a pass that installed nothing when the agent says it looked
|
||||
(`reboot_scanned`, agent ≥ 0.141.1 scans the host on every pass). A looked-and-clean pass ends the run, so the date
|
||||
and the alarm clear after a reboot. Reports from older agents behave as before (only passes with an install count).
|
||||
- Test `TestRebootNeeded_ClearedByAScannedPass`; red-proof in
|
||||
`documentation/audits/os-host-lane-2026-10-04/partB/live-defects-redproofs.txt`.
|
||||
|
||||
## v0.131.0 — the tunnel status is true (R-841); OS updates: the host fast lane's own approved set, the fleet view and four alarms (`11` §8 steps 3+4) (2026-10-04)
|
||||
|
||||
**Needs agent v0.141.0** for the tunnel's three states and the host layer. An older agent still reports
|
||||
|
||||
@@ -304,3 +304,27 @@ func TestFleet_OneLinePerBoxBothLayers(t *testing.T) {
|
||||
}
|
||||
t.Fatal("no hp line")
|
||||
}
|
||||
|
||||
// A reboot clears "reboot needed": the agent scans the host on every pass (reboot_scanned) and a scanned pass that
|
||||
// finds nothing ends the run, so no alarm fires 14 days later. Red-proof: ignore RebootScanned in layerLine's predicate
|
||||
// and the cleared step still shows a date.
|
||||
func TestRebootNeeded_ClearedByAScannedPass(t *testing.T) {
|
||||
f := newFix(t)
|
||||
f.ingest(t, "hp", Report{Layer: LayerHost, Trigger: "night", Mode: "apply", Outcome: "applied", Healthy: true,
|
||||
Upgraded: []Package{pk("libc6", "2")}, RebootNeeded: true, RebootScanned: true})
|
||||
f.now = f.now.Add(24 * time.Hour)
|
||||
f.ingest(t, "hp", Report{Layer: LayerHost, Trigger: "night", Mode: "apply", Outcome: "nothing", Healthy: true, RebootNeeded: true, RebootScanned: true})
|
||||
if l := f.s.layerLine("hp", LayerHost, 0); f.now.Sub(l.RebootNeededSince) != 24*time.Hour {
|
||||
t.Fatalf("since = %v", l.RebootNeededSince)
|
||||
}
|
||||
f.now = f.now.Add(24 * time.Hour) // the operator rebooted
|
||||
f.ingest(t, "hp", Report{Layer: LayerHost, Trigger: "night", Mode: "apply", Outcome: "nothing", Healthy: true, RebootScanned: true})
|
||||
if l := f.s.layerLine("hp", LayerHost, 0); !l.RebootNeededSince.IsZero() {
|
||||
t.Fatalf("a scanned pass after the reboot did not clear it: %v", l.RebootNeededSince)
|
||||
}
|
||||
f.now = f.now.Add(20 * 24 * time.Hour)
|
||||
f.s.Alarms()
|
||||
if f.count(EventRebootNeeded) != 0 {
|
||||
t.Fatal("reboot alarm after the reboot")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ type Report struct {
|
||||
RestartNeeded []string `json:"restart_needed,omitempty"`
|
||||
DockerRestartNeeded bool `json:"docker_restart_needed,omitempty"`
|
||||
RebootNeeded bool `json:"reboot_needed,omitempty"`
|
||||
RebootScanned bool `json:"reboot_scanned,omitempty"` // agent ≥ 0.141.1: the pass looked (host: every pass)
|
||||
Refused json.RawMessage `json:"refused,omitempty"`
|
||||
PassSeconds float64 `json:"pass_seconds,omitempty"`
|
||||
}
|
||||
@@ -534,8 +535,8 @@ func (s *Service) layerLine(hostID, layer string, ring int) LayerLine {
|
||||
}
|
||||
l.NotCoveredFast = len(s.notCoveredFast(layer, ring, r))
|
||||
l.RebootNeededSince = s.sinceContinuously(hostID, layer, func(x Report) (bool, bool) {
|
||||
if len(x.Upgraded) == 0 && x.Outcome != "applied" {
|
||||
return false, false // a report without an install says nothing about reboot-needed: skip it
|
||||
if !x.RebootScanned && len(x.Upgraded) == 0 && x.Outcome != "applied" {
|
||||
return false, false // a pass that did not look says nothing about reboot-needed: skip it
|
||||
}
|
||||
return x.RebootNeeded, true
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user