Commit graph

14 commits

Author SHA1 Message Date
Mitchell R
411d9900a9
chore: target latest-stable everywhere — Debian Trixie + gtk4 v4_14
- CI workflow container: debian:trixie-slim (was bookworm-slim)
- Server image base: node:23-trixie-slim (was bookworm-slim)
- Kiosk Cargo.toml: gtk4 features v4_14 (was v4_8) — matches Trixie's
  stock gtk 4.14 without backports juggling
- setup-pi-kiosk.sh header: Trixie+ target (was Bookworm+)

Glibc matches across Pi OS Trixie, Coolify host (Trixie), CI build
container — no symbol drift at runtime.
2026-05-19 04:21:14 +02:00
Mitchell R
a7abef1bba
fix(deploy): move docker-compose.yml to repo root
Coolify passes --project-directory <repo-root> so relative paths in
compose resolved from there, not from the compose file's directory.
context: ../.. then climbed to / and lstat /deploy failed.

Moving compose to repo root makes every relative path
project-dir-relative regardless of who's invoking compose. Local
'docker compose up' from repo root and Coolify's
--project-directory + -f both resolve identically.

Coolify users: update the resource's compose path to 'docker-compose.yml'
(was 'deploy/docker/docker-compose.yml'). Existing named volumes carry
over since the named: directive keeps them.
2026-05-18 12:05:09 +02:00
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