Blueforce-Linux/tests/test-firstboot-static.sh
2026-09-17 13:22:26 +03:00

516 lines
23 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Static and sandboxed behavior test for the first-boot terminal wizard.
#
# It never runs systemd, never touches apt, and never touches the real /var state: every
# scenario works inside a throwaway sandbox with a fake installer. Scenarios that require
# root run in a separate user namespace (unshare -r) and are reported as SKIP when the
# host does not permit that.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TEST_SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"
BF="$REPO_ROOT/provisioning/firstboot/bf-firstboot"
UNIT="$REPO_ROOT/provisioning/firstboot/blueforce-firstboot.service"
README_FILE="$REPO_ROOT/provisioning/firstboot/README.md"
WORK="$(mktemp -d)"
PASSED=0
FAILED=0
SKIPPED=0
trap 'rm -rf "$WORK"' EXIT
ok() {
if [[ -n "${BF_TEST_RESULTS:-}" ]]; then
printf 'PASS\t%s\n' "$*" >>"$BF_TEST_RESULTS"
else
printf 'OK %s\n' "$*"
PASSED=$((PASSED + 1))
fi
}
bad() {
if [[ -n "${BF_TEST_RESULTS:-}" ]]; then
printf 'FAIL\t%s\n' "$*" >>"$BF_TEST_RESULTS"
else
printf 'FAIL %s\n' "$*" >&2
FAILED=$((FAILED + 1))
fi
}
skip() {
if [[ -n "${BF_TEST_RESULTS:-}" ]]; then
printf 'SKIP\t%s\n' "$*" >>"$BF_TEST_RESULTS"
else
printf 'SKIP %s\n' "$*"
SKIPPED=$((SKIPPED + 1))
fi
}
section() { [[ -n "${BF_TEST_RESULTS:-}" ]] || printf '\n== %s ==\n' "$*"; }
assert_rc() {
if [[ "$1" == "$2" ]]; then ok "$3"; else bad "$3 (expected exit $1, got $2)"; fi
}
assert_output() {
if [[ "$2" == *"$1"* ]]; then ok "$3"; else bad "$3 (output lacks: $1)"; fi
}
assert_no_output() {
if [[ "$2" != *"$1"* ]]; then ok "$3"; else bad "$3 (output unexpectedly contains: $1)"; fi
}
assert_file() {
if [[ -f "$1" ]]; then ok "$2"; else bad "$2 (missing: $1)"; fi
}
assert_no_file() {
if [[ ! -e "$1" ]]; then ok "$2"; else bad "$2 (unexpected path: $1)"; fi
}
assert_eq() {
if [[ "$1" == "$2" ]]; then ok "$3"; else bad "$3 (expected '$1', got '$2')"; fi
}
assert_grep() {
if grep -qF -- "$1" "$2" 2>/dev/null; then ok "$3"; else bad "$3 (pattern not found in $2)"; fi
}
assert_no_grep() {
if grep -qF -- "$1" "$2" 2>/dev/null; then bad "$3 (forbidden pattern found in $2)"; else ok "$3"; fi
}
assert_no_directive() {
if grep -qE "^[[:space:]]*$1=" "$2" 2>/dev/null; then bad "$3 (forbidden unit directive in $2)"; else ok "$3"; fi
}
ENV_ARGS=()
SB=''
OUT=''
RC=0
new_sandbox() {
SB="$(mktemp -d "$WORK/sb.XXXXXX")"
{
printf '#!/usr/bin/env bash\n'
printf 'printf "%%s\\n" "$*" >> "%s/calls.log"\n' "$SB"
} >"$SB/fake-install.sh"
chmod 755 "$SB/fake-install.sh"
printf 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIexamplePublicKeyForStaticFirstbootTest field@blueforce\n' >"$SB/key.pub"
chmod 600 "$SB/key.pub"
ENV_ARGS=(
"BF_FIRSTBOOT_MARKER=$SB/marker"
"STATE_DIR=$SB/state"
"BF_INSTALLER_PATH=$SB/fake-install.sh"
"BF_ADMIN_PUBLIC_KEY_FILE=$SB/key.pub"
"BF_REIDENTITY_AUDIT_LOG=$SB/audit.log"
"BF_FIRSTBOOT_INPUT_TIMEOUT=10"
)
}
installer_calls() {
if [[ -f "$SB/calls.log" ]]; then wc -l <"$SB/calls.log" | tr -d ' '; else printf '0'; fi
}
installer_args() {
if [[ -f "$SB/calls.log" ]]; then cat "$SB/calls.log"; else printf ''; fi
}
sandbox_listing() {
(cd "$SB" && ls -1A | sort | tr '\n' ',')
}
write_marker() {
printf '%s\n' "$1" >"$SB/marker"
chmod 600 "$SB/marker"
}
marker_content() {
if [[ -f "$SB/marker" ]]; then tr -d '[:space:]' <"$SB/marker"; else printf '<no-marker>'; fi
}
file_mode() {
if [[ -e "$1" ]]; then stat -c '%a' "$1"; else printf '<missing>'; fi
}
# Non-interactive invocation: stdin is /dev/null, so the wizard can never prompt.
run_bf() {
set +e
OUT="$(timeout 60 env "${ENV_ARGS[@]}" "$@" 2>&1 </dev/null)"
RC=$?
set -e
}
# Interactive invocation behind a real pseudo terminal, with the given keystrokes.
# The command (with any VAR=value prefixes) is rebuilt inside the pty through env, so it
# is passed exactly like the plain run_bf helper.
pty_command() {
local inner='env' arg
for arg in "$@"; do inner+=" $(printf '%q' "$arg")"; done
printf '%s' "$inner"
}
run_bf_tty() {
local input="$1"
shift
local inner
inner="$(pty_command "$@")"
set +e
OUT="$(printf '%s\n' "$input" | env SHELL=/bin/bash "${ENV_ARGS[@]}" timeout 60 script -qec "$inner" /dev/null 2>&1)"
RC=$?
set -e
}
# Same, but with no bytes written to the pseudo terminal at all (timeout path).
run_bf_tty_silent() {
local inner
inner="$(pty_command "$@")"
set +e
OUT="$(printf '' | env SHELL=/bin/bash "${ENV_ARGS[@]}" timeout 60 script -qec "$inner" /dev/null 2>&1)"
RC=$?
set -e
}
# ---------------------------------------------------------------------------
# Source, unit and documentation checks (no execution).
# ---------------------------------------------------------------------------
check_sources() {
section 'static: script, unit, README'
[[ -x "$BF" ]] && ok 'bf-firstboot is executable' || bad 'bf-firstboot is executable'
assert_eq '#!/usr/bin/env bash' "$(head -n 1 "$BF")" 'bf-firstboot has a bash shebang'
if bash -n "$BF" 2>/dev/null; then ok 'bf-firstboot parses (bash -n)'; else bad 'bf-firstboot parses (bash -n)'; fi
assert_grep 'set -euo pipefail' "$BF" 'bf-firstboot uses strict mode'
assert_grep '^[0-9]{8}$' "$BF" 'bf-firstboot validates the dealer number with the shared regex'
assert_grep '# BLUEFORCE FIELD OS' "$BF" 'bf-firstboot prints the field console banner'
assert_grep "wizard_write '> '" "$BF" 'bf-firstboot prompts with the wizard input marker'
assert_grep '/dev/tty' "$BF" 'bf-firstboot opens /dev/tty when stdin is not a terminal'
assert_grep '/etc/blueforce/dealer-id' "$BF" 'bf-firstboot supports the seeded dealer id file'
assert_grep '--offline' "$BF" 'bf-firstboot calls the installer offline-only'
assert_grep 'blueforce-install.sh' "$BF" 'bf-firstboot targets the local installer'
assert_grep 'BF_FIRSTBOOT_TEST_MODE' "$BF" 'bf-firstboot keeps the mutation-free test mode'
assert_grep '--resume' "$BF" 'bf-firstboot resumes a partial install'
assert_grep '--force-reidentity' "$BF" 'bf-firstboot exposes the admin re-identity path'
assert_grep 'BF_ALLOW_REIDENTITY' "$BF" 'the re-identity path is gated by an operator switch'
assert_grep 'already completed' "$BF" 'bf-firstboot short-circuits on the completion marker'
assert_no_grep 'curl' "$BF" 'bf-firstboot fetches nothing from the network'
assert_no_grep 'wget' "$BF" 'bf-firstboot does not download via wget'
assert_no_grep 'set -x' "$BF" 'bf-firstboot never traces (no accidental key dump)'
if grep -nE '(^|[^A-Za-z_])(cat|tee|head|tail|awk|printf|echo|cp|scp)[[:space:]]+[^|]*\$KEY_FILE' "$BF" >/dev/null 2>&1; then
bad 'the administrator key file is never read out into a message or a copy'
else
ok 'the administrator key file is never read out into a message or a copy'
fi
assert_file "$UNIT" 'the first-boot unit is present'
assert_grep 'ConditionPathExists=/etc/blueforce/admin-authorized-key.pub' "$UNIT" 'the unit requires the administrator public key'
assert_grep 'ConditionPathExists=!/var/lib/blueforce/firstboot-complete' "$UNIT" 'the unit is skipped once the marker exists'
assert_grep 'TimeoutStartSec=' "$UNIT" 'the unit bounds its runtime'
assert_grep 'StandardInput=tty-force' "$UNIT" 'the unit attaches the wizard to the console'
assert_grep 'Type=oneshot' "$UNIT" 'the unit is a one-shot service'
assert_grep 'RemainAfterExit=yes' "$UNIT" 'the unit records its result'
assert_grep 'WantedBy=multi-user.target' "$UNIT" 'the unit runs once at boot'
assert_no_directive 'ProtectSystem' "$UNIT" 'the unit does not sandbox paths the offline installer must write'
assert_no_directive 'ProtectHome' "$UNIT" 'the unit keeps the identity-derived home writable for the user module'
assert_file "$README_FILE" 'the first-boot README is present'
assert_grep 'BLUEFORCE FIELD OS' "$README_FILE" 'the README documents the wizard screen'
assert_grep 'force-reidentity' "$README_FILE" 'the README documents the admin identity change procedure'
assert_grep 'BF_ALLOW_REIDENTITY' "$README_FILE" 'the README documents that identity change is off by default'
assert_grep 'public SSH key' "$README_FILE" 'the README states the administrator key rule'
assert_grep '/var/log/blueforce-reidentity.log' "$README_FILE" 'the README documents the identity change audit record'
assert_grep 'ConditionPathExists' "$README_FILE" 'the README explains the unit conditions'
}
# ---------------------------------------------------------------------------
# Command line behavior: check mode, validation, automation path, no terminal.
# ---------------------------------------------------------------------------
check_cli() {
section 'cli: validation, check mode, no-terminal fallback'
new_sandbox
run_bf bash "$BF" --check --dealer-id 12010193
assert_rc 0 "$RC" 'check mode accepts a valid dealer number'
assert_output 'no changes were made' "$OUT" 'check mode reports that it made no changes'
assert_no_file "$SB/marker" 'check mode writes no marker'
assert_no_file "$SB/state" 'check mode creates no state directory'
assert_eq '0' "$(installer_calls)" 'check mode never runs the installer'
assert_eq 'fake-install.sh,key.pub,' "$(sandbox_listing)" 'check mode leaves the sandbox untouched'
for candidate in 1234567 123456789 1234abcd '' '12 34 5678'; do
new_sandbox
run_bf bash "$BF" --check --dealer-id "$candidate"
assert_rc 2 "$RC" "invalid dealer number is rejected: '${candidate:-<empty>}'"
assert_output '8 digits' "$OUT" "rejection of '${candidate:-<empty>}' explains the expected format"
assert_no_file "$SB/marker" "rejection of '${candidate:-<empty>}' writes no marker"
done
new_sandbox
run_bf bash "$BF" --check
assert_rc 2 "$RC" 'check mode without any dealer number fails with a clear error'
assert_no_file "$SB/marker" 'a failed check mode writes no marker'
new_sandbox
run_bf bash "$BF" --not-a-flag
assert_rc 2 "$RC" 'an unknown argument is rejected'
assert_output 'unknown argument' "$OUT" 'an unknown argument is reported explicitly'
new_sandbox
run_bf bash "$BF" --dealer-id 1234567
assert_rc 2 "$RC" 'a 7-digit dealer number never reaches the installer'
assert_no_file "$SB/marker" 'a rejected dealer number writes no marker'
assert_eq '0' "$(installer_calls)" 'a rejected dealer number never runs the installer'
# Non-interactive mode with no seeded file and no flag must fail closed, without hanging.
new_sandbox
run_bf bash "$BF" --non-interactive
assert_rc 2 "$RC" 'non-interactive mode without any dealer number fails'
if [[ "$OUT" == *'dealer id file is missing or unreadable'* || "$OUT" == *'invalid dealer number'* ]]; then
ok 'non-interactive mode names the unusable dealer id input'
else
bad 'non-interactive mode names the unusable dealer id input'
fi
assert_no_file "$SB/marker" 'the no-input path writes no marker'
# Explicit file path (automation) is honoured and never opens the wizard.
new_sandbox
printf '12010193\n' >"$SB/dealer-id"
run_bf bash "$BF" --dealer-id-file "$SB/dealer-id"
assert_no_output '# BLUEFORCE FIELD OS' "$OUT" 'the automation path never opens the wizard'
assert_no_output '8 Haneli Bayi Numarası' "$OUT" 'the automation path asks nothing at the console'
assert_eq '0' "$(installer_calls)" 'the automation path runs no installer when it cannot install'
if [[ "$(id -u)" -eq 0 ]]; then
assert_rc 0 "$RC" 'the dealer id file path completes when the test runs as root'
else
assert_rc 1 "$RC" 'the dealer id file path fails closed without root'
assert_output 'must run as root' "$OUT" 'the automation path reports the missing privilege'
assert_no_file "$SB/marker" 'the automation path writes no marker when it cannot install'
fi
new_sandbox
printf 'nope\n' >"$SB/dealer-id"
run_bf bash "$BF" --dealer-id-file "$SB/dealer-id"
assert_rc 2 "$RC" 'an invalid value in the dealer id file is rejected'
assert_output 'invalid dealer number' "$OUT" 'an invalid file value names the format rule'
new_sandbox
printf '12010193\n' >"$SB/dealer-id"
run_bf BF_FIRSTBOOT_NONINTERACTIVE=1 bash "$BF" --dealer-id-file "$SB/dealer-id"
assert_no_output '# BLUEFORCE FIELD OS' "$OUT" 'explicit non-interactive mode never opens the wizard'
assert_eq '0' "$(installer_calls)" 'explicit non-interactive mode runs no installer when it cannot install'
}
# ---------------------------------------------------------------------------
# Wizard behavior through a pseudo terminal.
# ---------------------------------------------------------------------------
check_wizard() {
section 'wizard: pty input, confirmation, attempt limit'
new_sandbox
run_bf_tty '1234567
abcd
nope' bash "$BF"
assert_rc 2 "$RC" 'three malformed entries abort the wizard'
assert_output '# BLUEFORCE FIELD OS' "$OUT" 'the wizard shows the field console banner'
assert_output '8 Haneli Bayi Numarası' "$OUT" 'the wizard shows the Turkish dealer number prompt'
assert_output 'deneme 3/3' "$OUT" 'the wizard counts attempts and never accepts malformed input'
assert_output 'not accepted after 3 attempts' "$OUT" 'the wizard aborts with an explicit error after the limit'
assert_no_file "$SB/marker" 'the aborted wizard writes no marker'
assert_eq '0' "$(installer_calls)" 'the aborted wizard never runs the installer'
new_sandbox
run_bf_tty '1201 0193
12010193
e' bash "$BF"
assert_output 'Geçersiz giriş' "$OUT" 'the wizard rejects a malformed entry that contains a space'
assert_output 'deneme 1/3' "$OUT" 'the wizard re-asks once a malformed entry is rejected'
assert_output 'BF-12010193' "$OUT" 'the wizard accepts the corrected entry after a rejection'
new_sandbox
run_bf_tty '12010193
e' bash "$BF"
assert_output 'BF-12010193' "$OUT" 'the confirmed wizard shows Device ID BF-<dealer-id>'
assert_output 'bf-12010193' "$OUT" 'the confirmed wizard shows hostname bf-<dealer-id>'
assert_eq '0' "$(installer_calls)" 'the wizard run does not reach the installer without root'
if [[ "$(id -u)" -eq 0 ]]; then
assert_rc 0 "$RC" 'the confirmed wizard completes when the test runs as root'
else
assert_rc 1 "$RC" 'the confirmed wizard stops at the privilege gate without root'
assert_output 'must run as root' "$OUT" 'the confirmed wizard proceeds past identity validation'
fi
new_sandbox
run_bf_tty '12010193
n
12010193
n
12010193
n' bash "$BF"
assert_rc 2 "$RC" 'refusing the confirmation three times aborts the wizard'
assert_output 'Onay verilmedi' "$OUT" 'the wizard re-asks when the identity is not confirmed'
assert_eq '0' "$(installer_calls)" 'a refused confirmation never runs the installer'
new_sandbox
run_bf_tty_silent bash "$BF"
assert_rc 2 "$RC" 'a silent console aborts the wizard instead of waiting forever'
assert_output 'timed out' "$OUT" 'the silent console path explains the timeout'
assert_eq '0' "$(installer_calls)" 'the silent console path never runs the installer'
}
# ---------------------------------------------------------------------------
# Root-only behavior in a separate user namespace.
# ---------------------------------------------------------------------------
check_root_paths() {
section 'root (namespace): install run, marker, key gate, re-identity'
new_sandbox
run_bf BF_FIRSTBOOT_TEST_MODE=1 bash "$BF" --dealer-id 12010193
assert_rc 0 "$RC" 'test mode completes successfully as root'
assert_output "TEST: would run $SB/fake-install.sh --offline --dealer-id 12010193 --yes" "$OUT" 'test mode builds the exact offline installer command'
assert_no_file "$SB/marker" 'test mode is mutation-free (no marker)'
assert_eq '0' "$(installer_calls)" 'test mode never runs the installer'
new_sandbox
mkdir -p "$SB/state"
printf '01-precheck=OK\n' >"$SB/state/install-state"
run_bf BF_FIRSTBOOT_TEST_MODE=1 bash "$BF" --dealer-id 12010193
assert_rc 0 "$RC" 'a partial install state is accepted'
assert_output '--resume' "$OUT" 'a partial install is resumed instead of restarted'
new_sandbox
run_bf bash "$BF" --dealer-id 12010193
assert_rc 0 "$RC" 'first boot completes with the (fake) installer'
assert_file "$SB/marker" 'the completion marker is written'
assert_eq '600' "$(file_mode "$SB/marker")" 'the marker is mode 600'
assert_eq '12010193' "$(marker_content)" 'the marker records the provisioned dealer number'
assert_eq '--offline --dealer-id 12010193 --yes' "$(installer_args)" 'the installer is called offline with the validated dealer number'
run_bf bash "$BF" --dealer-id 12010193
assert_rc 0 "$RC" 'a second run exits successfully'
assert_output 'already completed' "$OUT" 'a provisioned device reports that first boot is done'
assert_eq '1' "$(installer_calls)" 'a provisioned device never runs the installer again'
run_bf bash "$BF" --dealer-id 87654321
assert_rc 0 "$RC" 'a different dealer number does not fail the run'
assert_output 'identity changes use the admin procedure' "$OUT" 'a different dealer number points at the admin procedure'
assert_eq '12010193' "$(marker_content)" 'the provisioned identity is unchanged'
assert_eq '1' "$(installer_calls)" 'the installer is not re-run for a different dealer number'
run_bf_tty '87654321
e' bash "$BF"
assert_eq '12010193' "$(marker_content)" 'the wizard cannot change a provisioned identity'
assert_eq '1' "$(installer_calls)" 'the wizard does not re-run the installer on a provisioned device'
new_sandbox
printf -- '-----BEGIN OPENSSH PRIVATE KEY-----\nAAAAB3NzaC1yc2EFIRSTBOOTSECRETBODY\n-----END OPENSSH PRIVATE KEY-----\n' >"$SB/priv.key"
chmod 600 "$SB/priv.key"
run_bf BF_ADMIN_PUBLIC_KEY_FILE="$SB/priv.key" bash "$BF" --dealer-id 12010193
assert_rc 1 "$RC" 'private key material is refused as an administrator key'
assert_output 'must contain only a public SSH key' "$OUT" 'the refusal states the public-key rule'
assert_no_output 'FIRSTBOOTSECRETBODY' "$OUT" 'no key material is echoed in the error output'
assert_no_output 'PRIVATE KEY' "$OUT" 'the private key header is never echoed'
assert_no_file "$SB/marker" 'a refused key writes no marker'
assert_eq '0' "$(installer_calls)" 'a refused key never runs the installer'
new_sandbox
chmod 644 "$SB/key.pub"
run_bf bash "$BF" --dealer-id 12010193
assert_rc 1 "$RC" 'a group/world readable administrator key file is refused'
assert_output 'root-owned' "$OUT" 'the refusal states the ownership and mode rule'
assert_no_file "$SB/marker" 'a refused key mode writes no marker'
new_sandbox
run_bf BF_ADMIN_PUBLIC_KEY_FILE="$SB/missing.pub" bash "$BF" --dealer-id 12010193
assert_rc 1 "$RC" 'a missing administrator key file blocks the offline install'
assert_output 'OFFLINE BLOCKED' "$OUT" 'a missing administrator key is reported as an offline block'
new_sandbox
run_bf bash "$BF" --check --dealer-id 12010193
assert_rc 0 "$RC" 'check mode succeeds as root'
assert_no_file "$SB/marker" 'check mode writes no marker as root'
assert_no_file "$SB/state" 'check mode creates no state directory as root'
assert_eq '0' "$(installer_calls)" 'check mode runs no installer as root'
assert_eq 'fake-install.sh,key.pub,' "$(sandbox_listing)" 'check mode leaves the sandbox untouched as root'
new_sandbox
write_marker 12010193
run_bf bash "$BF" --force-reidentity --dealer-id 55555555
assert_rc 1 "$RC" 're-identity is refused without the operator gate'
assert_output 'disabled by default' "$OUT" 'the refusal explains that identity change is off by default'
assert_eq '12010193' "$(marker_content)" 'a refused re-identity leaves the marker unchanged'
assert_eq '0' "$(installer_calls)" 'a refused re-identity runs no installer'
assert_no_file "$SB/audit.log" 'a refused re-identity writes no audit record'
new_sandbox
write_marker 12010193
run_bf_tty '99999999' BF_ALLOW_REIDENTITY=1 bash "$BF" --force-reidentity --dealer-id 55555555
assert_rc 2 "$RC" 'a mismatching confirmation aborts the identity change'
assert_output 'confirmation did not match' "$OUT" 'the aborted identity change says why'
assert_eq '12010193' "$(marker_content)" 'the aborted identity change leaves the marker unchanged'
assert_eq '0' "$(installer_calls)" 'the aborted identity change runs no installer'
new_sandbox
write_marker 12010193
printf 'not a directory\n' >"$SB/blocker"
run_bf_tty '55555555' BF_ALLOW_REIDENTITY=1 BF_REIDENTITY_AUDIT_LOG="$SB/blocker/audit.log" bash "$BF" --force-reidentity --dealer-id 55555555
assert_rc 1 "$RC" 'an unwritable audit log fails the identity change closed'
assert_output 'audit log is not writable' "$OUT" 'the failure names the unwritable audit log'
assert_eq '12010193' "$(marker_content)" 'a failed audit leaves the marker unchanged'
assert_eq '0' "$(installer_calls)" 'a failed audit runs no installer'
new_sandbox
write_marker 12010193
run_bf_tty '55555555' BF_ALLOW_REIDENTITY=1 bash "$BF" --force-reidentity --dealer-id 55555555
assert_rc 0 "$RC" 'an admitted identity change completes'
assert_eq '55555555' "$(marker_content)" 'the marker carries the new dealer number'
assert_eq '--offline --dealer-id 55555555 --yes' "$(installer_args)" 'the installer is re-run with the new dealer number'
if compgen -G "$SB/marker.reidentified-*" >/dev/null; then
ok 'the previous identity marker is archived'
else
bad 'the previous identity marker is archived'
fi
assert_output 'AUDIT: identity-change applied' "$OUT" 'the identity change is announced in the run log'
assert_file "$SB/audit.log" 'the identity change writes an audit record'
assert_eq '600' "$(file_mode "$SB/audit.log")" 'the audit record is mode 600'
assert_grep 'identity-change applied old=12010193 new=BF-55555555' "$SB/audit.log" 'the audit record names the old and the new identity'
new_sandbox
run_bf_tty '12010193
e' bash "$BF"
assert_rc 0 "$RC" 'the wizard completes the first boot as root'
assert_output '# BLUEFORCE FIELD OS' "$OUT" 'the interactive run shows the banner'
assert_output 'BF-12010193' "$OUT" 'the interactive run shows the Device ID'
assert_eq '12010193' "$(marker_content)" 'the interactive run writes the marker for the confirmed identity'
assert_eq '--offline --dealer-id 12010193 --yes' "$(installer_args)" 'the interactive run calls the installer offline'
}
if [[ -n "${BF_TEST_RESULTS:-}" ]]; then
# Child mode: only the root-required scenarios run; results go to the parent's file.
cd "$REPO_ROOT"
check_root_paths
exit 0
fi
check_sources
check_cli
check_wizard
section 'root (namespace): install run, marker, key gate, re-identity'
RESULTS_FILE="$WORK/root-results.tsv"
: >"$RESULTS_FILE"
if unshare -r true >/dev/null 2>&1 && [[ "$(unshare -r id -u 2>/dev/null)" == 0 ]]; then
CHILD_LOG="$WORK/child.log"
if unshare -r env BF_TEST_RESULTS="$RESULTS_FILE" bash "$TEST_SCRIPT" >"$CHILD_LOG" 2>&1; then
:
else
printf 'FAIL the privileged (namespace) section did not complete; see the log below\n' >&2
sed -n '1,20p' "$CHILD_LOG" >&2
FAILED=$((FAILED + 1))
fi
if [[ -s "$RESULTS_FILE" ]]; then
while IFS=$'\t' read -r status name; do
case "$status" in
PASS) ok "$name";;
SKIP) skip "$name";;
*) bad "$name";;
esac
done <"$RESULTS_FILE"
else
skip 'the privileged (namespace) section produced no results'
fi
else
skip 'unshare -r is unavailable here: root-only first-boot scenarios were not run'
fi
printf '\ntest-firstboot-static: %s passed, %s failed, %s skipped\n' "$PASSED" "$FAILED" "$SKIPPED"
if [[ "$FAILED" -ne 0 ]]; then
printf 'test-firstboot-static: FAILED\n' >&2
exit 1
fi
printf 'test-firstboot-static: all passed\n'