Files
git.stella-ops.org/ops/devops/sealed-mode-ci/run-sealed-ci.sh
master 536f6249a6
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Add SBOM, symbols, traces, and VEX files for CVE-2022-21661 SQLi case
- Created CycloneDX and SPDX SBOM files for both reachable and unreachable images.
- Added symbols.json detailing function entry and sink points in the WordPress code.
- Included runtime traces for function calls in both reachable and unreachable scenarios.
- Developed OpenVEX files indicating vulnerability status and justification for both cases.
- Updated README for evaluator harness to guide integration with scanner output.
2025-11-08 20:53:45 +02:00

170 lines
5.1 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
cd "$SCRIPT_DIR"
COMPOSE_FILE=${COMPOSE_FILE:-"$SCRIPT_DIR/sealed-mode-compose.yml"}
PROJECT_NAME=${COMPOSE_PROJECT_NAME:-sealedmode}
NETWORK_NAME="${PROJECT_NAME}_sealed-ci"
ARTIFACT_ROOT=${ARTIFACT_ROOT:-"$SCRIPT_DIR/artifacts/sealed-mode-ci"}
STAMP=$(date -u +"%Y%m%dT%H%M%SZ")
OUT_DIR="$ARTIFACT_ROOT/$STAMP"
mkdir -p "$OUT_DIR"
log() {
printf '[%s] %s\n' "$(date -u +%H:%M:%S)" "$*"
}
EXIT_CODE=0
IPTABLES_SNAPSHOT=""
cleanup() {
local exit_code=$?
log "Collecting docker compose logs"
docker compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" logs >"$OUT_DIR/compose.log" 2>&1 || true
docker compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" ps -a >"$OUT_DIR/compose.ps" 2>&1 || true
log "Tearing down sealed-mode stack"
docker compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" down -v >"$OUT_DIR/docker-down.log" 2>&1 || true
if [[ -n "$IPTABLES_SNAPSHOT" && -f "$IPTABLES_SNAPSHOT" ]]; then
log "Restoring iptables snapshot"
sudo iptables-restore <"$IPTABLES_SNAPSHOT" || true
rm -f "$IPTABLES_SNAPSHOT"
fi
log "Artifacts stored at $OUT_DIR"
exit $exit_code
}
trap cleanup EXIT
log "Pulling compose images (best effort)"
docker compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" pull --ignore-pull-failures || true
log "Starting sealed-mode stack"
docker compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" up -d --remove-orphans
wait_for_port() {
local port=$1
local label=$2
for attempt in $(seq 1 30); do
if curl -fsS --max-time 5 "http://127.0.0.1:${port}/healthz" >/dev/null 2>&1; then
log "$label responded on port $port"
return 0
fi
sleep 2
done
log "$label failed to respond on port $port"
return 1
}
wait_for_port 5088 "Authority" || EXIT_CODE=1
wait_for_port 6088 "Signer" || EXIT_CODE=1
wait_for_port 7088 "Attestor" || EXIT_CODE=1
log "Fetching probe helper image"
docker pull curlimages/curl:8.6.0 >/dev/null 2>&1 || true
log "Snapshotting iptables state"
IPTABLES_SNAPSHOT=$(mktemp)
sudo iptables-save >"$IPTABLES_SNAPSHOT"
log "Applying sealed-mode egress policy"
CHAIN="STELLAOPS_SEALED"
sudo iptables -N "$CHAIN" 2>/dev/null || sudo iptables -F "$CHAIN"
for cidr in 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16; do
sudo iptables -A "$CHAIN" -d "$cidr" -j RETURN
done
sudo iptables -A "$CHAIN" -j LOG --log-prefix "stellaops-sealed-deny " --log-level 4
sudo iptables -A "$CHAIN" -j DROP
sudo iptables -I DOCKER-USER 1 -j "$CHAIN"
sudo iptables -I OUTPUT 1 -j "$CHAIN"
check_health() {
local name=$1
local port=$2
local url="http://127.0.0.1:${port}/healthz"
local log_file="$OUT_DIR/${name}.health.log"
local status="fail"
for attempt in $(seq 1 20); do
if curl -fsS --max-time 5 "$url" >"$log_file" 2>&1; then
status="pass"
break
fi
sleep 2
done
if [[ "$status" == "pass" ]]; then
log "$name health check succeeded"
else
log "$name health check failed"
EXIT_CODE=1
fi
local upper
upper=$(echo "$name" | tr '[:lower:]' '[:upper:]')
eval "${upper}_HEALTH_STATUS=$status"
eval "${upper}_HEALTH_URL=$url"
}
check_health authority 5088
check_health signer 6088
check_health attestor 7088
log "Running egress probe via docker network $NETWORK_NAME"
EGRESS_JSON="$OUT_DIR/egress-probe.json"
if python3 "$SCRIPT_DIR/egress_probe.py" --network "$NETWORK_NAME" --image curlimages/curl:8.6.0 --timeout 8 --output "$EGRESS_JSON"; then
EGRESS_STATUS="pass"
else
EGRESS_STATUS="fail"
EXIT_CODE=1
fi
log "Dumping iptables counters"
sudo iptables -v -x -L DOCKER-USER >"$OUT_DIR/iptables-docker-user.txt"
sudo iptables -v -x -L OUTPUT >"$OUT_DIR/iptables-output.txt"
log "Recording summary JSON"
export PROJECT_NAME NETWORK_NAME EGRESS_STATUS EGRESS_JSON
export AUTHORITY_HEALTH_STATUS SIGNER_HEALTH_STATUS ATTESTOR_HEALTH_STATUS
export AUTHORITY_HEALTH_URL SIGNER_HEALTH_URL ATTESTOR_HEALTH_URL
python3 - <<'PY' >"$OUT_DIR/authority-sealed-ci.json"
import json
import os
import sys
from datetime import datetime, timezone
summary = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"project": os.environ.get("PROJECT_NAME"),
"network": os.environ.get("NETWORK_NAME"),
"health": {
"authority": {
"status": os.environ.get("AUTHORITY_HEALTH_STATUS", "unknown"),
"url": os.environ.get("AUTHORITY_HEALTH_URL"),
"log": "authority.health.log",
},
"signer": {
"status": os.environ.get("SIGNER_HEALTH_STATUS", "unknown"),
"url": os.environ.get("SIGNER_HEALTH_URL"),
"log": "signer.health.log",
},
"attestor": {
"status": os.environ.get("ATTESTOR_HEALTH_STATUS", "unknown"),
"url": os.environ.get("ATTESTOR_HEALTH_URL"),
"log": "attestor.health.log",
},
},
"egressProbe": {
"status": os.environ.get("EGRESS_STATUS", "unknown"),
"report": os.path.basename(os.environ.get("EGRESS_JSON", "egress-probe.json")),
},
}
json.dump(summary, sys.stdout, indent=2)
print()
PY
if [[ $EXIT_CODE -eq 0 ]]; then
log "Sealed-mode CI run completed successfully"
else
log "Sealed-mode CI run completed with failures"
fi
exit $EXIT_CODE