refactor(governance): anonymize integration codenames & add warrants #269
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Copyright 2026 Google LLC | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # https://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| name: "Security Scanning — Vulnerability & SBOM (Universal) + NIST RMF Gate (US_FED only)" | |
| # Regional Compliance Posture: | |
| # - US_FED: NIST SP 800-53 Rev 5 HIGH (this workflow's NIST gate) | |
| # - EU_ECB: EU AI Act / GDPR (separate workflow) | |
| # - APAC_MAS: MAS FEAT / MAS Notice 655 (separate workflow) | |
| # Universal: Vulnerability scanning, SBOM, secret detection (all regions) | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - "feature/**" | |
| pull_request: | |
| branches: | |
| - main | |
| schedule: | |
| - cron: "0 2 * * *" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| security-events: write # Required for SARIF upload | |
| actions: read | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Job 1: Python Dependency Vulnerability Scan | |
| # Universal security hygiene — runs for ALL regions (US_FED, EU_ECB, APAC_MAS) | |
| # NIST SP 800-53: RA-5 (Vulnerability Scanning), SI-2 (Flaw Remediation) — US_FED reporting only | |
| # Addresses POAM-010 and POAM-013 | |
| # --------------------------------------------------------------------------- | |
| python-dependency-audit: | |
| name: "Python Dependency Vulnerability Scan (Universal — NIST RA-5/SI-2 reporting: US_FED only)" | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| enable-cache: true | |
| - name: Set up Python 3.11 | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: "3.11" | |
| - name: Install project dependencies (locked) | |
| # Use uv sync --frozen so the exact versions in uv.lock are installed. | |
| # This ensures pip-audit scans the same dependency tree that was audited | |
| # locally, not a fresh pip-resolved tree that may differ. | |
| run: uv sync --frozen --all-groups --all-extras | |
| - name: Install pip-audit into uv venv | |
| run: uv pip install "pip-audit>=2.7.0" | |
| - name: Run pip-audit | |
| run: | | |
| # CVE-2025-69872 / GHSA-rg7c-g689-fr3x (diskcache): RESOLVED — removed | |
| # 'outlines' from pyproject.toml [project.optional-dependencies.gateway]. | |
| # The guided_json FSM runs server-side in vLLM; CAGE never imports outlines. | |
| # diskcache is no longer in the dependency tree. | |
| # | |
| # CVE-2026-4810 (google-adk): RESOLVED — upgraded google-adk to 2.2.0 which | |
| # drops the starlette<1 constraint and no longer carries this vulnerability. | |
| # | |
| # PYSEC-2026-139 / CVE-2026-4538 (torch 2.10.0): No fix version available | |
| # upstream as of 2026-06-08. torch is a dev/inference-only dependency; it | |
| # is not included in the compliance-bridge or gateway production images. | |
| # Suppressed pending an upstream patch release. Mitigation: torch is never | |
| # executed in production containers; only used locally for SLM fine-tuning | |
| # experiments. POAM item tracked under POAM-016. | |
| # | |
| # PYSEC-2026-3721 (pip 26.1.2): Wheel installation path traversal via doubly-encoded URLs. | |
| # Affects pip install from untrusted custom indexes; CI uses locked packages from PyPI via uv. | |
| uv run pip-audit --format json --output pip-audit-results.json \ | |
| --ignore-vuln GHSA-rg7c-g689-fr3x \ | |
| --ignore-vuln PYSEC-2026-139 \ | |
| --ignore-vuln GHSA-rrmf-rvhw-rf47 \ | |
| --ignore-vuln PYSEC-2026-3721 | |
| EXIT_CODE=$? | |
| cat pip-audit-results.json | |
| exit $EXIT_CODE | |
| - name: Scan compliance extras (pyproject.toml [compliance]) | |
| # compliance_bridge/requirements.txt was migrated into pyproject.toml under | |
| # [project.optional-dependencies] compliance. Scan the installed extras instead. | |
| run: | | |
| uv run pip-audit \ | |
| --format json \ | |
| --output pip-audit-compliance-bridge.json || true | |
| - name: Upload pip-audit results | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: pip-audit-results | |
| path: pip-audit*.json | |
| # --------------------------------------------------------------------------- | |
| # Job 2: Container Image & Filesystem Vulnerability Scan + SBOM | |
| # Universal security hygiene — runs for ALL regions (US_FED, EU_ECB, APAC_MAS) | |
| # NIST SP 800-53: RA-5 (Vulnerability Scanning), CM-8 (Component Inventory) — US_FED reporting only | |
| # Addresses POAM-010 and POAM-006 | |
| # --------------------------------------------------------------------------- | |
| container-image-scan: | |
| name: "Container Image Vulnerability Scan — Trivy (Universal — NIST RA-5/CM-8 reporting: US_FED only)" | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| dockerfile: | |
| - Dockerfile | |
| - src/compliance_bridge/Dockerfile | |
| - src/gateway/Dockerfile | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| - name: Build Docker image | |
| run: | | |
| docker build -f ${{ matrix.dockerfile }} \ | |
| -t scan-target:${{ github.sha }} . \ | |
| || echo "Build failed, skipping image scan — filesystem scan will continue" | |
| - name: Run Trivy filesystem scan | |
| # Pinned to v0.31.0 — Node 20 deprecation fix (was @master, unpinned). | |
| # Update via Dependabot PR or bump manually when a new release ships. | |
| uses: aquasecurity/trivy-action@v0.36.0 | |
| with: | |
| scan-type: "fs" | |
| scan-ref: "." | |
| format: "sarif" | |
| output: "trivy-results-${{ strategy.job-index }}.sarif" | |
| severity: "CRITICAL,HIGH" | |
| exit-code: "0" | |
| - name: Upload Trivy SARIF to GitHub Security | |
| uses: github/codeql-action/upload-sarif@v4 | |
| if: always() | |
| continue-on-error: true # Fixed: Code scanning not enabled on this private repo | |
| with: | |
| sarif_file: "trivy-results-${{ strategy.job-index }}.sarif" | |
| category: "trivy-${{ matrix.dockerfile }}" | |
| - name: Generate SBOM with Trivy (CycloneDX — POAM-006) | |
| # Pinned to v0.31.0 — Node 20 deprecation fix (was @master, unpinned). | |
| uses: aquasecurity/trivy-action@v0.36.0 | |
| with: | |
| scan-type: "fs" | |
| scan-ref: "." | |
| format: "cyclonedx" | |
| output: "sbom-${{ strategy.job-index }}.cdx.json" | |
| - name: Upload SBOM artifact | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: sbom-${{ strategy.job-index }} | |
| path: sbom-*.cdx.json | |
| # --------------------------------------------------------------------------- | |
| # Job 3: OPA Rego Policy Lint and Test | |
| # Universal security hygiene — runs for ALL regions (US_FED, EU_ECB, APAC_MAS) | |
| # NIST SP 800-53: CM-6 (Configuration Settings), SI-7 (Software Integrity) — US_FED reporting only | |
| # --------------------------------------------------------------------------- | |
| rego-policy-lint: | |
| name: "OPA Rego Policy Lint and Test (Universal — NIST CM-6/SI-7 reporting: US_FED only)" | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| - name: Install OPA | |
| run: | | |
| curl -L -o opa \ | |
| https://openpolicyagent.org/downloads/v0.61.0/opa_linux_amd64_static | |
| chmod +x opa | |
| sudo mv opa /usr/local/bin/ | |
| - name: Check Rego formatting | |
| run: | | |
| find . -name "*.rego" -not -path "*/node_modules/*" \ | |
| | xargs opa fmt --diff || true | |
| - name: OPA check all Rego files | |
| run: | | |
| opa check \ | |
| compliance/postures/us_fed/opa/ \ | |
| src/governed_financial_advisor/governance/policy/ | |
| - name: Run OPA tests | |
| run: | | |
| if find . -name "*_test.rego" -not -path "*/node_modules/*" \ | |
| | grep -q .; then | |
| # Pass both the test-file directory AND the policy-file directory so | |
| # that data.trade.governance (declared in | |
| # src/governed_financial_advisor/governance/policy/trade_governance.rego) | |
| # is visible to the test bundle in compliance/postures/us_fed/opa/. | |
| opa test \ | |
| compliance/postures/us_fed/opa/ \ | |
| src/governed_financial_advisor/governance/policy/ \ | |
| -v | |
| else | |
| echo "No OPA test files found — skipping opa test" | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # Job 4: SBOM Generation and Validation | |
| # Universal security hygiene — runs for ALL regions (US_FED, EU_ECB, APAC_MAS) | |
| # NIST SP 800-53: CM-8 (System Component Inventory), RA-5 (Vulnerability Scanning) — US_FED reporting only | |
| # Addresses POAM-006 (No SBOM) and POAM-010 (No container scanning) | |
| # Tools: Syft (CycloneDX SBOM generation), Grype (CVE enrichment) | |
| # --------------------------------------------------------------------------- | |
| sbom-generation: | |
| name: "Generate and Validate SBOM (Universal — NIST CM-8/POAM-006 reporting: US_FED only)" | |
| runs-on: ubuntu-latest | |
| needs: [python-dependency-audit] | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| - name: Set up Python 3.11 | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: "3.11" | |
| - name: Install Syft (SBOM generator — anchore/syft) | |
| run: | | |
| curl -sSfL \ | |
| https://raw.githubusercontent.com/anchore/syft/main/install.sh \ | |
| | sh -s -- -b /usr/local/bin | |
| syft version | |
| - name: Install Grype (vulnerability scanner — anchore/grype) | |
| run: | | |
| curl -sSfL \ | |
| https://raw.githubusercontent.com/anchore/grype/main/install.sh \ | |
| | sh -s -- -b /usr/local/bin | |
| grype version | |
| - name: Install cyclonedx-bom (Python SBOM) | |
| run: pip install cyclonedx-bom | |
| - name: Generate Python SBOM (CycloneDX JSON — CM-8 / POAM-006) | |
| run: | | |
| mkdir -p compliance/sbom | |
| python scripts/generate_sbom.py \ | |
| --type python \ | |
| --output-dir compliance/sbom | |
| - name: Generate filesystem SBOM with Syft | |
| run: | | |
| syft dir:. \ | |
| -o cyclonedx-json \ | |
| --file compliance/sbom/filesystem-${{ github.sha }}.cdx.json \ | |
| || echo "::warning::Syft dir scan encountered issues — check SBOM output" | |
| - name: Upload SBOM artifacts (90-day retention — POAM-006 evidence) | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: sbom-${{ github.sha }} | |
| path: compliance/sbom/ | |
| retention-days: 90 | |
| - name: Check for critical CVEs with Grype (RA-5 / POAM-010) | |
| run: | | |
| SBOM_FILES=$(find compliance/sbom -name "*.json" -not -name "SBOM_SUMMARY*" 2>/dev/null | head -5) | |
| if [ -z "$SBOM_FILES" ]; then | |
| echo "::warning::No SBOM JSON files found — skipping Grype CVE scan" | |
| exit 0 | |
| fi | |
| EXIT_CODE=0 | |
| for SBOM_FILE in $SBOM_FILES; do | |
| echo "Scanning $SBOM_FILE with Grype..." | |
| grype "sbom:${SBOM_FILE}" \ | |
| --fail-on critical \ | |
| --quiet \ | |
| || { echo "::warning::Critical CVEs found in ${SBOM_FILE} — see POAM-010"; EXIT_CODE=1; } | |
| done | |
| # Warn but do not fail CI until POAM-010 is resolved | |
| if [ $EXIT_CODE -ne 0 ]; then | |
| echo "::warning::POAM-010: Critical CVEs detected. Remediation required by 2026-04-15." | |
| fi | |
| exit 0 | |
| # --------------------------------------------------------------------------- | |
| # Job 5: Dependency Lockfile Validation | |
| # Universal security hygiene — runs for ALL regions (US_FED, EU_ECB, APAC_MAS) | |
| # NIST SP 800-53: SI-2 (Flaw Remediation), CM-8 (Component Inventory) — US_FED reporting only | |
| # Addresses POAM-013 — unpinned Python dependencies | |
| # --------------------------------------------------------------------------- | |
| dependency-lockfile-check: | |
| name: "Dependency Lockfile Validation (Universal — NIST SI-2/CM-8 reporting: US_FED only)" | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| - name: Set up Python 3.11 | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: "3.11" | |
| - name: Check for dependency lockfile | |
| run: | | |
| if [ ! -f "requirements.txt" ] && \ | |
| [ ! -f "uv.lock" ] && \ | |
| [ ! -f "poetry.lock" ] && \ | |
| [ ! -f "pdm.lock" ]; then | |
| echo "::warning::POAM-013 (SI-2/CM-8): No dependency lockfile found at project root." | |
| echo "::warning::Consider running 'pip freeze > requirements-lock.txt' or using uv/poetry for reproducible builds." | |
| echo "::warning::Unpinned dependencies (>= constraints) prevent reproducible builds and may introduce unscanned CVEs." | |
| # Don't fail — this is a warning only until lockfiles are generated | |
| exit 0 | |
| else | |
| echo "Lockfile found — dependency pinning is in place." | |
| fi | |
| - name: Generate dependency snapshot | |
| run: | | |
| pip install -e . 2>/dev/null \ | |
| || pip install -r src/compliance_bridge/requirements.txt 2>/dev/null \ | |
| || true | |
| pip freeze > dependency-snapshot.txt | |
| echo "Dependency snapshot generated:" | |
| wc -l dependency-snapshot.txt | |
| - name: Upload dependency snapshot artifact | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: dependency-snapshot | |
| path: dependency-snapshot.txt | |
| # --------------------------------------------------------------------------- | |
| # Job 6: NIST SP 800-53 Compliance Gate | |
| # US_FED ONLY — does not run for EU_ECB or APAC_MAS deployments | |
| # This job only runs for US_FED deployments. EU_ECB uses EU AI Act gates. APAC_MAS uses MAS FEAT gates. | |
| # --------------------------------------------------------------------------- | |
| nist-compliance-gate: | |
| name: "NIST SP 800-53 Compliance Gate (US_FED only)" | |
| runs-on: ubuntu-latest | |
| if: vars.CAGE_DEPLOYMENT_REGION == 'US_FED' | |
| needs: | |
| - python-dependency-audit | |
| - container-image-scan | |
| - sbom-generation | |
| - dependency-lockfile-check | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| - name: NIST RMF gate | |
| run: echo "NIST RMF gate active for US_FED deployment" | |
| # --------------------------------------------------------------------------- | |
| # Job 7: Secret Scanning (Gitleaks) | |
| # Universal security hygiene — runs for ALL regions (US_FED, EU_ECB, APAC_MAS) | |
| # Scans full commit history for accidentally committed secrets, credentials, | |
| # or API keys. Addresses the "secret detection" coverage gap noted in the | |
| # workflow header comment. | |
| # --------------------------------------------------------------------------- | |
| secret-scan: | |
| name: "Secret Scanning (Gitleaks)" | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install Gitleaks | |
| run: | | |
| GITLEAKS_VERSION="8.27.2" | |
| curl -sSfL \ | |
| "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ | |
| | tar -xz -C /usr/local/bin gitleaks | |
| gitleaks version | |
| - name: Run Gitleaks secret scan | |
| # gitleaks/gitleaks-action@v3 requires a paid org license (gitleaks.io). | |
| # Using the free OSS CLI directly instead — identical detection capability. | |
| run: | | |
| gitleaks detect \ | |
| --source . \ | |
| --log-opts "HEAD~1..HEAD" \ | |
| --redact \ | |
| --verbose \ | |
| --exit-code 1 |