refactor: transparent bootstrap output — name installs, show skips, drop dup apt update

This commit is contained in:
Your Name
2026-08-13 05:00:33 -04:00
parent a3c01a0394
commit 8b0ce3ba89
5 changed files with 40 additions and 16 deletions
+2
View File
@@ -16,6 +16,8 @@ summary (newest last).
## Done
- **2026-08-13** — Bootstrap output transparency (`install.sh` / `preinstall.sh` / `postinstall.sh`): removed the redundant `apt update` (preinstall.sh owns it — install.sh previously ran it twice, showing two identical `OK apt update` lines); Phase 2 now names what it installs — libs line (`libs -> /usr/local/bin (644): common.sh flags.sh …`), plugin names in the count line, x64_bin names, per-feature `feature installed/overwritten` + `feature flag set` logs with a `N features installed: …` summary — and the misleading `"47 scripts + libs"` label is fixed to `47 scripts + 6 libs` (the 6 libs were outside the counter); preinstall prints `Installing N packages (apt install -y):` with the 40-name list wrapped at 80 cols; postinstall now logs silent skips — `config/authorized_keys is empty — nothing to add` (empty file previously looped zero times with no message), `schedule.d already exists, keeping it` (restructured the condition so the message is accurate when the dest exists vs config/schedule.d absent), and a per-service `service enabled: <name>` line. No output-layer changes (no `--verbose`, no log file — decided scope). Verified: `bash -n` + `--dry-run` smokes of phases 1/2/3 showing every new line (learned: `install.sh:19` hardcodes `export DRY_RUN=0`, so an env `DRY_RUN=1` is ignored — the flag `--dry-run` is required), hand-maintained filetable count rows bumped (install.sh 206→223, preinstall.sh 73→75, postinstall.sh 163→168), `make gen && make check` green. usb-automount left live (user choice).
- **2026-08-13** — `usb-automount` feature, integrated exactly like `autostart`: `features/usb-automount.sh` (root-guard re-exec via sudo; first-root-run self-install of udev rule `/etc/udev/rules.d/99-usb-automount.rules``ACTION=="add", KERNEL=="sd[a-z]*", SUBSYSTEM=="block", ENV{ID_BUS}=="usb", TAG+="systemd", SYSTEMD_WANTS="usb-automount.service"` — + `udevadm control --reload` + `trigger --subsystem-match=block`; an existing/edited rule is never overwritten; scans `lsblk -J` for unmounted removable partitions/raw whole-disk filesystems, mounts each at `/media/<label>` — vfat/exfat/ntfs world-writable via `-o umask=000`, fallback plain mount, label-collision bump `-2`/`-3`, no label → `usb-<name>`, logs `${HOME:-/root}/.usb-automount.log`) + `systemd/usb-automount.service` (`Type=oneshot`, `WantedBy=multi-user.target` — boot + hotplug + manual `systemctl start usb-automount`), gated in postinstall.sh's systemd loop exactly like autostart (`flag_is_set usb-automount` → skip with hint). Purpose: a plugged-in stick is auto-mounted world-writable, ready for `pos system backup`'s post-verify USB copy. Docs: SYSTEMD.md (service section + gating code block), SCRIPTS.md (feature section + systemd bullet + TOC), AGENT_Context tree + filetable rows (postinstall.sh count corrected 152→163 — it was already 6 lines stale), README index rows. Verified with a stub suite (`/tmp/opencode/usb-automount-test` — lsblk JSON fixtures, mount/mountpoint/udevadm/sudo stubs, `MOUNT_BASE`/`UDEV_RULES_DIR` seams, HOME isolation): 47/47 green. `make gen && make check` green. Gotcha learned: `${VAR:-{...}}` with a `{` inside the parameter-expansion default mis-parses in bash (emits a stray `}` — printf of a multi-line value showed `}}`); avoid braces in `:-` defaults.
- **2026-08-13** — `pos system backup` copies the finished backup to a USB stick. Detection runs **after** the archive verifies (so a stick plugged in while the backup ran is found; if none is mounted, one re-scan prompt before giving up — `s` skips, EOF from cron skips silently, rc stays 0). Single stick → y/N confirm; several → numbered pick (0 = skip). Copy lands in `<usb>/backups/` (mkdir -p; `chmod 600` best-effort — vfat chmod failures warn, never fail), and the transfer is proven 100% by **sha256 source-vs-copy** before any success is announced: mismatch → warn with both hashes + `notify_send "USB copy FAILED…"` + rc=1 (the ERR trap is re-armed mid-script so a USB-phase failure no longer notifies "Backup FAILED"). Detection: `lsblk -J` → recursive jq filter (rm==true && mounted && type part|disk, space-safe via JSON) or pinned `BACKUP_USB_ROOT` seam (= `<root>/backups/`, skips detection — also the test seam). Docs: usage() Environment, POS.md backup row, howto/system.md (USB section + env table + mismatch troubleshooting), DEV.md system.env list. Verified with a stub suite (`/tmp/opencode/backup-test` — sudo/gpg/lsblk/sender stubs, HOME isolation, per-test lsblk JSON fixtures, corrupting-cp + vfat-chmod override stubs): 40/40 green (skip s/EOF, seam y/n, detect single, multi pick 2/0, re-scan after replug, corrupt copy rc=1 + honest notify, vfat tolerance). `make gen && make check` green.
- **2026-08-13** — `pos share smb-server share` now guards the two common `NT_STATUS_ACCESS_DENIED` causes at share time (warnings only): `--users` entries missing from the Samba passdb (`pdbedit -L`, cut to user column, `grep -qxF` per user — pointer to `pos share smb-server adduser <user>`), and ancestors of the share path lacking `other:+x` traversal (sticky dirs like `/tmp` count as traversable via the `t` slot; fix hint `chmod o+x <dir>`). Both wired into the `share` case after `require_root_dir`; howto/share.md SMB section + troubleshooting updated. Rooted in `reports/bug-report-smb-server-access-denied.md` (committed as the spec). Verified with a stub-PATH suite (`/tmp/opencode/smb-test` — pdbedit/systemctl/smbcontrol/testparm/smbpasswd stubs, `SMB_CONF` seam): 16/16 green.
+3 -3
View File
@@ -560,9 +560,9 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
| File | Lines | Purpose |
|------|-------|---------|
| `install.sh` | 206 | Main orchestrator — 4 phases with CLI flags, `--feature`, prebuilt arch bins |
| `preinstall.sh` | 73 | System packages + hotspot deps + yt-dlp + fail2ban |
| `postinstall.sh` | 163 | fail2ban config, PATH, bash completion, systemd (flag-gated) |
| `install.sh` | 223 | Main orchestrator — 4 phases with CLI flags, `--feature`, prebuilt arch bins |
| `preinstall.sh` | 75 | System packages + hotspot deps + yt-dlp + fail2ban |
| `postinstall.sh` | 168 | fail2ban config, PATH, bash completion, systemd (flag-gated) |
| `lib/common.sh` | 144 | Shared library (log/warn/err/run/spawn, dry-run aware, `load_system_env`) |
| `lib/flags.sh` | 60 | Feature flag store (set/clear/is_set/value/list/status) |
| `lib/notify.sh` | 76 | Multi-platform alerting (`notify_send`) — opt-in source, silent-fails |
+26 -11
View File
@@ -98,7 +98,7 @@ timer_start
if should_run 1 preinstall; then
step 1 4 "Installing system packages"
if [ -f preinstall.sh ]; then
spawn "apt update" sudo apt update
# preinstall.sh owns 'apt update' — no duplicate update here.
bash preinstall.sh
fi
fi
@@ -113,22 +113,26 @@ if should_run 2 scripts; then
run sudo install -m 755 "$f" /usr/local/bin/
count=$((count + 1))
done
run sudo install -m 644 lib/common.sh /usr/local/bin/common.sh
run sudo install -m 644 lib/flags.sh /usr/local/bin/flags.sh
run sudo install -m 644 lib/notify.sh /usr/local/bin/notify.sh
run sudo install -m 644 lib/entertainment-lib.sh /usr/local/bin/entertainment-lib.sh
run sudo install -m 644 lib/scheduler-lib.sh /usr/local/bin/scheduler-lib.sh
run sudo install -m 644 lib/config-ui.sh /usr/local/bin/config-ui.sh
lib_count=0
lib_names=""
for lf in common.sh flags.sh notify.sh entertainment-lib.sh scheduler-lib.sh config-ui.sh; do
run sudo install -m 644 "lib/$lf" "/usr/local/bin/$lf"
lib_count=$((lib_count + 1))
lib_names+="$lf "
done
log "libs -> /usr/local/bin (644): ${lib_names% }"
# ── Entertainment plugins ────────────────────────────────
# Installed into /usr/local/bin so the repo can be deleted afterwards.
pcount=0
pnames=""
for f in entertainment/*.sh; do
[ -f "$f" ] || continue
run sudo install -m 755 "$f" /usr/local/bin/
pcount=$((pcount + 1))
pnames+="$(basename "$f") "
done
ok "$pcount entertainment plugins -> /usr/local/bin"
ok "$pcount entertainment plugins -> /usr/local/bin: ${pnames% }"
# ── Precompiled architecture binaries ─────────────────────
# Manually-compiled binaries (not available on the internet),
@@ -140,15 +144,21 @@ if should_run 2 scripts; then
*) prebuilt_dir="" ;;
esac
if [ -n "$prebuilt_dir" ] && [ -d "$prebuilt_dir" ]; then
bcount=0
bnames=""
for f in "$prebuilt_dir"/*; do
[ -f "$f" ] || continue
run sudo install -m 755 "$f" /usr/local/bin/
bcount=$((bcount + 1))
bnames+="$(basename "$f") "
done
ok "$prebuilt_dir binaries -> /usr/local/bin"
ok "$bcount $prebuilt_dir binaries -> /usr/local/bin: ${bnames% }"
fi
# ── Optional features ──────────────────────────────────────
if [ "$RUN_FEATURES" -eq 1 ]; then
fcount=0
fnames=""
for f in features/*; do
[ -f "$f" ] || continue
name=$(basename "$f")
@@ -157,17 +167,22 @@ if should_run 2 scripts; then
if [ -e "$dest" ]; then
if confirm "Overwrite existing $dest?" n; then
run sudo install -m 755 "$f" "$dest"
log "feature overwritten: $name"
else
log "Keeping existing $dest"
fi
else
run sudo install -m 755 "$f" "$dest"
log "feature installed: $name"
fi
flag_set "$flag_name"
log "feature flag set: $flag_name"
fcount=$((fcount + 1))
fnames+="${name%.sh} "
done
ok "features installed"
ok "$fcount features installed: ${fnames% }"
fi
ok "$count scripts + libs -> /usr/local/bin"
ok "$count scripts + $lib_count libs -> /usr/local/bin"
fi
# ── Phase 3: postinstall ───────────────────────────────────────
+7 -2
View File
@@ -54,8 +54,10 @@ done
# thresholds, silent log cleanup). Ask before copying — only into an empty
# schedule.d/ (never overwrite existing jobs). Users with legacy event.env
# rules are pointed at `pos system schedule migrate` instead.
if [ -d config/schedule.d ] && [ ! -d "$ENT_DIR/schedule.d" ]; then
if [ -f "$ENT_DIR/event.env" ] && grep -vE '^[[:space:]]*(#.*)?$' "$ENT_DIR/event.env" >/dev/null 2>&1; then
if [ -d config/schedule.d ]; then
if [ -d "$ENT_DIR/schedule.d" ]; then
log "schedule.d already exists, keeping it"
elif [ -f "$ENT_DIR/event.env" ] && grep -vE '^[[:space:]]*(#.*)?$' "$ENT_DIR/event.env" >/dev/null 2>&1; then
log "legacy event.env rules found — convert them with 'pos system schedule migrate'"
elif confirm "Install the starter schedule jobs (NVMe health, CPU/disk thresholds, log cleanup)?"; then
if [ "${DRY_RUN:-0}" -eq 1 ]; then
@@ -127,6 +129,8 @@ if [ -f "$KEY_FILE" ]; then
done < "$KEY_FILE"
if [ "$added" -gt 0 ]; then
log "Installed $added SSH key(s)"
elif ! grep -qE '^[[:space:]]*[^#[:space:]]' "$KEY_FILE"; then
log "config/authorized_keys is empty — nothing to add"
fi
else
warn "config/authorized_keys not found, skipping SSH setup"
@@ -154,6 +158,7 @@ if [ -d systemd ] && [ -n "$(ls -A systemd/*.service 2>/dev/null)" ]; then
fi
run sudo systemctl enable --now "$svc_name" 2>/dev/null || \
run sudo systemctl enable "$svc_name"
log "service enabled: $svc_name"
done
log "Systemd services installed and enabled"
else
+2
View File
@@ -41,6 +41,8 @@ PACKAGES=(
)
spawn "apt update" sudo apt update
log "Installing ${#PACKAGES[@]} packages (apt install -y):"
echo " ${PACKAGES[*]}" | fold -s -w 80
spawn "Installing packages" sudo apt install -y "${PACKAGES[@]}"
# ── cpufreq tools ─────────────────────────────────────────────
# cpufrequtils (Ubuntu) was removed in Debian trixie+; linux-cpupower