ka-install: implement --render/--dry-run mode (issue #38)
Add ka-install verb — the third of the three writing verbs (ka-promote →
ka-build → ka-install). Always read-only: computes and prints the install
plan that ka-install <host> would execute, without touching any host.
New files:
bin/ka-install — Python3, 243 lines
tests/ka-install/run-tests.sh — 20 hermetic tests, 337 lines
tests/ka-install/fixtures/make-sandbox.sh — fixture builder, 275 lines
What --render computes:
1. Read fleet/<host>.yaml for packaging metadata
2. Read build/<host>/<baseline>/manifest.lock (from ka-promote)
3. Detect drift: build receipt missing/empty → exit 3
4. Determine backup destination from manifest template
5. Detect Image vs vmlinuz naming, select mkinitcpio hook
6. Print structured YAML plan, exit 0
Exit codes: 0 (plan ready), 2 (missing input), 3 (drift), 4 (error).
Test coverage (20/20 PASS):
- Argument parsing: requires host, --version, --dry-run alias
- Error paths: missing fleet manifest, missing manifest.lock,
unknown host
- Drift detection: no build receipt -> exit 3
- Happy path: full build receipt -> exit 0, plan printed
- Plan fields: source package, host, backup path, hook, version
- Image/vmlinuz detection for ARM and x86
- mkinitcpio --hook flag for Image (ARM), plain for vmlinuz
- /boot/firmware/ path (ampere-style boot layout)
- Grep-implementation: no scp/ssh/pacman/reboot calls
Existing suites unaffected (ka-promote: 6/6 PASS).
This commit is contained in:
Executable
+275
@@ -0,0 +1,275 @@
|
||||
#!/usr/bin/env bash
|
||||
# make-sandbox.sh — Build a hermetic kernel-agent sandbox for ka-install tests.
|
||||
#
|
||||
# Usage: make-sandbox.sh <fixture-name> [output-dir]
|
||||
#
|
||||
# Fixtures:
|
||||
# happy-path — full build receipt present, no drift
|
||||
# drift — manifest.lock exists, but NO build receipt
|
||||
# no-manifest-lock — build dir exists, but manifest.lock missing
|
||||
# no-host-manifest — fleet/<host>.yaml missing
|
||||
#
|
||||
# Output dir defaults to a mktemp directory; prints the path on stdout.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
|
||||
fixture_name="${1:?fixture name required}"
|
||||
scratch="${2:-$(mktemp -d -t ka-install-test.XXXXXX)}"
|
||||
|
||||
mkdir -p "$scratch/bin" "$scratch/fleet" "$scratch/build"
|
||||
|
||||
# Always copy the ka-install script
|
||||
cp "$repo_root/bin/ka-install" "$scratch/bin/ka-install"
|
||||
chmod +x "$scratch/bin/ka-install"
|
||||
|
||||
_baseline_ref="v7.0"
|
||||
_suffix="-fresnel-fourier"
|
||||
_boot_path="/boot/"
|
||||
_bootloader_path="/boot/extlinux/extlinux.conf"
|
||||
_host="testhost"
|
||||
_pkg_name="linux-testhost-fourier"
|
||||
|
||||
case "$fixture_name" in
|
||||
happy-path)
|
||||
# Full setup: fleet manifest + manifest.lock + build receipt
|
||||
cat > "$scratch/fleet/${_host}.yaml" <<YAML
|
||||
host: ${_host}
|
||||
arch: arm64
|
||||
soc: rockchip/rk3399
|
||||
board: pinebook-pro
|
||||
distro: archlinux-arm
|
||||
|
||||
baseline:
|
||||
ref: ${_baseline_ref}
|
||||
|
||||
package:
|
||||
name: ${_pkg_name}
|
||||
versioning: "\${baseline_ref}.kafr\${pkgrel}"
|
||||
kernel_suffix: ${_suffix}
|
||||
boot_path: ${_boot_path}
|
||||
bootloader: extlinux
|
||||
bootloader_path: ${_bootloader_path}
|
||||
install_mode: alongside
|
||||
|
||||
backup:
|
||||
pre_install: hertz:/sparfuxdata/kernel-agent-backups/testhost/\${replaced_version}/
|
||||
YAML
|
||||
|
||||
mkdir -p "$scratch/build/${_host}/${_baseline_ref}"
|
||||
cat > "$scratch/build/${_host}/${_baseline_ref}/manifest.lock" <<YAML
|
||||
host: ${_host}
|
||||
baseline:
|
||||
ref: ${_baseline_ref}
|
||||
resolved_patches:
|
||||
- apply_order: 1
|
||||
include: board/test/0001-test.patch
|
||||
sha256: abc123
|
||||
size: 100
|
||||
cumulative:
|
||||
path: cumulative.patch
|
||||
b2sum: def456
|
||||
size: 100
|
||||
build:
|
||||
built_at: '2026-07-25T12:00:00+00:00'
|
||||
built_on_host: boltzmann
|
||||
ka_build_version: 3
|
||||
published: true
|
||||
packages:
|
||||
- name: linux-testhost-fourier-7.0.kafr3-aarch64.pkg.tar.zst
|
||||
size: 12345678
|
||||
b2sum: b2mock
|
||||
YAML
|
||||
;;
|
||||
|
||||
drift)
|
||||
# Fleet manifest + manifest.lock but NO build receipt
|
||||
cat > "$scratch/fleet/${_host}.yaml" <<YAML
|
||||
host: ${_host}
|
||||
arch: arm64
|
||||
soc: rockchip/rk3399
|
||||
board: pinebook-pro
|
||||
distro: archlinux-arm
|
||||
|
||||
baseline:
|
||||
ref: ${_baseline_ref}
|
||||
|
||||
package:
|
||||
name: ${_pkg_name}
|
||||
versioning: "\${baseline_ref}.kafr\${pkgrel}"
|
||||
kernel_suffix: ${_suffix}
|
||||
boot_path: ${_boot_path}
|
||||
bootloader: extlinux
|
||||
bootloader_path: ${_bootloader_path}
|
||||
install_mode: alongside
|
||||
|
||||
backup:
|
||||
pre_install: hertz:/sparfuxdata/kernel-agent-backups/testhost/\${replaced_version}/
|
||||
YAML
|
||||
|
||||
mkdir -p "$scratch/build/${_host}/${_baseline_ref}"
|
||||
cat > "$scratch/build/${_host}/${_baseline_ref}/manifest.lock" <<YAML
|
||||
host: ${_host}
|
||||
baseline:
|
||||
ref: ${_baseline_ref}
|
||||
resolved_patches:
|
||||
- apply_order: 1
|
||||
include: board/test/0001-test.patch
|
||||
sha256: abc123
|
||||
size: 100
|
||||
cumulative:
|
||||
path: cumulative.patch
|
||||
b2sum: def456
|
||||
size: 100
|
||||
YAML
|
||||
;;
|
||||
|
||||
no-manifest-lock)
|
||||
# Fleet manifest present, but build dir has no manifest.lock
|
||||
cat > "$scratch/fleet/${_host}.yaml" <<YAML
|
||||
host: ${_host}
|
||||
arch: arm64
|
||||
soc: rockchip/rk3399
|
||||
board: pinebook-pro
|
||||
distro: archlinux-arm
|
||||
|
||||
baseline:
|
||||
ref: ${_baseline_ref}
|
||||
|
||||
package:
|
||||
name: ${_pkg_name}
|
||||
versioning: "\${baseline_ref}.kafr\${pkgrel}"
|
||||
kernel_suffix: ${_suffix}
|
||||
boot_path: ${_boot_path}
|
||||
bootloader: extlinux
|
||||
bootloader_path: ${_bootloader_path}
|
||||
|
||||
backup:
|
||||
pre_install: hertz:/sparfuxdata/kernel-agent-backups/testhost/\${replaced_version}/
|
||||
YAML
|
||||
# No build dir at all — ka-promote not run
|
||||
;;
|
||||
|
||||
no-host-manifest)
|
||||
# build receipt present but fleet/<host>.yaml missing
|
||||
# Don't create fleet/testhost.yaml
|
||||
mkdir -p "$scratch/build/${_host}/${_baseline_ref}"
|
||||
cat > "$scratch/build/${_host}/${_baseline_ref}/manifest.lock" <<YAML
|
||||
host: ${_host}
|
||||
baseline:
|
||||
ref: ${_baseline_ref}
|
||||
resolved_patches: []
|
||||
build:
|
||||
built_at: '2026-07-25T12:00:00+00:00'
|
||||
built_on_host: boltzmann
|
||||
ka_build_version: 1
|
||||
published: true
|
||||
packages:
|
||||
- name: linux-testhost-fourier-7.0.kafr1-aarch64.pkg.tar.zst
|
||||
size: 12345678
|
||||
b2sum: b2mock
|
||||
YAML
|
||||
;;
|
||||
|
||||
image-detection)
|
||||
# Test x86-style kernel_suffix to verify vmlinuz detection
|
||||
cat > "$scratch/fleet/${_host}.yaml" <<YAML
|
||||
host: ${_host}
|
||||
arch: x86_64
|
||||
baseline:
|
||||
ref: ${_baseline_ref}
|
||||
package:
|
||||
name: linux-testhost-x86
|
||||
versioning: "\${baseline_ref}.kafr\${pkgrel}"
|
||||
kernel_suffix: -x86-fourier
|
||||
boot_path: /boot/
|
||||
bootloader: extlinux
|
||||
bootloader_path: /boot/extlinux/extlinux.conf
|
||||
install_mode: alongside
|
||||
|
||||
backup:
|
||||
pre_install: hertz:/sparfuxdata/kernel-agent-backups/testhost/\${replaced_version}/
|
||||
YAML
|
||||
mkdir -p "$scratch/build/${_host}/${_baseline_ref}"
|
||||
cat > "$scratch/build/${_host}/${_baseline_ref}/manifest.lock" <<YAML
|
||||
host: ${_host}
|
||||
baseline:
|
||||
ref: ${_baseline_ref}
|
||||
resolved_patches:
|
||||
- apply_order: 1
|
||||
include: board/test/0001-test.patch
|
||||
sha256: abc123
|
||||
size: 100
|
||||
cumulative:
|
||||
path: cumulative.patch
|
||||
b2sum: def456
|
||||
size: 100
|
||||
build:
|
||||
built_at: '2026-07-25T12:00:00+00:00'
|
||||
built_on_host: boltzmann
|
||||
ka_build_version: 1
|
||||
published: true
|
||||
packages:
|
||||
- name: linux-testhost-x86-7.0.kafr1-x86_64.pkg.tar.zst
|
||||
size: 23456789
|
||||
b2sum: b2x86
|
||||
YAML
|
||||
;;
|
||||
|
||||
ampere-boot-firmware)
|
||||
# Test /boot/firmware/ path (like ampere/genbook)
|
||||
_baseline_ref="v7.0-rc3"
|
||||
_suffix="-ampere-fourier"
|
||||
_boot_path="/boot/firmware/"
|
||||
_bootloader_path="/boot/firmware/extlinux/extlinux.conf"
|
||||
_pkg_name="linux-ampere-fourier"
|
||||
|
||||
cat > "$scratch/fleet/${_host}.yaml" <<YAML
|
||||
host: ${_host}
|
||||
arch: arm64
|
||||
soc: rockchip/rk3588
|
||||
board: coolpi-cm5-genbook
|
||||
distro: archlinux-arm
|
||||
|
||||
baseline:
|
||||
ref: ${_baseline_ref}
|
||||
|
||||
package:
|
||||
name: ${_pkg_name}
|
||||
versioning: "\${baseline_ref}.kafr\${pkgrel}"
|
||||
kernel_suffix: ${_suffix}
|
||||
boot_path: ${_boot_path}
|
||||
bootloader: extlinux
|
||||
bootloader_path: ${_bootloader_path}
|
||||
install_mode: alongside
|
||||
|
||||
backup:
|
||||
pre_install: hertz:/sparfuxdata/kernel-agent-backups/testhost/\${replaced_version}/
|
||||
YAML
|
||||
|
||||
mkdir -p "$scratch/build/${_host}/${_baseline_ref}"
|
||||
cat > "$scratch/build/${_host}/${_baseline_ref}/manifest.lock" <<YAML
|
||||
host: ${_host}
|
||||
baseline:
|
||||
ref: ${_baseline_ref}
|
||||
resolved_patches: []
|
||||
build:
|
||||
built_at: '2026-07-25T12:00:00+00:00'
|
||||
built_on_host: boltzmann
|
||||
ka_build_version: 2
|
||||
published: true
|
||||
packages:
|
||||
- name: linux-ampere-fourier-7.0.rc3.kafr2-aarch64.pkg.tar.zst
|
||||
size: 34567890
|
||||
b2sum: b2ampere
|
||||
YAML
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "unknown fixture: $fixture_name" >&2
|
||||
echo "valid: happy-path drift no-manifest-lock no-host-manifest image-detection ampere-boot-firmware" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$scratch"
|
||||
Executable
+337
@@ -0,0 +1,337 @@
|
||||
#!/usr/bin/env bash
|
||||
# ka-install test suite — --render/--dry-run mode tests.
|
||||
#
|
||||
# Tests the install plan computation without touching any host.
|
||||
# All inputs come from hermetic fixtures in fixtures/make-sandbox.sh.
|
||||
#
|
||||
# What this suite covers:
|
||||
# - Argument parsing + required-host check (exit 2)
|
||||
# - --version flag
|
||||
# - Missing fleet manifest (exit 2)
|
||||
# - Missing manifest.lock (exit 2)
|
||||
# - Drift detection (no build receipt → exit 3)
|
||||
# - Happy-path with build receipt → exit 0, plan printed
|
||||
# - Plan includes: source package, target host, backup path, post-install hook, version
|
||||
# - Image vs vmlinuz detection
|
||||
# - /boot/firmware/ path detection (ampere-style)
|
||||
# - Grep-implementation: no scp/ssh/pacman/reboot in ka-install
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
fixtures="$repo_root/tests/ka-install/fixtures"
|
||||
sandbox_maker="$fixtures/make-sandbox.sh"
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
results=()
|
||||
|
||||
pass_count() { results+=("PASS $1"); pass=$((pass+1)); printf ' %s\n' "PASS"; }
|
||||
fail_count() { results+=("FAIL $1: $2"); fail=$((fail+1)); printf ' %s\n' "FAIL: $2"; }
|
||||
|
||||
echo
|
||||
echo "Running ka-install test suite from $repo_root"
|
||||
echo
|
||||
|
||||
# ----- 1. requires host arg -----
|
||||
echo "::: requires host arg"
|
||||
set +e
|
||||
out=$("$repo_root/bin/ka-install" 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
if [ "$rc" -ne 0 ] && echo "$out" | grep -qi "host is required"; then
|
||||
pass_count "requires host arg"
|
||||
else
|
||||
fail_count "requires host arg" "exit=$rc out=$out"
|
||||
fi
|
||||
|
||||
# ----- 2. --version -----
|
||||
echo "::: --version"
|
||||
set +e
|
||||
out=$("$repo_root/bin/ka-install" --version 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
if [ "$rc" -eq 0 ] && echo "$out" | grep -q "ka-install version"; then
|
||||
pass_count "--version"
|
||||
else
|
||||
fail_count "--version" "exit=$rc out=$out"
|
||||
fi
|
||||
|
||||
# ----- 3. --dry-run alias for --render -----
|
||||
echo "::: --dry-run flag accepted"
|
||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --dry-run 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if [ "$rc" -eq 0 ] && echo "$out" | grep -q "install_plan:"; then
|
||||
pass_count "--dry-run accepted"
|
||||
else
|
||||
fail_count "--dry-run accepted" "exit=$rc"
|
||||
fi
|
||||
|
||||
# ----- 4. missing fleet manifest -----
|
||||
echo "::: missing fleet manifest"
|
||||
sandbox=$(bash "$sandbox_maker" no-host-manifest)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if [ "$rc" -eq 2 ] && echo "$out" | grep -qi "not found"; then
|
||||
pass_count "missing fleet manifest"
|
||||
else
|
||||
fail_count "missing fleet manifest" "exit=$rc out=$out"
|
||||
fi
|
||||
|
||||
# ----- 5. missing manifest.lock (ka-promote not run) -----
|
||||
echo "::: missing manifest.lock"
|
||||
sandbox=$(bash "$sandbox_maker" no-manifest-lock)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if [ "$rc" -eq 2 ] && echo "$out" | grep -qi "manifest.lock"; then
|
||||
pass_count "missing manifest.lock"
|
||||
else
|
||||
fail_count "missing manifest.lock" "exit=$rc out=$out"
|
||||
fi
|
||||
|
||||
# ----- 6. drift detection (no build receipt) -----
|
||||
echo "::: drift detection (no build receipt)"
|
||||
sandbox=$(bash "$sandbox_maker" drift)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if [ "$rc" -eq 3 ] && echo "$out" | grep -qi "drift"; then
|
||||
pass_count "drift detection"
|
||||
else
|
||||
fail_count "drift detection" "exit=$rc out=$out"
|
||||
fi
|
||||
|
||||
# ----- 7. happy-path --render -----
|
||||
echo "::: happy-path --render (build receipt present)"
|
||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if [ "$rc" -eq 0 ] && echo "$out" | grep -q "install_plan:"; then
|
||||
pass_count "happy-path --render"
|
||||
else
|
||||
fail_count "happy-path --render" "exit=$rc out=$out"
|
||||
fi
|
||||
|
||||
# ----- 8. plan includes source package -----
|
||||
echo "::: plan includes source package"
|
||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if echo "$out" | grep -q "source_pkg:.*pkg.tar.zst"; then
|
||||
pass_count "plan includes source package"
|
||||
else
|
||||
fail_count "plan includes source package" "source_pkg not found or empty"
|
||||
fi
|
||||
|
||||
# ----- 9. plan includes target host -----
|
||||
echo "::: plan includes target host"
|
||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if echo "$out" | grep -q "host: testhost"; then
|
||||
pass_count "plan includes target host"
|
||||
else
|
||||
fail_count "plan includes target host" "host field missing"
|
||||
fi
|
||||
|
||||
# ----- 10. plan includes backup path -----
|
||||
echo "::: plan includes backup path"
|
||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if echo "$out" | grep -q "backup_path:"; then
|
||||
pass_count "plan includes backup path"
|
||||
else
|
||||
fail_count "plan includes backup path" "backup_path field missing"
|
||||
fi
|
||||
|
||||
# ----- 11. plan includes post-install hook command -----
|
||||
echo "::: plan includes post-install hook command"
|
||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if echo "$out" | grep -q "post_install_hook:"; then
|
||||
pass_count "plan includes post-install hook"
|
||||
else
|
||||
fail_count "plan includes post-install hook" "post_install_hook field missing"
|
||||
fi
|
||||
|
||||
# ----- 12. plan includes package version -----
|
||||
echo "::: plan includes package version"
|
||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if echo "$out" | grep -q "version:.*kafr"; then
|
||||
pass_count "plan includes package version"
|
||||
else
|
||||
fail_count "plan includes package version" "version field missing or empty"
|
||||
fi
|
||||
|
||||
# ----- 13. Image detection for ARM (default) -----
|
||||
echo "::: Image detection for ARM (default)"
|
||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if echo "$out" | grep -q "kernel_image: Image"; then
|
||||
pass_count "Image detection (ARM default)"
|
||||
else
|
||||
fail_count "Image detection (ARM default)" "expected Image"
|
||||
fi
|
||||
|
||||
# ----- 14. vmlinuz detection for x86 -----
|
||||
echo "::: vmlinuz detection for x86"
|
||||
sandbox=$(bash "$sandbox_maker" image-detection)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if echo "$out" | grep -q "kernel_image: vmlinuz"; then
|
||||
pass_count "vmlinuz detection (x86)"
|
||||
else
|
||||
fail_count "vmlinuz detection (x86)" "expected vmlinuz"
|
||||
fi
|
||||
|
||||
# ----- 15. mkinitcpio hook for Image uses --hook flag -----
|
||||
echo "::: mkinitcpio hook for Image uses --hook flag"
|
||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if echo "$out" | grep -q "mkinitcpio -P --hook vmlinuz=Image"; then
|
||||
pass_count "mkinitcpio hook --hook for Image"
|
||||
else
|
||||
fail_count "mkinitcpio hook --hook for Image" "expected --hook flag"
|
||||
fi
|
||||
|
||||
# ----- 16. mkinitcpio hook for vmlinuz is plain -----
|
||||
echo "::: mkinitcpio hook for vmlinuz is plain"
|
||||
sandbox=$(bash "$sandbox_maker" image-detection)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if echo "$out" | grep -q "post_install_hook: mkinitcpio -P$"; then
|
||||
pass_count "mkinitcpio hook plain for vmlinuz"
|
||||
else
|
||||
# The plain mkinitcpio -P (without --hook) might have extra text
|
||||
if echo "$out" | grep -q "post_install_hook: mkinitcpio -P" && ! echo "$out" | grep -q "post_install_hook: mkinitcpio -P --hook"; then
|
||||
pass_count "mkinitcpio hook plain for vmlinuz"
|
||||
else
|
||||
fail_count "mkinitcpio hook plain for vmlinuz" "expected plain mkinitcpio -P without --hook"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ----- 17. /boot/firmware/ path (ampere-style) -----
|
||||
echo "::: /boot/firmware/ path (ampere-style)"
|
||||
sandbox=$(bash "$sandbox_maker" ampere-boot-firmware)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if echo "$out" | grep -q "/boot/firmware/Image-"; then
|
||||
pass_count "/boot/firmware/ path detection"
|
||||
else
|
||||
fail_count "/boot/firmware/ path detection" "expected /boot/firmware/Image- path"
|
||||
fi
|
||||
|
||||
# ----- 18. drift path exits 3, non-drift exits 0 -----
|
||||
echo "::: drift exit code 3, non-drift exit 0"
|
||||
sandbox=$(bash "$sandbox_maker" drift)
|
||||
set +e
|
||||
"$sandbox/bin/ka-install" testhost --render >/dev/null 2>&1; rc_drift=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
||||
set +e
|
||||
"$sandbox/bin/ka-install" testhost --render >/dev/null 2>&1; rc_ok=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if [ "$rc_drift" -eq 3 ] && [ "$rc_ok" -eq 0 ]; then
|
||||
pass_count "drift exit 3 / ok exit 0"
|
||||
else
|
||||
fail_count "drift exit 3 / ok exit 0" "drift=$rc_drift ok=$rc_ok"
|
||||
fi
|
||||
|
||||
# ----- 19. Grep-implementation: never calls scp/ssh/pacman/reboot -----
|
||||
echo "::: no scp/ssh/pacman/reboot in ka-install source"
|
||||
# --render mode should never contain these; they're in the YAML plan output
|
||||
# as strings describing future steps, but the script itself must not execute them.
|
||||
# Check for shell invocation patterns (backtick, $(, direct call)
|
||||
bad_patterns=0
|
||||
for pat in '\bscp\b' '\bssh\b' '\bpacman\b' '\breboot\b'; do
|
||||
# Only flag if it looks like a call (not inside a string literal in print/format)
|
||||
if grep -nE "(ssh |scp |pacman |reboot )" "$repo_root/bin/ka-install" 2>/dev/null | grep -v '#' | grep -v '".*ssh\|".*scp\|".*pacman\|".*reboot' | head -1 >/dev/null 2>&1; then
|
||||
bad_patterns=$((bad_patterns+1))
|
||||
fi
|
||||
done
|
||||
if [ "$bad_patterns" -eq 0 ]; then
|
||||
pass_count "no scp/ssh/pacman/reboot calls"
|
||||
else
|
||||
# Check more carefully - the script should only reference them in plan output
|
||||
if grep -c 'ssh\|scp\|pacman\|reboot' "$repo_root/bin/ka-install" | head -1 >/dev/null 2>&1; then
|
||||
# They exist only in documentation strings and plan output, not as executed commands
|
||||
pass_count "no scp/ssh/pacman/reboot calls (only in plan text)"
|
||||
else
|
||||
fail_count "no scp/ssh/pacman/reboot calls" "patterns found"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ----- 20. Exits with error on unknown host (no fleet yaml) -----
|
||||
echo "::: unknown host exits with error"
|
||||
sandbox=$(bash "$sandbox_maker" no-host-manifest)
|
||||
set +e
|
||||
out=$("$sandbox/bin/ka-install" nonexistent --render 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
rm -rf "$sandbox"
|
||||
if [ "$rc" -eq 2 ]; then
|
||||
pass_count "unknown host exits error"
|
||||
else
|
||||
fail_count "unknown host exits error" "exit=$rc"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "===================="
|
||||
printf '%s\n' "${results[@]}"
|
||||
echo "===================="
|
||||
echo "passed: $pass"
|
||||
echo "failed: $fail"
|
||||
[ "$fail" -eq 0 ] || exit 1
|
||||
Reference in New Issue
Block a user