Skip to content

fix(rpi-image): patch the host OS automatically, unfreeze the Docker engine - #1001

Merged
frahlg merged 3 commits into
srcfl:masterfrom
HuggeK:pi-host-os-security-updates
Sep 3, 2026
Merged

fix(rpi-image): patch the host OS automatically, unfreeze the Docker engine#1001
frahlg merged 3 commits into
srcfl:masterfrom
HuggeK:pi-host-os-security-updates

Conversation

@HuggeK

@HuggeK HuggeK commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Fixes #770.

Pressing Update in the app updates Core, the Optimizer and drivers — and nothing else. A flashed Pi never received a host OS security update, and because the image build deletes Docker's apt source after installing the engine, not even a manual sudo apt upgrade could patch docker-ce. This PR implements options 1–3 from #770:

  • unattended-upgrades on the appliance image. Origins: Debian security plus the Raspberry Pi archive, applied daily; Automatic-Reboot "false" is pinned explicitly — a reboot stops dispatch, so a staged kernel waits for an operator-chosen reboot.
  • The Docker engine is no longer frozen. The build now parks docker.list as docker.list.disabled (apt only reads *.list/*.sources, so the pi-gen export-image OOM workaround is preserved) and ftw-firstboot restores it on the device. Engine patching becomes a normal apt upgrade.
  • The boundary is documented. docs/self-update.md, docs/operations.md and docs/rpi-image.md now say plainly that self-update never touches the host, and rpi-image.md carries a retrofit block for devices flashed from older images.
Why the Raspberry Pi archive is in the origins, but Docker is not

The Raspberry Pi archive (Origin: Raspberry Pi Foundation) is where linux-image-rpi-v8, raspi-firmware and the bootloader packages come from, and it has no separate security pocket. Restricting unattended-upgrades to Debian's security pocket alone would leave exactly the packages the issue worries about — the kernel — permanently unpatched. Kernel updates install but only take effect at the next operator reboot, so including the archive costs no unplanned downtime.

Docker's repository is deliberately not auto-upgraded: a docker-ce upgrade restarts the daemon and with it every container, which is a dispatch interruption that should happen at a moment the operator picks, not at the apt-daily timer's. Restoring the source makes that manual action possible at all; the fragment's comment records the decision.

Verification
  • bash -n passes on both modified scripts (same check the validate installer scaffolding job runs).
  • Origin patterns verified against the live Release files: archive.raspberrypi.com/debian/dists/trixie/Release reports Origin: Raspberry Pi Foundation / Codename: trixie; download.docker.com/linux/debian/dists/trixie/Release reports Origin: Docker.
  • APT config lists append across apt.conf.d files, so 52ftw-unattended-upgrades extends the Debian defaults in 50unattended-upgrades instead of replacing them.
  • Not tested on hardware yet — a maintainer can dispatch rpi-image-build.yml without publishing to get a flashable candidate.

Option 4 from the issue (surfacing host patch state in Update Center) is deliberately left out: it crosses the core-has-no-host-visibility boundary and deserves its own discussion. Existing installations get the documented retrofit, not an automatic migration — core never touches the host.

🤖 Generated with Claude Code

https://claude.ai/code/session_012taMkhFbYYNyVQmCTU26sn

…engine

Self-update covers only FTW's own containers; the flashed Pi never
received an OS security update, and the image build deleted Docker's apt
source, so even a manual `apt upgrade` could not patch the engine.

- install unattended-upgrades: Debian security + the Raspberry Pi
  archive (the kernel/firmware source has no security pocket), with
  automatic reboots pinned off — a reboot stops dispatch
- park docker.list as docker.list.disabled during the image build (same
  export-image OOM workaround) and restore it in ftw-firstboot, so
  engine patching becomes a normal operator apt action
- document the self-update/host boundary and a retrofit for devices
  flashed from older images

Fixes srcfl#770

Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
Claude-Session: https://claude.ai/code/session_012taMkhFbYYNyVQmCTU26sn
@HuggeK
HuggeK marked this pull request as ready for review August 29, 2026 17:38
Master moved from srcfl#756 to srcfl#998 under the branch; the only real conflict
was firstboot.sh, where srcfl#980-era work made first boot try `docker
compose up -d` on locally present images before falling back to the
GHCR pull loop. Kept that up-first flow and placed the docker.list
restore (srcfl#770) before it, right after cd /opt/ftw.

Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
Claude-Session: https://claude.ai/code/session_012taMkhFbYYNyVQmCTU26sn

@miravoss26 miravoss26 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds unattended-upgrades to the Pi image: Debian security + Raspberry Pi Foundation origins auto-patch daily, automatic reboot stays off (this is a dispatch-critical appliance), and Docker's engine is deliberately excluded from the auto-upgrade pattern (restored via firstboot instead of staying frozen at build time).

  • The docker.listdocker.list.disabled rename (build time) / restore (firstboot.sh) is correctly gated with [ -f ... ] — idempotent across a re-run or a reboot mid-provision.
  • Origins-Pattern appends to Debian's defaults rather than replacing them; Docker's own repo is correctly left out, matching the "engine upgrade = manual, operator-timed" comment.
  • No secrets, no new inbound surface. The Raspberry Pi Foundation archive isn't a new apt source here, just named for auto-upgrade scope.
  • Worth flagging, not a blocker: kernel/firmware patches land but sit inert until an operator reboots. That gap between "patched" and "running patched" is real for fleet-exposure auditing, even though the reasoning (reboot stops dispatch) is sound.

Safe to merge from my read.

@frahlg frahlg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes the two real holes in #770: the host never got Debian/Raspberry Pi security updates, and deleting docker.list froze the engine for the life of the flash.

The park-and-restore (docker.listdocker.list.disabled at build, restore in firstboot) is the right shape — apt only reads *.list/*.sources, so the pi-gen OOM workaround stays, and the [ -f ] gate is idempotent across a reboot mid-provision. Automatic reboot stays off, which is the load-bearing appliance constraint.

Origins: listing Debian-Security again in 52ftw-unattended-upgrades is the safe form whether APT merges or replaces the list from 50unattended-upgrades. Raspberry Pi archive belongs there (no separate security pocket). Docker stays out of unattended-upgrades on purpose.

Accepted trade-off, not a blocker: kernel/firmware land but sit inert until an operator reboots. Retrofit block is docs-only, which is correct — core never touches the host.

Not tested on hardware here; validate installer scaffolding is green. Fine to land.

@frahlg
frahlg merged commit 37df5fe into srcfl:master Sep 3, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nothing patches the host OS after install — self-update covers FTW's own containers only

4 participants