| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
`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.
|
| |
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
/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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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).
|
| |
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
| |
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).
|
| |
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
| |
- /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.
|
| |
|
|
|
| |
ZFS and Btrfs tested on bare metal. Fixed archzfs repo URL, LUKS pbkdf2
for GRUB, no-color default, and missing inetutils. Tagged v0.8.
|
| |
|
|
| |
Provides hostname, ping, and other networking basics on the target system.
|
| |
|
|
|
| |
GRUB's LUKS2 support only handles pbkdf2. When /boot is inside the
encrypted volume, argon2id causes GRUB to reject the correct password.
|
| |
|
|
| |
Keeps logs and SSH output clean. Use archangel --color for colored output.
|
| |
|
|
|
| |
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.
|
| |
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| | |
|
| | |
|
| | |
|
| |
|
|
|
| |
Add vm, vm-multi, vm-multi3, vm-boot, and vm-clean targets. Update
README to reference make targets instead of raw script invocations.
|
| | |
|
| |
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
| |
- 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
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| |
|
|
| |
review comments
|
| | |
|
| |
|
|
|
|
|
|
| |
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.
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
| |
- 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 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
|
| |
|
|
|
|
| |
Configure shellcheck to ignore false positives from sourced file
patterns (SC2034), intentional word splitting (SC2086), and other
stylistic warnings that don't represent bugs.
|
| |
|
|
|
|
| |
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.
|
| |
|
|
|
|
| |
Remove outdated "btrfs coming soon" note, add LUKS_PASSPHRASE option
for btrfs installs, and simplify encryption skip documentation to
cover both filesystem types.
|