diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e64632..0d303ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,69 @@ +## v0.174.0 (2026-11-14) — the box removes its old kernels (R-1368); security profiles are refreshed after a kernel change (R-1388, R-1301); Go 1.27.4 (R-1391) — RELEASED 2026-11-14 (release-agent.sh from the clean working clone at `cc63dd5`, CI run id 2641; agent sha256 6efbb97809135483bc446d71d1321f9e2f7fc3268fe9b20e7fe742a2eb13db92, bundle sha256 7d87d0584dee79eee766f01c27b9e89273d39c89a14b0725a6e5564a55b3ec5f) and VOUCHED 2026-11-14 15:21:45 CET + +Release 2a of the build order (felhom.eu `09` §3 decision 306). Design: felhom.eu `11-os-updates.md` §5.11.1 and §5.12. +`configs/` changed (the wrapper), so a box needs BOTH signed jobs: `agent_update`, then `agent_config_update`. + +**Part A — old kernels (`09` §3 decision 286).** Nothing removed old kernels; a ring-0 box got about one a week, 1 GB +each. Now: + +- **The wrapper** (`configs/felhom-os-apply`, layer `kernel`, new mode `kernel-cleanup`): the hand-proven rule of + 2026-11-10 as a program. Keep the running kernel, the step's `from`, `to` and `default_before`, both defaults, the + flag's kernel, an operator's boot pin and the newest installed; remove every other installed kernel image in ONE + `apt-get purge` by exact name. Refusals P1, P2, P3, K1, N1, S1, S2 (the design's table), C1 (the plan names + something — it may carry only `dry_run`), R9, R12. „Not run" (exit 0): no root-owned ring-0 mark, no kernel step yet, + the newest step did not end `good`, the box does not run its newest kernel, a step within the last 20 hours. K1 reads + the box a second time, by itself. Repair-first. After the purge it proves the default, the pinned file, the two + generators and the state file unchanged; a left-over folder is reported, never deleted. **Rule R4 and every update + plan are unchanged; `apt-get autoremove` is not used.** +- **The agent** (`internal/osupdate/kernel.go`): the clean-up is the night leg's last call, after a healthy host step, + never in a night with a kernel step, never in a debug pass, never on a BYO host. The hub hears `cleaned`, `refused` + or `failed` (a kernel-layer report with NO kernel version — the hub would read that as a kernel step); „nothing to + remove" and „not run" are log lines. `--selftest=kernel-cleanup-dry-run` prints what it would do and changes nothing. +- **No new sudo line.** The wrapper is reached by the one `--plan` line (pinned by `test_cleanup_needs_no_new_sudo_line`). + +**Part B — security profiles (spike first: felhom.eu `audits/profile-refresh-spike-2026-11-14/`).** After a kernel +went back and forth a box can load an old compiled AppArmor profile; on the N100 this stopped the time service. + +- **The wrapper**, new host-layer mode `profile-refresh` (an appliance only; no package change; the plan names + nothing, F1): once per kernel the box starts on (a root-owned record), `apparmor_parser --replace --skip-read-cache + --write-cache -- /etc/apparmor.d`; then ONE restart for a `failed` service whose own program's cached profile the + rewrite changed (at most 3). Measured on demo-hp: 0.5 s, no guest or container touched. +- **The agent** (`internal/osupdate/profilerefresh.go`) asks at every start and after a config bundle install, under + the heavy-op gate; nothing is sent to the hub. + +**Part C — Go 1.27.4** (GO-2026-6859; hygiene: the agent's one `MaxBytesReader` place does not match the advisory). + +**Tests, each seen red** (felhom.eu `audits/release-2a-2026-11-14/A/redproof*.txt`, `B/redproof*.txt`): 31 wrapper +cases for the clean-up, one per acceptance scenario and one per kept-kernel kind (14 mutations, all red); 11 for the +profile refresh (10 mutations); 5 + 4 agent tests (3 + 3 mutations). Two existing agent tests list the night's calls +exactly and gained the clean-up call (`TestRing0_OneCallPerLayer`, `TestRing1_NoReleaseIsInventory`). + +**Delivered 2026-11-14 to the three test boxes by signed `agent_update` + `agent_config_update` each** (Tester 1, +demo-hp, the N100): update committed, bundle installed (written 1 of 31), capability probe 77/77, the running binary +reads `go1.27.4`. **On boxes** (felhom.eu `audits/release-2a-2026-11-14/D/`): + +- **Profile refresh, by the product's own path, on all three:** refused by the OLD wrapper at the agent's start + (R11, logged), then run right after the bundle install: 0.5 s each, nothing restarted on Tester 1 and demo-hp. + **On the N100 it repaired the time service:** the cached chrony profile was rewritten, `chrony.service` (failed + since 2026-10-16) was restarted and is active, the clock stepped +32.7 s; offset to DooPlex −32.55 s → +0.18 s. After + a restart of Tester 1 the agent answered „not needed" (the same kernel). +- **Clean-up:** dry runs through the released agent on all three (demo-hp: nothing to remove; the N100: 6 of 8 will + go tonight; Tester 1: „not run", it has no ring-0 mark). Refusals P1, P2 and P3 by dry run on demo-hp against states + set and put back. **A real removal on Tester 1**, with the ring-0 mark set for the test on the operator's yes and + put back: `proxmox-kernel-7.0.14-20-pve-signed` removed, 1.12 GB gained, 8.5 s, the default, the pinned file, the + generators and the state file unchanged, no left-over; the second call removed nothing; one orderly restart came + back on the same kernel, healthy, a clean stop for the crash guard. **This real run was started by hand** (the + agent user, the one sudo line, the night leg's own plan), not by the night leg. +- **Not proven:** the step by the agent at night (the N100's and demo-hp's own night, 2026-11-15); a box whose running + kernel is not its newest and a self-revert into the kept kernel (tests only); refusal K1 on a box (it guards a wrong + computation; tests only); a restart by the profile refresh of any program but chrony. +- **Found:** a clock step makes the CONTROLLER read a new boot (its boot identity is `/proc/stat` btime): on the N100 + it recreated its three drive-backed apps 9 s after the step (felhom.eu R-1395). The crash guard (kernel `boot_id`) + was not fooled. + +**Vouched by the operator 2026-11-14 15:21:45 CET** (the hub log: `Artifact manifest set: agent=0.174.0`, the bundle +sha = the release; the hub's System page: „vouched agent: 0.174.0"). `pinned.day0_agent` = 0.174.0 (D50). + ## Unreleased (2026-11-11) — docs only: a repository address holds no credential (R-925, Part C of the clock/end-dates run) - `scripts/release-agent.sh` header: the tag push needs `GITEA_GIT_TOKEN` from the secret store (`sec run`). The origin diff --git a/CONTEXT.md b/CONTEXT.md index c064e92..cc9e8af 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -1,5 +1,7 @@ # CONTEXT — felhom-agent working state +> **2026-11-14 (day, attended) — v0.174.0 RELEASED and VOUCHED (15:21:45 CET); on the three test boxes (agent + bundle, 77/77).** sha `6efbb978…`, bundle `7d87d058…`. Two new wrapper modes: `kernel-cleanup` (layer kernel; old kernel images by the hand-proven rule; ring-0 mark only; the plan names nothing; the night leg's last call, never with a kernel step) and `profile-refresh` (layer host; AppArmor profiles from a fresh compile once per kernel; one restart for a failed service whose cached profile was stale). Go 1.27.4. The N100's time service was repaired by the product path (+32.7 s step). A real kernel removal ran on Tester 1 by hand with a temporary ring-0 mark (operator's yes). **Next:** read the N100's and demo-hp's night (the clean-up by the agent at night is not proven yet); a ruling for ring-1 boxes; release 2b (trust in Proxmox by the root CA copy, D80). Report: felhom.eu `REPORT-release-2a-2026-11-14.md`. + > **2026-11-10 (afternoon, attended) — v0.173.0 RELEASED and VOUCHED (16:29:16 CET); on the three test boxes.** sha `752b2727…`, bundle `51ebc1f4…` (`configs/` unchanged since 0.172.1, so no bundle job). Measured: a box cleans its self-update folder at the commit of the update that BRINGS the code (49 → 1, 48 → 1, 33 → 1 entries; about 16 MB stays). The line below („at the first good update AFTER that release") was wrong. A rollback after the clean-up was proven on Tester 1 with a signed update to 0.172.1 and one crash in the dwell. `pinned.day0_agent` = 0.173.0. Open: the `.bak-*` files (R-1368 part 4). > **2026-11-10 (day, operator brief) — COMMITTED, NOT RELEASED: the self-update folder cleans itself (R-1368 part 2).** After a healthy `commit` the agent removes every staged binary but the running version's (`internal/selfupdate/prune.go`; tests `TestPrune_*`, the wrapper's real `rollback` verb run in a sandbox). No version bump, no build, no vouch: it rides the next agent release. A box cleans its folder at the first good update AFTER that release. Not reached: `/usr/local/bin/felhom-agent.bak-*` (root-owned, R-1368 part 4). The old-kernel clean-up is a design only (felhom.eu `11-os-updates.md` §5.11.1, proven by hand on demo-hp); nothing of it is in this repo. diff --git a/REPORT.md b/REPORT.md index 0f090eb..714f10f 100644 --- a/REPORT.md +++ b/REPORT.md @@ -1,56 +1,31 @@ -# REPORT — v0.173.0 released, vouched and delivered to the three test boxes (2026-11-10, attended) +# REPORT — v0.174.0 released, vouched and delivered to the three test boxes (2026-11-14, attended) -**Plain words first.** Each agent update left its downloaded file on the box for ever. Version 0.173.0 removes the old -files after an update that ended well. It is released and it runs on the three test boxes. The folders went from -49, 48 and 33 files to 1 file each. A rollback still works after the clean-up. The operator vouched it at 16:29 CET. +**Plain words first.** A box now removes its old kernels by itself, and it reloads its security profiles after it +starts on another kernel. Version 0.174.0 is released and runs on Tester 1, demo-hp and the N100. The operator vouched +it at 15:21 CET. The N100's time service runs again; the product repaired it, with no hand step. -The full report of the run is in `felhom.eu`: `REPORT-release-space-fixes-2026-11-10.md`. +The full report of the run is in `felhom.eu`: `REPORT-release-2a-2026-11-14.md`. -## One claim that was wrong +## What a reader must know -The CHANGELOG entry and the report of the morning said: a box cleans its folder at the first good update AFTER the -release. That was wrong. The commit runs in the new binary. So the box cleans the folder at the commit of the update -that brings the code. Measured on three boxes; the CHANGELOG entry is corrected. - -## The release +1. **The clean-up runs on a box with the root-owned ring-0 mark only.** Tester 1 has no mark, so the program answers + „not run" there. For the proof the operator allowed the mark on Tester 1 for some minutes; it is back as before. +2. **The real removal on Tester 1 was started by hand**, with the agent's own command line. The night leg cannot be + started by day: it follows only the night's own backup (R-899). So „the step by the agent at night" is **not proven + yet**; the N100's and demo-hp's night of 2026-11-15 is the proof. +3. **The profile refresh was spiked first** on demo-hp (felhom.eu `audits/profile-refresh-spike-2026-11-14/`). Three + things it found are built in: a stale copy is told by the cached file changing, not by the kernel's hash; one + profile never compiles the same twice; a refresh hides other kernel audit lines for a few seconds. +4. **A clock step makes the controller read a new boot** (felhom.eu R-1395, a controller row): on the N100 it + recreated three apps once. | | | |---|---| -| Version | 0.173.0, `scripts/release-agent.sh` from a clean clone of `776025c8` (tag `v0.173.0`) | -| Agent sha256 | `752b2727fb6043417ae5f342acbda52330521b21bb799fda90760b960feef7ea` | -| Bundle sha256 | `51ebc1f4c66d87918c87c035b4297c0e40e10ed31e3250c3837dfeaa0002e1c1` | -| CI | `776025c8`: run 2608, `gates #311`, success (read by commit on the public Actions page) | -| Delivery | one signed `agent_update` per box. No bundle job: `configs/` did not change since v0.172.1 | -| Vouch | the operator, 2026-11-10 16:29:16 CET. Read from the hub log: `Artifact manifest set: agent=0.173.0`, bundle sha = the release. `pinned.day0_agent` = 0.173.0 (D50) | - -## The folder `/var/lib/felhom-agent/selfupdate`, before and after - -| Box | Before (on 0.172.1) | After the commit of 0.173.0 | Commit (UTC) | -|---|---|---|---| -| demo-hp | 49 entries, 722,596 KB | 1 entry, 16,028 KB | 14:59:19, `removed=49` | -| demo-felhom | 48 entries, 706,968 KB | 1 entry, 16,028 KB | 14:51:50, `removed=48` | -| Tester 1 | 33 entries, 497,244 KB | 1 entry, 16,028 KB | 15:00:19, `removed=33` | - -After each commit: `pending.json` absent, `/usr/local/bin/felhom-agent.prev` = 0.172.1, the unit active, no restart. - -## The rollback proof (Tester 1) - -1. A signed `agent_update` to 0.172.1 (the vouched version) was uploaded at 15:01:19 UTC. The box took it at its next - report, 15:14:31 UTC. The wrapper installed 0.172.1 and wrote the pending marker. -2. At 15:14:40 UTC, inside the 60-second dwell, one `systemctl kill -s SEGV` hit the agent's main process. -3. The unit's `OnFailure` ran the wrapper's `rollback`. Journal: `rolled back to previous binary and restarted - felhom-agent.service`. 0.173.0 started at 15:14:40 UTC. -4. Read at 15:15:56 UTC: agent 0.173.0, active, `pending.json` absent, no failed unit. The folder holds 2 files - (32,040 KB): the running version's and the failed 0.172.1. The failed file stays by design, until the next good - update. - -This is the path the repo already has. No second version was released for the proof. - -## What stays open - -- `/usr/local/bin/felhom-agent.bak-*` (R-1368 part 4): demo-felhom holds 11 such files, demo-hp 1. The agent cannot - reach them. -- After a rollback, `/usr/local/bin/felhom-agent.prev` holds the same version as the running binary. That is how the - wrapper works; it is not new. - -Evidence: felhom.eu `documentation/audits/release-space-fixes-2026-11-10/agent/`. +| Version | 0.174.0, sha256 `6efbb97809135483bc446d71d1321f9e2f7fc3268fe9b20e7fe742a2eb13db92`, bundle `7d87d0584dee79eee766f01c27b9e89273d39c89a14b0725a6e5564a55b3ec5f`, Go 1.27.4 | +| Code commit, CI | `cc63dd5`, run id 2641 success | +| Tests | wrapper 191 (42 new), agent `internal/osupdate` green; 30 mutations, each seen red (felhom.eu `audits/release-2a-2026-11-14/A`, `B`) | +| Tester 1 | 3 kernels → 2, 1.12 GB gained, 8.5 s; second run: nothing; one restart, same kernel, healthy, clean stop | +| demo-hp | nothing to remove; refusals P1, P2, P3 by dry run | +| The N100 | time service repaired (offset −32.55 s → +0.18 s); tonight it removes 6 of 8 kernels | +| Vouch | the operator, 2026-11-14 15:21:45 CET; `pinned.day0_agent` = 0.174.0 | +| Not proven | the step at night by the agent; a fell-back box and a self-revert into the kept kernel on a box; K1 on a box | diff --git a/scripts/retention-policy.json b/scripts/retention-policy.json index 9359ce1..fd33a8a 100644 --- a/scripts/retention-policy.json +++ b/scripts/retention-policy.json @@ -24,10 +24,10 @@ "readers": [ "scripts/check-published-versions.py — asserts the newest N versions plus every pinned version" ], - "recorded": "2026-11-10", - "recorded_by": "CC 2026-11-10: day0_agent 0.173.0 (operator vouch 2026-11-10 16:29:16 CET, read from the hub log: agent=0.173.0, bundle 51ebc1f4… = the release; the save took 232 ms); earlier 0.172.1 (CC 2026-11-07) (operator vouch 2026-11-07 ~23:00 CET, read from the hub DB with its WAL: artifact_agent_version=0.172.1, bundle 3e7acaee… = the release); earlier 0.172.0 (CC 2026-11-03) (operator vouch 2026-11-03 10:18:10 CET, read from the hub log and DB: agent=0.172.0, bundle cc34b0bc… = the release); earlier 0.171.0 (CC 2026-10-30) (operator vouch 2026-10-30 10:47:36 CET, read from the hub log: agent=0.171.0, bundle 95f977f6… = the release; the save took 132 ms with hub 0.178.0, R-1346); earlier 0.170.0 (operator vouch 2026-10-29 18:57:48 CET, read from the hub log: agent=0.170.0, bundle 03f2ff64… = the release; the save took 38.3 s, R-1346); earlier 0.169.0 (operator vouch 2026-10-29 14:06:09 CET, read from the hub log: agent=0.169.0, bundle 3ca33f9c… = the release; his browser got a 504 but the save went through); earlier 0.168.0 (vouch 10:21:56 CET); 0.167.0 (vouch 2026-10-27); 0.166.0 (vouch 2026-10-26 10:04:55 CET); D50 = A (operator 2026-10-25); earlier history: R-287 (2026-08-09), R-291 (2026-10-05)", + "recorded": "2026-11-14", + "recorded_by": "CC 2026-11-14: day0_agent 0.174.0 (operator vouch 2026-11-14 15:21:45 CET, read from the hub log and from the hub's System page: agent=0.174.0, bundle 7d87d058… = the release; the save took 428 ms); earlier 0.173.0 (CC 2026-11-10) (operator vouch 2026-11-10 16:29:16 CET, read from the hub log: agent=0.173.0, bundle 51ebc1f4… = the release; the save took 232 ms); earlier 0.172.1 (CC 2026-11-07) (operator vouch 2026-11-07 ~23:00 CET, read from the hub DB with its WAL: artifact_agent_version=0.172.1, bundle 3e7acaee… = the release); earlier 0.172.0 (CC 2026-11-03) (operator vouch 2026-11-03 10:18:10 CET, read from the hub log and DB: agent=0.172.0, bundle cc34b0bc… = the release); earlier 0.171.0 (CC 2026-10-30) (operator vouch 2026-10-30 10:47:36 CET, read from the hub log: agent=0.171.0, bundle 95f977f6… = the release; the save took 132 ms with hub 0.178.0, R-1346); earlier 0.170.0 (operator vouch 2026-10-29 18:57:48 CET, read from the hub log: agent=0.170.0, bundle 03f2ff64… = the release; the save took 38.3 s, R-1346); earlier 0.169.0 (operator vouch 2026-10-29 14:06:09 CET, read from the hub log: agent=0.169.0, bundle 3ca33f9c… = the release; his browser got a 504 but the save went through); earlier 0.168.0 (vouch 10:21:56 CET); 0.167.0 (vouch 2026-10-27); 0.166.0 (vouch 2026-10-26 10:04:55 CET); D50 = A (operator 2026-10-25); earlier history: R-287 (2026-08-09), R-291 (2026-10-05)", "pinned": { "hub_min_agent": "0.158.1", - "day0_agent": "0.173.0" + "day0_agent": "0.174.0" } }