Files
wehub-resource-sync 161ef94b4f
Sirius CI/CD Pipeline / Merge API Manifest (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build API (${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build UI (${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge UI Manifest (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build Engine (${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Engine Manifest (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build Infra (${{ matrix.service }}, ${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-postgres) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-rabbitmq) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-valkey) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Integration Test (push) Blocked by required conditions
Sirius CI/CD Pipeline / Public Stack Contract (push) Blocked by required conditions
Sirius CI/CD Pipeline / Dispatch Demo Deployment (sirius-demo branch) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Dispatch Demo Canary (main branch) (push) Blocked by required conditions
Check engine pin consistency / Dockerfile / CI pin consistency (push) Successful in 8s
Sirius CI/CD Pipeline / Detect Changes (push) Successful in 23s
Sirius CI/CD Pipeline / Guard Registry Namespace (push) Waiting to run
Validate Docker Configuration / Validate Docker Compose Configuration (push) Successful in 47s
chore: import upstream snapshot with attribution
2026-07-13 12:32:25 +08:00

12 KiB

Sirius Operations & Troubleshooting Runbook

This document contains operational procedures, verification runbooks, and advanced troubleshooting for Sirius maintainers and operators. For getting started, see the README.

Clean Rollout Verification (Fresh Clone)

Use this sequence to validate a production rollout from a fresh checkout.

# 1) Start from a clean runtime state
docker compose down -v --remove-orphans

# 2) Generate runtime secrets/config
docker compose -f docker-compose.installer.yaml run --rm sirius-installer --non-interactive --no-print-secrets

# 3) Build from local source deterministically
docker compose -f docker-compose.yaml -f docker-compose.build.yaml up -d --build

# 4) Confirm all services are healthy
docker compose ps

# 5) Validate API auth behavior
curl -i http://localhost:9001/host/            # expect 401 (no key)
# Internal key: prefer the mounted secret file path inside the container, else env.
RUNTIME_KEY=$(docker exec sirius-api sh -lc 'if [ -r "${SIRIUS_API_KEY_FILE:-}" ]; then tr -d "\r\n" < "$SIRIUS_API_KEY_FILE"; elif [ -n "${SIRIUS_API_KEY:-}" ]; then printf %s "$SIRIUS_API_KEY"; fi')
curl -i -H "X-API-Key: ${RUNTIME_KEY}" http://localhost:9001/host/   # expect 200

# 6) Ensure startup regressions are absent
docker compose logs --no-color sirius-ui sirius-engine | rg -i "ENOTFOUND|permission denied|Failed to open log file"

If step 6 returns any lines, capture full logs and investigate before rollout.

Migrating existing .env deployments to file-based internal key

If docker compose up errors on the sirius_api_key secret file, create it once from your current key (same value as SIRIUS_API_KEY in .env):

mkdir -p secrets
printf '%s\n' "$SIRIUS_API_KEY" > secrets/sirius_api_key.txt
chmod 644 secrets/sirius_api_key.txt

Use 644 (owner read/write, world read) on secrets/sirius_api_key.txt, not 600. Compose bind-mounts that file into the container as /run/secrets/sirius_api_key; sirius-api runs as a non-root UID (1001) and must be able to open it. 600 keeps “other” from reading, so you get permission denied on /run/secrets/sirius_api_key even when SIRIUS_API_KEY is set in .env (older API builds failed before env fallback; current sirius-api falls back to SIRIUS_API_KEY if the file is unreadable when the env is set). The installer writes this file as 644 by default.

Re-run the installer to add SIRIUS_API_KEY_FILE=/run/secrets/sirius_api_key to .env if it is missing. Services accept either the file or SIRIUS_API_KEY during transition.

Release Image Propagation Verification

Use this path to validate what operators experience when running pulled release images.

# 1) Ensure local builds are not used
docker compose down -v --remove-orphans

# 2) Generate runtime secrets/config
docker compose -f docker-compose.installer.yaml run --rm sirius-installer --non-interactive --no-print-secrets

# 3) Validate the public release path for a published tag
export IMAGE_TAG=v0.4.1
bash scripts/validate-public-compose-path.sh "$IMAGE_TAG"

# 4) Verify running container image IDs match pulled release images
bash scripts/verify-release-images.sh

Expected result: the public-stack validator passes, all checks print a pass, and no service is running an unexpected local image.

If verify-ghcr-public-access.sh reports Anonymous access denied, treat it as a registry visibility failure and stop before rollout. If it reports Manifest missing, the selected release tag was not published successfully. If validate-public-compose-path.sh fails after pull succeeds, investigate runtime contract drift before rollout.

Runtime Auth Contract Verification

Use this check any time you run reset, switch between source/release mode, or see 401 and DB auth errors.

bash scripts/verify-runtime-auth-contract.sh

The script assumes default Docker Compose container names (sirius-ui, sirius-api, sirius-engine, sirius-postgres) and curls the API at http://localhost:9001. For a different Compose project name (non-default container_name pattern), set:

  • SIRIUS_CONTRACT_CONTAINER_UI, SIRIUS_CONTRACT_CONTAINER_API, SIRIUS_CONTRACT_CONTAINER_ENGINE, SIRIUS_CONTRACT_CONTAINER_POSTGRES
  • SIRIUS_API_PUBLIC_URL if the published API port differs

See the header comment in scripts/verify-runtime-auth-contract.sh.

If this script fails, do not start new scans until the mismatch is corrected.

If sirius-engine is still restarting after this passes, verify runtime preflight tooling:

docker exec sirius-engine sh -lc 'which psql && psql --version'

Expected result: prints /usr/bin/psql and a PostgreSQL client version. If missing, pull the corrected release image and recreate services.

Scan-Stuck Troubleshooting Runbook

If scans complete in backend logs but UI remains non-terminal, run:

# 0) Do NOT use command-scoped secret overrides for single-service restarts.
# Bad (causes key drift): SIRIUS_API_KEY=local-dev docker compose up -d sirius-engine
# Good: keep secrets in .env and recreate dependent services together.

# 1) Verify API key contract is consistent across services
docker inspect sirius-ui --format '{{range .Config.Env}}{{println .}}{{end}}' | rg '^SIRIUS_API_KEY='
docker inspect sirius-api --format '{{range .Config.Env}}{{println .}}{{end}}' | rg '^SIRIUS_API_KEY='
docker inspect sirius-engine --format '{{range .Config.Env}}{{println .}}{{end}}' | rg '^SIRIUS_API_KEY='

# 2) Check engine scanner warnings and terminal status persistence
docker compose logs --no-color sirius-engine | rg -i "source-aware|status|completed|failed|warning|401"

# 3) Check UI auth/session and API bridge logs
docker compose logs --no-color sirius-ui | rg -i "JWT_SESSION_ERROR|SIRIUS_API_KEY|fetch failed|401"

# 4) Verify DB credential consistency from runtime containers
docker compose logs --no-color sirius-postgres sirius-api sirius-engine | rg -i "password authentication failed|database connection not available"

# 5) Run contract verifier
bash scripts/verify-runtime-auth-contract.sh

# 6) Verify templates endpoint is populated and not in missing/empty state
API_KEY=$(docker inspect sirius-api --format '{{range .Config.Env}}{{println .}}{{end}}' | rg '^SIRIUS_API_KEY=' | sed 's/^SIRIUS_API_KEY=//')
curl -s -D - -o /tmp/sirius-templates.json -H "X-API-Key: ${API_KEY}" http://localhost:9001/templates | rg '^HTTP/|^X-Sirius-Template-State'
python3 -c 'import json; print(len(json.load(open("/tmp/sirius-templates.json"))))'

If any command surfaces key/secret mismatch, re-run installer and restart:

docker compose -f docker-compose.installer.yaml run --rm sirius-installer --non-interactive --no-print-secrets
docker compose up -d --force-recreate

Expected result for step 6: HTTP 200 and template count >= 1. If X-Sirius-Template-State: missing or empty appears, sirius-engine has not initialized template data yet.

Host Discovery Validation

# Confirm compose renders successfully and includes NET_RAW
docker compose config | rg "NET_RAW"

# Confirm scanner system template is canonicalized on startup
docker compose exec sirius-valkey valkey-cli GET template:quick | rg '"scan_types"'

# Run a scan from UI/API, then verify queue consumers and scan state
docker compose exec sirius-rabbitmq rabbitmqctl list_queues name consumers messages_ready messages_unacknowledged | rg "scan|scan_control"
docker compose exec sirius-valkey valkey-cli GET currentScan

Emergency Recovery

Complete System Reset

# Stop all services
docker compose down

# Remove all data (this deletes all scan data)
docker compose down -v

# Clean Docker system
docker system prune -a -f

# Recreate .env using installer (required after reset)
docker compose -f docker-compose.installer.yaml run --rm sirius-installer --non-interactive --no-print-secrets

# Fresh source rebuild
docker compose -f docker-compose.yaml -f docker-compose.build.yaml up -d --build

# Verify auth contract before interacting with UI
bash scripts/verify-runtime-auth-contract.sh

Backup Current Data

# Backup database
docker exec sirius-postgres pg_dump -U postgres sirius > backup.sql

# Backup scan results directory
docker cp sirius-engine:/opt/sirius/ ./sirius-backup/

Common Issues

Container Issues

Services fail to start:

docker compose ps              # Check service status
docker compose logs <service>  # View service logs
docker system df              # Check disk space

Infrastructure services don't start (dev overlay):

# The dev file is an OVERRIDE file, not standalone.
# Wrong:  docker compose -f docker-compose.dev.yaml up -d
# Correct:
docker compose -f docker-compose.yaml -f docker-compose.dev.yaml up -d

Port already in use:

lsof -i :3000
# Stop the conflicting process, then restart

Scanner Issues

Nmap errors or scanning failures:

docker logs sirius-engine | grep -i nmap
docker exec sirius-engine nmap --version
docker restart sirius-engine

Database Issues

Connection failures:

docker exec sirius-postgres pg_isready
docker logs sirius-postgres
docker exec sirius-postgres psql -U postgres -d sirius -c "SELECT version();"

Message Queue Issues

RabbitMQ connectivity or schema errors:

docker exec sirius-rabbitmq rabbitmqctl status
docker exec sirius-rabbitmq rabbitmqctl list_queues
# For schema integrity failures, remove old volumes:
docker compose down -v && docker compose up -d

Network Issues

Services can't communicate:

docker exec sirius-ui ping sirius-api
docker network inspect sirius

GHCR Pull Issues

docker compose pull returns unauthorized:

bash scripts/verify-ghcr-public-access.sh "${IMAGE_TAG:-latest}"

Expected result: all compose-rendered GHCR refs pass anonymously. If the script reports Anonymous access denied, the package visibility contract is broken and the GHCR publicization workflow or token scope needs maintenance.

docker compose pull returns manifest unknown or not found:

bash scripts/verify-ghcr-public-access.sh "${IMAGE_TAG:-latest}"

Expected result: the script identifies the missing tag explicitly. Re-run the publishing workflow for the missing release tag before retrying deployment.

Maintainer: GHCR distribution checklist (public operators)

A Git tag and GitHub Release do not create container tags on GHCR. Third parties need all six images (sirius-ui, sirius-api, sirius-engine, sirius-postgres, sirius-rabbitmq, sirius-valkey) published under the same semver tag, and each package must be public for anonymous docker pull.

  1. Package visibility (per package) — In SiriusScan org packages, open each container image, set Package settings to Public, and link the package to this repository if needed. Partial visibility explains “works when logged in” vs failures for everyone else (see issue #119).
  2. Publish semver tags — Run Publish Release Image Tags with source_tag = the tag that exists on GHCR for all six (usually latest) and target_tag = the release (e.g. v1.0.0). Confirm the workflow run succeeds end-to-end.
  3. Verify anonymously — From a machine not logged in to ghcr.io:
bash scripts/verify-ghcr-public-access.sh v1.0.0

CI runs the same check on every published release and weekly via .github/workflows/verify-ghcr-release-tag.yml.