Production Release Checklist¶
P8 machine release gate¶
Before tag or deployment review, run uv run python scripts/release_gate.py from a
locked checkout. The command must finish with exit code zero and
release/evidence/p8-release-evidence.v1.json must report release_status as
passed, identical required/executed gate counts, no missing or failed gates, and
SHA-256 entries for every release artifact. A missing test, skipped command, stale
generated artifact, or unavailable scanner is a failure; manual narrative cannot
replace this evidence package.
The versioned inputs reviewed with that package are under release/: schema catalog,
Agent Tool Registry, OpenAPI, Skill metadata, provider coverage, migration manifest,
and SPDX SBOM. CLI, MCP, REST, Skill, and generated documentation remain Registry
consumers rather than independently maintained inventories.
Casdoor OAuth gate¶
- [ ] The deployed website serves the current English and Simplified Chinese Terms of Service, Privacy Notice, and Account Deletion Guide; each page shows its effective date and version, and the global footer links all three.
- [ ] Casdoor
admin/argus-clilinks the current Terms, requires Agreement on username/password signup only, hides it on ordinary sign-in, leaves custom signup HTML empty, and shows the versioned Terms/Privacy disclosure for GitHub signup plus all three legal footer links. - [ ] A request to every legal page with
Origin: https://auth.argusfa.comreturns that exact origin inAccess-Control-Allow-Origin, while unrelated pages and unapproved origins do not receive a CORS grant; opening the Casdoor Agreement displays the Terms. - [ ] The GitHub provider requests only identity scopes (
read:useranduser:email), and a fresh test registration visibly encounters the legal disclosure before the provider redirect. If affirmative, versioned consent evidence is contractually required, an application-owned consent gate and receipt store are in place; Casdoor's provider button alone is insufficient. -
[ ]
[email protected]can receive privacy and account-deletion requests, and the operator has a documented process to verify, fulfil, retain lawful exceptions, and record completion of those requests. -
[ ] API and MCP use distinct configured audiences/resources.
- [ ] Discovery issuer is exactly
https://auth.argusfa.com; authorization, token, and JWKS endpoints use HTTPS. - [ ] Every access token has
0 < exp-iat <= 3600; Casdoor applications use the minimum one-hour lifetime. - [ ] DCR is disabled and ChatGPT, Claude, and CLI are pre-registered because Casdoor DCR applications default to 7 days.
- [ ] Casdoor application
admin/argus-cliexposes the compiled public Client ID, registers exactlyhttp://127.0.0.1:8765/callback, and uses PKCE plus refresh rotation; the root-owned Casdoor management credential lives in a separate preflight-only directory and lets production preflight verify the unmasked callback, grant types, and one-hour access-token lifetime before validating that the live authorization endpoint accepts the release ID, scopes, response type, and callback. - [ ]
ARGUS_CLIENT_DISTRIBUTION__*values are empty; the CLI wheel is bundled in the signed API image and its compiled client ID matches server configuration. - [ ] MCP clients are pre-registered and every approved redirect URI is configured in Casdoor; DCR remains disabled.
- [ ]
/mcp-machineis live for machine clients and public/mcpis OAuth-only. - [ ] Production uses
ARGUS_MCP_ROLLOUT_PHASE=oauth-cutover. - [ ] Email, SMS, GitHub, Google, Codex, Claude, and ChatGPT staging smoke passes.
- [ ] Casdoor disablement is confirmed to reject refresh immediately; an already issued access token expires within one hour.
- [ ] OAuth shared institution cannot cross into machine institutions; caller-owned resources remain isolated.
Use this checklist for every staging or production release. A historical 15.2 completed note means contract and local acceptance passed; production release is allowed only after the live data, internal distribution, Compose startup, and operations gates below pass for the target institution.
Public edition¶
- [ ] Bump the public version in
pyproject.tomlandsrc/argus/__init__.pyto the same value. Use that current project version rather than a historical checklist value; the website masthead, OpenAPIinfo.version, Skill package version, and/health/liveall read this number. - [ ] Set
website/package.json(and the rootwebsite/package-lock.jsonpackage version) to the same value, and update the fallback version inwebsite/src/pages/index.astroandwebsite/src/pages/404.astro. - [ ] Regenerate
website/generated/authority-data.jsonviascripts/generate_website_data.pyso the header cannot keep showing a stale edition. - [ ] Regenerate tracked release artifacts with
uv run python scripts/generate_release_artifacts.pyso OpenAPI and the SBOM match. - [ ] From
website/, runnpm run build:brand,npm run build:screenshots, andnpm run verify:screenshots; confirm the screenshot manifest reports this release version, the current Registry and tool count, and onlyCLI + Skill,MCP, andREST. - [ ] Confirm all 12 locales have section-specific Open Graph cards, localized campaign lockups use reviewed website copy, the 9:16 lockup remains inside the platform-safe area, and
assets/brand/source/asset-manifest.jsonmatches both source-plate hashes and the approved distribution record.
Required Gates¶
- Confirm the release commit and
ARGUS_IMAGEregistry digest are immutable; do not deploy a tag. The image must beghcr.io/ksahdsambn/argus@sha256:..., and Cosign must be installed so the preflight can verify therelease.ymlGitHub Actions identity before the image receives production secrets. Confirm the image signature identity is a semanticv*tag, points exactly to the current protectedmaincommit, and that the release workflow's reusablequality-gatejob passed for that exact tagged commit. Protect theproduction-releaseGitHub Environment with required reviewers before enabling releases. - Run migrations against staging or a restored production backup first, and record the successful restore rehearsal identifier and elapsed time.
- Confirm
ARGUS_DATA_LICENSE__ENFORCEMENT_ENABLED=falseandARGUS_CONNECTORS__FAIL_CLOSED_ON_LICENSE_ERROR=false. Verify the mounted production policy still preserves source-specific prohibited uses, restricted fields, and redistribution metadata so enforcement can be restored later. The application user must be able to read the mounted policy file. The prepared preflight explicitly parses and compares that file even with generic enforcement disabled, so an unreadable/invalid mount cannot pass through the runtime's empty-table fallback. Verify the actual service uid/groups against the file and parent directories; retain the content checksum when repairing permissions. A readable placeholder table still does not prove customer institution eligibility or source subscription rights. - Confirm production settings reject placeholder secrets before deployment,
that
ARGUS_SECRETS_DIR_HOSTis root-owned with groupARGUS_SECRETS_GIDand exact mode0750or0550, and that every required file below it is a non-placeholder, root-owned one-line value with mode0640or0440, group matchingARGUS_SECRETS_GID, and no world access. Confirm the separateARGUS_CASDOOR_PREFLIGHT_SECRETS_DIR_HOSTfollows the same permissions, contains only the two management credential files, and is absent from every long-running service mount. Confirmdocker compose configanddocker inspectdo not contain the PostgreSQL, Redis, signing, metrics, model, Voyage, or connector secret values. - Confirm the provider keys and identifiers are present for SEC EDGAR, FRED, OpenFIGI, and Voyage vector/rerank evidence retrieval.
- Run the protected GitHub Actions Staging validation workflow with real provider keys. It must complete its live connector smoke and deployed API checks before production promotion. It must also pass the known-filing structured evidence assertion and the public MCP initialize plus authenticated tool-call assertion.
- Validate production Compose configuration:
docker compose --env-file .env.production -f docker-compose.prod.yml config --quiet
scripts/production-preflight.sh
- Before application deployment, issue an
institution:argus-primarymachine credential from the migrated production database, store its one-time plaintext key, and update every production caller. Existinginstitution:prodcredentials are not compatible. SetARGUS_PRIMARY_MACHINE_CREDENTIAL_READY=YESonly after the new key has been distributed and its institution id verified. - Run the guarded deployment entrypoint. It checks the credential migration gate, starts dependencies, runs migrations, verifies the exact Alembic head, and waits for every app service to become healthy:
- Verify health and readiness:
docker compose --env-file .env.production -f docker-compose.prod.yml exec -T api \
python -m argus.container_health --json --require postgres redis object-storage
curl -fsS https://api.argusfa.com/health/ready
Verify the service-role checks too:
docker compose --env-file .env.production -f docker-compose.prod.yml exec -T worker \
python -m argus.container_health --json --require celery-worker
docker compose --env-file .env.production -f docker-compose.prod.yml exec -T beat \
python -m argus.container_health --json --require celery-beat
- Verify the replacement
institution:argus-primarycredential through REST or MCP, then revoke the supersededinstitution:prodcredential. - Confirm authenticated Redis access is reachable, because production machine rate limiting is distributed through Redis and fails closed when Redis is unavailable. Kill one worker while a test task is running and confirm the late- acknowledged persistent message is redelivered, reaches a terminal persisted status, and does not create a duplicate business result.
- Confirm
/metricsrequiresX-Argus-Metrics-Keyor a bearer token. Validatedeploy/prometheus/argus.rules.ymland the active Prometheus configuration withpromtool; prove API/MCP blackbox, node_exporter textfile, cAdvisor, queue depth, object-storage free space, and audit-integrity metrics are present. Trigger controlled alerts for disk, container restart, API error rate, queue backlog, stale backup, certificate expiry, and missing monitoring signals, and confirm Alertmanager sends them to an attended receiver. Confirm the MCP metrics port is bound only to loopback or the approved RFC1918 private/VPN address, the external Prometheus target resolves to that address, and the firewall permits the port only from the monitoring host. Confirm Celery beat containsaudit-log-retention, verify the configuredARGUS_AUDIT__RETENTION_DAYSmatches the approved retention policy, and confirm the latest run persisted a system audit with cutoff, deleted-record count, retention days, and a success or failure terminal status. - Confirm API and MCP remain bound to loopback and are reachable only through
the TLS reverse proxy. Verify the rendered Nginx configuration with
nginx -t; confirm per-IP limit responses are429, request size and timeout limits are active, and filesystem object storage is writable and persisted on the host volume. ConfirmARGUS_MCP_PUBLIC_URLuses HTTPS; non-local startup must reject HTTP. If the S3 backend is selected, confirm its endpoint uses HTTPS andARGUS_OBJECT_STORAGE__SECURE_TRANSPORT=true. - Run a scoped internal smoke query through REST or MCP and verify the response carries facts, evidence, license status, output restrictions, and an audit id.
- Capture rollback steps: previous image digest, migration downgrade decision,
backup identifier, restore rehearsal identifier, and operator owner.
Confirm
restore-production.shrefuses to run while API, MCP, worker, or beat is running, paused, restarting, created, dead, or removing, then perform the rehearsal in an isolated Compose project and verify transactional PostgreSQL restore plus the known object-storage file. - Confirm the systemd backup timer is active,
.env.productionis mode0600, local retention is approved, and the latest restic snapshot exists when encrypted off-host replication is enabled. Confirm whether optional Redis queue backup is intentionallytrueorfalse. Confirm/var/lib/argus-backupsis owned byargus-deployand a forcedsystemctl start argus-backup.servicereports restart failures rather than silently succeeding. During that forced run, verify API and MCP remain available; the online backup must not stop application services. Confirm node_exporter reports the newly updatedargus_backup_last_success_unixtimevalue. - Verify the release digest has passed Trivy repository/image scans and has a Cosign signature, SPDX SBOM attestation, and build provenance attestation.
Static website release gate¶
- Build the static website from the lockfile and confirm all locales and generated tool pages,
/docs/, search, Markdown/JSON copy fallbacks, only the documented Skill download routes, localized section-specific Open Graph/Twitter cards, SEO/hreflang, axe, Lighthouse, and static artifact audit pass. Rebuild and verify product screenshots rather than carrying images forward from an earlier release. - Confirm the release contains no API key input, secret, internal address, production Usage data, Registry/OpenAPI/Skill mirror, or page-level Markdown/JSON export. Verify Usage privacy thresholds and stale-state text.
- Set
.env.websiteto mode0600, run the website production preflight, build both Compose website images from the lockfiles with the same Git SHA, validatedocker-compose.website.yml, and confirm its Nginx cache policy, MIME, security headers, 404 behavior, machine discovery files, and loopback-only reverse-proxy origin port. For a legacy state file, verify the actual:localUsage image was migrated to the previous release SHA before activation. Record current and previous Git-SHA state for website and Usage images, then rehearse their jointscripts/rollback-website-compose.sh, including failed-activation recovery, without touching API/MCP or the Usage volume. - Confirm the
website-usageCompose service is healthy with only its Prometheus token mount and persistent Usage volume; require/data/usage.jsonto exist and pass checksum validation, record the last valid snapshot age, and retry any pending IndexNow notification separately from release status.
CI Expectations¶
GitHub Actions must run unit, integration, end-to-end, documentation, container
build, production Compose config, and production Compose startup smoke on normal
pull requests and main pushes. Live connector smoke is intentionally excluded
from ordinary commits and is required when the reusable quality gate is invoked
with run_live_connector_smoke: true; the secure release workflow does so and
must provide SEC_USER_AGENT, FRED_API_KEY,
OPENFIGI_API_KEY, BEA_API_KEY, BLS_API_KEY, and EIA_API_KEY.
Staging validation continues to run the same provider
checks explicitly with staging secrets.
The prepared release includes an immutable build manifest inside its installed
wheel and OCI revision label. /v1/release-identity reports the build commit,
package/Registry versions and dependency-lock SHA-256; local or older builds
without the manifest explicitly report that identity is unavailable. Runtime
environment variables cannot substitute a release commit.
Dispatch staging validation at the candidate commit and supply that same full
SHA as expected_commit. Before provider and business checks, the workflow
requires the deployed API manifest to match the workflow source, versions and
lock checksum. Redirects and mismatches fail the gate; preserve its JSON receipt
even on failure. Use /mcp-machine for staging machine credentials, and verify
ordinary OAuth independently. API identity does not prove that MCP, worker or
beat uses the same digest: retain Compose/container digest and revision evidence
for every deployed role, signed image provenance and the complete business
matrix. This identity gate does not replace source or business acceptance.