- infra/scripts/simulate-two-host/: real two-Docker-network simulation (Gateway genuinely isolated from any Lab bridge network) proving the Lab Host Router fix - 13/13 real assertions (HTTP+WebSocket through the Router, Alice/Bob isolation, garbage/destroyed tokens, mTLS-only Router access). - infra/scripts/drills/: Lab Host loss/rebuild (9/9), deployment rollback, CI-fails-closed (6 required failure modes), fake cohort dress rehearsal (14/14, one continuous narrative through the real app). - infra/ci/gitea-workflows/build-and-test.yml: new security-scan job (npm audit, gitleaks, hadolint, shellcheck, trivy - all free/open-source), severity policy in docs/SECURITY_SCANNING.md (CRITICAL/HIGH blocks, MEDIUM/LOW reported only). Gates build-images alongside regression. Found and fixed two real pre-existing bugs via the CI-fails-closed drill: staging-smoke-test.sh and production-smoke-test.sh both had a classic set -e gotcha (curl ... && echo "OK" as one statement - a failing command that isn't last in an && chain doesn't trigger -e) that let an unreachable/broken endpoint fall through silently instead of failing the smoke test. platform/test/e2e-phase3a.js updated for the new paginated /api/admin/audit-events response shape (Phase 4.1 pagination work).
77 lines
3.2 KiB
Bash
Executable File
77 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Orchestrates the Phase 4.1 two-host routing simulation end-to-end: generates a real TLS
|
|
# bundle, computes the sim-platform-net gateway IP, renders the lab_hosts seed with it, brings
|
|
# the stack up, runs test-remote-routing.js, tears everything down. See README.md in this
|
|
# directory and docs/PHASE4_1_PREPRODUCTION_HARDENING.md §6.
|
|
#
|
|
# Usage: ./run-simulation.sh [--keep-up] (--keep-up skips teardown, for debugging)
|
|
set -euo pipefail
|
|
cd "$(dirname "${BASH_SOURCE[0]}")"
|
|
|
|
KEEP_UP=false
|
|
[ "${1:-}" = "--keep-up" ] && KEEP_UP=true
|
|
|
|
WORK_DIR="$(mktemp -d)"
|
|
trap 'rm -rf "$WORK_DIR"' EXIT
|
|
|
|
export PROVISIONER_SHARED_SECRET="${PROVISIONER_SHARED_SECRET:-sim-shared-secret-not-for-real-use}"
|
|
export LAB_IMAGE_REF="${LAB_IMAGE_REF:-rootnode-academy:test}"
|
|
export SIM_TLS_DIR="$WORK_DIR/tls"
|
|
export SIM_LAB_HOSTS_SEED="$WORK_DIR/lab-hosts.seed.yaml"
|
|
|
|
echo "==> [1/6] Creating sim-platform-net so we know its real gateway IP before generating certs"
|
|
NET_NAME="rootnode-sim-platform-net"
|
|
docker network inspect "$NET_NAME" >/dev/null 2>&1 || docker network create "$NET_NAME" >/dev/null
|
|
GW_IP="$(docker network inspect "$NET_NAME" --format '{{(index .IPAM.Config 0).Gateway}}')"
|
|
echo " sim-platform-net gateway IP: $GW_IP (lab-router and provisioner/api, all host-networked, are reachable from Gateway's isolated network through this address)"
|
|
|
|
echo "==> [2/6] Generating a real mTLS bundle for this simulation run (SAN covers the real gateway IP above)"
|
|
../docker-tls/generate-docker-tls.sh --out-dir "$SIM_TLS_DIR" --lab-host-ip "$GW_IP" --lab-host-dns lab-router-sim >/dev/null
|
|
|
|
# Rewrite the compose file's network name to match what we just created/inspected, and point
|
|
# the sim gateway/router services at the shared network by that exact name.
|
|
export COMPOSE_NET_NAME="$NET_NAME"
|
|
|
|
echo "==> [3/6] Rendering lab-hosts.seed.yaml with routing_mode: router at the real gateway IP"
|
|
cat > "$SIM_LAB_HOSTS_SEED" <<EOF
|
|
lab_hosts:
|
|
- lab_host_id: sim-lab-host-01
|
|
display_name: "Simulated rn-lab-host-01"
|
|
endpoint: "unix:///var/run/docker.sock"
|
|
enabled: true
|
|
routing_mode: router
|
|
router_endpoint: "https://${GW_IP}:8443"
|
|
EOF
|
|
|
|
export SIM_PROVISIONER_URL="http://${GW_IP}:4101"
|
|
export SIM_PLATFORM_API_URL="http://${GW_IP}:4301"
|
|
|
|
echo "==> [4/6] Building and starting the simulated two-host stack"
|
|
docker compose -f docker-compose.simulate.yml -p rootnode-sim up -d --build
|
|
|
|
cleanup() {
|
|
if [ "$KEEP_UP" = true ]; then
|
|
echo "==> --keep-up set, leaving the stack running (docker compose -f docker-compose.simulate.yml -p rootnode-sim down to clean up)"
|
|
return
|
|
fi
|
|
echo "==> [6/6] Tearing down the simulation stack"
|
|
docker compose -f docker-compose.simulate.yml -p rootnode-sim down -v >/dev/null 2>&1 || true
|
|
docker network rm "$NET_NAME" >/dev/null 2>&1 || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
echo "==> Waiting for services to become healthy"
|
|
for i in $(seq 1 60); do
|
|
if curl -sf http://localhost:4301/healthz >/dev/null 2>&1 && curl -sf http://localhost:4210/healthz >/dev/null 2>&1; then
|
|
break
|
|
fi
|
|
sleep 2
|
|
done
|
|
|
|
echo "==> [5/6] Running the routing test"
|
|
GATEWAY_URL=http://localhost:4210 \
|
|
PROVISIONER_URL=http://localhost:4101 \
|
|
PROVISIONER_SHARED_SECRET="$PROVISIONER_SHARED_SECRET" \
|
|
GATEWAY_CONTAINER=rootnode-sim-gateway-1 \
|
|
node test-remote-routing.js
|