ecdba833d9
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---
205 lines
6.3 KiB
Bash
Executable File
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
|