aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
* refactor: extract get_raid_level fzf preview into raid.sh helperCraig Jennings2026-04-263-102/+194
| | | | | | | | | | | | | | `get_raid_level()` carried a 98-line inline fzf `--preview` shell snippet that contained five nearly-parallel `case` branches emitting per-level preview text, plus three exported variables (`RAID_DISK_COUNT`, `RAID_TOTAL_GB`, `RAID_SMALLEST_GB`) just to pass values into the fzf preview subshell. The inline shell-in-shell had no syntax highlighting, no shellcheck on the inner snippet, and any edit to preview copy meant editing inside a single-quoted argument. I extracted the per-level text into a new `raid_preview(level, disk_count, total_gb, smallest_gb)` helper in `lib/raid.sh`. It reuses the existing `raid_fault_tolerance` and `raid_usable_bytes` primitives for the data lines instead of redoing the arithmetic inline. That keeps the math in one place. The fzf `--preview` argument is now a one-liner that calls `raid_preview` with the sizing values, and the env-var exports are gone. `export -f raid_preview raid_fault_tolerance raid_usable_bytes` makes the functions visible in fzf's preview subshell. I verified this against a fresh `bash -c` subshell, which is what fzf spawns internally. `get_raid_level()` shrinks from 144 to 49 lines. Preview text is now bats-tested. Added 8 unit tests across the 5 RAID levels (headline, fault-tolerance line, computed usable space), mixed-size handling for mirror (smallest disk, not average), unknown level returning 1 with empty output, and a sanity loop confirming every valid level produces non-empty output. No behavior change. The preview pane shows the same text, the same level options, the same selected output. The pure logic in `lib/raid.sh` is unchanged.
* fix: fail fast on missing ZFSBootMenu efibootmgr entryCraig Jennings2026-04-263-10/+116
| | | | | | | | | | The post-bootloader boot-order step in `configure_zfsbootmenu` parsed `efibootmgr` output through a `grep | head | grep -oP` chain with no null guards. If any link returned empty (the entry wasn't created, the label was different, or efibootmgr itself failed), the surrounding `if [[ -n "$bootnum" ]]` silently skipped, the install reported success, and the user rebooted into a machine that wouldn't boot ZFSBootMenu by default. I replaced the chain with two pure helpers in `lib/common.sh`, `parse_efibootmgr_entry` and `parse_efibootmgr_bootorder`. The caller in `archangel` invokes them with explicit `|| error` guards on each parse stage. The helpers capture `efibootmgr` output once and reuse it (it was called twice before). The same hardening covers the BootOrder lookup at the adjacent line. It used to rely on the now-removed `bootnum` guard for safety. The helpers are stdin-driven and use bash regex, so they're easy to test in bats without exercising the real efibootmgr binary. Added 9 unit tests across normal cases, hex-character boot numbers, multi-match selection, missing label, missing BootOrder line, empty input, and an empty label argument. The empty-label case would otherwise falsely match `BootCurrent` via the hex regex, capturing "C". The helper now guards it explicitly. Verified manually against real efibootmgr output (GRUB entry at Boot0001, BootOrder 0006,0001,2001,2002,2003). Both helpers parsed correctly. VM integration not re-run for this small post-bootloader change. The next scheduled `make test-install` exercises the green path.
* fix: don't mask test-install exit codes through teeCraig Jennings2026-04-211-1/+14
| | | | | | | | | | | | | | | | | | | | | | | | | The Makefile let failures slip through silently when the caller piped output: `make test-install 2>&1 | tee log` returned 0 even when the inner build or VM run failed, because tee's zero exit masked the pipeline. This happened today during an ISO rebuild — the first attempt failed on corrupted pacman cache but the task notification reported exit 0. Two changes: 1. Set the recipe shell flags to enable pipefail (`SHELL := /bin/bash` + `.SHELLFLAGS := -o pipefail -c`). Any intra-recipe pipeline now propagates the first non-zero exit instead of the last. Safe to add — no existing recipe uses intra-recipe pipes today. 2. Bake tee into the test-install recipe itself. Output writes to `test-logs/make-test-install-YYYY-MM-DD-HHMM.log` so callers never need to pipe through tee externally. With SHELLFLAGS pipefail in place, the test script's exit code propagates through the baked-in tee back to the caller cleanly. Verified with a repro: a recipe shaped like `failing-cmd | tee log` returns non-zero; the 71-test bats suite still passes.
* fix: cleanup on empty findmnt + stale profiledef entriesCraig Jennings2026-04-211-3/+5
| | | | | | | | | | | | | | | | | | | | | | | Two pre-existing build.sh bugs surfaced while rebuilding the ISO for the first time since the April lib/ refactor. 1. safe_cleanup_work_dir runs findmnt | grep | sort in a command substitution. When no mounts match (the common case — this is a defensive sweep on top of the explicit known-mount loop), grep exits 1, pipefail propagates it, set -e exits the script. The trap then reports "Build interrupted or failed" and the build aborts before doing any work. Swallow the grep status with || true; no-match is not an error here. 2. The profiledef.sh file_permissions seds drifted out of sync with the lib/ refactor: - lib/zfs.sh was removed in 3321f0f but its sed block stayed, producing a warning every build ("Cannot change permissions of '.../lib/zfs.sh': no such file"). - lib/raid.sh was added in 19f4624 without a corresponding sed, so the file shipped with whatever permissions cp gave it. Drop the zfs.sh block and add the raid.sh block.
* fix: verify_rollback sentinel must live on the rolled-back datasetCraig Jennings2026-04-211-5/+11
| | | | | | | | | | | | | | | | | | | | | | /root is mounted on a separate dataset (zroot/home/root, created by archangel:create_datasets), but verify_rollback was snapshotting zroot/ROOT/default. The rollback was a no-op for the sentinel file, so the post-rollback existence check failed — the visible symptom was a PASSED test with a soft-failure warning ("Rollback failed - test file not restored" → "Rollback verification had issues") that persisted across ZFS configs for weeks. Move the sentinel to /etc/archangel-rollback-test. /etc has no child dataset mounted there, so the file lives on zroot/ROOT/default — the dataset actually being snapshotted and rolled back. Defensively single-quote $test_file at the five ssh_cmd call-sites so future path changes (whitespace, special chars) stay correct without touching each call again. The 2026-04-21 VM run logged "Rollback verified - test file restored" on zfs-mirror-encrypt, confirming the fix.
* feat: PrivateTmp=yes drop-in for systemd-tmpfiles on ZFS-rootCraig Jennings2026-04-214-0/+174
| | | | | | | | | | | | | | | | | | | | | | On ZFS-on-root, statx() across sibling services' /var/tmp/systemd-private-*/tmp mounts returns errno 132 (ENOTNAM). This produces 10-30 journal errors per boot and causes systemd-tmpfiles-clean.service to fail every periodic run (exit 73 / CANTCREAT). Running tmpfiles inside its own mount namespace avoids traversing sibling private-tmp paths. install_zfs() now calls configure_tmpfiles_private_tmp() between configure_zfs_tools and sync_efi_partitions, so the genesis snapshot captures the drop-ins. Btrfs path is untouched — errno 132 is ZFS-specific. The drop-in file-writing is factored into install_dropin() in lib/common.sh (service, name, root; body from stdin). Six bats tests exercise path, content, directory permissions, idempotent overwrite, empty content, and special-character preservation. Full root-cause write-up and verification steps in docs/zfs-tmpfiles-private-tmp-fix.md.
* chore: gitignore .ai/ tooling dir, untrack notes.orgCraig Jennings2026-04-202-703/+1
|
* session: overnight refactor + testing infra + 12/12 VM install passCraig Jennings2026-04-131-1/+193
| | | | | | | | | | | | | | | | | | | | | Session 2026-04-12 23:12 → 2026-04-13 08:10 EDT. Full write-up in Session History. - Security scrub of leaked velox passphrase from 182 commits + v0.8 tag (filter-branch + force-push) - bats-core added; 65 unit tests across test_common/config/raid - 5 high/critical refactors from /refactor scan applied (dead code drop, passphrase helper unify, install_base merge, findmnt dedupe, install_btrfs decompose) - lib/raid.sh extraction with 30 bats tests - INSTALL_TIMEOUT 600→1800 for kernel 6.18+ DKMS builds - 12/12 VM install scenarios passing end-to-end - Docs: testing-strategy.org unit-test section, README sync, todo.org at project root with 8 remaining refactors Active reminder added for a zfs-mirror-encrypt rollback soft-failure surfaced during the VM run (not a regression; pre-existing drift in verify_rollback vs. ZFS rollback semantics on a mirrored pool).
* fix: bump INSTALL_TIMEOUT from 600 to 1800 for kernel 6.18+ DKMS buildsCraig Jennings2026-04-131-1/+4
| | | | | | | | | | | ZFS DKMS compile + depmod against kernel 6.18.22 in a 4-CPU VM under host load exceeds 10 minutes. With INSTALL_TIMEOUT=600, all 6 ZFS test configs timed out during the DKMS install step after pacstrap. The one ZFS config that passed ('custom-locale', first ZFS config alphabetically) squeaked in just under the deadline. Bumped to 1800s (30 min). Session notes from 2026-02-12 mention this bump but the change never made it into git.
* docs: document bats unit tests + sync stale README bitsCraig Jennings2026-04-132-18/+80
| | | | | | | | | | | | | | | | | testing-strategy.org: - Frame the two test layers (bats unit / VM integration) in Overview - Add 'Unit Tests (bats)' section: what's covered, what's deliberately not, how to run, how to install, and the extract-then-test pattern - Fix stale Makefile Targets table (bats row, test row now lint+bats) README.org: - Rename 'Testing with VMs' to 'Testing' and add the two-layer framing - Surface make test / make bats / make lint in the bulleted list - Project Structure tree: drop zfs.sh (deleted last session), add raid.sh with description, add tests/unit/ entry - Point archzfs link to GitHub Releases (archzfs.com was abandoned mid-2025; url updated in code last session) - Fix #testing-with-vms internal link to match the renamed heading
* refactor: decompose install_btrfs into named orchestration stagesCraig Jennings2026-04-133-62/+97
| | | | | | | | | | | | | | | | | | | | | | | | | Pull the single-vs-multi-disk and LUKS-vs-no-encryption branching out of install_btrfs() into five helpers in lib/btrfs.sh: - btrfs_open_encryption — LUKS open + fill devices array - btrfs_make_filesystem — create_btrfs_volume dispatch - btrfs_configure_luks_target — in-chroot LUKS config - btrfs_install_grub — GRUB primary + multi-disk mirror - btrfs_close_encryption — LUKS close (cleanup) Helpers use namerefs (local -n) to take the caller's arrays as locals instead of promoting them to globals. install_btrfs() drops from ~99 lines of nested if-then-else to a ~45-line flat sequence of named stages — matching the style of install_zfs(). Behavior preserved — this is pure code movement, no new disk/LUKS operations. No unit tests added for the new helpers: they all wrap real LUKS/mkfs.btrfs calls that need block devices and root; VM integration tests in scripts/test-install.sh remain the source of truth. .shellcheckrc: disable SC2178 (nameref array heuristic) and SC2153 (globals from sourced files) — both recurring false positives. make test: 65/65. shellcheck clean.
* refactor: dedupe findmnt invocation in safe_cleanup_work_dirCraig Jennings2026-04-131-4/+8
| | | | | | | | | | | The catch-all mount-cleanup block called findmnt twice (once as an existence guard, once in the pipe). Consolidate to a single call captured to a local, guard with -n test. No behavior change — same mounts, same order, same lazy-unmount. Left the explicit known-mount loop alone; it's a faster path for the deterministic mkarchiso bind mounts, with findmnt as the catch-all for anything else. Not parallel strategies, just fast path + fallback.
* refactor: merge install_base and install_base_btrfsCraig Jennings2026-04-133-69/+106
| | | | | | | | | | | | | | | | Extract the pacstrap package list into pacstrap_packages(filesystem) in lib/common.sh (common + filesystem-specific). install_base() now dispatches on FILESYSTEM for both the archzfs-repo-append and the package list. install_base_btrfs() deleted; install_btrfs() call site updated to invoke install_base. Old: 49 + 38 lines of ~95% copy-paste. New: 32 lines + a 20-line pure helper. 7 bats tests cover: zfs has zfs-dkms/zfs-utils, btrfs has btrfs-progs + grub + grub-btrfs + snapper + snap-pac, each flavor excludes the other's specifics, common packages are in both, unknown filesystem returns status 1, output is one-per-line. make test: 65/65.
* refactor: unify get_{luks,zfs}_passphrase and get_root_passwordCraig Jennings2026-04-133-54/+70
| | | | | | | | | | | | | | | Extract the prompt/confirm/min-length loop into prompt_password() in lib/common.sh using a nameref for the output variable, so UI output stays on the terminal (no command-substitution capture) and the three callers collapse from ~30 lines each to a single helper call. - get_luks_passphrase() — min 8 chars - get_zfs_passphrase() — min 8 chars - get_root_password() — no min (was unchecked before; preserved) 5 bats tests added: match+min-ok path, length-retry loop, mismatch-retry loop, min_len=0 disables check, empty passphrase when min_len=0. make test: 58/58.
* refactor: drop dead mount_efi and select_raid_level from lib/disk.shCraig Jennings2026-04-131-41/+0
| | | | | | | lib/disk.sh:mount_efi() was shadowed by installer/archangel:mount_efi() (different signature, no-arg ZFS-specific) and had zero callers. lib/disk.sh:select_raid_level() was superseded by get_raid_level() in archangel and also had zero callers. Both removed.
* refactor: extract pure RAID logic to lib/raid.sh with bats coverageCraig Jennings2026-04-123-6/+274
| | | | | | | | | | | | | | | | | | | | Peel the testable pieces of get_raid_level() out of the 1600-line installer monolith into installer/lib/raid.sh: - raid_valid_levels_for_count(count) — replaces the inline option-list builder in get_raid_level() - raid_is_valid(level, count) — useful for unattended-config validation - raid_usable_bytes(level, count, smallest, total) — usable-space math - raid_fault_tolerance(level, count) — max tolerable disk failures archangel now sources lib/raid.sh and uses raid_valid_levels_for_count for the fzf option list. Fzf preview subshell still inlines its own usable-bytes arithmetic (calling exported lib functions across preview subshells is fragile; left for a later pass). 30 bats tests in tests/unit/test_raid.bats cover the full enumeration table, every valid/invalid level-vs-count combo from 2 to 5 disks, mixed-size mirror, and unknown-level error paths. make test: 53/53.
* test: add bats unit tests for common.sh and config.shCraig Jennings2026-04-123-4/+211
| | | | | | | | 23 bats tests covering the pure logic in installer/lib/common.sh (command_exists, require_command, info/warn/error, enable_color, require_root, log) and installer/lib/config.sh (parse_args, load_config, validate_config, check_config). Makefile adds a 'bats' target; 'test' now runs lint + bats (VM integration tests remain under test-install).
* security: gitignore host configs, add .example templatesCraig Jennings2026-04-123-0/+3
| | | | | | velox-{zfs,btrfs}.conf contain LUKS/ZFS passphrases and root passwords. Untrack them and add velox-*.conf to .gitignore. Committed .example templates show the expected structure with 'welcome' placeholders.
* refactor: remove dead installer/lib/zfs.shCraig Jennings2026-04-122-378/+8
| | | | | | | | | | | | | The library was sourced but only zfs_preflight was reachable from install_zfs(); the other ten functions either had names that were never called (create_zfs_datasets, configure_zfs_pacman_hook, etc.) or were shadowed by same-named definitions in the monolithic installer/archangel (create_zfs_pool, configure_zfsbootmenu, configure_zfs_services). Inlined zfs_preflight into archangel and dropped the source line. Removes a trap where fixes appear to be "mirrored" but only one copy actually runs.
* fix: drop zroot/tmp dataset and dedup pacman snapshot hookCraig Jennings2026-04-122-8/+46
| | | | | | | | | | - /tmp on ZFS breaks systemd-tmpfiles-clean (statx ENOLINK on PrivateTmp paths). Use tmpfs via fstab instead; keep zroot/var/tmp. - zfs-pre-snapshot gains a 60s lockfile in /run so burst transactions (archsetup produced 357 snapshots in one run) collapse to one. Both fixes mirrored in installer/archangel and installer/lib/zfs.sh. Already applied and verified on velox.
* session: first bare metal install on velox, multiple fixesCraig Jennings2026-04-103-0/+540
| | | | | ZFS and Btrfs tested on bare metal. Fixed archzfs repo URL, LUKS pbkdf2 for GRUB, no-color default, and missing inetutils. Tagged v0.8.
* fix: add inetutils to installed system packagesCraig Jennings2026-04-091-0/+2
| | | | Provides hostname, ping, and other networking basics on the target system.
* fix: use pbkdf2 for LUKS2 containers instead of argon2idCraig Jennings2026-04-091-2/+5
| | | | | GRUB's LUKS2 support only handles pbkdf2. When /boot is inside the encrypted volume, argon2id causes GRUB to reject the correct password.
* feat: default to no-color output, add --color flag to enableCraig Jennings2026-04-092-11/+16
| | | | Keeps logs and SSH output clean. Use archangel --color for colored output.
* fix: migrate archzfs repo from stale archzfs.com to GitHub ReleasesCraig Jennings2026-04-092-4/+4
| | | | | archzfs.com was abandoned mid-2025; latest packages were ZFS 2.3.2 for kernel 6.12.29. The new GitHub-hosted repo has ZFS 2.4.1 for 6.18.21.
* session: add logo candidates and build new ISOCraig Jennings2026-03-283-0/+0
| | | | | | Added three archangel logo candidate images to assets/. Built and distributed archangel-2026-03-28 ISO (linux-lts 6.18.20) to Ventoy USB and TrueNAS.
* docs: reorganize README sections to follow logical user journeyCraig Jennings2026-02-241-161/+131
| | | | | | | | | | | | Eliminate Bare Metal Installation section by redistributing its content: - dd command → Building the ISO > Writing to USB - Secure Boot/boot steps → new Booting the ISO section - SSH/Avahi → SSH Access subsection under Booting the ISO - archangel invocation → Installation intro - ZFS/Btrfs first-boot → new Post-Reboot section Rename sections: Connecting via SSH Server → Booting the ISO, Arch Linux Install Walkthrough → Installation.
* docs: add Running Tests section to testing strategy, link from READMECraig Jennings2026-02-242-1/+36
|
* docs: move Testing with VMs section above Troubleshooting in READMECraig Jennings2026-02-241-49/+49
|
* refactor: rename vm-* Makefile targets to test-* for discoverabilityCraig Jennings2026-02-242-21/+21
|
* feat: add Makefile targets for manual VM testingCraig Jennings2026-02-242-17/+53
| | | | | Add vm, vm-multi, vm-multi3, vm-boot, and vm-clean targets. Update README to reference make targets instead of raw script invocations.
* docs: add testing-strategy.org with ZFS encryption notes and test recipeCraig Jennings2026-02-241-0/+287
|
* feat: add ZFS encrypted volume tests (single disk + mirror)Craig Jennings2026-02-243-10/+110
| | | | | | | Add automated tests for ZFS native encryption, matching existing Btrfs LUKS test coverage. ZFS encrypted boot requires two passphrase entries (ZFSBootMenu + mkinitcpio zfs hook), both sent via QEMU monitor sendkey with timed delays since ZFSBootMenu renders to VGA, not serial.
* feat: add preflight checks, rename ISO format, use Makefile targets in docsCraig Jennings2026-02-232-18/+27
| | | | | | | - Add Arch Linux and disk space preflight checks to build.sh - Rename ISO format: archangel-YYYY-MM-DD-vmlinuz-version-lts-x86_64.iso - Update README to use Makefile targets throughout (make build, make clean) - Note preflight checks in Prerequisites section
* docs: fix overview paragraph breaks and missing conjunctionCraig Jennings2026-02-231-1/+5
|
* docs: use inline code for make build in overviewCraig Jennings2026-02-231-7/+1
|
* docs: update README overview wordingCraig Jennings2026-02-231-12/+11
|
* chore: remove default Makefile target, update README overviewCraig Jennings2026-02-232-9/+2
|
* docs: update README subtitle and fix internal linksCraig Jennings2026-02-231-1/+1
|
* docs: fix internal links to use GitHub-compatible anchor formatCraig Jennings2026-02-231-9/+9
|
* docs: expand README with rescue disk, SSH, config example, and address ↵Craig Jennings2026-02-231-44/+134
| | | | review comments
* docs: add CONTRIBUTING.md for open-source contributorsCraig Jennings2026-02-231-0/+58
|
* refactor: rename custom/ to installer/ for clarityCraig Jennings2026-02-2316-14/+15
| | | | | | | | The custom/ directory name was an archiso implementation detail. Renamed to installer/ which clearly communicates that this directory contains the installer scripts and utilities that ship on the ISO. Updated all references in build.sh, Makefile, test-install.sh, and README.
* docs: reorganize README features and fix table formattingCraig Jennings2026-02-231-12/+12
|
* chore: add inbox/ to .gitignoreCraig Jennings2026-02-231-0/+1
|
* feat: add LUKS passphrase automation to VM test frameworkCraig Jennings2026-02-231-1/+117
| | | | | | | | | | - Add monitor_sendkeys() to type strings into QEMU via monitor socket - Add send_luks_passphrase() that detects GRUB passphrase prompt in serial log and sends passphrase via sendkey, supporting multi-disk LUKS (one passphrase per encrypted disk) - Add QEMU monitor socket to start_vm_from_disk() for LUKS configs - Auto-detect LUKS configs and handle passphrase entry during reboot test - Add socat dependency check
* fix: support multi-disk LUKS and fix cryptkey format for btrfsCraig Jennings2026-02-231-20/+48
| | | | | | | | | | | | - Fix cryptkey parameter format: use rootfs: prefix so the encrypt hook finds the keyfile embedded in the initramfs (was treating bare path as a device name) - Switch multi-disk LUKS to sd-encrypt hook which reads crypttab.initramfs to open ALL LUKS containers (the traditional encrypt hook only supports a single cryptdevice) - Create crypttab.initramfs during LUKS initramfs setup - Skip cryptdevice/cryptkey cmdline params for multi-disk LUKS since sd-encrypt reads crypttab instead
* chore: add .shellcheckrc to suppress intentional shellcheck warningsCraig Jennings2026-02-231-0/+20
| | | | | | Configure shellcheck to ignore false positives from sourced file patterns (SC2034), intentional word splitting (SC2086), and other stylistic warnings that don't represent bugs.
* fix: resolve remaining SC2155 warnings across all scriptsCraig Jennings2026-02-234-21/+40
| | | | | | Declare and assign local variables separately in custom/archangel, scripts/full-test.sh, scripts/test-install.sh, and remove unused variable in custom/lib/zfs.sh.
* docs: update archangel.conf.example for btrfs supportCraig Jennings2026-02-231-8/+8
| | | | | | Remove outdated "btrfs coming soon" note, add LUKS_PASSPHRASE option for btrfs installs, and simplify encryption skip documentation to cover both filesystem types.