From 7e9ae9f07e1c5951dcc3e096e8b8de527ed4b59d Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 6 Oct 2026 16:47:49 +0200 Subject: [PATCH] Carry the controller's new self-check grant; stop telling people to delete kept data (hq ADR 0233) The installer's first user list must match the controller's composed grant, which now reads every machine's backup holder; and a kept directory's report pointed at the one act that loses data. --- examples/foundation-first-node-nats.lock | 2 +- internal/apply/apply.go | 9 +++++++-- internal/apply/apply_test.go | 6 ++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/examples/foundation-first-node-nats.lock b/examples/foundation-first-node-nats.lock index 6db0542..ead533b 100644 --- a/examples/foundation-first-node-nats.lock +++ b/examples/foundation-first-node-nats.lock @@ -161,7 +161,7 @@ "type": "file", "path": "/var/lib/mesh-bus-conf/accounts.conf", "mode": "0600", - "content": "// The first user list, carried by the installer because at genesis there is no mesh to\n// compose one. A bootstrap credential, rotated with the store's and replaced by the\n// controller's own composition from its first start onward.\naccounts {\n MESH {\n jetstream: enabled\n users = [\n { user: \"controller\", password: \"$2a$10$AHqJgOifIVbU41KmATiMhuXFs8xa7Wl2HuN4UVBCXdN2jIQzjqApy\", permissions: {\n publish: { allow: [\"$JS.ACK.CONTROL.controller.>\", \"$JS.ACK.EVENTS.controller.>\", \"$JS.API.>\", \"$KV.mesh-controller_calls.>\", \"$KV.mesh-controller_hand-acts.>\", \"$KV.mesh-controller_conditions.>\", \"$KV.mesh-controller_condition-history.>\", \"$KV.mesh-controller_lease.>\", \"$KV.SEAT_MESH_BUILD_MACHINE_cancelled.>\", \"$KV.SEAT_NODE_BUILD_AGENT_cancelled.>\", \"_INBOX.enrol.>\", \"mesh.assignment.>\", \"mesh.mod.*.tool.>\", \"mesh.node.>\", \"mesh.seat.mesh-build-machine.accept.>\", \"mesh.seat.node-build-agent.accept.>\", \"mesh.seat.mesh-build-machine.tool.>\", \"mesh.seat.node-build-agent.tool.>\", \"mesh.seat.mesh-controller.event.applied\", \"mesh.seat.mesh-controller.event.built-before\", \"mesh.seat.mesh-controller.event.refused\", \"mesh.seat.mesh-controller.event.condition-raised\", \"mesh.seat.mesh-controller.event.condition-changed\", \"mesh.seat.mesh-controller.event.condition-cleared\", \"mesh.seat.mesh-controller.event.doctor-heartbeat\", \"mesh.seat.mesh-controller.event.secret-replaced\", \"mesh.seat.mesh-controller.event.healer-acted\", \"$SRV.INFO\", \"mesh.seat.node-intrusion-prevention.tool.banned.*\"] }\n subscribe: { allow: [\"$JS.API.>\", \"$JS.EVENT.ADVISORY.CONSUMER.MAX_DELIVERIES.>\", \"$JS.EVENT.ADVISORY.CONSUMER.DELETED.>\", \"_DELIVER.controller\", \"_DELIVER.controller.>\", \"_INBOX.controller.>\", \"mesh.control.>\", \"mesh.mod.*.event.provisioner.failing\", \"mesh.mod.*.event.provisioner.recovered\", \"mesh.mod.*.event.provisioner.retirement\", \"mesh.mod.gitea.event.pull.merged\", \"mesh.mod.mesh-catalog.event.catching-up\", \"mesh.mod.mesh-catalog.event.upgraded\", \"mesh.seat.mesh-build-machine.event.built\", \"mesh.seat.node-build-agent.event.built\", \"mesh.seat.mesh-controller.tool.>\", \"$SRV.PING\", \"$SRV.INFO\", \"$SRV.PING.mesh-controller\", \"$SRV.PING.mesh-controller.>\", \"$SRV.INFO.mesh-controller\", \"$SRV.INFO.mesh-controller.>\", \"$SRV.STATS\", \"$SRV.STATS.mesh-controller\", \"$SRV.STATS.mesh-controller.>\"] }\n allow_responses: { max: 1, ttl: \"1m\" }\n } }\n ]\n }\n}\n" + "content": "// The first user list, carried by the installer because at genesis there is no mesh to\n// compose one. A bootstrap credential, rotated with the store's and replaced by the\n// controller's own composition from its first start onward.\naccounts {\n MESH {\n jetstream: enabled\n users = [\n { user: \"controller\", password: \"$2a$10$AHqJgOifIVbU41KmATiMhuXFs8xa7Wl2HuN4UVBCXdN2jIQzjqApy\", permissions: {\n publish: { allow: [\"$JS.ACK.CONTROL.controller.>\", \"$JS.ACK.EVENTS.controller.>\", \"$JS.API.>\", \"$KV.mesh-controller_calls.>\", \"$KV.mesh-controller_hand-acts.>\", \"$KV.mesh-controller_conditions.>\", \"$KV.mesh-controller_condition-history.>\", \"$KV.mesh-controller_lease.>\", \"$KV.SEAT_MESH_BUILD_MACHINE_cancelled.>\", \"$KV.SEAT_NODE_BUILD_AGENT_cancelled.>\", \"_INBOX.enrol.>\", \"mesh.assignment.>\", \"mesh.mod.*.tool.>\", \"mesh.node.>\", \"mesh.seat.mesh-build-machine.accept.>\", \"mesh.seat.node-build-agent.accept.>\", \"mesh.seat.mesh-build-machine.tool.>\", \"mesh.seat.node-build-agent.tool.>\", \"mesh.seat.mesh-controller.event.applied\", \"mesh.seat.mesh-controller.event.built-before\", \"mesh.seat.mesh-controller.event.refused\", \"mesh.seat.mesh-controller.event.condition-raised\", \"mesh.seat.mesh-controller.event.condition-changed\", \"mesh.seat.mesh-controller.event.condition-cleared\", \"mesh.seat.mesh-controller.event.doctor-heartbeat\", \"mesh.seat.mesh-controller.event.secret-replaced\", \"mesh.seat.mesh-controller.event.healer-acted\", \"$SRV.INFO\", \"mesh.seat.node-intrusion-prevention.tool.banned.*\", \"mesh.seat.node-backup.tool.backed-up.*\"] }\n subscribe: { allow: [\"$JS.API.>\", \"$JS.EVENT.ADVISORY.CONSUMER.MAX_DELIVERIES.>\", \"$JS.EVENT.ADVISORY.CONSUMER.DELETED.>\", \"_DELIVER.controller\", \"_DELIVER.controller.>\", \"_INBOX.controller.>\", \"mesh.control.>\", \"mesh.mod.*.event.provisioner.failing\", \"mesh.mod.*.event.provisioner.recovered\", \"mesh.mod.*.event.provisioner.retirement\", \"mesh.mod.gitea.event.pull.merged\", \"mesh.mod.mesh-catalog.event.catching-up\", \"mesh.mod.mesh-catalog.event.upgraded\", \"mesh.seat.mesh-build-machine.event.built\", \"mesh.seat.node-build-agent.event.built\", \"mesh.seat.mesh-controller.tool.>\", \"$SRV.PING\", \"$SRV.INFO\", \"$SRV.PING.mesh-controller\", \"$SRV.PING.mesh-controller.>\", \"$SRV.INFO.mesh-controller\", \"$SRV.INFO.mesh-controller.>\", \"$SRV.STATS\", \"$SRV.STATS.mesh-controller\", \"$SRV.STATS.mesh-controller.>\"] }\n allow_responses: { max: 1, ttl: \"1m\" }\n } }\n ]\n }\n}\n" }, { "id": "broker", diff --git a/internal/apply/apply.go b/internal/apply/apply.go index c1af80e..b2ff24f 100644 --- a/internal/apply/apply.go +++ b/internal/apply/apply.go @@ -1615,10 +1615,15 @@ func remove(ctx context.Context, sys system.System, a store.Applied, run Runner, if err != nil { return "", "", err } + // **And it is never removed by hand on this host's word** (novox/hq ADR 0233). What a module + // declares as its data the controller retires — kept, listed by `cleanup list` — and only a + // person's `cleanup delete` removes it, after a last restore point. This line used to say + // "remove it by hand", which is the one instruction that takes the restore point away. if len(entries) > 0 { return "kept", fmt.Sprintf( - "no longer declared, and %d item(s) inside that the mesh did not put there — "+ - "remove it by hand once you know what it is", len(entries)), nil + "no longer declared, and %d item(s) inside that the mesh did not put there — kept: an "+ + "unassignment never deletes data; if it is a module's declared data the mesh retires it "+ + "(`cleanup list`), and only `cleanup delete` removes it", len(entries)), nil } if err := os.Remove(a.Target); err != nil { return "", "", err diff --git a/internal/apply/apply_test.go b/internal/apply/apply_test.go index fdde6c0..b5a11d4 100644 --- a/internal/apply/apply_test.go +++ b/internal/apply/apply_test.go @@ -1565,6 +1565,12 @@ func TestADirectoryHoldingAnythingTheMeshDidNotPutThereIsKept(t *testing.T) { for _, o := range report.Outcomes { if o.Action == "kept" && strings.Contains(o.Detail, "did not put there") { said = true + // And it says how data goes, which is never by hand on this line's word (novox/hq ADR + // 0233): a person's `cleanup delete`, after a last restore point. + if strings.Contains(o.Detail, "by hand") || !strings.Contains(o.Detail, "never deletes data") || + !strings.Contains(o.Detail, "cleanup delete") { + t.Errorf("the kept directory is said as %q", o.Detail) + } } } if !said {