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

284 lines
12 KiB
Markdown

# 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](../README.md).
## Clean Rollout Verification (Fresh Clone)
Use this sequence to validate a production rollout from a fresh checkout.
```bash
# 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`):
```bash
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.
```bash
# 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
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:
```bash
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:
```bash
# 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:
```bash
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
```bash
# 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
```bash
# 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
```bash
# 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:**
```bash
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):**
```bash
# 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:**
```bash
lsof -i :3000
# Stop the conflicting process, then restart
```
### Scanner Issues
**Nmap errors or scanning failures:**
```bash
docker logs sirius-engine | grep -i nmap
docker exec sirius-engine nmap --version
docker restart sirius-engine
```
### Database Issues
**Connection failures:**
```bash
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:**
```bash
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:**
```bash
docker exec sirius-ui ping sirius-api
docker network inspect sirius
```
### GHCR Pull Issues
**`docker compose pull` returns `unauthorized`:**
```bash
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
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](https://github.com/orgs/SiriusScan/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](https://github.com/SiriusScan/Sirius/issues/119)).
2. **Publish semver tags** — Run [Publish Release Image Tags](https://github.com/SiriusScan/Sirius/actions/workflows/publish-release-image-tags.yml) 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
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](.github/workflows/verify-ghcr-release-tag.yml).