Commit graph

12 commits

Author SHA1 Message Date
Mitchell R
69cd0391b5 feat(ota): phase 3 — rollouts + automated rollback
Rollouts (server side):
- /admin/firmware/rollouts page lists + creates campaigns. Pick release,
  target kiosk_ids (empty = whole channel), percentage (1-100).
- Active rollouts override channel-latest in /api/kiosk/firmware/check.
- Deterministic bucket via sha256(rollout_id:kiosk_id) % 100 — same kiosk
  consistently lands in the same bucket across re-checks.
- Pause / resume / complete state controls.

Rollback (kiosk side):
- Before swap, kiosk writes firmware-applying.json marker.
- After clean boot + first successful heartbeat, marker deleted.
- New ExecStartPre hook (/usr/local/sbin/betterframe-firmware-rollback.sh)
  runs every service start; stale marker (>120s) + .prev present →
  restore .prev. Pairs with systemd's StartLimit to catch crash loops.
2026-05-14 07:28:20 +02:00
Mitchell R
2bfecb2819 feat(deploy): apt full-upgrade on every setup run
Adds an OS + dist upgrade step before the BetterFrame install logic so
re-running the script keeps the host current. Uses
  --force-confdef --force-confold
so package maintainer scripts never block on prompts, and follows with
autoremove + autoclean. Kernel/libc updates set /var/run/reboot-required
which the existing REBOOT_NEEDED guard picks up → auto-reboot at end.

BF_SKIP_UPGRADE=1 bypasses the upgrade for fast iteration.
2026-05-13 13:08:36 +02:00
Mitchell R
d5bd64d05c feat(deploy): self-update + auto-reboot on boot-file changes
Two ergonomics fixes so one invocation does the right thing:

  1. After git pull, re-exec the script if the installer itself changed
     in the pull. Previously you'd need a second run to pick up new
     logic. BF_REEXEC=1 guard prevents loops.

  2. Track REBOOT_NEEDED when cmdline.txt / config.txt get edited or
     /var/run/reboot-required appears (apt kernel/libc update). At end
     of run, auto-reboot after a 10s cancellable window. Override with
     BF_NO_REBOOT=1.
2026-05-13 12:58:20 +02:00
Mitchell R
bb67c26a1c fix(deploy): mark setup-pi-kiosk.sh executable in git index + add .gitattributes
Windows chmod doesn't propagate to git's mode bits, so the script
landed as 100644 (non-exec) and `./deploy/scripts/setup-pi-kiosk.sh`
gave "command not found" on the Pi. Update index to 100755 and add
.gitattributes to force LF on shell scripts / systemd units to head off
the related CRLF-shebang trap.
2026-05-13 03:33:41 +02:00
Mitchell R
93cf261f07 fix(deploy): purge Pi welcome wizard + mask display managers
systemctl disable lets apt upgrades re-enable a DM. Mask everything
that could put a desktop on tty1. Purge piwiz + userconf-pi (the
"Welcome to Raspberry Pi" first-run wizard) and wipe /etc/motd +
/etc/update-motd.d so even on console nothing identifies as Pi.
2026-05-13 03:31:47 +02:00
Mitchell R
ad909e9c93 fix(deploy): drop nonexistent 'seat' supplementary group
systemd refuses to spawn the unit with code=216/GROUP when any group in
SupplementaryGroups= doesn't exist. Debian's seatd uses -g video — there
is no 'seat' group on the system. Removing it lets cage start; the video
group already covers seatd access.
2026-05-13 03:23:49 +02:00
Mitchell R
85a0bcae87 feat(deploy): BetterFrame plymouth boot splash
Replace Pi rainbow + kernel boot text with a black BG + centered BF logo
during boot. Installer renders logo.png from the existing SVG asset via
rsvg-convert, drops a script-based plymouth theme, and appends the
quiet/splash flags to cmdline.txt + disable_splash=1 in config.txt.

cmdline.txt edits are idempotent: each flag only added if missing.
2026-05-13 03:21:37 +02:00
Mitchell R
b42e972fcf feat(deploy): client|server|both positional arg for installer
Pick install mode at the command line instead of multiple SKIP_* env
flags. Defaults to 'both' so existing single-host usage is unchanged.
2026-05-13 03:17:55 +02:00
Mitchell R
bfbaa72022 feat(deploy): single-file end-to-end installer/updater
Expand setup-pi-kiosk.sh to be the one-and-only entry point: clones (or
git-pulls) the repo into the invoking user's home, installs Docker +
compose plugin + GTK/GStreamer/WebKit/cage/seatd + rustup (if missing),
brings up the docker-compose stack, builds the kiosk binary, and
provisions the bfkiosk user + cage PAM + systemd unit.

Every step is idempotent so re-running pulls latest, rebuilds, and
redeploys. SKIP_DOCKER / SKIP_KIOSK / SKIP_BUILD env flags let an
operator partition the work for kiosk-only or server-only hosts.
2026-05-13 03:16:40 +02:00
Mitchell R
5656d430ff fix(deploy): run cargo build under a login shell
sudo -u <user> cargo fails when cargo lives in ~/.cargo/bin and root's
PATH doesn't carry it. Switch to sudo -u <user> -i sh -c so the user's
.profile / cargo env is sourced.
2026-05-13 03:13:39 +02:00
Mitchell R
f320b680a1 feat(deploy): setup-pi-kiosk.sh builds + installs the kiosk binary
Script now installs GTK/GStreamer/webkit dev libs, runs cargo build
--release as the invoking user, then drops the binary at
/opt/betterframe/kiosk/betterframe-kiosk where the systemd unit
expects it. Set SKIP_BUILD=1 to bypass when iterating.
2026-05-13 03:13:15 +02:00
Mitchell R
81a64766ae feat(deploy): Pi kiosk bring-up via cage + low-priv bfkiosk user
Replace the user-mode kiosk service with a system unit that runs cage
(single-app Wayland compositor) on tty1 as a dedicated unprivileged
user. No desktop, no display manager, auto-restart on crash via
Restart=always.

setup-pi-kiosk.sh provisions the user, installs cage + seatd, disables
any display manager, points default.target at multi-user, drops the
PAM stack, and enables the service. Idempotent.

Screen wake "auto-login": with no DM and no lockscreen, DPMS-driven
sleep just turns the panel back on — the kiosk process is already
running.
2026-05-13 03:11:06 +02:00