diff --git a/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-block-states.txt b/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-block-states.txt new file mode 100644 index 00000000..b61b1ebf --- /dev/null +++ b/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-block-states.txt @@ -0,0 +1,5 @@ +11:34:43 container=running/healthy hub=running alarm=none +11:35:45 container=running/healthy hub=running alarm=none +11:36:47 container=running/unhealthy hub=running alarm=none +11:37:49 container=running/unhealthy hub=not_running alarm=none +11:38:51 container=running/unhealthy hub=not_running alarm=none diff --git a/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-block.txt b/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-block.txt new file mode 100644 index 00000000..746f7f0a --- /dev/null +++ b/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-block.txt @@ -0,0 +1,5 @@ +block at 2026-10-04T11:34:33Z: DOCKER-USER DROP tcp+udp dport 7844 in guest 9201 on demo-hp +Chain DOCKER-USER (1 references) +target prot opt source destination +DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:7844 +DROP udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:7844 diff --git a/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-states.txt b/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-states.txt new file mode 100644 index 00000000..c3ea5231 --- /dev/null +++ b/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-states.txt @@ -0,0 +1,22 @@ +11:23:25 running +11:23:56 running +11:24:26 running +11:24:57 running +11:25:27 running +11:25:58 running +11:26:28 running +11:26:59 running +11:27:29 running +11:28:00 running +11:28:31 running +11:29:01 running +11:29:32 running +11:30:02 running +11:30:33 running +11:31:03 running +11:31:34 running +11:32:04 running +11:32:35 running +11:33:05 running +11:33:36 running +11:34:06 running diff --git a/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-stop.txt b/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-stop.txt new file mode 100644 index 00000000..9a165d0a --- /dev/null +++ b/documentation/audits/os-host-lane-2026-10-04/partA/live/demo-hp-stop.txt @@ -0,0 +1,3 @@ +stop at 2026-10-04T11:23:17Z +cloudflared +exited 0 diff --git a/documentation/audits/os-host-lane-2026-10-04/partB/live-defects-redproofs.txt b/documentation/audits/os-host-lane-2026-10-04/partB/live-defects-redproofs.txt new file mode 100644 index 00000000..940ca369 --- /dev/null +++ b/documentation/audits/os-host-lane-2026-10-04/partB/live-defects-redproofs.txt @@ -0,0 +1,36 @@ +# Live-found defects in agent 0.141.0 / hub 0.131.0 and their red-proofs, 2026-10-04T11:39:07Z + +## 1. the host restart scan hid lxc-start (cgroup 0::/lxc.monitor/9201 matched the skip pattern "lxc") +live: demo-felhom after the 108-package host pass: lxc-start had 20 deleted maps, report said reboot_needed=false +mutation: RESTART_SKIP_CGROUP host ':/lxc/' -> 'lxc' + self.assertFalse(self.grep(host, "0::/lxc.monitor/9201"), "lxc-start must NOT be skipped (it runs the guest)") + ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +AssertionError: True is not false : lxc-start must NOT be skipped (it runs the guest) + +---------------------------------------------------------------------- +Ran 1 test in 0.005s + +FAILED (failures=1) + +## 2. the host scanned only after an install, so a reboot never cleared 'reboot needed' +mutation: wrapper 'if self.layer == "host" and ...' -> 'if False and ...' +---------------------------------------------------------------------- +Ran 1 test in 0.002s + +FAILED (failures=1) + +mutation: agent leg drops rep.RebootScanned copy +=== RUN TestHostReport_CarriesRebootScanned + leg_test.go:367: hub got [{RunID:20261004T040000Z Layer:guest Trigger:night Mode:apply Ring:0 ReleaseID:ring0-20261004T040000Z Outcome:nothing Healthy:true HealthReason: VMID:9201 Upgraded:[] Inst +--- FAIL: TestHostReport_CarriesRebootScanned (0.00s) +FAIL +FAIL gitea.dooplex.hu/admin/felhom-agent/internal/osupdate 0.008s +FAIL + +mutation: hub layerLine predicate ignores RebootScanned +=== RUN TestRebootNeeded_ClearedByAScannedPass + alarms_test.go:323: a scanned pass after the reboot did not clear it: 2026-10-04 12:00:00 +0000 UTC +--- FAIL: TestRebootNeeded_ClearedByAScannedPass (0.03s) +FAIL +FAIL gitea.dooplex.hu/admin/felhom-hub/internal/osupdates 0.037s +FAIL diff --git a/documentation/audits/os-host-lane-2026-10-04/partB/live/b1-demo-felhom-ring0.log b/documentation/audits/os-host-lane-2026-10-04/partB/live/b1-demo-felhom-ring0.log new file mode 100644 index 00000000..f4461ea1 --- /dev/null +++ b/documentation/audits/os-host-lane-2026-10-04/partB/live/b1-demo-felhom-ring0.log @@ -0,0 +1,716 @@ +=== felhom-agent 0.141.0 selftest=os-update vmid=9201 ring=0 enabled=true guest-release=false host-release=false appliance=true === +time=2026-10-04T13:34:48.263+02:00 level=INFO msg="osupdate: START" run=20261004T113448Z layer=guest vmid=9201 ring=0 trigger=debug enabled=true release=ring0-20261004T113448Z +time=2026-10-04T13:34:59.917+02:00 level=INFO msg="osupdate: wrapper" line="os-apply: START release=ring0-20261004T113448Z layer=guest:9201 lane=fast mode=apply select=pending-fast packages=0" +time=2026-10-04T13:34:59.917+02:00 level=INFO msg="osupdate: wrapper" line="os-apply: REPAIR configured=0 fixed=0" +time=2026-10-04T13:34:59.917+02:00 level=INFO msg="osupdate: wrapper" line="os-apply: PLAN upgrade=0 already=0 not-installed=0 from-snapshot=0" +time=2026-10-04T13:34:59.917+02:00 level=INFO msg="osupdate: wrapper" line="os-apply: DONE rc=0 seconds=0 upgraded=0 (nothing to do)" +time=2026-10-04T13:34:59.917+02:00 level=INFO msg="osupdate: DONE" run=20261004T113448Z layer=guest vmid=9201 ring=0 trigger=debug outcome=nothing healthy=true reason="" upgraded=0 pending=6 not_covered=6 restart_needed=0 reboot_needed=false wrapper_seconds=11.6 +time=2026-10-04T13:34:59.927+02:00 level=INFO msg="osupdate: START" run=20261004T113448Z layer=host vmid=9201 ring=0 trigger=debug enabled=true release=ring0-20261004T113448Z +time=2026-10-04T13:35:57.810+02:00 level=INFO msg="osupdate: wrapper" line="os-apply: START release=ring0-20261004T113448Z layer=host lane=fast mode=apply select=pending-fast packages=0" +time=2026-10-04T13:35:57.810+02:00 level=INFO msg="osupdate: wrapper" line="os-apply: REPAIR configured=0 fixed=0" +time=2026-10-04T13:35:57.810+02:00 level=INFO msg="osupdate: wrapper" line="os-apply: PLAN upgrade=108 already=0 not-installed=0 from-snapshot=0" +time=2026-10-04T13:35:57.810+02:00 level=INFO msg="osupdate: wrapper" line="os-apply: CONFFILE updated /etc/debian_version (it was not changed locally)" +time=2026-10-04T13:35:57.810+02:00 level=INFO msg="osupdate: wrapper" line="os-apply: DONE rc=0 seconds=41.1 upgraded=108 restart-needed=(sd-pam),agetty,bash,blkmapd,chronyd,cron,dbus-daemon,dmeventd,felhom-agent,felhom-os-apply,ksmtuned,pmxcfs,proxmox-firewal,pve-firewall,pve-ha-crm,pve-ha-lrm,pvedaemon,pvedaemon worke,pvefw-logger,pveproxy,pveproxy worker,pvescheduler,pvestatd,qmeventd,rpcbind,rrdcached,smartd,spiceproxy,spiceproxy work,sshd,sshd-session,sudo,systemd-logind,systemd-udevd,watchdog-mux,zed reboot-needed=no" +time=2026-10-04T13:35:58.613+02:00 level=INFO msg="osupdate: DONE" run=20261004T113448Z layer=host vmid=9201 ring=0 trigger=debug outcome=applied healthy=true reason="" upgraded=108 pending=80 not_covered=80 restart_needed=36 reboot_needed=false wrapper_seconds=57.8 + --- os-update report (guest) --- + { + "health_reason": "", + "healthy": true, + "mode": "apply", + "not_covered": [ + "docker-ce-cli", + "containerd.io", + "docker-ce", + "docker-buildx-plugin", + "docker-ce-rootless-extras", + "docker-compose-plugin" + ], + "outcome": "nothing", + "pending": 6, + "reboot_needed": false, + "refused": null, + "release_id": "ring0-20261004T113448Z", + "restart_needed": null, + "ring": 0, + "run_id": "20261004T113448Z", + "upgraded": [], + "wrapper_seconds": 11.6 + } + --- os-update report (host) --- + { + "health_reason": "", + "healthy": true, + "mode": "apply", + "not_covered": [ + "frr", + "shim-signed-common", + "shim-unsigned", + "shim-helpers-amd64-signed", + "shim-signed", + "libradosstriper1", + "librgw2", + "ceph-common", + "librbd1", + "librados2", + "python3-cephfs", + "libcephfs2", + "python3-rgw", + "python3-rados", + "python3-ceph-argparse", + "python3-ceph-common", + "python3-rbd", + "ceph-fuse", + "chrony", + "libcorosync-common4", + "libcfg7", + "libcmap4", + "libcpg4", + "libknet1t64", + "libnozzle1t64", + "libquorum5", + "libvotequorum8", + "corosync", + "frr-pythontools", + "libjs-extjs", + "libnvpair3linux", + "libproxmox-acme-plugins", + "libproxmox-backup-qemu0", + "pve-qemu-kvm", + "libpve-notify-perl", + "libpve-cluster-api-perl", + "libpve-cluster-perl", + "pve-cluster", + "libpve-access-control", + "libpve-apiclient-perl", + "librados2-perl", + "proxmox-backup-client", + "proxmox-backup-file-restore", + "pve-manager", + "libproxmox-acme-perl", + "libpve-common-perl", + "libpve-guest-common-perl", + "qemu-server", + "libpve-storage-perl", + "pve-edk2-firmware-legacy", + "pve-edk2-firmware-ovmf", + "libpve-network-api-perl", + "libpve-network-perl", + "proxmox-firewall-data", + "pve-firewall", + "pve-container", + "pve-ha-manager", + "novnc-pve", + "proxmox-enterprise-support-keyring", + "proxmox-mini-journalreader", + "proxmox-widget-toolkit", + "pve-docs", + "pve-i18n", + "pve-xtermjs", + "pve-yew-mobile-i18n", + "pve-yew-mobile-gui", + "libuutil3linux", + "libzfs7linux", + "libzpool7linux", + "proxmox-first-boot", + "pve-firmware", + "proxmox-kernel-7.0.14-20-pve-signed", + "proxmox-kernel-7.0", + "proxmox-kernel-helper", + "pve-edk2-firmware-aarch64", + "pve-edk2-firmware", + "zfs-initramfs", + "zfsutils-linux", + "zfs-zed", + "tailscale" + ], + "outcome": "applied", + "pending": 80, + "reboot_needed": false, + "refused": null, + "release_id": "ring0-20261004T113448Z", + "restart_needed": [ + "(sd-pam)", + "agetty", + "bash", + "blkmapd", + "chronyd", + "cron", + "dbus-daemon", + "dmeventd", + "felhom-agent", + "felhom-os-apply", + "ksmtuned", + "pmxcfs", + "proxmox-firewal", + "pve-firewall", + "pve-ha-crm", + "pve-ha-lrm", + "pvedaemon", + "pvedaemon worke", + "pvefw-logger", + "pveproxy", + "pveproxy worker", + "pvescheduler", + "pvestatd", + "qmeventd", + "rpcbind", + "rrdcached", + "smartd", + "spiceproxy", + "spiceproxy work", + "sshd", + "sshd-session", + "sudo", + "systemd-logind", + "systemd-udevd", + "watchdog-mux", + "zed" + ], + "ring": 0, + "run_id": "20261004T113448Z", + "upgraded": [ + { + "name": "libc6", + "version": "2.41-12+deb13u4", + "origin": "" + }, + { + "name": "base-files", + "version": "13.8+deb13u7", + "origin": "" + }, + { + "name": "bash", + "version": "5.2.37-2+b10", + "origin": "" + }, + { + "name": "bsdutils", + "version": "1:2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "gzip", + "version": "1.13-1+deb13u1", + "origin": "" + }, + { + "name": "libperl5.40", + "version": "5.40.1-6+deb13u1", + "origin": "" + }, + { + "name": "perl", + "version": "5.40.1-6+deb13u1", + "origin": "" + }, + { + "name": "perl-base", + "version": "5.40.1-6+deb13u1", + "origin": "" + }, + { + "name": "perl-modules-5.40", + "version": "5.40.1-6+deb13u1", + "origin": "" + }, + { + "name": "liblastlog2-2", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "eject", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "bsdextrautils", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "util-linux-extra", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "fdisk", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "libsmartcols1", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "libblkid1", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "libmount1", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "mount", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "libuuid1", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "util-linux", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "libfdisk1", + "version": "2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "libaudit-common", + "version": "1:4.0.2-2+deb13u1", + "origin": "" + }, + { + "name": "libaudit1", + "version": "1:4.0.2-2+deb13u1", + "origin": "" + }, + { + "name": "sqlite3", + "version": "3.46.1-7+deb13u2", + "origin": "" + }, + { + "name": "libsqlite3-0", + "version": "3.46.1-7+deb13u2", + "origin": "" + }, + { + "name": "libc-bin", + "version": "2.41-12+deb13u4", + "origin": "" + }, + { + "name": "login", + "version": "1:4.16.0-2+really2.41.5-0+deb13u1", + "origin": "" + }, + { + "name": "logsave", + "version": "1.47.2-3+b12", + "origin": "" + }, + { + "name": "libext2fs2t64", + "version": "1.47.2-3+b12", + "origin": "" + }, + { + "name": "e2fsprogs", + "version": "1.47.2-3+b12", + "origin": "" + }, + { + "name": "dnsmasq-base", + "version": "2.91-1+deb13u2", + "origin": "" + }, + { + "name": "dnsmasq", + "version": "2.91-1+deb13u2", + "origin": "" + }, + { + "name": "libcap2", + "version": "1:2.75-10+deb13u1+b3", + "origin": "" + }, + { + "name": "libpcre2-8-0", + "version": "10.46-1~deb13u3", + "origin": "" + }, + { + "name": "libpcre2-posix3", + "version": "10.46-1~deb13u3", + "origin": "" + }, + { + "name": "libexpat1", + "version": "2.8.3-1~deb13u1", + "origin": "" + }, + { + "name": "openssl-provider-legacy", + "version": "3.5.7-1~deb13u3", + "origin": "" + }, + { + "name": "libssl3t64", + "version": "3.5.7-1~deb13u3", + "origin": "" + }, + { + "name": "postfix", + "version": "3.10.13-0+deb13u1", + "origin": "" + }, + { + "name": "python3.13", + "version": "3.13.5-2+deb13u5", + "origin": "" + }, + { + "name": "libpython3.13-stdlib", + "version": "3.13.5-2+deb13u5", + "origin": "" + }, + { + "name": "python3.13-minimal", + "version": "3.13.5-2+deb13u5", + "origin": "" + }, + { + "name": "libpython3.13-minimal", + "version": "3.13.5-2+deb13u5", + "origin": "" + }, + { + "name": "tzdata", + "version": "2026c-0+deb13u1", + "origin": "" + }, + { + "name": "liblzma5", + "version": "5.8.1-1+deb13u1", + "origin": "" + }, + { + "name": "rsync", + "version": "3.5.0+ds1-0+deb13u1", + "origin": "" + }, + { + "name": "openssl", + "version": "3.5.7-1~deb13u3", + "origin": "" + }, + { + "name": "dhcpcd-base", + "version": "1:10.1.0-11+deb13u4", + "origin": "" + }, + { + "name": "libgssapi-krb5-2", + "version": "1.21.3-5+deb13u1", + "origin": "" + }, + { + "name": "libkrb5-3", + "version": "1.21.3-5+deb13u1", + "origin": "" + }, + { + "name": "libkrb5support0", + "version": "1.21.3-5+deb13u1", + "origin": "" + }, + { + "name": "libk5crypto3", + "version": "1.21.3-5+deb13u1", + "origin": "" + }, + { + "name": "libcom-err2", + "version": "1.47.2-3+b12", + "origin": "" + }, + { + "name": "libxml2", + "version": "2.12.7+dfsg+really2.9.14-2.1+deb13u3", + "origin": "" + }, + { + "name": "bind9-dnsutils", + "version": "1:9.20.29-1~deb13u1", + "origin": "" + }, + { + "name": "bind9-host", + "version": "1:9.20.29-1~deb13u1", + "origin": "" + }, + { + "name": "bind9-libs", + "version": "1:9.20.29-1~deb13u1", + "origin": "" + }, + { + "name": "krb5-locales", + "version": "1.21.3-5+deb13u1", + "origin": "" + }, + { + "name": "libc-l10n", + "version": "2.41-12+deb13u4", + "origin": "" + }, + { + "name": "locales", + "version": "2.41-12+deb13u4", + "origin": "" + }, + { + "name": "xz-utils", + "version": "5.8.1-1+deb13u1", + "origin": "" + }, + { + "name": "busybox", + "version": "1:1.37.0-6+b9", + "origin": "" + }, + { + "name": "curl", + "version": "8.14.1-2+deb13u5", + "origin": "" + }, + { + "name": "libssh2-1t64", + "version": "1.11.1-1+deb13u2", + "origin": "" + }, + { + "name": "libcurl4t64", + "version": "8.14.1-2+deb13u5", + "origin": "" + }, + { + "name": "librabbitmq4", + "version": "0.15.0-1+deb13u2", + "origin": "" + }, + { + "name": "libnss3", + "version": "2:3.110-1+deb13u4", + "origin": "" + }, + { + "name": "libgcrypt20", + "version": "1.11.0-7+deb13u1", + "origin": "" + }, + { + "name": "gpgsm", + "version": "2.4.7-21+deb13u1+b5", + "origin": "" + }, + { + "name": "dirmngr", + "version": "2.4.7-21+deb13u1+b5", + "origin": "" + }, + { + "name": "gpg", + "version": "2.4.7-21+deb13u1+b5", + "origin": "" + }, + { + "name": "gpgconf", + "version": "2.4.7-21+deb13u1+b5", + "origin": "" + }, + { + "name": "gpg-agent", + "version": "2.4.7-21+deb13u1+b5", + "origin": "" + }, + { + "name": "libasound2t64", + "version": "1.2.14-1+deb13u1", + "origin": "" + }, + { + "name": "libasound2-data", + "version": "1.2.14-1+deb13u1", + "origin": "" + }, + { + "name": "libbytes-random-secure-perl", + "version": "0.29-4~deb13u1", + "origin": "" + }, + { + "name": "libcap2-bin", + "version": "1:2.75-10+deb13u1+b3", + "origin": "" + }, + { + "name": "libcurl3t64-gnutls", + "version": "8.14.1-2+deb13u5", + "origin": "" + }, + { + "name": "libevent-2.1-7t64", + "version": "2.1.13-stable-1~deb13u1", + "origin": "" + }, + { + "name": "libevent-core-2.1-7t64", + "version": "2.1.13-stable-1~deb13u1", + "origin": "" + }, + { + "name": "libgbm1", + "version": "25.0.7-2+deb13u1", + "origin": "" + }, + { + "name": "mesa-libgallium", + "version": "25.0.7-2+deb13u1", + "origin": "" + }, + { + "name": "libglib2.0-0t64", + "version": "2.84.4-3~deb13u5", + "origin": "" + }, + { + "name": "libgraphite2-3", + "version": "1.3.14-2+deb13u1", + "origin": "" + }, + { + "name": "libgstreamer-plugins-base1.0-0", + "version": "1.26.2-1+deb13u2", + "origin": "" + }, + { + "name": "libhtml-parser-perl", + "version": "3.83-2~deb13u1", + "origin": "" + }, + { + "name": "libhttp-daemon-perl", + "version": "6.16-1+deb13u1", + "origin": "" + }, + { + "name": "libtalloc2", + "version": "2:2.4.3+samba4.22.11+dfsg-0+deb13u1", + "origin": "" + }, + { + "name": "libtevent0t64", + "version": "2:0.16.2+samba4.22.11+dfsg-0+deb13u1", + "origin": "" + }, + { + "name": "libsmbclient0", + "version": "2:4.22.11+dfsg-0+deb13u1", + "origin": "" + }, + { + "name": "samba-common", + "version": "2:4.22.11+dfsg-0+deb13u1", + "origin": "" + }, + { + "name": "smbclient", + "version": "2:4.22.11+dfsg-0+deb13u1", + "origin": "" + }, + { + "name": "libtdb1", + "version": "2:1.4.13+samba4.22.11+dfsg-0+deb13u1", + "origin": "" + }, + { + "name": "libldb2", + "version": "2:2.11.0+samba4.22.11+dfsg-0+deb13u1", + "origin": "" + }, + { + "name": "samba-libs", + "version": "2:4.22.11+dfsg-0+deb13u1", + "origin": "" + }, + { + "name": "libwbclient0", + "version": "2:4.22.11+dfsg-0+deb13u1", + "origin": "" + }, + { + "name": "libnet-dns-perl", + "version": "1.56-0+deb13u1", + "origin": "" + }, + { + "name": "libpcre2-16-0", + "version": "10.46-1~deb13u3", + "origin": "" + }, + { + "name": "libpng16-16t64", + "version": "1.6.48-1+deb13u6", + "origin": "" + }, + { + "name": "libslirp0", + "version": "4.8.0-1+deb13u1", + "origin": "" + }, + { + "name": "libxml-libxml-perl", + "version": "2.0207+dfsg+really+2.0134-5+deb13u1", + "origin": "" + }, + { + "name": "socat", + "version": "1.8.0.3-1+deb13u1", + "origin": "" + }, + { + "name": "libss2", + "version": "1.47.2-3+b12", + "origin": "" + }, + { + "name": "libtasn1-6", + "version": "4.20.0-2+deb13u1", + "origin": "" + }, + { + "name": "libunbound8", + "version": "1.26.1-0+deb13u1", + "origin": "" + }, + { + "name": "python3-idna", + "version": "3.10-1+deb13u1", + "origin": "" + }, + { + "name": "python3-urllib3", + "version": "2.3.0-3+deb13u2", + "origin": "" + }, + { + "name": "xfsprogs", + "version": "6.13.0-2+deb13u1", + "origin": "" + } + ], + "wrapper_seconds": 57.8 + } + pass took 1m10.4s +WALL_SECONDS=70.462688397 diff --git a/documentation/audits/os-host-lane-2026-10-04/partD/before-demo-hp-agent0.140.0.log b/documentation/audits/os-host-lane-2026-10-04/partD/before-demo-hp-agent0.140.0.log new file mode 100644 index 00000000..37a490da --- /dev/null +++ b/documentation/audits/os-host-lane-2026-10-04/partD/before-demo-hp-agent0.140.0.log @@ -0,0 +1,8 @@ +=== felhom-agent 0.140.0 selftest=os-update vmid=9201 ring=0 enabled=true release=false === +time=2026-10-04T13:19:32.683+02:00 level=INFO msg="osupdate: START" run=20261004T111932Z vmid=9201 ring=0 trigger=debug enabled=true release=ring0-20261004T111932Z +time=2026-10-04T13:19:46.617+02:00 level=INFO msg="osupdate: wrapper" line="os-apply: START release=ring0-20261004T111932Z layer=guest:9201 lane=fast mode=inventory packages=0" +time=2026-10-04T13:19:46.618+02:00 level=INFO msg="osupdate: DONE" run=20261004T111932Z vmid=9201 ring=0 trigger=debug outcome=nothing healthy=true reason="" upgraded=0 pending=6 not_covered=6 restart_needed=10 + "outcome": "nothing", + "pending": 6, + "upgraded": null +WALL_SECONDS=14.029320302 diff --git a/documentation/audits/os-host-lane-2026-10-04/partG/wrapper-copied-by-hand.txt b/documentation/audits/os-host-lane-2026-10-04/partG/wrapper-copied-by-hand.txt new file mode 100644 index 00000000..d2588081 --- /dev/null +++ b/documentation/audits/os-host-lane-2026-10-04/partG/wrapper-copied-by-hand.txt @@ -0,0 +1,2 @@ +demo-felhom wrapper 4729769ce32e25e6 755 root; sudoers 02df92d751f1780a +demo-hp wrapper 4729769ce32e25e6 755 root; sudoers 02df92d751f1780a diff --git a/hub/CHANGELOG.md b/hub/CHANGELOG.md index a7f30aa0..28ea01b5 100644 --- a/hub/CHANGELOG.md +++ b/hub/CHANGELOG.md @@ -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 diff --git a/hub/internal/osupdates/alarms_test.go b/hub/internal/osupdates/alarms_test.go index 39c73ac1..30c994ec 100644 --- a/hub/internal/osupdates/alarms_test.go +++ b/hub/internal/osupdates/alarms_test.go @@ -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") + } +} diff --git a/hub/internal/osupdates/service.go b/hub/internal/osupdates/service.go index 8be30a9d..8e29fb73 100644 --- a/hub/internal/osupdates/service.go +++ b/hub/internal/osupdates/service.go @@ -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 })