CI/CD Pipeline¶
Verity uses GitHub Actions for continuous integration and deployment. Two workflow files define the build pipeline:
.github/workflows/ci.yml— Main CI/CD pipeline: lint, test, build, deploy.github/workflows/security.yml— Security scanning: vulnerabilities, SAST, container images
Pipeline Overview¶
graph TB
subgraph Trigger["Trigger"]
PUSH["Push to main"]
PR["Pull Request"]
end
subgraph CI["CI Pipeline (.github/workflows/ci.yml)"]
LINT["Lint & Type Check<br/><i>Ruff + Mypy</i>"]
UNIT["Unit Tests<br/><i>pytest + coverage ≥90%</i>"]
INTEGRATION["Integration Tests<br/><i>Docker Compose + pytest</i>"]
SECURITY_CI["Security Scan<br/><i>Bandit + Trivy</i>"]
BUILD["Build & Push Images<br/><i>Multi-arch: amd64 + arm64</i>"]
HELM_LINT["Helm Lint<br/><i>helm lint + kubeconform</i>"]
DEPLOY["Deploy to Staging<br/><i>Helm upgrade</i>"]
end
subgraph Security["Security Pipeline (.github/workflows/security.yml)"]
TRIVY["Trivy Scan<br/><i>Filesystem + Config</i>"]
BANDIT["Bandit SAST<br/><i>Python security</i>"]
SEMGREP["Semgrep SAST<br/><i>Cross-language</i>"]
IMAGE_SCAN["Container Image Scan<br/><i>Trivy per service</i>"]
end
PUSH --> LINT
PR --> LINT
PUSH --> TRIVY & BANDIT & SEMGREP
LINT --> UNIT
LINT --> SECURITY_CI
UNIT --> INTEGRATION
UNIT & INTEGRATION & SECURITY_CI --> BUILD
BUILD --> DEPLOY
PUSH --> HELM_LINT
BUILD & HELM_LINT --> DEPLOY
PUSH --> IMAGE_SCAN
style LINT fill:#6366f1,color:#fff
style UNIT fill:#6366f1,color:#fff
style INTEGRATION fill:#6366f1,color:#fff
style BUILD fill:#10b981,color:#fff
style DEPLOY fill:#f59e0b,color:#000
style TRIVY fill:#ef4444,color:#fff
style BANDIT fill:#ef4444,color:#fff
style SEMGREP fill:#ef4444,color:#fff
style IMAGE_SCAN fill:#ef4444,color:#fff
CI Pipeline (ci.yml)¶
Triggered on pushes and pull requests to main.
Environment¶
Jobs¶
1. Lint & Type Check¶
Runs on every push and PR:
| Step | Command | Description |
|---|---|---|
| Ruff lint | ruff check . |
Python linting (fast, Rust-based) |
| Ruff format | ruff format --check . |
Code formatting verification |
| Mypy | mypy --strict services/ libs/ |
Strict static type checking |
2. Unit Tests¶
Depends on: Lint & Type Check
- Coverage threshold: 90% minimum
- Coverage report uploaded as build artifact
3. Integration Tests¶
Depends on: Unit Tests
# Start test infrastructure
docker compose -f tests/integration/docker-compose.yml up -d --wait
# Run integration tests
pytest tests/integration/ -x -v
# Tear down
docker compose -f tests/integration/docker-compose.yml down -v
- Uses a dedicated
tests/integration/docker-compose.ymlfor isolated infrastructure - Timeout: 10 minutes for tests, 5 minutes for infrastructure startup
4. Security Scan (in CI)¶
Depends on: Lint & Type Check (runs in parallel with tests)
| Tool | Scope | Output |
|---|---|---|
| Bandit | services/ and libs/ |
JSON report artifact |
| Trivy | Full filesystem | Blocks on HIGH/CRITICAL |
5. Build & Push Images¶
Depends on: Unit Tests + Integration Tests + Security Scan
Main branch only
This job only runs on pushes to main, not on pull requests.
Build matrix — 7 service images built in parallel:
| Service Image |
|---|
verity/connectors |
verity/ingestion |
verity/decision |
verity/remediation |
verity/api-gateway |
verity/analytics |
verity/audit |
Multi-architecture builds:
Image tags:
Caching:
Uses GitHub Actions cache for Docker layer caching, significantly reducing build times for incremental changes.
6. Helm Lint¶
Runs on every push and PR (independent of other jobs):
# Lint the chart
helm lint infra/helm/verity/ --values infra/helm/verity/values.yaml
# Validate generated manifests
helm template verity infra/helm/verity/ --values infra/helm/verity/values.yaml \
| kubeconform -strict -summary -output json
7. Deploy to Staging¶
Depends on: Build & Push + Helm Lint
Main branch only
Deploys to the staging GitHub environment.
helm upgrade --install verity infra/helm/verity/ \
--namespace verity \
--create-namespace \
--values infra/helm/verity/values.yaml \
--values infra/helm/verity/values-staging.yaml \
--set global.image.tag=${GITHUB_SHA} \
--wait \
--timeout 10m
Authentication flow:
- Azure Login via OIDC (federated credentials — no stored secrets)
- Set AKS context for
aks-verity-staginginrg-verity-staging - Helm upgrade with staging values
Security Pipeline (security.yml)¶
Triggered on pushes to main, pull requests, and weekly on Monday at 06:00 UTC.
Jobs¶
1. Trivy Vulnerability Scan¶
Scans two targets:
| Scan Type | Target | Severity | Output |
|---|---|---|---|
| Filesystem | . (full repo) |
MEDIUM, HIGH, CRITICAL | SARIF → GitHub Security |
| Config | infra/ |
MEDIUM, HIGH, CRITICAL | SARIF → GitHub Security |
Results are uploaded to GitHub's Security tab via CodeQL SARIF integration.
2. Bandit Python Security¶
Scans all Python code for security issues (SQL injection, hardcoded credentials, unsafe deserialization, etc.). Results uploaded as SARIF to GitHub Security.
3. Semgrep SAST¶
Cross-language static analysis using Semgrep's auto ruleset. Runs in the official Semgrep container. Results uploaded as SARIF to GitHub Security.
4. Container Image Scan¶
Main branch only
Only runs on pushes to main.
Builds and scans each service image with Trivy:
strategy:
matrix:
service:
- connectors
- ingestion
- decision
- remediation
- api-gateway
- analytics
- audit
Each image is built locally (not pushed), scanned for HIGH/CRITICAL vulnerabilities, and results uploaded as SARIF.
GitHub Permissions¶
permissions:
contents: read # Checkout code
packages: write # Push container images
id-token: write # OIDC for Azure login
security-events: write # Upload SARIF results
Container Registry¶
| Setting | Value |
|---|---|
| Registry | verityacr.azurecr.io |
| Repository prefix | verity/ |
| Tag strategy | Git SHA + latest |
| Architectures | linux/amd64, linux/arm64 |
| Authentication | ACR username/password (CI), Azure Workload Identity (AKS) |
Pipeline Duration¶
Typical pipeline execution times:
| Stage | Duration |
|---|---|
| Lint & Type Check | ~2 min |
| Unit Tests | ~3 min |
| Integration Tests | ~8 min |
| Security Scan | ~3 min |
| Build & Push (7 images) | ~10 min |
| Helm Lint | ~1 min |
| Deploy to Staging | ~5 min |
| Total (main branch) | ~20 min |