Migrate CUPS Printing addon; restructure install.sh into Core Settings/Addons/Advanced; bump to v2.5.0

First Addon migrated: menus/addon_cups.sh (install, reconfigure for
network access, complete uninstall/purge). Different risk profile from
everything migrated so far - it genuinely mutates real system state
(apt install/remove --purge, /etc/cups, ufw) at fixed paths CUPS itself
doesn't let us relocate, unlike the systemd/cron/bin paths this project
already controls via $SYSTEMD_DIR etc. Only the polkit rule's directory
is parameterized ($POLKIT_DIR, lib/config.sh, since that one is ours to
place); everything else gets full command-level `sudo` stubbing in
every test - there is no scratch equivalent for a real apt-managed
subsystem's own file layout. Also added $BUILD_USER (the admin account
actually running the tool, as opposed to $KIOSK_USER) since CUPS needs
to grant it lpadmin group membership.

Restructured install.sh's top-level menu into Core Settings / Addons /
Advanced (matching the legacy tool) instead of one flat list, now that
Addons exists as its own category - cheap to do with one item in it,
much more annoying to retrofit once the flat list has fifteen.

Two bugs caught and fixed before they shipped:

- A "wait for CUPS to start" retry loop used a bare `cmd1 && cmd2 &&
  break` as its body while "simplifying" the legacy script's `if cmd1
  && cmd2; then break; fi`. Being inside a loop doesn't protect a bare
  &&/|| list from set -e - only if/while/until conditions and the
  protected side of &&/|| do that - so the first command failing on an
  early iteration (near-certain right after a fresh install, before
  CUPS has actually started) would have crashed the entire session.
  Restored the `if` form; noted the lesson in the file's own header
  comment since it's a general trap, not CUPS-specific.

- Resolved real uncertainty, rather than assuming: how far does
  run_menu's `handler || true` guard (v2.1.0) actually protect? Wrote a
  minimal isolated test (a bare `false` three function calls deep,
  called via `outer || true` at the top) and confirmed bash's errexit
  exemption for the left side of `||` covers the *entire* evaluation,
  arbitrarily deep through function calls - not just the immediately
  invoked function. So the session-crash risk this project has been
  chasing since v2.1.0 is already covered end-to-end by that one fix.
  Per-statement guards (`|| true`, explicit `if`) still earn their keep
  for a different reason: without them a deep failure bubbles silently
  past the menu actually responsible for it to wherever the nearest
  `|| true` happens to sit, which can be several menu levels above
  where the user actually was - not a crash, but a confusing jump.

Verified:
- Full regression: re-ran every existing scratch-config/stub test suite
  after the lib/config.sh change (new $BUILD_USER/$POLKIT_DIR) and
  after the install.sh restructuring - all still clean.
- New scratch/stub test for addon_cups.sh: full state-machine coverage
  (not installed -> decline -> install -> running -> reconfigure ->
  stopped -> start -> uninstall decline -> uninstall confirm -> not
  installed again) with every `sudo` call intercepted and only `rm`
  targeting the scratch $POLKIT_DIR ever actually executed; confirmed
  the polkit rule's content and that declining install makes zero sudo
  calls. Added both apt-failure paths (update fails, install fails)
  and confirmed the tool reports clearly and returns to the menu
  instead of dying, exercising the exact bug class just fixed.
- End-to-end: ran the real install.sh as a genuine non-root, non-
  "kiosk" user through the full new three-level structure - Core
  Settings -> Sites -> back -> back, Addons -> CUPS -> declined install
  (using this container's real, unstubbed dpkg check, correctly
  reporting "not installed" and making no apt/systemctl calls) -> back
  -> back, Advanced -> Diagnostics -> System status -> back -> back ->
  Exit. Zero invalid-choice errors, clean exit code 0 throughout.
This commit is contained in:
Claude
2026-08-18 19:10:43 +00:00
parent 459da53182
commit 1b16bcf3ee
5 changed files with 258 additions and 17 deletions
+40 -2
View File
@@ -1,8 +1,46 @@
#!/bin/bash
################################################################################
### Ubuntu Based Kiosk v2.4.0 ###
### Ubuntu Based Kiosk v2.5.0 ###
################################################################################
#
# RELEASE v2.5.0 - First Addon Migrated (CUPS), Menu Restructured
# - New in ./install.sh: CUPS Printing (menus/addon_cups.sh) - the first
# Addon migrated. Install/reconfigure/complete uninstall (purge),
# genuinely mutating real system state (apt install/remove --purge,
# /etc/cups, ufw) at fixed paths CUPS itself doesn't let us relocate -
# unlike the systemd/cron/bin paths this project controls, there is no
# scratch equivalent for a real apt-managed subsystem's own file
# layout, so every test uses full command-level `sudo` stubbing
# instead. Only the polkit rule's directory is parameterized
# ($POLKIT_DIR, since that one is ours to place).
# - install.sh's top-level menu is now grouped the same way the legacy
# menu groups things - Core Settings / Addons / Advanced - instead of
# one flat list, ahead of that list getting unwieldy as more Addons
# and Advanced items migrate in.
# - Two bugs caught and fixed before they ever shipped, both instructive
# beyond this one file:
# - A "wait for service to start" retry loop used a bare `cmd1 &&
# cmd2 && break` as its body. That's not safe merely because it's
# inside a loop - a bare &&/|| list used as a standalone statement
# (not the condition of if/while/until) is fully subject to set -e,
# and cmd1 failing on an early iteration (near-certain right after
# a fresh install) would have killed the whole session. Restored
# the `if cmd1 && cmd2; then break; fi` form the legacy script
# already used correctly, rather than "simplifying" it away.
# - Resolved real uncertainty about how far run_menu's `handler ||
# true` guard (added in v2.1.0) actually reaches: verified with a
# minimal isolated test that it protects against a bare failing
# command no matter how many function calls deep it occurs - bash's
# errexit exemption for the left side of `||` covers the entire
# evaluation, not just the immediately-called function. So the
# session-crash risk this project has been chasing since v2.1.0 is
# already covered end-to-end by that one fix. Per-statement guards
# (`|| true`, explicit `if`) still matter for a different reason:
# without them a deep failure silently bubbles up past the menu
# that's actually responsible for it to wherever the nearest `||
# true` happens to catch it, which may be several menu levels
# higher than where the user actually was.
#
# RELEASE v2.4.0 - Diagnostics Migrated
# - New in ./install.sh: Diagnostics (menus/diagnostics.sh) - system
# status, log viewing (Electron/LightDM/journal), an 8-step audio
@@ -188,7 +226,7 @@ set -euo pipefail
### SECTION 1: CONSTANTS & GLOBALS
################################################################################
SCRIPT_VERSION="2.4.0"
SCRIPT_VERSION="2.5.0"
# Resolve the real path to this script file.
# When piped (curl|bash or wget|bash), BASH_SOURCE[0] is a pipe descriptor,