diff options
| author | Craig Jennings <c@cjennings.net> | 2026-04-27 12:45:48 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-04-27 12:45:48 -0500 |
| commit | 8c69aaaff13da3b7d1d24ed34975e8c5b30409e6 (patch) | |
| tree | b296d568c124d1d8ca83275e8c197c1c0d53bca0 | |
| parent | 822075bf99cda84782ef04419855f6c289a6fc13 (diff) | |
| download | archangel-8c69aaaff13da3b7d1d24ed34975e8c5b30409e6.tar.gz archangel-8c69aaaff13da3b7d1d24ed34975e8c5b30409e6.zip | |
refactor: consolidate installer defaults and FILESYSTEM validation into config.sh
The installer had three sites touching FILESYSTEM: a top-level default in the monolith, a re-default block in gather_input, and a runtime validation block also in gather_input. The same scattering existed for LOCALE, KEYMAP, ENABLE_SSH, and NO_ENCRYPT. A future contributor changing one site wouldn't have known the other two existed.
Move all five defaults into the lib/config.sh declarations so config.sh is the single source of truth. Add validate_filesystem() in lib/config.sh and call it from main() between check_config and gather_input, so a typo in a config file's FILESYSTEM= fails fast before any install action runs.
The behavior change is stricter. An empty FILESYSTEM in a config file used to be silently defaulted to zfs, now it errors. Interactive mode is unaffected. select_filesystem still controls the value and already errored on cancellation.
Bats: 140 → 142. Five tests added in test_config.bats for the defaults pinning and validate_filesystem coverage. Three removed from test_archangel.bats for behavior that moved out of gather_input. Lint clean.
| -rwxr-xr-x | installer/archangel | 40 | ||||
| -rw-r--r-- | installer/lib/config.sh | 23 | ||||
| -rw-r--r-- | testing-strategy.org | 2 | ||||
| -rw-r--r-- | tests/unit/test_archangel.bats | 45 | ||||
| -rw-r--r-- | tests/unit/test_config.bats | 49 |
5 files changed, 84 insertions, 75 deletions
diff --git a/installer/archangel b/installer/archangel index e04b8d9..12f1cd0 100755 --- a/installer/archangel +++ b/installer/archangel @@ -34,32 +34,20 @@ source "$SCRIPT_DIR/lib/raid.sh" ############################# # Configuration ############################# - -# Filesystem selection (zfs or btrfs) -FILESYSTEM="zfs" # Default to ZFS, can be changed interactively or via config - -# These will be set interactively -HOSTNAME="" -TIMEZONE="" -LOCALE="en_US.UTF-8" -KEYMAP="us" -ROOT_PASSWORD="" -ZFS_PASSPHRASE="" -WIFI_SSID="" -WIFI_PASSWORD="" +# +# User-facing config variables (FILESYSTEM, LOCALE, KEYMAP, ENABLE_SSH, +# NO_ENCRYPT, HOSTNAME, TIMEZONE, SELECTED_DISKS, RAID_LEVEL, WIFI_*, +# ROOT_PASSWORD, ZFS_PASSPHRASE, LUKS_PASSPHRASE) are declared in +# lib/config.sh with their defaults. The monolith trusts those values. # ZFS Configuration POOL_NAME="zroot" COMPRESSION="zstd" ASHIFT="12" # 4K sectors (use 13 for 8K) -# Multi-disk RAID support -SELECTED_DISKS=() # Array of selected disk paths (/dev/sda, /dev/sdb, ...) -ROOT_PARTS=() # Array of root partition paths (populated by partition_disks) -EFI_PARTS=() # Array of EFI partition paths (populated by partition_disks) -RAID_LEVEL="" # "", "mirror", "raidz1", "raidz2", "raidz3" -ENABLE_SSH="yes" # Enable SSH with root login (default yes for headless) -NO_ENCRYPT="no" # Skip ZFS encryption (for testing only) +# Partition arrays populated by partition_disks +ROOT_PARTS=() +EFI_PARTS=() # Logging — initialized by init_logging() at install time only. Sourcing # this script (e.g. from a bats test) loads the function definitions @@ -117,12 +105,6 @@ gather_input() { if [[ -z "$ROOT_PASSWORD" ]]; then error "Config missing required: ROOT_PASSWORD"; fi if [[ ${#SELECTED_DISKS[@]} -eq 0 ]]; then error "Config missing required: DISKS"; fi - # Set defaults for optional values - [[ -z "$FILESYSTEM" ]] && FILESYSTEM="zfs" || true - [[ -z "$LOCALE" ]] && LOCALE="en_US.UTF-8" || true - [[ -z "$KEYMAP" ]] && KEYMAP="us" || true - [[ -z "$ENABLE_SSH" ]] && ENABLE_SSH="yes" || true - # ZFS-specific validation if [[ "$FILESYSTEM" == "zfs" ]]; then if [[ "$NO_ENCRYPT" != "yes" && -z "$ZFS_PASSPHRASE" ]]; then @@ -137,11 +119,6 @@ gather_input() { fi fi - # Validate filesystem choice - if [[ "$FILESYSTEM" != "zfs" && "$FILESYSTEM" != "btrfs" ]]; then - error "Invalid FILESYSTEM: $FILESYSTEM (must be 'zfs' or 'btrfs')" - fi - # Determine RAID level if not specified if [[ -z "$RAID_LEVEL" && ${#SELECTED_DISKS[@]} -gt 1 ]]; then RAID_LEVEL="mirror" @@ -1384,6 +1361,7 @@ main() { parse_args "$@" preflight_checks check_config + validate_filesystem gather_input filesystem_preflight diff --git a/installer/lib/config.sh b/installer/lib/config.sh index fefc838..65703d0 100644 --- a/installer/lib/config.sh +++ b/installer/lib/config.sh @@ -9,12 +9,18 @@ CONFIG_FILE="" UNATTENDED=false -# These get populated by config file or interactive prompts -FILESYSTEM="" # "zfs" or "btrfs" +# These get populated by config file or interactive prompts. +# Optional fields carry their default value here so config.sh is the +# single source of truth — gather_input trusts what's loaded. +FILESYSTEM="zfs" # "zfs" or "btrfs" +LOCALE="en_US.UTF-8" +KEYMAP="us" +ENABLE_SSH="yes" # SSH with root login (default yes for headless) +NO_ENCRYPT="no" # Skip filesystem encryption (testing only) + +# Required fields — installer errors out if any are still empty at install time. HOSTNAME="" TIMEZONE="" -LOCALE="" -KEYMAP="" SELECTED_DISKS=() RAID_LEVEL="" WIFI_SSID="" @@ -134,3 +140,12 @@ validate_config() { fi info "Config validation passed" } + +# Catches a typo in FILESYSTEM= from a config file before the install +# starts. Called from main() after check_config so a bad value never +# reaches gather_input or filesystem_preflight. +validate_filesystem() { + if [[ "$FILESYSTEM" != "zfs" && "$FILESYSTEM" != "btrfs" ]]; then + error "Invalid FILESYSTEM: $FILESYSTEM (must be 'zfs' or 'btrfs')" + fi +} diff --git a/testing-strategy.org b/testing-strategy.org index cfc3953..b008cc1 100644 --- a/testing-strategy.org +++ b/testing-strategy.org @@ -62,7 +62,7 @@ Current coverage lives in =tests/unit/=: | File | What it covers | |------+----------------| | =test_common.bats= | =command_exists=, =require_command=, =info=/=warn=/=error=, =enable_color=, =log=, =prompt_password=, =pacstrap_packages=, =install_dropin= | -| =test_config.bats= | =parse_args=, =load_config=, =validate_config=, =check_config= | +| =test_config.bats= | =parse_args=, =load_config=, =validate_config=, =validate_filesystem=, =check_config=, default values pinned in config.sh | | =test_raid.bats= | =raid_valid_levels_for_count=, =raid_is_valid=, =raid_usable_bytes=, =raid_fault_tolerance= | | =test_disk.bats= | =get_efi_partition=, =get_root_partition=, =partition_disks= (orchestration shape) | | =test_btrfs.bats= | =get_luks_devices= | diff --git a/tests/unit/test_archangel.bats b/tests/unit/test_archangel.bats index ccabec7..749f786 100644 --- a/tests/unit/test_archangel.bats +++ b/tests/unit/test_archangel.bats @@ -70,33 +70,9 @@ setup() { ############################# # Optional-field defaults ############################# - -@test "gather_input unattended defaults FILESYSTEM to zfs when empty" { - HOSTNAME=h - TIMEZONE=UTC - ROOT_PASSWORD=x - SELECTED_DISKS=(/dev/sda) - FILESYSTEM="" - NO_ENCRYPT=yes - gather_input >/dev/null - [ "$FILESYSTEM" = "zfs" ] -} - -@test "gather_input unattended defaults LOCALE, KEYMAP, ENABLE_SSH when empty" { - HOSTNAME=h - TIMEZONE=UTC - ROOT_PASSWORD=x - SELECTED_DISKS=(/dev/sda) - FILESYSTEM=zfs - NO_ENCRYPT=yes - LOCALE="" - KEYMAP="" - ENABLE_SSH="" - gather_input >/dev/null - [ "$LOCALE" = "en_US.UTF-8" ] - [ "$KEYMAP" = "us" ] - [ "$ENABLE_SSH" = "yes" ] -} +# Default values themselves are pinned in test_config.bats (config.sh +# is the single source of truth). The remaining test here covers the +# adjacent guarantee: gather_input doesn't clobber values the user set. @test "gather_input unattended preserves explicit non-default values" { HOSTNAME=h @@ -160,18 +136,9 @@ setup() { ############################# # Filesystem validity ############################# - -@test "gather_input unattended errors when FILESYSTEM is neither zfs nor btrfs" { - HOSTNAME=h - TIMEZONE=UTC - ROOT_PASSWORD=x - SELECTED_DISKS=(/dev/sda) - FILESYSTEM=ext4 - NO_ENCRYPT=yes - run gather_input - [ "$status" -eq 1 ] - [[ "$output" == *"Invalid FILESYSTEM"* ]] -} +# Validation moved to validate_filesystem in lib/config.sh — covered +# by test_config.bats. main() calls it between check_config and +# gather_input so a bad FILESYSTEM= never reaches install time. ############################# # RAID-level defaulting diff --git a/tests/unit/test_config.bats b/tests/unit/test_config.bats index c0c4e42..46f0236 100644 --- a/tests/unit/test_config.bats +++ b/tests/unit/test_config.bats @@ -156,3 +156,52 @@ EOF [ "$CONFIG_FILE" = "/tmp/foo.conf" ] [ -n "$RED" ] } + +############################# +# Default values sourced from config.sh +############################# +# config.sh is the single source of truth for installer defaults. The +# monolith no longer re-applies them in gather_input. These tests pin +# the values so a regression that drops a default surfaces here, not +# halfway through an unattended install. + +@test "config.sh sets defaults for FILESYSTEM, LOCALE, KEYMAP, ENABLE_SSH, NO_ENCRYPT" { + [ "$FILESYSTEM" = "zfs" ] + [ "$LOCALE" = "en_US.UTF-8" ] + [ "$KEYMAP" = "us" ] + [ "$ENABLE_SSH" = "yes" ] + [ "$NO_ENCRYPT" = "no" ] +} + +############################# +# validate_filesystem +############################# +# Called from main() between check_config and gather_input. Catches a +# typo in FILESYSTEM= from a config file before the install starts. + +@test "validate_filesystem accepts zfs" { + FILESYSTEM=zfs + run validate_filesystem + [ "$status" -eq 0 ] +} + +@test "validate_filesystem accepts btrfs" { + FILESYSTEM=btrfs + run validate_filesystem + [ "$status" -eq 0 ] +} + +@test "validate_filesystem rejects an unknown filesystem" { + FILESYSTEM=ext4 + run validate_filesystem + [ "$status" -eq 1 ] + [[ "$output" == *"Invalid FILESYSTEM"* ]] + [[ "$output" == *"ext4"* ]] +} + +@test "validate_filesystem rejects an empty FILESYSTEM" { + FILESYSTEM="" + run validate_filesystem + [ "$status" -eq 1 ] + [[ "$output" == *"Invalid FILESYSTEM"* ]] +} |
