diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-20 07:27:16 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-20 07:27:16 -0500 |
| commit | 2e062cc27285f79d75ce49f15a26ea8ebba9764f (patch) | |
| tree | 46708b4e2e3c0c2b725be83b2f27828f157fbdb0 /todo.org | |
| parent | 0468fedb23ae34a140b6a5a903adedb4e9873ca5 (diff) | |
| download | archsetup-2e062cc27285f79d75ce49f15a26ea8ebba9764f.tar.gz archsetup-2e062cc27285f79d75ce49f15a26ea8ebba9764f.zip | |
docs: log overnight code audit and file triaged installer bugs
Overnight sentry ran its hygiene passes plus a code-inspection pass over the installer and the scripts/ directory. It archived 6 completed tasks to Resolved and logged 19 bugs and 12 refactors in docs/design/2026-07-19-sentry-code-findings.org. I filed the bugs as tasks graded by severity times frequency. Nothing in the codebase changed, this was detection only.
Two things stand out. The installer does no partitioning (it's a post-install config layer), so the real data-loss surface is boot config, and it overwrites GRUB_CMDLINE wholesale, which can drop a cryptdevice or resume param and leave a machine unbootable. Three WireGuard configs with live private keys are tracked in git, flagged for a rotate-or-keep decision.
Diffstat (limited to 'todo.org')
| -rw-r--r-- | todo.org | 192 |
1 files changed, 112 insertions, 80 deletions
@@ -45,45 +45,44 @@ below): input-side-spec.org (DRAFT, four decisions open). * Archsetup Open Work -** DONE [#A] Velox boot recovery — no kernel in BE :bug:velox:zfs: -CLOSED: [2026-07-19 Sun] -Recovered. Velox boots linux-lts 6.18.38 and is back on the tailnet (up 1d+, /boot holds initramfs-linux-lts.img). The pre-pacman ZFS snapshot rollback restored the kernel from the ZBM recovery shell. -Velox won't boot: ZBM prompts for the passphrase, unlocks, then reports no bootable environment with a kernel. Cause: an interrupted kernel =-Syu= removed the old kernel and never installed the new one — /mnt/be/boot (from zroot/ROOT/default) holds ONLY intel-ucode.img; vmlinuz-linux + both initramfs are gone. /boot lives inside zroot/ROOT/default (no separate boot dataset), so root-dataset snapshots capture it. - -Status 2026-07-15: a first rollback attempt did NOT fix it (square zero after reboot) — suspected typo in the snapshot name, so the rollback likely errored and did nothing. NOT verified. Next session: verify state in the ZBM recovery shell BEFORE any reboot. - -Recovery lever: the pre-pacman ZFS snapshot hook (live on velox since 2026-06-29) snapshots zroot/ROOT/default@pre-pacman_<ts> before every pacman transaction. The newest =pre-pacman_<ts>= predating the failed upgrade holds the intact old kernel — roll back to it. - -Morning steps (Craig at velox ZBM → recovery shell, Ctrl+R): -#+begin_src sh -# 1. pool writable + key loaded -zpool get readonly zroot -zfs get -H -o value keystatus zroot/ROOT/default -# if readonly=on: zpool export zroot && zpool import -f -N zroot -# if keystatus=unavailable: zfs load-key zroot - -# 2. list snapshots — COPY THE EXACT NAME (the typo bit here last time) -zfs list -t snapshot -o name,creation zroot/ROOT/default | grep pre-pacman - -# 3. see current /boot state (read-only mount) -umount /mnt/be 2>/dev/null; mkdir -p /mnt/be -mount -t zfs -o zfsutil,ro zroot/ROOT/default /mnt/be -ls -la /mnt/be/boot - -# 4. if /boot still shows only intel-ucode.img: redo rollback with the exact name -umount /mnt/be 2>/dev/null -zfs rollback -r zroot/ROOT/default@pre-pacman_<EXACT-TS> # -r, NOT -R - -# 5. VERIFY before reboot — remount RO, confirm the kernel is back -mount -t zfs -o zfsutil,ro zroot/ROOT/default /mnt/be -ls -la /mnt/be/boot # MUST show vmlinuz-linux + initramfs-linux.img -umount /mnt/be - -# 6. only once /boot shows a kernel: -zpool export zroot && reboot -#+end_src -Scope: only zroot/ROOT/default reverts; /home, /var, /media are separate datasets, untouched. After boot: =pacman -Syu= attended, confirm /boot holds vmlinuz-linux + initramfs before any shutdown. Full diagnosis: =inbox/PROCESSED-2026-07-15-0002-from-.emacs.d-velox-boot-failure-handoff.org=; ZBM photo: =inbox/PROCESSED-2026-07-15-0002-from-.emacs.d-PXL_20260715_043758976.jpg= (local on ratio; inbox is gitignored). - +** TODO [#B] Installer GRUB_CMDLINE overwrite drops boot params :bug:solo: +Grading: Critical severity (unbootable) x some-users-sometimes (machines whose base install set a cryptdevice=/resume=/zfs= cmdline param) = P2 = [#B]. +archsetup:3054 rewrites the whole GRUB_CMDLINE_LINUX_DEFAULT line with a fixed string; nothing re-adds a pre-existing cryptdevice/resume/zfs token, so grub-mkconfig (3059) can bake an unbootable config. Fix: read the current value and append only the missing tokens; assert any pre-existing boot-critical token survives before grub-mkconfig. See [[file:docs/design/2026-07-19-sentry-code-findings.org][sentry code findings]] (S3). +** TODO [#B] Tracked WireGuard private keys in repo :bug:security:network: +Grading: security carve-out (graded on severity alone) — live Proton VPN private keys committed to git. Private remote (git@cjennings.net) mitigates immediate exposure, but archsetup is a code project and a server-side mirror hook could republish; keys are live = P2 = [#B]. Bump to [#A]+date to act now. +assets/wireguard-config/wg-NL-781.conf, wg-US-CA-144.conf, wg-US-TX-714.conf each hold an [Interface] PrivateKey (added c7b7d16, 2026-07-05), not gitignored. Decision: if not meant to be tracked, rotate the three Proton keys, git rm + gitignore assets/wireguard-config/, scrub history (filter-repo/BFG), force-push. If intentional, confirm no mirror hook and record the decision in notes.org so audits stop flagging it. Not :solo: — needs Craig's call. +** TODO [#C] Installer chpasswd unguarded — unloggable primary user :bug:solo:quick: +Grading: Major severity (fresh system's primary user can't log in) x rare edge case (chpasswd seldom fails) = P3 = [#C]. +archsetup:1168 runs =echo "$user:$pass" | chpasswd= with no guard, then unsets the password next line; set -e is off (line 21), so a silent failure leaves no password and no log entry. Fix: guard with error_fatal (report + "set it by hand: passwd $user") before unsetting. See findings doc (S2). +** TODO [#C] Installer nvme early module never built into initramfs :bug:solo: +Grading: Minor severity (module autoload still boots the system) x most-machines (all Craig's ZFS-root boxes) = P3 = [#C]. +archsetup:2910 writes MODULES=(nvme) but the only mkinitcpio -P in boot_ux runs =if ! is_zfs_root=, so on ZFS-root non-Framework machines the early-load hardening is never compiled in. Also archsetup:2918 greps the whole file for "nvme" (not the MODULES line). Fix: rebuild initramfs after the MODULES edit regardless of ZFS; scope the presence grep to =^MODULES=(=. See findings doc (S3). +** TODO [#C] Installer disk-space pre-flight check is fragile :bug:solo:quick: +Grading: Major severity (aborts a valid install) x some (df wraps long device names on a live ISO / device-mapper root) = P3 = [#C]. +archsetup:487 parses =df / | awk 'NR==2'=, which reads the device-name line (empty $4 -> 0 GB) when df wraps; archsetup:488 also integer-truncates the GB compare against the 20 GB floor. Fix: =df -P /= (single-line) or =df --output=avail=; compare in KB to avoid the rounding bias. See findings doc (S1). +** TODO [#C] Installer run_step state + exit-code handling :bug:solo: +Grading: Major severity (resume re-runs steps and can abort on a survivable warning) x some (a step whose last action is a non-fatal failure) = P3 = [#C]. +archsetup:298 marks a step complete only when its function returns 0, but error_warn/run_task return 1, so a non-fatal-failing step never writes its marker and re-runs on resume. Also archsetup:1034 reports =$?= of the =false= test, not pacman's real exit code; and run_step locals (290/318) leak to global scope. Fix: step functions =return 0= explicitly (or gate run_step on a per-step error flag); capture the real exit code; add =local=. See findings doc (S1). +** TODO [#C] cmail password decrypted world-readable before chmod :bug:security:solo:quick:cmail: +Grading: security carve-out — brief local plaintext exposure of the mail password, requires a concurrent local shell during install; narrow window = low severity = P3 = [#C]. +scripts/cmail-setup-finish.sh:52 gpg-decrypts to ~/.config/.cmailpass at the process umask (often 0644), then chmod 600 on the next line. Fix: =(umask 077; gpg ... --output ...)= or decrypt to a mktemp 0600 file and mv into place (mirror the import-wireguard mktemp -d 0700 pattern). See findings doc (S4). +** TODO [#C] Installer sudoers.pacnew blind copy risks lockout :bug:solo:quick: +Grading: Major severity (a malformed sudoers locks out privilege escalation) x rare edge case = P3 = [#C]. +archsetup:1146 does =[ -f /etc/sudoers.pacnew ] && cp /etc/sudoers.pacnew /etc/sudoers= with no validation, right before the NOPASSWD rule at 1183. Fix: =visudo -cf /etc/sudoers.pacnew && cp ... || error_warn=. See findings doc (S2). +** TODO [#C] WireGuard import leaves full-tunnel VPN live on failure :bug:solo:network: +Grading: Major severity (all traffic silently routed through Proton until manual cleanup) x rare (nmcli modify failure) = P3 = [#C]. +scripts/import-wireguard-configs.sh:51-62 imports (which brings the 0.0.0.0/0 tunnel up), renames, then deactivates; under set -e a failed modify aborts before the down, leaving the tunnel live. Fix: bring the connection down right after parsing the UUID, before the rename. See findings doc (S4). +** TODO [#D] Installer resume-idempotency cluster :bug:solo: +Grading: Minor severity x rare edge case (re-run after a mid-step failure) = P4 = [#D]. Group of small non-idempotent / wrong-target spots. +crontab log-cleanup line duplicates on resume (archsetup:1713 — guard on absence); zfs scrub timer picks an arbitrary pool via =head -1= and yields =@.timer= when empty (archsetup:1857); gamemode enabled via =systemctl --user= which the script itself documents fails at install time (archsetup:2419 — use the manual wants-symlink like syncthing). See findings doc (S2, S3). +** TODO [#D] Installer unguarded chmod/cp after non-fatal ops :bug:solo:quick: +Grading: Minor severity x rare edge case (only when a preceding non-fatal cp/clone failed) = P4 = [#D]. +With set -e off, unguarded chmod/cp hit missing/partial files silently: hypr-live-update-guard chmods (archsetup:2108/2144), zfs-replicate cp (archsetup:1820) leaving a service with a dead ExecStart, zfs-pre-snapshot cp (archsetup:1943) leaving a broken pacman hook. Fix: wrap each in =(...) >> log 2>&1 || error_warn=. See findings doc (S2, S3). +** TODO [#D] normalize-notify-sounds temp/atomicity can corrupt tracked file :bug:solo:quick: +Grading: Minor severity (corrupts a repo-tracked sound file, recoverable via git) x rare (ffmpeg failure/interrupt) = P4 = [#D]. +scripts/normalize-notify-sounds.sh:39-46 has no EXIT trap on the mktemp and does =cat "$tmp" > "$f"= (truncate-first) where $f is a stow symlink into the repo; a zero-byte/failed encode writes a corrupt file. Fix: EXIT trap; =[ -s "$tmp" ]= guard; write $f.tmp and overwrite on success. See findings doc (S4). +** TODO [#D] Installer + scripts refactor opportunities :refactor: +Grading: no behavior change; parking lot. 12 refactors from the sentry audit — duplicated GPU-modalias scan, triple hand-rolled retry loop, stow x4, display_server/window_manager dispatch dup, Maia ELO range x3, per-script log helpers, GRUB/snapper/fsck sed clusters, waybar-battery positional sed. Full list with line numbers in [[file:docs/design/2026-07-19-sentry-code-findings.org][sentry code findings]] (High/Medium/Low tagged). Pull individual ones out as their own tasks when tackled. ** TODO [#B] Velox boot-failure retrospective — upgrade guard gaps :bug:zfs:maint: Post-mortem for the 2026-07-15 velox no-kernel boot failure, from the archsetup/maint code review: - maint's UPDATE remedy runs a plain =yay -Syu --noconfirm= (remedies.py:297). The live-update guard (guard.py) only matches mesa/hyprland (the 2026-06-07 live-swap class) — it never checks /boot, kernel, initramfs, or mkinitcpio exit. No post-upgrade /boot assertion exists. An interrupted kernel transaction slips straight through. @@ -94,28 +93,6 @@ Post-mortem for the 2026-07-15 velox no-kernel boot failure, from the archsetup/ ** TODO [#C] Add inetutils to install base :feature:solo:quick:network: TRAMP's /ftp: method (ange-ftp) shells out to a command-line ftp client; Arch ships none by default. GNU inetutils provides =/usr/bin/ftp=. Craig's dirvish config has an FTP quick-access entry (phone FTP server), so it's a config dependency. Installed manually on ratio 2026-07-14; velox needs it once it boots. Add to the install base so future machines get it for free; verify via VM test. From .emacs.d handoff 2026-07-14-1751. -** DONE [#C] Restore date-format scrolling on the waybar date module :feature:waybar:dotfiles:quick: -CLOSED: [2026-07-19 Sun] -Shipped dotfiles 9dfe082: date-only ring (ordinal/full/longdate), on-scroll rewired, layout guard flipped. UTC/time stay on the time module. -Date and time are separate fixed-position controls. The time display cycles its -own formats, including UTC; the date/calendar control cycles date-only formats -and never displays a second time. Implement the dedicated format rings, -tooltip behavior, and tests together in the dotfiles Waybar configuration. -Reference material for the compact clock/chronograph treatment is filed in -[[file:working/clock-display-references/][working/clock-display-references/]]. - -*** 2026-07-19 Sun @ 04:36:26 -0500 Folded clock-panel interaction direction -The clock-panel handoff settled the prior open question: UTC belongs only to -the time ring, while the date ring is date-only. The existing task is therefore -a focused follow-up, not a two-line restoration of the old combined ring. - -** DONE [#C] Notification sound loudness :chore:audio:quick:solo: -CLOSED: [2026-07-19 Sun] -Shipped dotfiles 808ca23: NOTIFY_VOLUME default 65536->39322 (0.6 gain) in both notify copies. -Reduce notification-sound playback loudness by 40% (0.6 gain, approximately --4.4 dB). Change the =NOTIFY_VOLUME= playback control rather than re-encoding -the normalized sound files; verify each notification type still plays clearly. - ** TODO [#C] Dupre theme waybar.css drifted from live style.css :bug:dotfiles:waybar: Grading: Minor severity (cosmetic, reverts only on a theme switch) × rare edge case (dupre is already the active theme) = P4 = [#D] on user impact, bumped to [#C] because the dotfiles =make test= stays RED until synced, poisoning the green baseline for every future commit. The weather-kit work added =#custom-weather= selectors to =hyprland/.config/waybar/style.css= but never mirrored them into =hyprland/.config/themes/dupre/waybar.css=. =tests/theme-css= asserts the two files are identical (set-theme copies the theme file over the live one), so switching to dupre would silently revert the weather chip styling. Fix: sync the theme file to live. Pre-existing; found 2026-07-19 during an unrelated commit's green-baseline run. @@ -130,33 +107,14 @@ any binding. Offer a period-appropriate selector for timer duration, likely drawing on the tape-counter idiom, while preserving the existing direct-entry path. -** DONE [#C] Show the active wired interface in the Waybar network module :feature:waybar:network: -CLOSED: [2026-07-19 Sun] -Shipped dotfiles 22867f9: select_device prefers connected wifi -> connected ethernet -> wifi fallback, so a live cable shows the wired glyph+iface instead of Offline. -When Ethernet is active, replace the offline-WiFi presentation with the wired -interface glyph and interface name. - ** TODO [#C] Order network-panel connections by availability :feature:network: Present saved and currently available networks in this order: available saved profiles, available unsaved networks, then saved profiles that are unavailable. -** DONE [#C] Let the clock panel dismiss itself on right click :feature:clock:waybar: -CLOSED: [2026-07-19 Sun] -Shipped dotfiles fc9a2b7: secondary-button gesture -> ClockApplication._dismiss hides the open panel. Live-verified with Craig 2026-07-19. -Make a right click inside the open clock panel toggle it closed. Preserve left -click for its established interaction; the Waybar time module remains the -explicit way to reopen the panel. - ** TODO [#C] Indicate hotspot or metered WiFi in amber :feature:network:waybar: Detect hotspot/metered connectivity and render the WiFi icon plus SSID amber, while ordinary WiFi stays white. -** DONE [#C] Make the WiFi toggle connect the best available profile :feature:network: -CLOSED: [2026-07-19 Sun] -Shipped dotfiles 9105361: manage.wifi_radio -> _connect_best_saved activates the strongest in-range saved profile on enable; nothing in range falls back to NM autoconnect. -When enabling WiFi, automatically connect to the highest-priority available -saved network instead of requiring a panel selection first. - ** TODO [#B] Reconcile panel keybindings around Super+N :feature:hyprland: Swap the notification and networking bindings so primary panels are one Super-plus-letter chord away, audit the other exceptions, and bring the @@ -1799,3 +1757,77 @@ Addendum (Craig, 2026-07-07): DO backport the 3.5-entry height convention — ev ** DONE [#B] Absorb the clock-panel project into the dotfiles :feature:waybar:dotfiles: CLOSED: [2026-07-18 Sat] Absorbed into =~/.dotfiles= (commit 3fab11d): package =clock/src/clock/= (renamed from clock_panel), the six PNG watchface layers packaged inside the module at =clock/src/clock/assets/=, a stowed =clock-panel= shell shim (LD_PRELOADs gtk4-layer-shell), waybar left-click now =clock-panel toggle= with the absolute path dropped, tests converted pytest→unittest into =tests/clock/= plus an asset-load guard. Kept the layer-shell overlay and the socket toggle. The standalone repo is archived (ARCHIVED.md), kept for its design history. Verified live: the bar click renders the polished watchface. +** DONE [#A] Velox boot recovery — no kernel in BE :bug:velox:zfs: +CLOSED: [2026-07-19 Sun] +Recovered. Velox boots linux-lts 6.18.38 and is back on the tailnet (up 1d+, /boot holds initramfs-linux-lts.img). The pre-pacman ZFS snapshot rollback restored the kernel from the ZBM recovery shell. +Velox won't boot: ZBM prompts for the passphrase, unlocks, then reports no bootable environment with a kernel. Cause: an interrupted kernel =-Syu= removed the old kernel and never installed the new one — /mnt/be/boot (from zroot/ROOT/default) holds ONLY intel-ucode.img; vmlinuz-linux + both initramfs are gone. /boot lives inside zroot/ROOT/default (no separate boot dataset), so root-dataset snapshots capture it. + +Status 2026-07-15: a first rollback attempt did NOT fix it (square zero after reboot) — suspected typo in the snapshot name, so the rollback likely errored and did nothing. NOT verified. Next session: verify state in the ZBM recovery shell BEFORE any reboot. + +Recovery lever: the pre-pacman ZFS snapshot hook (live on velox since 2026-06-29) snapshots zroot/ROOT/default@pre-pacman_<ts> before every pacman transaction. The newest =pre-pacman_<ts>= predating the failed upgrade holds the intact old kernel — roll back to it. + +Morning steps (Craig at velox ZBM → recovery shell, Ctrl+R): +#+begin_src sh +# 1. pool writable + key loaded +zpool get readonly zroot +zfs get -H -o value keystatus zroot/ROOT/default +# if readonly=on: zpool export zroot && zpool import -f -N zroot +# if keystatus=unavailable: zfs load-key zroot + +# 2. list snapshots — COPY THE EXACT NAME (the typo bit here last time) +zfs list -t snapshot -o name,creation zroot/ROOT/default | grep pre-pacman + +# 3. see current /boot state (read-only mount) +umount /mnt/be 2>/dev/null; mkdir -p /mnt/be +mount -t zfs -o zfsutil,ro zroot/ROOT/default /mnt/be +ls -la /mnt/be/boot + +# 4. if /boot still shows only intel-ucode.img: redo rollback with the exact name +umount /mnt/be 2>/dev/null +zfs rollback -r zroot/ROOT/default@pre-pacman_<EXACT-TS> # -r, NOT -R + +# 5. VERIFY before reboot — remount RO, confirm the kernel is back +mount -t zfs -o zfsutil,ro zroot/ROOT/default /mnt/be +ls -la /mnt/be/boot # MUST show vmlinuz-linux + initramfs-linux.img +umount /mnt/be + +# 6. only once /boot shows a kernel: +zpool export zroot && reboot +#+end_src +Scope: only zroot/ROOT/default reverts; /home, /var, /media are separate datasets, untouched. After boot: =pacman -Syu= attended, confirm /boot holds vmlinuz-linux + initramfs before any shutdown. Full diagnosis: =inbox/PROCESSED-2026-07-15-0002-from-.emacs.d-velox-boot-failure-handoff.org=; ZBM photo: =inbox/PROCESSED-2026-07-15-0002-from-.emacs.d-PXL_20260715_043758976.jpg= (local on ratio; inbox is gitignored). +** DONE [#C] Restore date-format scrolling on the waybar date module :feature:waybar:dotfiles:quick: +CLOSED: [2026-07-19 Sun] +Shipped dotfiles 9dfe082: date-only ring (ordinal/full/longdate), on-scroll rewired, layout guard flipped. UTC/time stay on the time module. +Date and time are separate fixed-position controls. The time display cycles its +own formats, including UTC; the date/calendar control cycles date-only formats +and never displays a second time. Implement the dedicated format rings, +tooltip behavior, and tests together in the dotfiles Waybar configuration. +Reference material for the compact clock/chronograph treatment is filed in +[[file:working/clock-display-references/][working/clock-display-references/]]. + +*** 2026-07-19 Sun @ 04:36:26 -0500 Folded clock-panel interaction direction +The clock-panel handoff settled the prior open question: UTC belongs only to +the time ring, while the date ring is date-only. The existing task is therefore +a focused follow-up, not a two-line restoration of the old combined ring. +** DONE [#C] Notification sound loudness :chore:audio:quick:solo: +CLOSED: [2026-07-19 Sun] +Shipped dotfiles 808ca23: NOTIFY_VOLUME default 65536->39322 (0.6 gain) in both notify copies. +Reduce notification-sound playback loudness by 40% (0.6 gain, approximately +-4.4 dB). Change the =NOTIFY_VOLUME= playback control rather than re-encoding +the normalized sound files; verify each notification type still plays clearly. +** DONE [#C] Show the active wired interface in the Waybar network module :feature:waybar:network: +CLOSED: [2026-07-19 Sun] +Shipped dotfiles 22867f9: select_device prefers connected wifi -> connected ethernet -> wifi fallback, so a live cable shows the wired glyph+iface instead of Offline. +When Ethernet is active, replace the offline-WiFi presentation with the wired +interface glyph and interface name. +** DONE [#C] Let the clock panel dismiss itself on right click :feature:clock:waybar: +CLOSED: [2026-07-19 Sun] +Shipped dotfiles fc9a2b7: secondary-button gesture -> ClockApplication._dismiss hides the open panel. Live-verified with Craig 2026-07-19. +Make a right click inside the open clock panel toggle it closed. Preserve left +click for its established interaction; the Waybar time module remains the +explicit way to reopen the panel. +** DONE [#C] Make the WiFi toggle connect the best available profile :feature:network: +CLOSED: [2026-07-19 Sun] +Shipped dotfiles 9105361: manage.wifi_radio -> _connect_best_saved activates the strongest in-range saved profile on enable; nothing in range falls back to NM autoconnect. +When enabling WiFi, automatically connect to the highest-priority available +saved network instead of requiring a panel selection first. |
