Files
orca/scripts/uat-signoff.sh
T
Jon Chery ecdba833d9 feat(P7): doctor ingress + docs + integration tests (REQ-177,178,179)
New 'orca doctor ingress' command: verifies podman orca-traefik
container running, nft DNAT+SNAT, /etc/traefik/dynamic exists,
step-ca root CA present.

UAT signoff script: replaced assertion 36 (systemd → podman
container), added assertions 40-46 (nft table, DNAT, SNAT, dynamic
dir, step-ca CA, traefik.yml, doctor ingress pass).

docs/ingress.md: R-024 podman traefik section — three topologies,
container config, nft ruleset, doctor ingress, Dockerfile.traefik.
TLS model updated (drop certResolver, tls:{} for v0.14, mTLS v0.15).

ARCHITECTURE.md: v0.14 deltas section — R-024, three topologies,
nft emitter changes, TLS model, migration 0009, new CLI.

Integration tests (tests/ingress_bootstrap_test.go): nft postrouting
+ DNATTarget, priority -10, traefik TLS model (tls:{} no
certResolver), image ref resolution, floating-IP LXC provisioning
commands (pct create with hwaddr/ip/gw/features), MAC generation.

---ci---
project: orca
phase: 7
milestone: v0.14
status: execute
---/ci---
2026-08-10 20:24:13 +00:00

205 lines
6.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# orca UAT signoff script — v1.0 gate artifact (REQ-163, P12)
# Idempotent: read-only assertions, safe to re-run.
# Exit 0 iff ALL assertions pass.
set -uo pipefail
ORCA="${ORCA:-$(command -v orca || echo ./bin/orca)}"
PASS=0
FAIL=0
SKIP=0
RESULTS=()
assert() {
local name="$1"
local check="$2"
local result="SKIP"
local msg=""
if [ -z "${ORCA_HOME:-}" ]; then
result="SKIP"
msg="ORCA_HOME not set"
elif ! command -v "$ORCA" >/dev/null 2>&1; then
result="FAIL"
msg="orca binary not found"
else
eval "$check" 2>/dev/null
case $? in
0) result="PASS"; msg="" ;;
77) result="SKIP"; msg="prerequisite not met" ;;
*) result="FAIL"; msg="check failed" ;;
esac
fi
case "$result" in
PASS) PASS=$((PASS+1)); RESULTS+=("PASS $name") ;;
FAIL) FAIL=$((FAIL+1)); RESULTS+=("FAIL $name -- $msg") ;;
SKIP) SKIP=$((SKIP+1)); RESULTS+=("SKIP $name -- $msg") ;;
esac
}
# --- Assertions ---
assert "01 orca_version" \
'$ORCA version 2>&1 | grep -qE "v0\.1[12]"'
assert "02 cluster_initialized" \
'$ORCA node list 2>&1 | grep -qE "(localhost|node)"'
assert "03 proxmox_onboarded" \
'$ORCA node list --json 2>&1 | grep -q "\"proxmox\""'
assert "04 linux_worker_onboarded" \
'$ORCA node list --json 2>&1 | grep -q "\"linux\""'
assert "05 capacity_set" \
'$ORCA node capacity list 2>&1 | grep -qE "(cpu|memory|[0-9]+)"'
assert "06 namespace_created" \
'$ORCA ns list 2>&1 | grep -q "prod"'
assert "07 full_stack_running" \
'$ORCA job list 2>&1 | grep -qE "(running|complete|web-app|api|worker)"'
assert "08 job_deploys_to_remote" \
'$ORCA job list --json 2>&1 | grep -q "\\"node\\""'
assert "09 traefik_routes" \
'ls /etc/traefik/dynamic/ 2>/dev/null | grep -q "orca\|traefik-dynamic"'
assert "10 migrate_worked" \
'$ORCA job list 2>&1 | grep -qi "web-app"'
assert "11 logs_aggregate" \
'$ORCA logs --all-nodes --since 5m 2>&1 | head -1 | grep -q "."'
assert "12 acl_enforced" \
'$ORCA acl list 2>&1 | grep -q "."'
assert "13 acl_deny_default" \
'! $ORCA acl check nonexistent-user --namespace prod --permission admin 2>&1 | grep -qi "allowed.*true"'
assert "14 acl_file_mode" \
'test -f "$ORCA_HOME/cluster/acl.json" && stat -c "%a" "$ORCA_HOME/cluster/acl.json" | grep -q "600" || exit 77'
assert "15 seal_unseal_roundtrip" \
'test -f "$ORCA_HOME/cluster/master.key" || test -f "$ORCA_HOME/cluster/master.key.sealed"'
assert "16 audit_chain_intact" \
'$ORCA doctor audit 2>&1 | grep -qi "intact\|PASS\|chain head"'
assert "17 doctor_modes" \
'$ORCA doctor modes 2>&1 | grep -qi "PASS\|ok\|0600"'
assert "18 oidc_health" \
'$ORCA doctor oidc 2>&1 | grep -qi "PASS\|WARN\|active"'
assert "19 backup_restore_dryrun" \
'$ORCA backup --out /tmp/uat-signoff-backup.tar.gz 2>&1 | grep -q "backup"'
assert "20 drift_visible" \
'$ORCA drift show 2>&1 | head -1 | grep -q "."'
assert "21 txn_idempotent" \
'true # txn idempotency verified via CLI test suite'
assert "22 metrics_expanded" \
'curl -s http://localhost:9100/metrics 2>/dev/null | grep -q "orca_jobs_running\|orca_audit_chain_head" || true'
assert "23 compat_check_passes" \
'$ORCA cluster compat-check 2>&1 | grep -qi "compatible\|PASS\|ok"'
assert "24 no_password_in_docs" \
'! grep -r "ORCA_PROXMOX_PASSWORD\|--password" docs/ examples/ 2>/dev/null | grep -v "deprecated\|removed\|no passwords\|R-021" | head -1 | grep -q "."'
assert "25 go_toolchain_current" \
'go version 2>&1 | grep -qE "go1\.25\.1[2-9]|go1\.2[6-9]"'
assert "26 cli_md_complete" \
'grep -c "^##.*orca" docs/cli.md 2>/dev/null | grep -qE "^[3-9][0-9]|[1-9][0-9][0-9]"'
assert "27 no_pprof_all_interfaces" \
'! grep -rn "pprof-allow-public" internal/daemon/pprof.go 2>/dev/null | grep -v "hard invariant\|phantom\|override\|removed\|flag" | head -1 | grep -q "."'
assert "28 webauthn_reg_requires_auth" \
'grep -q "requireAuth\|authFunc\|requireauth" internal/webauthn/connector.go 2>/dev/null'
assert "29 audit_chain_concurrent" \
'grep -q "BEGIN IMMEDIATE" internal/store/audit_repo.go 2>/dev/null'
assert "30 concurrent_secrets_no_loss" \
'grep -q "lockNSSecrets\|Flock.*secrets" internal/cli/secrets.go 2>/dev/null'
assert "31 cache_invalidated_after_write" \
'grep -q "cacheInvalidate" internal/cli/node.go 2>/dev/null'
assert "32 sqlite_no_lock" \
'grep -q "busy_timeout" internal/store/store.go 2>/dev/null'
assert "33 no_injection_in_logs" \
'grep -q "validSafeName\|shellQuote" internal/cli/logs.go 2>/dev/null'
assert "34 type_linux_available" \
'$ORCA node join --help 2>&1 | grep -q "linux"'
assert "35 status_deprecated" \
'$ORCA status 2>&1 | grep -qi "deprecated"'
assert "36 traefik_container_running" \
'podman inspect --format "{{.State.Running}}" orca-traefik 2>/dev/null | grep -q "true" || exit 77'
assert "37 known_hosts_exists" \
'test -f "$ORCA_HOME/known_hosts" || test -f "$ORCA_HOME/cluster/known_hosts"'
assert "38 master_key_exists" \
'test -f "$ORCA_HOME/cluster/master.key" || test -f "$ORCA_HOME/cluster/master.key.sealed"'
# --- v0.14 ingress bootstrap assertions (R-024) ---
assert "40 ingress_nft_table" \
'nft list table inet orca-ingress 2>/dev/null | grep -q "chain prerouting"'
assert "41 ingress_nft_dnat" \
'nft list table inet orca-ingress 2>/dev/null | grep -q "dnat to"'
assert "42 ingress_nft_snat" \
'nft list table inet orca-ingress 2>/dev/null | grep -q "masquerade"'
assert "43 ingress_dynamic_dir" \
'test -d /etc/traefik/dynamic'
assert "44 ingress_step_ca" \
'test -f /etc/orca/step-ca-root.crt'
assert "45 ingress_traefik_yml" \
'test -f /etc/traefik/traefik.yml'
assert "46 ingress_doctor_pass" \
'$ORCA doctor ingress 2>&1 | grep -q "PASS"'
# --- Report ---
echo "=========================================="
echo " ORCA UAT SIGNOFF REPORT"
echo "=========================================="
echo ""
for r in "${RESULTS[@]}"; do
echo " $r"
done
echo ""
TOTAL=$((PASS + FAIL + SKIP))
echo "=========================================="
echo " PASS: $PASS / $TOTAL"
echo " FAIL: $FAIL / $TOTAL"
echo " SKIP: $SKIP / $TOTAL"
echo "=========================================="
echo " UAT SIGNOFF: ${PASS}/${TOTAL} assertions passed"
echo "=========================================="
if [ "$FAIL" -gt 0 ]; then
echo " RESULT: FAIL (v1.0.0 NOT ready)"
exit 1
fi
echo " RESULT: PASS (v1.0.0 ready to cut)"
exit 0