Files
serverAppConfigs/tests/deployment_flow.bats
T
Frank 8001132744 tests: LLM unit integrity, sudo-password leak guard, deploy LLM coverage
New seams (written first, red against the pre-merge tree):
- llm_units.bats: every scripts/*.service unit points at files that
  exist in this repo (the merged checkout path), env files included
- llm_secrets.bats: the live sudo password is never tracked (the
  vllmScripts AGENTS.md once documented it)
- deployment_flow.bats: deploy.sh must restart the LLM services on
  both targets and health-check both endpoints (7770, 52625)
- helpers.bash: has_no_leaked_sudo_pw (two-part assembly, same
  pattern as the gitea check)
2026-08-22 15:49:44 -07:00

91 lines
3.9 KiB
Bash

#!/usr/bin/env bats
# Seam: target reachability and deployment flow integrity.
# These tests assert the deployment contract of the unified repo:
# - a deploy.sh exists and accepts <dankclaw|dankserver> 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
# still runs during offline development.
load helpers
@test "deploy.sh exists and is executable" {
[ -x "$REPO_ROOT/scripts/deploy.sh" ]
}
@test "deploy.sh accepts the two known targets" {
run bash "$REPO_ROOT/scripts/deploy.sh" --help 2>&1
[ "$status" -eq 0 ] || true
grep -qE 'dankclaw|dankserver' "$REPO_ROOT/scripts/deploy.sh"
}
@test "git remote origin is configured" {
git -C "$REPO_ROOT" remote get-url origin >/dev/null 2>&1 \
|| skip "no origin remote configured yet"
}
@test "dankclaw is reachable over ssh" {
timeout 8 ssh -o BatchMode=yes -o ConnectTimeout=5 dank@dankclaw 'true' 2>/dev/null \
|| skip "dankclaw not reachable from this host"
}
@test "dankserver is reachable over ssh" {
timeout 8 ssh -o BatchMode=yes -o ConnectTimeout=5 dank@dankserver 'true' 2>/dev/null \
|| skip "dankserver not reachable from this host"
}
# Regression: the Caddyfile render step in deploy.sh must survive a bcrypt
# hash (which contains '/' characters). Reproduce the sed expression with a
# slash-bearing hash and confirm the placeholder is replaced.
@test "deploy.sh reloads Caddy after rendering (hot reload, not just container start)" {
# The caddy container often survives 'up -d' (a Caddyfile change is a
# bind-mount content change, not a container config change). Without an
# explicit reload, a rendered fix can sit on disk while Caddy serves the
# stale in-memory config.
grep -q 'caddy reload' "$REPO_ROOT/scripts/deploy.sh"
}
@test "deploy.sh restarts caddy when the reload cannot be applied" {
# If the running config has the admin API disabled (or the API is down),
# 'caddy reload' can never apply the new file -- the fix cannot be
# delivered over the API it is meant to enable. The fallback is a
# container restart, which always reads the file.
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
rendered=$(sed "s|REPLACE_WITH_HASH|${hash}|g" "$REPO_ROOT/dankclaw/Caddyfile")
[ -n "$rendered" ]
[[ "$rendered" == *"${hash}"* ]]
! grep -q 'REPLACE_WITH_HASH' <<< "$rendered"
# The rendered line must be exactly "dank <hash>". A template that keeps
# its own $2a$14$ prefix renders an invalid double-prefixed hash and
# every basicauth vhost returns 401 (2026-08-22 incident).
grep -qF "dank ${hash}" <<< "$rendered"
! grep -qF '$2a$14$$2a$14$' <<< "$rendered"
}