hub v0.159.0 (R-1154, after security review): the enroll reuse path re-issues nothing, it warns the operator

The first draft (5121536f, unpushed) re-issued the claim code and the off-site login on a
reuse whose old box was stale or switched off. A security review flagged it: the caller
holds only the household's retrieval passphrase, and both re-issues are operator
session-only actions (05 section 17.5, 09 decision 252, R-1055/R-1059). Now the reuse
path classifies the old box and re-issues nothing: gone -> host_reinstall_over_old_host
(warning, mailed to the operator: delete the old host and re-run, or re-issue by hand);
live -> host_reenroll_while_live (info). The mint path after the operator's delete is
unchanged and still re-issues. The once-per-silence record and the claim engine comment
edit are reverted. 05 section 8, README and CHANGELOG updated; tests red-proved.
This commit is contained in:
admin committed 2026-10-19 03:29:44 +02:00
1 parent 5121536f10
commit b505ce4ba0
9 files changed
+265 -268

No files matched your search

+6 -6
View File
@@ -890,12 +890,12 @@ var operatorOnlyEvents = map[string]bool{
// since v0.44.0, and only configuration (enabled_events) made that true — the R-97c shape. Now structural.
"agent_capability_degraded": true,
"agent_capability_recovered": true,
// R-1154 (v0.159.0): a host-enroll that reused the old host record — re-issued the clean-slate credentials, or
// did NOT because the box is live. Info (recorded, never mailed), host ids and report ages: the operator's
// record. Hub-origin only (api/reenroll.go; not in api.allowedEventTypes — a box must not plant the
// once-per-silence record). Listed in the SAME commit that mints them.
"host_reenroll_reissued": true,
"host_reenroll_not_reissued": true,
// R-1154 (v0.159.0): a host-enroll that reused the old host record — a reinstall over it (warning: the operator
// deletes the old host or re-issues by hand) or a live box enrolling again (info). Host ids, report ages, and an
// instruction only the operator can carry out. Hub-origin only (api/reenroll.go; not in api.allowedEventTypes).
// Listed in the SAME commit that mints them.
"host_reinstall_over_old_host": true,
"host_reenroll_while_live": true,
}
// IsOperatorOnly reports whether an event type is barred from customer dispatch. Exported so the
@@ -15,7 +15,8 @@ import "testing"
//
// Restored.
func TestR1150_RefusedBackupAndCapabilityEventsNeverReachTheCustomer(t *testing.T) {
for _, et := range []string{"whole_guest_backup_refused", "agent_capability_degraded"} {
// R-1154 (v0.159.0): the reinstall-over-the-old-host warning rides the same register and the same proof.
for _, et := range []string{"whole_guest_backup_refused", "agent_capability_degraded", "host_reinstall_over_old_host"} {
st := opOnlyStore(t)
if err := st.SaveNotificationPrefs("c1", "customer@example.com", []string{et}, 6); err != nil {
t.Fatalf("SaveNotificationPrefs: %v", err)
@@ -35,7 +36,7 @@ func TestR1150_RefusedBackupAndCapabilityEventsNeverReachTheCustomer(t *testing.
t.Errorf("%s: the operator was not mailed — the guard must be customer-only", et)
}
}
for _, et := range []string{"whole_guest_backup_refusal_cleared", "agent_capability_recovered"} {
for _, et := range []string{"whole_guest_backup_refusal_cleared", "agent_capability_recovered", "host_reenroll_while_live"} {
if !operatorOnlyEvents[et] {
t.Errorf("%s must be operator-only (the pair's other edge)", et)
}