From 99a26d7de23bbfc757957c08e47606c3690df4cb Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Thu, 25 Jun 2026 00:54:53 -0400 Subject: test(archsetup): scaffold Testinfra post-install validation (P1) Stand up the Testinfra/pytest harness alongside the existing shell sweep so the two can be compared for parity before pytest takes over. Adds scripts/testing/tests/ (conftest with failure attribution markers, a report hook, and a target_user fixture, plus three parity checks: user, ufw, dotfiles) and scripts/testing/lib/testinfra.sh, which injects a throwaway SSH key into the VM and runs pytest over SSH. The sweep is advisory here (RUN_TESTINFRA toggle, non-fatal) and does not yet affect pass/fail. Pulls python-pytest and python-pytest-testinfra into make deps. Verified on the host: py_compile clean, pytest --collect-only green, bash -n and shellcheck clean. The sweep running against a real VM is verified by the next make test run. --- scripts/testing/lib/testinfra.sh | 81 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 scripts/testing/lib/testinfra.sh (limited to 'scripts/testing/lib') diff --git a/scripts/testing/lib/testinfra.sh b/scripts/testing/lib/testinfra.sh new file mode 100644 index 0000000..0db0ec9 --- /dev/null +++ b/scripts/testing/lib/testinfra.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Testinfra post-install validation sweep (runs on the host, over SSH). +# +# P1 status: advisory. This runs alongside the shell sweep (run_all_validations) +# so a real VM run can diff the two and prove parity before pytest becomes the +# primary validator (P3 cutover). It never sets the run's pass/fail here. +# +# Auth: a throwaway ed25519 keypair is generated per run, its pubkey authorized +# in the VM over the existing sshpass channel, and pytest/testinfra connects +# key-only via a generated ssh-config. The keypair lives in the results dir and +# is discarded with it. +# +# Uses globals from run-test.sh / vm-utils.sh: SCRIPT_DIR, VM_IP, SSH_PORT, +# ROOT_PASSWORD, ARCHSETUP_VM_CONF. Toggle with RUN_TESTINFRA=false. + +# run_testinfra_validation +run_testinfra_validation() { + local results_dir="$1" + local tests_dir="$SCRIPT_DIR/tests" + local key="$results_dir/testinfra_key" + local sshcfg="$results_dir/testinfra_ssh_config" + + if [ "${RUN_TESTINFRA:-true}" != "true" ]; then + return 0 + fi + if ! command -v pytest >/dev/null 2>&1 || ! python3 -c 'import testinfra' >/dev/null 2>&1; then + warn "Testinfra/pytest not installed on host - skipping pytest sweep (run: make deps)" + return 0 + fi + + step "Running Testinfra validation sweep (advisory)" + + # Ephemeral keypair; authorize the pubkey in the VM over the existing channel. + rm -f "$key" "$key.pub" + if ! ssh-keygen -t ed25519 -N "" -q -f "$key"; then + warn "testinfra: ssh-keygen failed - skipping" + return 0 + fi + if ! copy_to_vm "$key.pub" "/tmp/testinfra_key.pub" "$ROOT_PASSWORD"; then + warn "testinfra: pubkey copy failed - skipping" + return 0 + fi + if ! vm_exec "$ROOT_PASSWORD" \ + "mkdir -p /root/.ssh && chmod 700 /root/.ssh && cat /tmp/testinfra_key.pub >> /root/.ssh/authorized_keys && chmod 600 /root/.ssh/authorized_keys"; then + warn "testinfra: authorizing key in VM failed - skipping" + return 0 + fi + + # ssh-config so testinfra connects key-only, no host-key prompt. + cat > "$sshcfg" </dev/null | head -n1) + : "${test_user:=cjennings}" + + ARCHSETUP_TEST_USER="$test_user" pytest "$tests_dir" \ + --hosts="ssh://testinfra-target" \ + --ssh-config="$sshcfg" \ + --attribution-file="$results_dir/testinfra-attribution.txt" \ + -v >> "$results_dir/testinfra.log" 2>&1 + local rc=$? + + if [ "$rc" -eq 0 ]; then + success "Testinfra sweep passed (advisory; see testinfra.log)" + else + warn "Testinfra sweep reported failures (advisory; see testinfra.log + testinfra-attribution.txt)" + fi + return 0 +} -- cgit v1.2.3