Operations - rsys-bshankar/ai-ran-smo GitHub Wiki

Operations

Upgrading

  • Take a backup first: scripts/db_backup.sh (one checked pg_dump file, mode 0600) and scripts/db_restore.sh.
  • Docker Compose: docker compose up -d --build runs the migrations (docker compose logs migrate). Outside compose run python scripts/migrate.py. On Kubernetes see Helm on Kubernetes: the migration runs as a Job before any pod of the new version.
  • From 0.2.0 to 0.3.0: the schema moves to revision 0021, all additive (KPI schedules, KPI guard, the audit chain), and the 0.2.0 code runs on it. Three things to know:
    • R1 Termination now needs the database, for the audit chain and the kill switch. Compose does this already; a deployment of your own must give it the same SMO_DATABASE_URL and password as a module.
    • An rApp may now change only what it uses. A third-party rApp that calls a route outside the allow-list gets 403 ROLE_NOT_PERMITTED. Set SMO_ROLE_ENFORCEMENT=audit on SME and R1 Termination to log instead while you move it.
    • A new service, ran-nf-oam-worker, does the periodic work (staged job advance, KPI schedules and guards). Those run only while it does.
  • From 0.1.0 to 0.2.0: run scripts/init_secrets.sh once on the host first (it creates secrets/enrollment_secret and leaves db_password alone). During a mixed-version rolling upgrade set SMO_ROLE_ENFORCEMENT=audit on SME and R1 Termination.
  • CI upgrades a real previous-release database with data on every change to the migrations, so an upgrade that works only on an empty schema fails there.

Audit trail

Every authenticated change through the gateway is recorded in a hash chain. Check it and export it from any module's image:

docker compose exec r1-termination python -m smo_shared.audit verify
docker compose exec r1-termination python -m smo_shared.audit export --format jsonl > audit.jsonl

verify exits 1 and names the first broken row if a row was edited, removed or inserted. export ends with a head line: keep it somewhere the database's writers cannot reach, because someone who can write the database and recompute every hash is not caught by the chain alone. R1_AUDIT=off turns recording off.

Secrets

Inventory, *_FILE convention and a rotation runbook for each secret: smo/docs/SECRETS.md.

Observability

Structured logs and Prometheus-style metrics per module, readiness vs liveness endpoints, and a slow-query log: Postgres logs statements slower than POSTGRES_SLOW_QUERY_MS (default 500, -1 off): docker compose logs postgres | grep duration. The gateway counts refusals (smo_role_refusals_total) and audit writes (smo_audit_writes_total).

Releases

Tag smo-vX.Y.Z on a merged release PR (smo/docs/RELEASES.md). The tag starts release-images.yml: it builds every image, pushes ghcr.io/rsys-bshankar/ai-ran-ref/smo-<module>:<version>, signs each by digest with cosign (keyless), attaches provenance and an SBOM, and writes the release notes.

Verify an image before running it:

cosign verify ghcr.io/rsys-bshankar/ai-ran-ref/smo-ran-nf-oam:0.3.0 \
  --certificate-identity-regexp '^https://github.com/rsys-bshankar/ai-ran-ref/\.github/workflows/release-images\.yml@refs/' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
docker buildx imagetools inspect ghcr.io/rsys-bshankar/ai-ran-ref/smo-ran-nf-oam:0.3.0 --format '{{ json .Provenance }}'

Contributing

Before opening a PR run the verification battery in smo/CLAUDE.md (lint, every module's unit suite, the integration suite, the migration check against a real Postgres, GUI typecheck/tests/build). CI runs the same on every PR, plus a Helm install and upgrade on kind.

⚠️ **GitHub.com Fallback** ⚠️