Skip to content

SecOps Platform Deployment Guide

Overview

This document covers how to deploy the bedrock-soc platform — the deployment pipeline, how to trigger a manual redeploy, how to check revision health, how to roll back, and how database migrations work.

For day-to-day platform operations (triage workflow, known-good rules, API reference) see SecOps Platform Operations Guide.


Stack Reference

ComponentResourceDetails
Repositorybedrock-socGitHub org Cirius-Group-Inc
Container Appca-soc-prodrg-logging-logs, logging subscription
Container Registryciriusagentsprod.azurecr.ioimage: soc-web
Databasepsql-secops-prodPostgreSQL, logging subscription
Key Vaultcirius-openai-kv-prodlogging subscription

Note: Some older docs reference ca-secops-prod. The actual Container App is ca-soc-prod. Use ca-soc-prod in all CLI commands.


Normal Deployment Path

Deploys happen automatically on merge to main when the following paths change:

app/**
alembic/**
Dockerfile

Changes to documentation, agent scripts, or config outside these paths do not trigger a deploy.

CI Pipeline Steps

The GitHub Actions workflow (.github/workflows/deploy.yml) runs four jobs in sequence:

test → security-gate → build → deploy

1. test — runs pytest against the full test suite. Any failure blocks deployment.

2. security-gate — runs two scanners:

  • Bandit — Python SAST; fails on high-severity findings
  • pip-audit — dependency vulnerability scan; fails on known CVEs

3. build — builds the Docker image and pushes to ACR:

ciriusagentsprod.azurecr.io/soc-web:<git-sha>
ciriusagentsprod.azurecr.io/soc-web:latest

4. deploy — creates a new Container App revision and routes 100% traffic to it.

Watching a Deployment in Progress

GitHub Actions → bedrock-soc repo → Actions → Deploy

Each step shows its logs in real time. A successful run ends with the deploy job reporting the new revision name.

After deployment, the Container App starts the new revision, runs migrations (see below), then begins serving traffic. The old revision scales to zero.


Manual Redeploy (No Code Change)

To redeploy the current main without changing code — for example, if the Container App needs a fresh start or a Key Vault secret was rotated:

  1. GitHub → bedrock-socActions → Deploy
  2. Run workflow (top right) → select branch mainRun workflow

This runs the full pipeline (test → security-gate → build → deploy) against the current HEAD of main. The image is rebuilt and a new revision is created.

Alternatively, to restart the existing revision without redeploying:

bash
az containerapp revision restart \
  --name ca-soc-prod \
  --resource-group rg-logging-logs \
  --revision <revision-name>

To list current revisions and find the active one:

bash
az containerapp revision list \
  --name ca-soc-prod \
  --resource-group rg-logging-logs \
  --output table

Checking Deployment Health

Container App Status

Azure Portal → rg-logging-logs → ca-soc-prod → Revisions and replicas

Shows all revisions, their traffic weight, and replica status. The active revision should show:

  • Traffic weight: 100%
  • Replicas: at least 1 running
  • Status: Active

Log Stream (Live Logs)

Azure Portal → ca-soc-prod → Log stream

Shows stdout from running replicas in real time. Use this to watch startup, migration output, and application errors immediately after a deploy.

Structured Logs (Query)

bash
# Last 50 log lines from the Container App
az monitor log-analytics query \
  --workspace 5d76d1f2 \
  --analytics-query "ContainerAppConsoleLogs_CL | where ContainerAppName_s == 'ca-soc-prod' | sort by TimeGenerated desc | take 50" \
  --output table

Application Health Check

bash
# Verify the platform is responding
curl -I https://secops.bedrockcybersecurity.org

A 200 OK or 302 Found (redirect to SSO) means the app is serving. A 502 Bad Gateway or 503 means the Container App is down or the replica is unhealthy.


Rolling Back

If a deployment introduces a regression and you need to roll back immediately:

Option 1 — Route Traffic to Previous Revision (Fast)

This activates the previous revision without redeploying. Takes effect in under a minute.

bash
# List revisions to find the previous one
az containerapp revision list \
  --name ca-soc-prod \
  --resource-group rg-logging-logs \
  --output table

# Set 100% traffic to the previous revision
az containerapp ingress traffic set \
  --name ca-soc-prod \
  --resource-group rg-logging-logs \
  --revision-weight <previous-revision-name>=100

The previous revision will scale back up to serve traffic.

Caveat: If the bad deployment ran database migrations, rolling back the app may leave the schema in a state the old code doesn't fully understand. For migration-only rollbacks, see below.

Option 2 — Revert via Git and Redeploy

For a clean rollback that resets the code and is tracked in git:

  1. Identify the last good commit: git log --oneline main
  2. Create a revert PR: git revert <bad-commit-sha>
  3. Merge the revert PR → the pipeline redeploys the reverted code automatically

This is the preferred path when time allows — it keeps the deployment history clean and the rollback is visible in git.


Database Migrations (Alembic)

Migrations run automatically on container startup via alembic upgrade head. This runs before the application begins serving traffic.

Migration Behavior

  • If migrations are up to date, startup continues immediately (seconds)
  • If a migration is pending, Alembic applies it before the app starts
  • If a migration fails, the container exits and the revision is marked as failed — the old revision continues serving traffic

Checking Migration Status

bash
# View migration logs from the most recent deploy
az monitor log-analytics query \
  --workspace 5d76d1f2 \
  --analytics-query "ContainerAppConsoleLogs_CL | where ContainerAppName_s == 'ca-soc-prod' | where Log_s contains 'alembic' | sort by TimeGenerated desc | take 20" \
  --output table

Or check the log stream immediately after a deploy — Alembic prints each migration step to stdout.

If a Migration Fails

The Container App revision will fail to start. Signs:

  • New revision shows 0 running replicas
  • Log stream shows an Alembic error (sqlalchemy.exc.*, alembic.util.exc.*)
  • The platform is still up because the old revision is still serving (fail-safe behavior)

Steps:

  1. Read the migration error in the logs
  2. If the migration has a SQL syntax or data error, fix it in a new PR
  3. If the issue is a pre-existing data state conflict, fix the migration script to handle it (add IF NOT EXISTS, handle nulls, etc.)
  4. Merge the fix — the pipeline deploys the corrected version

Do not manually run alembic commands in production. All schema changes go through the CI/CD pipeline.

Adding a New Migration

bash
# From the bedrock-soc repo, in your local dev environment
cd bedrock-soc
alembic revision --autogenerate -m "description of change"

Review the generated migration in alembic/versions/. Autogenerated migrations sometimes miss complex changes (indexes, constraints) — review before committing. Include the migration in the same PR as the code change that requires it.


Environment Variables and Key Vault

The Container App reads secrets from cirius-openai-kv-prod via its managed identity. Secrets are not stored in environment variables as plaintext.

Adding a New Secret

  1. Add the secret to Key Vault: Azure Portal → cirius-openai-kv-prod → Secrets
  2. Add a Key Vault reference in the Container App:
    bash
    az containerapp secret set \
      --name ca-soc-prod \
      --resource-group rg-logging-logs \
      --secrets "new-secret-name=keyvaultref:https://cirius-openai-kv-prod.vault.azure.net/secrets/secret-name,identityref:/subscriptions/.../managedidentity"
  3. Reference the secret in the container env vars in Terraform (azure-infra) — do not set environment variables manually, they will be overwritten on next deploy

Rotating a Secret

After rotating a secret in Key Vault, the Container App needs to restart to pick up the new value. Force a redeploy or restart the revision (see Manual Redeploy above).


Deployment Checklist

Before merging a PR to main that changes the platform:

  • [ ] pytest passes locally
  • [ ] Bandit shows no high-severity findings
  • [ ] If a migration is included, test it against a local PostgreSQL dev instance
  • [ ] If environment variables changed, the Terraform in azure-infra is updated in a separate PR (or same PR if the workflow allows)
  • [ ] A CM ticket will be auto-created on merge — no manual action needed

After merge:

  • [ ] Watch the GitHub Actions workflow complete successfully
  • [ ] Verify the new revision is running: az containerapp revision list ...
  • [ ] Check https://secops.bedrockcybersecurity.org responds
  • [ ] If a migration ran, verify the schema change in the DB


Document History

DateChangeAuthor
May 2026Initial draft — CI pipeline, manual redeploy, revision health, rollback, Alembic migrations, Key Vault integration. Based on bedrock-soc deploy.yml.Rory

Internal use only — Cirius Group