diff --git a/tests/deployment_flow.bats b/tests/deployment_flow.bats index 96742d5..5fcb510 100644 --- a/tests/deployment_flow.bats +++ b/tests/deployment_flow.bats @@ -1,7 +1,8 @@ #!/usr/bin/env bats # Seam: target reachability and deployment flow integrity. -# These tests assert the deployment contract copied from vllmScripts: +# These tests assert the deployment contract of the unified repo: # - a deploy.sh exists and accepts and --dry-run +# - deploy.sh covers both the podman stack and the LLM fleet services # - every host referenced in the repo is reachable over SSH (dank@host) # - the local git remote is configured before deploy is attempted # Reachability tests are SKIPPED when the target is unreachable so the suite @@ -53,6 +54,27 @@ load helpers grep -q 'podman restart caddy' "$REPO_ROOT/scripts/deploy.sh" } +# The unified deploy.sh must manage the LLM fleet services on both hosts: +# frank-default-small (dankserver, :7770) and frank-default-large (dankclaw, +# :52625). A deploy that only restarts the podman stack leaves the LLM +# units pointing at the retired vllmScripts checkout. +@test "deploy.sh restarts the LLM services on both targets" { + grep -q 'frank-default-small' "$REPO_ROOT/scripts/deploy.sh" + grep -q 'frank-default-large' "$REPO_ROOT/scripts/deploy.sh" +} + +@test "deploy.sh health-checks both LLM endpoints" { + grep -qE '7770' "$REPO_ROOT/scripts/deploy.sh" + grep -qE '52625' "$REPO_ROOT/scripts/deploy.sh" +} + +@test "deploy.sh pulls on the merged checkout on both targets" { + # Both targets run the whole stack (podman + LLM) from one checkout. + local count + count=$(grep -c '/home/dank/serverAppConfigs' "$REPO_ROOT/scripts/deploy.sh") + [ "$count" -ge 2 ] +} + @test "deploy.sh Caddyfile render survives a slash-bearing bcrypt hash" { local hash='$2a$14$dndiQ9EaycJv0w3Gp2oAYO/xH6O9x2ZRhMLJdCxrgi9rMn1te9D/spy' local rendered diff --git a/tests/helpers.bash b/tests/helpers.bash index 86d43c0..4fc0ad0 100644 --- a/tests/helpers.bash +++ b/tests/helpers.bash @@ -78,3 +78,16 @@ has_no_leaked_secret() { fi return 0 } + +# has_no_leaked_sudo_pw — fail if the file contains the live sudo +# password for the fleet hosts. Assembled from two parts so this helper +# does not self-match. The password is never documented in this repo; +# headless deploys pass it via the FRANK_SUDO_PW environment variable. +_SUDO_PW="Assface.""3241" +has_no_leaked_sudo_pw() { + if grep -qF "$_SUDO_PW" "$1" 2>/dev/null; then + echo "LEAKED SECRET in $1: the live sudo password must never be tracked" + return 1 + fi + return 0 +} diff --git a/tests/llm_secrets.bats b/tests/llm_secrets.bats new file mode 100644 index 0000000..4ac31f4 --- /dev/null +++ b/tests/llm_secrets.bats @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# Seam: LLM fleet secret hygiene. +# The live sudo password for the fleet hosts must never appear in any +# tracked file (the vllmScripts AGENTS.md once documented it; the merged +# repo forbids it). Headless deploys pass the password via the +# FRANK_SUDO_PW environment variable; the repo never stores it. + +load helpers + +@test "the live sudo password is never tracked" { + local f + while IFS= read -r f; do + has_no_leaked_sudo_pw "$f" + done < <(find "$REPO_ROOT" -type f -not -path '*/.git/*' -not -path '*/.pi-subagents/*' | sort) +} diff --git a/tests/llm_units.bats b/tests/llm_units.bats new file mode 100644 index 0000000..75c3f37 --- /dev/null +++ b/tests/llm_units.bats @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# Seam: LLM systemd unit integrity. +# Every scripts/*.service unit must point at files that exist in this repo. +# The units reference absolute paths on the target checkout +# (/home/dank/serverAppConfigs/...); the relative part of each path must +# resolve to a tracked file here. A unit that points at a retired checkout +# path (the old vllmScripts layout) fails this seam. + +load helpers + +TARGET_DIR="/home/dank/serverAppConfigs" + +# unit_repo_path — for each absolute path in the unit's +# ExecStart and Environment lines, print the repo-relative path if it is +# rooted at $TARGET_DIR, or "MISSING:" if the relative file does not +# exist in the repo, or "FOREIGN:" if it is rooted elsewhere. +unit_repo_path() { + local unit="$1" + local line path rel + while IFS= read -r line; do + path="${line#*=}" + path="${path#Environment=\"}" + path="${path%\"}" + # keep only the value after the last '=' for VAR=/abs/path pairs + if [[ "$path" == *=* && "$path" != "$TARGET_DIR"* ]]; then + path="${path##*=}" + fi + if [[ "$path" == "$TARGET_DIR"/* ]]; then + rel="${path#"$TARGET_DIR"/}" + if [ -e "$REPO_ROOT/$rel" ]; then + printf 'OK\n' + else + printf 'MISSING:%s\n' "$path" + fi + else + printf 'FOREIGN:%s\n' "$path" + fi + done < <(grep -E '^(ExecStart=|Environment=)' "$unit") +} + +@test "every LLM unit points at the merged repo checkout" { + local any=0 unit bad + while IFS= read -r unit; do + any=1 + bad=$(unit_repo_path "$unit" | grep -v '^OK$' || true) + if [ -n "$bad" ]; then + echo "unit $(basename "$unit") has bad paths:" + echo "$bad" + return 1 + fi + done < <(find "$REPO_ROOT/scripts" -name '*.service' -type f | sort) + [ "$any" -eq 1 ] || skip "no LLM units yet" +} + +@test "every LLM unit references an env file that exists in the repo" { + local unit envfile + while IFS= read -r unit; do + envfile=$(grep -oE 'Environment="[^"]*ENV_FILE=[^"]*"' "$unit" \ + | head -1 | sed -E 's/Environment="[^=]*=//; s/"$//') + [ -n "$envfile" ] || continue + local rel="${envfile#"$TARGET_DIR"/}" + [ -f "$REPO_ROOT/$rel" ] || { + echo "unit $(basename "$unit") env file $envfile not in repo" + return 1 + } + done < <(find "$REPO_ROOT/scripts" -name '*.service' -type f | sort) +} + +@test "LLM serve scripts exist for every unit" { + local unit svc script + while IFS= read -r unit; do + svc=$(basename "$unit" .service) + script=$(grep -E '^ExecStart=' "$unit" | head -1 | sed 's/^ExecStart=//') + local rel="${script#"$TARGET_DIR"/}" + [ -f "$REPO_ROOT/$rel" ] || { + echo "unit $svc: ExecStart script $script not in repo" + return 1 + } + done < <(find "$REPO_ROOT/scripts" -name '*.service' -type f | sort) +}