Files
Charon/docs/plans/archive/supply_chain_security_implementation.md
akanealw eec8c28fb3
Some checks are pending
Go Benchmark / Performance Regression Check (push) Waiting to run
Cerberus Integration / Cerberus Security Stack Integration (push) Waiting to run
Upload Coverage to Codecov / Backend Codecov Upload (push) Waiting to run
Upload Coverage to Codecov / Frontend Codecov Upload (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (go) (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (javascript-typescript) (push) Waiting to run
CrowdSec Integration / CrowdSec Bouncer Integration (push) Waiting to run
Docker Build, Publish & Test / build-and-push (push) Waiting to run
Docker Build, Publish & Test / Security Scan PR Image (push) Blocked by required conditions
Quality Checks / Auth Route Protection Contract (push) Waiting to run
Quality Checks / Codecov Trigger/Comment Parity Guard (push) Waiting to run
Quality Checks / Backend (Go) (push) Waiting to run
Quality Checks / Frontend (React) (push) Waiting to run
Rate Limit integration / Rate Limiting Integration (push) Waiting to run
Security Scan (PR) / Trivy Binary Scan (push) Waiting to run
Supply Chain Verification (PR) / Verify Supply Chain (push) Waiting to run
WAF integration / Coraza WAF Integration (push) Waiting to run
changed perms
2026-04-22 18:19:14 +00:00

59 KiB
Executable File

Supply Chain Security Implementation Plan

Version: 2.0 Date: 2026-01-10 Updated: 2026-01-10 (Supervisor Feedback) Target Completion: Phase 3 (3-4 weeks) Assignee: DevOps Agent


Executive Summary

Implement a comprehensive supply chain security solution for Charon using SBOM verification (Software Bill of Materials), Cosign (artifact signing), and SLSA (provenance attestation). This plan integrates signing and verification into GitHub Actions workflows, creates production-ready GitHub Skills for local development, adds VS Code tasks for developer workflows, and includes complete key management procedures.

Key Goals:

  1. Automate SBOM generation, verification, and vulnerability scanning
  2. Sign all Docker images and binaries with Cosign (keyless and local key support)
  3. Generate and verify SLSA provenance for all releases
  4. Enable local testing via complete, tested GitHub Skills
  5. Update Management agent Definition of Done with supply chain verification
  6. Establish performance baselines and monitoring
  7. Implement fallback mechanisms for service outages

Implementation Priority (Revised):

  • Phase 1: SBOM Verification (Week 1) - Foundation for supply chain visibility
  • Phase 2: Cosign Integration (Week 2) - Artifact signing and integrity
  • Phase 3: SLSA Provenance (Week 3) - Build transparency and attestation

Background

Current State

  • SBOM generation exists in docker-build.yml (Anchore SBOM action)
  • SBOM attestation exists in docker-build.yml (actions/attest-sbom)
  • No SBOM vulnerability scanning or semantic diffing
  • No Cosign signing for artifacts
  • No SLSA provenance generation
  • No verification workflows with PR triggers
  • No local testing skills (complete implementation)
  • No local key management procedures
  • No performance baselines or monitoring
  • No Rekor fallback mechanisms

Security Requirements

  • SLSA Level 2+: Provenance generation with isolated build system
  • Keyless Signing: Use GitHub OIDC tokens (no long-lived keys in CI)
  • Local Key Management: Secure procedures for development signing with key-based signing
  • Transparency Logs: All signatures stored in Rekor with fallback for outages
  • Verification: Automated verification in CI (including PRs) and pre-deployment
  • Developer Access: Complete, tested local signing/verification via Skills
  • Vulnerability Scanning: Automated SBOM scanning with Grype/Trivy
  • Semantic SBOM Diffing: Use sbom-diff or similar for component analysis
  • Performance Monitoring: Baseline measurements and continuous tracking
  • Air-Gapped Support: Local signing without internet connectivity
  • Standardization: SPDX format for all SBOMs

Architecture Overview

Component Stack

┌─────────────────────────────────────────────────────────────┐
│                    GitHub Actions (CI/CD)                    │
├─────────────────────────────────────────────────────────────┤
│  Workflow: docker-build.yml                                 │
│  ├─ Build Docker Image                                      │
│  ├─ Generate SBOM (SPDX format)        [ENHANCED]         │
│  ├─ Scan SBOM with Grype/Trivy         [NEW]              │
│  ├─ Diff SBOM with baseline            [NEW]              │
│  ├─ Sign with Cosign (keyless OIDC)    [NEW]              │
│  ├─ Generate SLSA Provenance           [NEW]              │
│  └─ Attest SBOM (existing, enhanced)                       │
│                                                              │
│  Workflow: release-goreleaser.yml                           │
│  ├─ Build Binaries                                          │
│  ├─ Sign with GoReleaser hooks          [NEW]              │
│  ├─ Generate SLSA Provenance           [NEW]              │
│  └─ Attach to GitHub Release                                │
│                                                              │
│  Workflow: supply-chain-verify.yml     [NEW]              │
│  ├─ Trigger: releases, PRs, schedule                       │
│  ├─ Verify Cosign Signatures (with Rekor fallback)        │
│  ├─ Verify SLSA Provenance                                 │
│  ├─ Verify SBOM (semantic diff + vuln scan)               │
│  └─ Generate verification report                            │
├─────────────────────────────────────────────────────────────┤
│                       GitHub Skills                          │
├─────────────────────────────────────────────────────────────┤
│  security-verify-sbom                   [NEW, COMPLETE]    │
│  security-sign-cosign                   [NEW, COMPLETE]    │
│  security-slsa-provenance               [NEW, COMPLETE]    │
├─────────────────────────────────────────────────────────────┤
│                      VS Code Tasks                           │
├─────────────────────────────────────────────────────────────┤
│  Security: Verify SBOM                  [NEW]              │
│  Security: Sign with Cosign            [NEW]              │
│  Security: Generate SLSA Provenance     [NEW]              │
│  Security: Full Supply Chain Audit      [NEW]              │
├─────────────────────────────────────────────────────────────┤
│                  Local Key Management                        │
├─────────────────────────────────────────────────────────────┤
│  ├─ Key generation procedures                              │
│  ├─ Secure storage with encryption                         │
│  ├─ Air-gapped signing support                             │
│  └─ Key rotation and backup                                │
├─────────────────────────────────────────────────────────────┤
│               Performance Monitoring                         │
├─────────────────────────────────────────────────────────────┤
│  ├─ Build time impact tracking                             │
│  ├─ Verification duration metrics                          │
│  └─ Alert thresholds and dashboards                        │
└─────────────────────────────────────────────────────────────┘

Phase 1: SBOM Verification (Week 1)

Priority: CRITICAL - Foundation for supply chain visibility Status: New implementation with enhancements

1.1 Workflow Enhancement

File: .github/workflows/docker-build.yml

Location: Enhance existing SBOM generation (around line 160)

Changes:

  1. Standardize SBOM format to SPDX
  2. Add vulnerability scanning with Grype
  3. Implement semantic SBOM diffing
  4. Add baseline comparison
# Replace existing SBOM generation step with enhanced version

- name: Generate SBOM (SPDX Format)
  if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
  uses: anchore/sbom-action@d94f46e13c6c62f59525ac9a1e147a99dc0b9bf5  # v0.21.0
  with:
    image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}
    format: spdx-json
    output-file: sbom-spdx.json
    upload-artifact: true
    upload-release-assets: true

- name: Scan SBOM for Vulnerabilities
  if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
  run: |
    # Install Grype
    curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin

    # Scan SBOM
    echo "Scanning SBOM for vulnerabilities..."
    grype sbom:sbom-spdx.json -o json > vuln-results.json
    grype sbom:sbom-spdx.json -o table

    # Check for critical/high vulnerabilities
    CRITICAL_COUNT=$(jq '[.matches[] | select(.vulnerability.severity == "Critical")] | length' vuln-results.json)
    HIGH_COUNT=$(jq '[.matches[] | select(.vulnerability.severity == "High")] | length' vuln-results.json)

    echo "Critical vulnerabilities: ${CRITICAL_COUNT}"
    echo "High vulnerabilities: ${HIGH_COUNT}"

    if [[ ${CRITICAL_COUNT} -gt 0 ]]; then
      echo "❌ Critical vulnerabilities found - review required"
      # Don't fail build, but warn
      echo "::warning::${CRITICAL_COUNT} critical vulnerabilities found in SBOM"
    fi

- name: SBOM Semantic Diff
  if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
  continue-on-error: true
  run: |
    # Install sbom-diff tool
    go install github.com/interlynk-io/sbomasm/cmd/sbomasm@latest

    # Download previous SBOM if exists
    if gh release view latest --json assets -q '.assets[] | select(.name == "sbom-spdx.json") | .url' > /dev/null 2>&1; then
      gh release download latest --pattern "sbom-spdx.json" --output sbom-baseline.json

      echo "Comparing current SBOM with baseline..."

      # Compare component counts
      BASELINE_COUNT=$(jq '.packages | length' sbom-baseline.json)
      CURRENT_COUNT=$(jq '.packages | length' sbom-spdx.json)

      echo "Baseline packages: ${BASELINE_COUNT}"
      echo "Current packages: ${CURRENT_COUNT}"
      echo "Delta: $((CURRENT_COUNT - BASELINE_COUNT))"

      # Identify added/removed packages
      jq -r '.packages[].name' sbom-baseline.json | sort > baseline-packages.txt
      jq -r '.packages[].name' sbom-spdx.json | sort > current-packages.txt

      echo "Removed packages:"
      comm -23 baseline-packages.txt current-packages.txt || true

      echo "Added packages:"
      comm -13 baseline-packages.txt current-packages.txt || true
    else
      echo "No baseline SBOM found - this will become the baseline"
    fi
  env:
    GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Attest SBOM
  if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
  uses: actions/attest-sbom@210638bd5681be69f5648391e3b0a389d2d08e5b  # v3.0.0
  with:
    subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
    subject-digest: ${{ steps.build-and-push.outputs.digest }}
    sbom-path: sbom-spdx.json
    push-to-registry: true

1.2 Workflow Creation: Verification with PR Triggers

File: .github/workflows/supply-chain-verify.yml [NEW]

Location: .github/workflows/supply-chain-verify.yml

Purpose: Automated verification workflow triggered on releases, PRs, and schedules

name: Supply Chain Verification

on:
  release:
    types: [published]
  pull_request:  # NEW: Add PR trigger
    paths:
      - '.github/workflows/docker-build.yml'
      - '.github/workflows/release-goreleaser.yml'
      - 'Dockerfile'
      - 'backend/**'
      - 'frontend/**'
  schedule:
    # Run weekly on Mondays at 00:00 UTC
    - cron: '0 0 * * 1'
  workflow_dispatch:

permissions:
  contents: read
  packages: read
  id-token: write        # NEW: OIDC token for keyless verification
  attestations: write    # NEW: Create/verify attestations
  security-events: write
  pull-requests: write   # NEW: Comment on PRs

jobs:
  verify-sbom:
    name: Verify SBOM
    runs-on: ubuntu-latest
    if: github.event_name != 'schedule' || github.ref == 'refs/heads/main'
    steps:
      - name: Checkout
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

      - name: Install Verification Tools
        run: |
          # Install Syft
          curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

          # Install Grype
          curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin

          # Install sbom-diff
          go install github.com/interlynk-io/sbomasm/cmd/sbomasm@latest

      - name: Determine Image Tag
        id: tag
        run: |
          if [[ "${{ github.event_name }}" == "release" ]]; then
            TAG="${{ github.event.release.tag_name }}"
          elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
            TAG="pr-${{ github.event.pull_request.number }}"
          else
            TAG="latest"
          fi
          echo "tag=${TAG}" >> $GITHUB_OUTPUT

      - name: Verify SBOM Completeness
        env:
          IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }}
        run: |
          echo "Verifying SBOM for ${IMAGE}..."

          # Generate fresh SBOM
          syft ${IMAGE} -o spdx-json > sbom-generated.json

          # Download attested SBOM
          gh attestation download ${IMAGE} --digest-alg sha256 \
            --predicate-type https://spdx.dev/Document \
            --output sbom-attested.json || {
              echo "⚠️ No attested SBOM found - may be PR build"
              exit 0
            }

          # Semantic comparison using sbomasm
          GENERATED_COUNT=$(jq '.packages | length' sbom-generated.json)
          ATTESTED_COUNT=$(jq '.packages | length' sbom-attested.json)

          echo "Generated SBOM packages: ${GENERATED_COUNT}"
          echo "Attested SBOM packages: ${ATTESTED_COUNT}"

          # Allow 5% variance
          DIFF=$((GENERATED_COUNT - ATTESTED_COUNT))
          DIFF_ABS=${DIFF#-}
          DIFF_PCT=$((100 * DIFF_ABS / GENERATED_COUNT))

          if [[ ${DIFF_PCT} -gt 5 ]]; then
            echo "❌ SBOM package mismatch exceeds 5%"
            exit 1
          fi

          echo "✅ SBOM verification passed (${DIFF_PCT}% variance)"
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Scan for Vulnerabilities
        continue-on-error: true
        env:
          IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }}
        run: |
          echo "Scanning for vulnerabilities..."
          grype ${IMAGE} -o json > vuln-scan.json
          grype ${IMAGE} -o table

          CRITICAL=$(jq '[.matches[] | select(.vulnerability.severity == "Critical")] | length' vuln-scan.json)
          HIGH=$(jq '[.matches[] | select(.vulnerability.severity == "High")] | length' vuln-scan.json)

          echo "Critical: ${CRITICAL}, High: ${HIGH}"

          if [[ ${CRITICAL} -gt 0 ]]; then
            echo "::warning::${CRITICAL} critical vulnerabilities found"
          fi

      - name: Comment on PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea  # v7.0.1
        with:
          script: |
            const fs = require('fs');
            const vulnData = JSON.parse(fs.readFileSync('vuln-scan.json', 'utf8'));
            const critical = vulnData.matches.filter(m => m.vulnerability.severity === 'Critical').length;
            const high = vulnData.matches.filter(m => m.vulnerability.severity === 'High').length;

            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `## 🔒 Supply Chain Verification\n\n✅ SBOM verified\n📊 Vulnerabilities: ${critical} Critical, ${high} High\n\n[View full report](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`
            });

  verify-docker-image:
    name: Verify Docker Image Supply Chain
    runs-on: ubuntu-latest
    if: github.event_name == 'release'
    needs: verify-sbom
    steps:
      - name: Checkout
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

      - name: Install Verification Tools
        run: |
          # Install Cosign (pinned to commit SHA)
          curl -sLO https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64
          echo "4e84f155f98be2c2d3e63dea0e80b0ca5b4d843f5f4b1d3e8c9b7e4e7c0e0e0e  cosign-linux-amd64" | sha256sum -c
          sudo install cosign-linux-amd64 /usr/local/bin/cosign
          rm cosign-linux-amd64

          # Install SLSA Verifier (pinned to commit SHA)
          curl -sLO https://github.com/slsa-framework/slsa-verifier/releases/download/v2.6.0/slsa-verifier-linux-amd64
          echo "7e4c88e0de4b5e3e0e8f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f  slsa-verifier-linux-amd64" | sha256sum -c
          sudo install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier
          rm slsa-verifier-linux-amd64

      - name: Determine Image Tag
        id: tag
        run: |
          TAG="${{ github.event.release.tag_name }}"
          echo "tag=${TAG}" >> $GITHUB_OUTPUT

      - name: Verify Cosign Signature with Rekor Fallback
        env:
          IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }}
        run: |
          echo "Verifying Cosign signature for ${IMAGE}..."

          # Try with Rekor
          if cosign verify ${IMAGE} \
            --certificate-identity-regexp="https://github.com/${{ github.repository }}" \
            --certificate-oidc-issuer="https://token.actions.githubusercontent.com" 2>&1; then
            echo "✅ Cosign signature verified (with Rekor)"
          else
            echo "⚠️ Rekor verification failed, trying offline verification..."

            # Fallback: verify without Rekor
            if cosign verify ${IMAGE} \
              --certificate-identity-regexp="https://github.com/${{ github.repository }}" \
              --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
              --insecure-ignore-tlog 2>&1; then
              echo "✅ Cosign signature verified (offline mode)"
              echo "::warning::Verified without Rekor - transparency log unavailable"
            else
              echo "❌ Signature verification failed"
              exit 1
            fi
          fi

      - name: Verify SLSA Provenance
        env:
          IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }}
        run: |
          echo "Verifying SLSA provenance for ${IMAGE}..."

          # Download provenance
          gh attestation download ${IMAGE} --digest-alg sha256 \
            --predicate-type https://slsa.dev/provenance/v1 \
            --output provenance.json

          # Verify provenance
          slsa-verifier verify-image ${IMAGE} \
            --provenance-path provenance.json \
            --source-uri github.com/${{ github.repository }}

          echo "✅ SLSA provenance verified"
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Create Verification Report
        if: always()
        run: |
          cat << EOF > verification-report.md
          # Supply Chain Verification Report

          **Image**: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }}
          **Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
          **Workflow**: ${{ github.workflow }}
          **Run**: ${{ github.run_id }}

          ## Results

          - **SBOM Verification**: ${{ needs.verify-sbom.result }}
          - **Cosign Signature**: ${{ job.status }}
          - **SLSA Provenance**: ${{ job.status }}

          ## Verification Failure Recovery

          If verification failed:
          1. Check workflow logs for detailed error messages
          2. Verify signing steps ran successfully in build workflow
          3. Confirm attestations were pushed to registry
          4. Check Rekor status: https://status.sigstore.dev
          5. For Rekor outages, manual verification may be required
          6. Re-run build if signatures/provenance are missing
          EOF

          cat verification-report.md >> $GITHUB_STEP_SUMMARY

  verify-release-artifacts:
    name: Verify Release Artifacts
    runs-on: ubuntu-latest
    if: github.event_name == 'release'
    steps:
      - name: Checkout
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

      - name: Install Verification Tools
        run: |
          # Install Cosign (pinned)
          curl -sLO https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64
          sudo install cosign-linux-amd64 /usr/local/bin/cosign
          rm cosign-linux-amd64

          # Install SLSA Verifier (pinned)
          curl -sLO https://github.com/slsa-framework/slsa-verifier/releases/download/v2.6.0/slsa-verifier-linux-amd64
          sudo install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier
          rm slsa-verifier-linux-amd64

      - name: Download Release Assets
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          TAG=${{ github.event.release.tag_name }}
          gh release download ${TAG} --dir ./release-assets

      - name: Verify Artifact Signatures with Fallback
        run: |
          echo "Verifying Cosign signatures for release artifacts..."

          for artifact in ./release-assets/*; do
            # Skip signature and certificate files
            if [[ "$artifact" == *.sig || "$artifact" == *.pem || "$artifact" == *provenance* ]]; then
              continue
            fi

            if [[ -f "$artifact" ]]; then
              echo "Verifying: $(basename $artifact)"

              # Try with Rekor
              if cosign verify-blob "$artifact" \
                --signature "${artifact}.sig" \
                --certificate "${artifact}.pem" \
                --certificate-identity-regexp="https://github.com/${{ github.repository }}" \
                --certificate-oidc-issuer="https://token.actions.githubusercontent.com" 2>&1; then
                echo "✅ Verified with Rekor"
              else
                echo "⚠️ Rekor unavailable, trying offline..."
                cosign verify-blob "$artifact" \
                  --signature "${artifact}.sig" \
                  --certificate "${artifact}.pem" \
                  --certificate-identity-regexp="https://github.com/${{ github.repository }}" \
                  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
                  --insecure-ignore-tlog
                echo "✅ Verified offline"
              fi
            fi
          done

          echo "✅ All artifact signatures verified"

      - name: Verify Release Provenance
        run: |
          echo "Verifying SLSA provenance for release..."

          if [[ -f "./release-assets/provenance-release.json" ]]; then
            slsa-verifier verify-artifact \
              --provenance-path ./release-assets/provenance-release.json \
              --source-uri github.com/${{ github.repository }}
            echo "✅ Release provenance verified"
          else
            echo "⚠️ No provenance file found"
            exit 1
          fi

1.3 GitHub Skill: security-verify-sbom (Complete Implementation)

File: .github/skills/security-verify-sbom.SKILL.md

Location: .github/skills/security-verify-sbom.SKILL.md

Content: Full SKILL.md specification with parameter validation

---
name: "security-verify-sbom"
version: "1.0.0"
description: "Verify SBOM completeness, scan for vulnerabilities, and perform semantic diff analysis"
author: "Charon Project"
license: "MIT"
tags: ["security", "sbom", "verification", "supply-chain", "vulnerability-scanning"]
compatibility:
  os: ["linux", "darwin"]
  shells: ["bash"]
requirements:
  - name: "syft"
    version: ">=1.17.0"
    optional: false
    install_url: "https://github.com/anchore/syft"
  - name: "grype"
    version: ">=0.85.0"
    optional: false
    install_url: "https://github.com/anchore/grype"
  - name: "jq"
    version: ">=1.6"
    optional: false
environment_variables:
  - name: "SBOM_FORMAT"
    description: "SBOM format (spdx-json, cyclonedx-json)"
    default: "spdx-json"
    required: false
  - name: "VULN_SCAN_ENABLED"
    description: "Enable vulnerability scanning"
    default: "true"
    required: false
parameters:
  - name: "target"
    type: "string"
    description: "Docker image or file path"
    required: true
    validation: "^[a-zA-Z0-9:/@._-]+$"
  - name: "baseline"
    type: "string"
    description: "Baseline SBOM file path for comparison"
    required: false
    default: ""
  - name: "vuln_scan"
    type: "boolean"
    description: "Run vulnerability scan"
    required: false
    default: true
exit_codes:
  0: "Verification successful"
  1: "Verification failed or critical vulnerabilities found"
  2: "Missing dependencies or invalid parameters"
---

# Security: Verify SBOM

Verify Software Bill of Materials (SBOM) completeness, scan for vulnerabilities, and perform semantic diff analysis.

## Features

- Generate SBOM in SPDX format (standardized)
- Compare with baseline SBOM (semantic diff)
- Scan for vulnerabilities (Critical/High/Medium/Low)
- Validate SBOM structure and completeness
- Support Docker images and local files
- Air-gapped operation support (skip vulnerability scanning)

## Usage

```bash
# Verify Docker image SBOM with vulnerability scan
.github/skills/scripts/skill-runner.sh security-verify-sbom ghcr.io/user/charon:latest

# Verify with baseline comparison
.github/skills/scripts/skill-runner.sh security-verify-sbom charon:local sbom-baseline.json

# Verify local image without vulnerability scan (air-gapped)
VULN_SCAN_ENABLED=false .github/skills/scripts/skill-runner.sh security-verify-sbom charon:local

# Negative test: verify tampered image (should fail)
.github/skills/scripts/skill-runner.sh security-verify-sbom tampered:image

Examples

Basic Verification

$ .github/skills/scripts/skill-runner.sh security-verify-sbom charon:test
[INFO] Generating SBOM for charon:test...
[INFO] SBOM contains 247 packages
[INFO] Scanning for vulnerabilities...
[INFO] Found: 0 Critical, 2 High, 15 Medium
✅ Verification complete

With Baseline Comparison

$ .github/skills/scripts/skill-runner.sh security-verify-sbom charon:latest sbom-baseline.json
[INFO] Generating SBOM for charon:latest...
[INFO] Comparing with baseline...
[INFO] Baseline: 245 packages, Current: 247 packages
[INFO] Added packages: golang.org/x/crypto@v0.30.0, github.com/pkg/errors@v0.9.1
[INFO] Removed packages: (none)
✅ Verification complete (0.8% variance)

### 1.1 Workflow Updates

#### File: `.github/workflows/docker-build.yml`

**Location**: After `steps.build-and-push` (line ~145)

**Changes**:
1. Add Cosign installation step
2. Add Docker image signing step
3. Store signature in Rekor transparency log

```yaml
# Add after "Build and push Docker image" step

- name: Install Cosign
  if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
  uses: sigstore/cosign-installer@v3.8.1
  with:
    cosign-release: 'v2.4.1'

- name: Sign Docker Image with Cosign
  if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
  env:
    DIGEST: ${{ steps.build-and-push.outputs.digest }}
    TAGS: ${{ steps.meta.outputs.tags }}
  run: |
    echo "Signing image with Cosign (keyless OIDC)..."
    images=""
    for tag in ${TAGS}; do
      images+="${tag}@${DIGEST} "
    done

    # Sign with keyless mode (GitHub OIDC token)
    cosign sign --yes ${images}

    echo "✅ Image signed and uploaded to Rekor transparency log"
    echo "Verification command: cosign verify ${REGISTRY}/${IMAGE_NAME}@${DIGEST} \\"
    echo "  --certificate-identity-regexp='https://github.com/${GITHUB_REPOSITORY}' \\"
    echo "  --certificate-oidc-issuer='https://token.actions.githubusercontent.com'"

File: .github/workflows/release-goreleaser.yml

Location: After Run GoReleaser step (line ~60)

Changes:

  1. Add Cosign installation
  2. Sign all release binaries
  3. Upload signatures as release assets
# Add after "Run GoReleaser" step

- name: Install Cosign
  uses: sigstore/cosign-installer@v3.8.1
  with:
    cosign-release: 'v2.4.1'

- name: Sign Release Artifacts with Cosign
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: |
    echo "Signing release artifacts..."

    # Get release tag
    TAG=${GITHUB_REF#refs/tags/}

    # Download artifacts from release
    gh release download ${TAG} --dir ./release-artifacts

    # Sign each binary
    for artifact in ./release-artifacts/*; do
      if [[ -f "$artifact" && ! "$artifact" == *.sig && ! "$artifact" == *.pem ]]; then
        echo "Signing: $(basename $artifact)"
        cosign sign-blob --yes --output-signature="${artifact}.sig" \
          --output-certificate="${artifact}.pem" \
          "$artifact"
      fi
    done

    # Upload signatures back to release
    gh release upload ${TAG} ./release-artifacts/*.sig ./release-artifacts/*.pem --clobber

    echo "✅ All artifacts signed and signatures uploaded to release"

1.2 GitHub Skill: security-sign-cosign

File: .github/skills/security-sign-cosign.SKILL.md

Location: .github/skills/security-sign-cosign.SKILL.md

Content: Full SKILL.md specification (see appendix A1)

File: .github/skills/security-sign-cosign-scripts/run.sh

Location: .github/skills/security-sign-cosign-scripts/run.sh

Content: Bash script implementing local Cosign signing (see appendix A2)

Key Features:

  • Sign local Docker images
  • Sign arbitrary files (binaries, archives)
  • Support keyless (OIDC) and key-based signing
  • Verify signatures after signing
  • Output signature files (.sig, .pem)

1.3 VS Code Task

File: .vscode/tasks.json

Location: Add to tasks array

{
    "label": "Security: Sign with Cosign",
    "type": "shell",
    "command": ".github/skills/scripts/skill-runner.sh security-sign-cosign",
    "group": "test",
    "problemMatcher": []
}

1.4 Secrets Configuration

No secrets required for keyless signing (uses GitHub OIDC tokens automatically).

Optional: For key-based signing (local development):

  • COSIGN_PRIVATE_KEY: Base64-encoded private key
  • COSIGN_PASSWORD: Password for private key

1.5 Testing & Validation

Acceptance Criteria:

  • Docker images signed in docker-build.yml workflow
  • Release binaries signed in release-goreleaser.yml workflow
  • Signatures visible in Rekor transparency log
  • Local skill can sign test images
  • VS Code task executes successfully
  • Signature verification passes via cosign verify

Phase 2: SLSA Provenance (Week 2)

2.1 Workflow Updates

File: .github/workflows/docker-build.yml

Location: After Cosign signing step

Changes:

  1. Generate SLSA provenance using slsa-github-generator
  2. Attach provenance to image as attestation
- name: Generate SLSA Provenance
  if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
  uses: slsa-framework/slsa-github-generator/.github/actions/generator-generic-slsa3@v2.1.0
  with:
    base64-subjects: ${{ steps.build-and-push.outputs.digest }}
    provenance-name: "provenance.json"
    upload-assets: true

- name: Attest Provenance to Image
  if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
  uses: actions/attest-build-provenance@v2.1.0
  with:
    subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
    subject-digest: ${{ steps.build-and-push.outputs.digest }}
    push-to-registry: true

File: .github/workflows/release-goreleaser.yml

Location: After Cosign signing step

Changes:

  1. Generate SLSA provenance for all release artifacts
  2. Upload provenance as release asset
- name: Generate SLSA Provenance for Release
  uses: slsa-framework/slsa-github-generator/.github/actions/generator-generic-slsa3@v2.1.0
  with:
    base64-subjects: |
      ${{ hashFiles('release-artifacts/*') }}
    provenance-name: "provenance-release.json"
    upload-assets: true
    upload-tag-name: ${{ github.ref_name }}

2.2 GitHub Skill: security-slsa-provenance

File: .github/skills/security-slsa-provenance.SKILL.md

Location: .github/skills/security-slsa-provenance.SKILL.md

Content: Full SKILL.md specification (see appendix B1)

File: .github/skills/security-slsa-provenance-scripts/run.sh

Location: .github/skills/security-slsa-provenance-scripts/run.sh

Content: Bash script implementing SLSA provenance generation and verification (see appendix B2)

Key Features:

  • Generate SLSA provenance for local artifacts
  • Verify provenance against policy
  • Parse and display provenance metadata
  • Check SLSA level compliance

2.3 VS Code Task

File: .vscode/tasks.json

Location: Add to tasks array

{
    "label": "Security: Generate SLSA Provenance",
    "type": "shell",
    "command": ".github/skills/scripts/skill-runner.sh security-slsa-provenance",
    "group": "test",
    "problemMatcher": []
}

2.4 Testing & Validation

Acceptance Criteria:

  • SLSA provenance generated for Docker images
  • SLSA provenance generated for release binaries
  • Provenance attestations pushed to registry
  • Provenance files uploaded to GitHub releases
  • Local skill can generate/verify provenance
  • VS Code task executes successfully
  • SLSA level 2+ compliance verified

Phase 3: SBOM Verification (Week 3)

3.1 Workflow Creation

File: .github/workflows/supply-chain-verify.yml [NEW]

Location: .github/workflows/supply-chain-verify.yml

Purpose: Automated verification workflow triggered on releases and schedules

name: Supply Chain Verification

on:
  release:
    types: [published]
  schedule:
    # Run weekly on Mondays at 00:00 UTC
    - cron: '0 0 * * 1'
  workflow_dispatch:

permissions:
  contents: read
  packages: read
  security-events: write

jobs:
  verify-docker-image:
    name: Verify Docker Image Supply Chain
    runs-on: ubuntu-latest
    if: github.event_name != 'schedule' || github.ref == 'refs/heads/main'
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Install Verification Tools
        run: |
          # Install Cosign
          curl -sLO https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64
          sudo install cosign-linux-amd64 /usr/local/bin/cosign
          rm cosign-linux-amd64

          # Install SLSA Verifier
          curl -sLO https://github.com/slsa-framework/slsa-verifier/releases/download/v2.6.0/slsa-verifier-linux-amd64
          sudo install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier
          rm slsa-verifier-linux-amd64

          # Install Syft (SBOM generation/verification)
          curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

      - name: Determine Image Tag
        id: tag
        run: |
          if [[ "${{ github.event_name }}" == "release" ]]; then
            TAG="${{ github.event.release.tag_name }}"
          else
            TAG="latest"
          fi
          echo "tag=${TAG}" >> $GITHUB_OUTPUT

      - name: Verify Cosign Signature
        env:
          IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }}
        run: |
          echo "Verifying Cosign signature for ${IMAGE}..."
          cosign verify ${IMAGE} \
            --certificate-identity-regexp="https://github.com/${{ github.repository }}" \
            --certificate-oidc-issuer="https://token.actions.githubusercontent.com"
          echo "✅ Cosign signature verified"

      - name: Verify SLSA Provenance
        env:
          IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }}
        run: |
          echo "Verifying SLSA provenance for ${IMAGE}..."

          # Download provenance
          gh attestation download ${IMAGE} --digest-alg sha256 \
            --predicate-type https://slsa.dev/provenance/v1 \
            --output provenance.json

          # Verify provenance
          slsa-verifier verify-image ${IMAGE} \
            --provenance-path provenance.json \
            --source-uri github.com/${{ github.repository }}

          echo "✅ SLSA provenance verified"

      - name: Verify SBOM Completeness
        env:
          IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }}
        run: |
          echo "Verifying SBOM for ${IMAGE}..."

          # Generate fresh SBOM
          syft ${IMAGE} -o cyclonedx-json > sbom-generated.json

          # Download attested SBOM
          gh attestation download ${IMAGE} --digest-alg sha256 \
            --predicate-type https://spdx.dev/Document \
            --output sbom-attested.json

          # Compare component counts
          GENERATED_COUNT=$(jq '.components | length' sbom-generated.json)
          ATTESTED_COUNT=$(jq '.components | length' sbom-attested.json)

          echo "Generated SBOM components: ${GENERATED_COUNT}"
          echo "Attested SBOM components: ${ATTESTED_COUNT}"

          # Allow 5% variance
          DIFF=$((GENERATED_COUNT - ATTESTED_COUNT))
          DIFF_PCT=$((100 * DIFF / GENERATED_COUNT))

          if [[ ${DIFF_PCT#-} -gt 5 ]]; then
            echo "❌ SBOM component mismatch exceeds 5%"
            exit 1
          fi

          echo "✅ SBOM verification passed"

      - name: Create Verification Report
        if: always()
        run: |
          cat << EOF > verification-report.md
          # Supply Chain Verification Report

          **Image**: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }}
          **Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
          **Workflow**: ${{ github.workflow }}
          **Run**: ${{ github.run_id }}

          ## Results

          - **Cosign Signature**: ${{ job.status }}
          - **SLSA Provenance**: ${{ job.status }}
          - **SBOM Verification**: ${{ job.status }}

          ## Next Steps

          If any verification failed:
          1. Check workflow logs for detailed error messages
          2. Verify signing steps ran successfully in build workflow
          3. Confirm attestations were pushed to registry
          4. Re-run build if necessary
          EOF

          cat verification-report.md >> $GITHUB_STEP_SUMMARY

  verify-release-artifacts:
    name: Verify Release Artifacts
    runs-on: ubuntu-latest
    if: github.event_name == 'release'
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Install Verification Tools
        run: |
          # Install Cosign
          curl -sLO https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64
          sudo install cosign-linux-amd64 /usr/local/bin/cosign
          rm cosign-linux-amd64

          # Install SLSA Verifier
          curl -sLO https://github.com/slsa-framework/slsa-verifier/releases/download/v2.6.0/slsa-verifier-linux-amd64
          sudo install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier
          rm slsa-verifier-linux-amd64

      - name: Download Release Assets
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          TAG=${{ github.event.release.tag_name }}
          gh release download ${TAG} --dir ./release-assets

      - name: Verify Artifact Signatures
        run: |
          echo "Verifying Cosign signatures for release artifacts..."

          for artifact in ./release-assets/*; do
            # Skip signature and certificate files
            if [[ "$artifact" == *.sig || "$artifact" == *.pem || "$artifact" == *provenance* ]]; then
              continue
            fi

            if [[ -f "$artifact" ]]; then
              echo "Verifying: $(basename $artifact)"

              # Verify blob signature
              cosign verify-blob "$artifact" \
                --signature "${artifact}.sig" \
                --certificate "${artifact}.pem" \
                --certificate-identity-regexp="https://github.com/${{ github.repository }}" \
                --certificate-oidc-issuer="https://token.actions.githubusercontent.com"
            fi
          done

          echo "✅ All artifact signatures verified"

      - name: Verify Release Provenance
        run: |
          echo "Verifying SLSA provenance for release..."

          if [[ -f "./release-assets/provenance-release.json" ]]; then
            slsa-verifier verify-artifact \
              --provenance-path ./release-assets/provenance-release.json \
              --source-uri github.com/${{ github.repository }}
            echo "✅ Release provenance verified"
          else
            echo "⚠️ No provenance file found"
            exit 1
          fi

3.2 GitHub Skill: security-verify-sbom

File: .github/skills/security-verify-sbom.SKILL.md

Location: .github/skills/security-verify-sbom.SKILL.md

Content: Full SKILL.md specification (see appendix C1)

File: .github/skills/security-verify-sbom-scripts/run.sh

Location: .github/skills/security-verify-sbom-scripts/run.sh

Content: Bash script implementing SBOM verification (see appendix C2)

Key Features:

  • Generate SBOM from local Docker images
  • Compare SBOM against attested version
  • Check for known vulnerabilities in SBOM
  • Validate SBOM format and completeness
  • Report drift between builds

3.3 VS Code Tasks

File: .vscode/tasks.json

Location: Add to tasks array

{
    "label": "Security: Verify SBOM",
    "type": "shell",
    "command": ".github/skills/scripts/skill-runner.sh security-verify-sbom",
    "group": "test",
    "problemMatcher": []
},
{
    "label": "Security: Full Supply Chain Audit",
    "type": "shell",
    "dependsOn": [
        "Security: Sign with Cosign",
        "Security: Generate SLSA Provenance",
        "Security: Verify SBOM"
    ],
    "dependsOrder": "sequence",
    "command": "echo '✅ Supply chain audit complete'",
    "group": "test",
    "problemMatcher": []
}

3.4 Testing & Validation

Acceptance Criteria:

  • Verification workflow runs on releases
  • Verification workflow runs weekly
  • Docker image signatures verified
  • Release artifact signatures verified
  • SLSA provenance verified
  • SBOM completeness verified
  • Local skill can verify SBOM
  • VS Code tasks execute successfully
  • Full audit task chains all verifications

Management Agent Definition of Done Updates

File: .github/agents/Managment.agent.md

Location: Section ## DEFINITION OF DONE ## (line 70)

Changes: Add supply chain verification as mandatory step

## DEFINITION OF DONE ##

The task is not complete until ALL of the following pass with zero issues:

1. **Coverage Tests (MANDATORY - Verify Explicitly)**:
    - **Backend**: Ensure `Backend_Dev` ran VS Code task "Test: Backend with Coverage" or `scripts/go-test-coverage.sh`
    - **Frontend**: Ensure `Frontend_Dev` ran VS Code task "Test: Frontend with Coverage" or `scripts/frontend-test-coverage.sh`
    - **Why**: These are in manual stage of pre-commit for performance. Subagents MUST run them via VS Code tasks or scripts.
    - Minimum coverage: 85% for both backend and frontend.
    - All tests must pass with zero failures.

2. **Type Safety (Frontend)**:
    - Ensure `Frontend_Dev` ran VS Code task "Lint: TypeScript Check" or `npm run type-check`
    - **Why**: This check is in manual stage of pre-commit for performance. Subagents MUST run it explicitly.

3. **Pre-commit Hooks**: Ensure `QA_Security` ran `pre-commit run --all-files` (fast hooks only; coverage was verified in step 1)

4. **Security Scans**: Ensure `QA_Security` ran CodeQL and Trivy with zero Critical or High severity issues

5. **Supply Chain Security (NEW - MANDATORY for releases)**: [NEW]
    - **Docker Images**: Ensure DevOps signed images with Cosign and generated SLSA provenance
    - **Release Artifacts**: Ensure DevOps signed all binaries and attached SLSA provenance
    - **SBOM Verification**: Ensure DevOps verified SBOM completeness
    - **Verification**: Run VS Code task "Security: Full Supply Chain Audit" to verify all attestations
    - **Why**: Supply chain attacks are a critical threat. All artifacts must be cryptographically signed and provenance-verified.
    - **When**: Required for all releases, recommended for development builds

6. **Linting**: All language-specific linters must pass

**Your Role**: You delegate implementation to subagents, but YOU are responsible for verifying they completed the Definition of Done. Do not accept "DONE" from a subagent until you have confirmed they ran coverage tests, type checks, security scans, **and supply chain verification** explicitly.

**Critical Note**: Leaving this unfinished prevents commit, push, and leaves users open to security concerns. All issues must be fixed regardless of whether they are unrelated to the original task. This rule must never be skipped. It is non-negotiable anytime any bit of code is added or changed.

File Changes Summary

Files to Create (10 new files)

  1. .github/skills/security-sign-cosign.SKILL.md
  2. .github/skills/security-sign-cosign-scripts/run.sh
  3. .github/skills/security-slsa-provenance.SKILL.md
  4. .github/skills/security-slsa-provenance-scripts/run.sh
  5. .github/skills/security-verify-sbom.SKILL.md
  6. .github/skills/security-verify-sbom-scripts/run.sh
  7. .github/workflows/supply-chain-verify.yml
  8. docs/plans/supply_chain_security_implementation.md (this file)
  9. docs/reports/supply_chain_verification_report_template.md
  10. .github/skills/examples/supply-chain-example.sh

Files to Modify (3 existing files)

  1. .github/workflows/docker-build.yml

    • Add Cosign installation step (after line 145)
    • Add Cosign signing step (after build-and-push)
    • Add SLSA provenance generation (after signing)
  2. .github/workflows/release-goreleaser.yml

    • Add Cosign installation step (after line 60)
    • Add artifact signing step (after GoReleaser)
    • Add SLSA provenance generation (after signing)
  3. .vscode/tasks.json

    • Add 4 new tasks (lines to append to tasks array)
  4. .github/agents/Managment.agent.md

    • Update Definition of Done section (line 70)

Secret Requirements

GitHub Secrets (Repository Level)

None required for keyless signing. The following are optional for advanced scenarios:

  1. COSIGN_PRIVATE_KEY (Optional)

    • Purpose: Key-based signing for non-CI environments
    • Format: Base64-encoded private key
    • Generation: cosign generate-key-pair
    • Usage: Local development, air-gapped signing
  2. COSIGN_PASSWORD (Optional)

    • Purpose: Password for private key
    • Format: String
    • Usage: Decrypt COSIGN_PRIVATE_KEY

GitHub Permissions (Workflow Level)

Required permissions for workflows:

permissions:
  contents: write        # Upload signatures to releases
  packages: write        # Push attestations to registry
  id-token: write        # OIDC token for keyless signing
  attestations: write    # Create attestations
  security-events: write # Upload verification results

Environment Variables (CI/CD)

Default values work for standard setup:

  • COSIGN_EXPERIMENTAL=1 (Enable keyless signing)
  • COSIGN_YES=true (Non-interactive mode)
  • SLSA_LEVEL=2 (Minimum SLSA level)

Verification & Testing Plan

Phase 1 Testing (Cosign)

Test Case 1.1: Docker Image Signing

# Trigger workflow
git tag -a v1.0.0-rc1 -m "Test release"
git push origin v1.0.0-rc1

# Verify signature
cosign verify ghcr.io/$USER/charon:v1.0.0-rc1 \
  --certificate-identity-regexp="https://github.com/$USER/charon" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com"

Test Case 1.2: Local Signing via Skill

# Build local image
docker build -t charon:test .

# Sign with skill
.github/skills/scripts/skill-runner.sh security-sign-cosign docker charon:test

# Verify signature
cosign verify charon:test --key cosign.pub

Test Case 1.3: VS Code Task

# Open Command Palette (Ctrl+Shift+P)
# Type: "Tasks: Run Task"
# Select: "Security: Sign with Cosign"
# Verify output shows successful signing

Phase 2 Testing (SLSA)

Test Case 2.1: SLSA Provenance Generation

# Check release assets
gh release view v1.0.0-rc1 --json assets

# Download provenance
gh attestation download ghcr.io/$USER/charon:v1.0.0-rc1 \
  --predicate-type https://slsa.dev/provenance/v1

# Verify provenance
slsa-verifier verify-image ghcr.io/$USER/charon:v1.0.0-rc1 \
  --source-uri github.com/$USER/charon

Test Case 2.2: Local Provenance via Skill

# Generate provenance for local artifact
.github/skills/scripts/skill-runner.sh security-slsa-provenance generate charon-binary

# Verify provenance
.github/skills/scripts/skill-runner.sh security-slsa-provenance verify charon-binary

Phase 3 Testing (SBOM)

Test Case 3.1: SBOM Verification Workflow

# Trigger verification workflow
gh workflow run supply-chain-verify.yml

# Check results
gh run list --workflow=supply-chain-verify.yml --limit 1

Test Case 3.2: Local SBOM Verification via Skill

# Verify SBOM
.github/skills/scripts/skill-runner.sh security-verify-sbom ghcr.io/$USER/charon:latest

# Check output for component counts and vulnerabilities

Test Case 3.3: Full Supply Chain Audit Task

# Run complete audit via VS Code
# Tasks: Run Task -> Security: Full Supply Chain Audit
# Verify all three sub-tasks complete successfully

Integration Testing

End-to-End Test: Release Pipeline

  1. Create feature branch
  2. Make code change
  3. Create PR
  4. Merge to main
  5. Create release tag
  6. Verify workflow builds and signs artifacts
  7. Run verification workflow
  8. Download release assets
  9. Verify all signatures and attestations locally

Success Criteria:

  • All workflows complete without errors
  • Signatures verify successfully
  • Provenance matches expected source
  • SBOM contains all dependencies
  • Rekor transparency log contains entries

Rollout Strategy

Development Environment (Week 1)

  • Deploy Phase 1 (Cosign) to development branch
  • Test with beta releases
  • Validate skill execution locally
  • Gather developer feedback

Staging Environment (Week 2)

  • Deploy Phase 2 (SLSA) to development branch
  • Test full signing pipeline
  • Validate provenance generation
  • Performance testing

Production Environment (Week 3)

  • Deploy Phase 3 (SBOM verification) to main branch
  • Enable verification workflow
  • Monitor for issues
  • Update documentation

Rollback Plan

If critical issues arise:

  1. Disable verification workflow (comment out triggers)
  2. Remove signing steps from build workflows (make optional with flag)
  3. Maintain SBOM generation (already exists, low risk)
  4. Document issues and plan remediation

Monitoring & Alerts

Metrics to Track

  1. Signing Success Rate: Percentage of successful Cosign signings
  2. Provenance Generation Rate: Percentage of builds with SLSA provenance
  3. Verification Failure Rate: Failed verification attempts
  4. Rekor Log Entries: Transparency log entries created
  5. SBOM Drift: Variance between builds

Alerting Rules

  1. Critical: Signing failure in production release
  2. High: Verification failure in scheduled check
  3. Medium: SBOM drift exceeds 10%
  4. Low: Skill execution failures

Dashboards

Create GitHub insights dashboard:

  • Total artifacts signed (weekly)
  • Verification workflow runs (success/failure)
  • SLSA level compliance
  • Skill usage statistics

Documentation Requirements

User-Facing Documentation

  1. README.md Updates

    • Add supply chain security section
    • Link to verification instructions
    • Show verification commands
  2. SECURITY.md Updates

    • Document signing process
    • Add verification procedures
    • List transparency log URLs
  3. Developer Guide (new file: docs/development/supply-chain-security.md)

    • How to sign artifacts locally
    • How to verify signatures
    • Troubleshooting guide

Internal Documentation

  1. Runbook: docs/runbooks/supply-chain-incident-response.md

    • Signature verification failures
    • Provenance mismatches
    • SBOM vulnerabilities
  2. Architecture Decision Records

    • Why Cosign over other tools
    • Keyless vs key-based signing
    • SLSA level rationale

Dependencies & Prerequisites

Tool Versions

Tool Minimum Version Installation
Cosign v2.4.1 go install github.com/sigstore/cosign/v2/cmd/cosign@latest
SLSA Verifier v2.6.0 go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest
Syft v1.17.0 curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh
GitHub CLI v2.62.0 brew install gh or GitHub CLI

GitHub Actions

Action Version Purpose
sigstore/cosign-installer v3.8.1 Install Cosign in workflows
slsa-framework/slsa-github-generator v2.1.0 Generate SLSA provenance
actions/attest-build-provenance v2.1.0 Attest provenance to registry
actions/attest-sbom v3.0.0 Attest SBOM (existing)
anchore/sbom-action v0.21.0 Generate SBOM (existing)

External Services

  • Rekor Transparency Log: https://rekor.sigstore.dev
  • Fulcio Certificate Authority: https://fulcio.sigstore.dev
  • GitHub Packages: ghcr.io (for attestations)

Risk Assessment

High Risks

  1. Key Compromise: Signing keys leaked

    • Mitigation: Use keyless signing (OIDC tokens)
    • Detection: Monitor Rekor logs for unauthorized signatures
  2. Workflow Compromise: Attacker modifies CI/CD

    • Mitigation: Branch protection rules, required reviews
    • Detection: Audit logs, signature mismatches
  3. Supply Chain Attack: Compromised dependency

    • Mitigation: SBOM verification, vulnerability scanning
    • Detection: Trivy/Grype scans, GitHub security advisories

Medium Risks

  1. Verification Failures: False positives blocking releases

    • Mitigation: Comprehensive testing, retry logic
    • Fallback: Manual verification procedures
  2. Performance Impact: Signing adds latency to builds

    • Mitigation: Parallel execution, caching
    • Monitoring: Track build times

Low Risks

  1. Tool Updates: Breaking changes in Cosign/SLSA
    • Mitigation: Pin versions, test updates
    • Monitoring: Renovate bot, release notes

Success Metrics

Quantitative Goals

  • 100% of Docker images signed within 4 weeks
  • 100% of release binaries signed within 4 weeks
  • ≥95% verification success rate
  • <5% SBOM drift between builds
  • <30s added to build time for signing
  • <10 false positive verification failures per month

Qualitative Goals

  • Developers can verify signatures locally
  • Security team has visibility into supply chain
  • Compliance requirements met (SOC2, SLSA)
  • Zero supply chain incidents post-implementation

Appendices

Appendix A: Cosign Skill Implementation

A1: SKILL.md Specification

---
name: "security-sign-cosign"
version: "1.0.0"
description: "Sign Docker images and artifacts with Cosign (Sigstore)"
author: "Charon Project"
license: "MIT"
tags: ["security", "signing", "cosign", "supply-chain"]
compatibility:
  os: ["linux", "darwin"]
  shells: ["bash"]
requirements:
  - name: "cosign"
    version: ">=2.4.0"
    optional: false
environment_variables:
  - name: "COSIGN_EXPERIMENTAL"
    description: "Enable keyless signing"
    default: "1"
    required: false
parameters:
  - name: "type"
    type: "string"
    description: "Artifact type (docker, file)"
    default: "docker"
    required: false
  - name: "target"
    type: "string"
    description: "Image tag or file path"
    required: true
---

# Security: Sign with Cosign

Sign Docker images and files using Cosign for supply chain security.

## Usage

```bash
# Sign Docker image
.github/skills/scripts/skill-runner.sh security-sign-cosign docker charon:local

# Sign file
.github/skills/scripts/skill-runner.sh security-sign-cosign file ./dist/charon-binary

#### A2: Execution Script Skeleton

```bash
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/../scripts/_logging_helpers.sh"

TYPE="${1:-docker}"
TARGET="${2:-}"

if [[ -z "${TARGET}" ]]; then
    log_error "Usage: security-sign-cosign <type> <target>"
    exit 1
fi

case "${TYPE}" in
    docker)
        log_step "COSIGN" "Signing Docker image: ${TARGET}"
        cosign sign --yes "${TARGET}"
        ;;
    file)
        log_step "COSIGN" "Signing file: ${TARGET}"
        cosign sign-blob --yes --output-signature="${TARGET}.sig" \
          --output-certificate="${TARGET}.pem" "${TARGET}"
        ;;
    *)
        log_error "Invalid type: ${TYPE}"
        exit 1
        ;;
esac

log_success "Signature created and stored in Rekor"

Appendix B: SLSA Provenance Skill Implementation

B1: SKILL.md Specification

---
name: "security-slsa-provenance"
version: "1.0.0"
description: "Generate and verify SLSA provenance attestations"
author: "Charon Project"
license: "MIT"
tags: ["security", "slsa", "provenance", "supply-chain"]
---

# Security: SLSA Provenance

Generate and verify SLSA provenance for build artifacts.

## Usage

```bash
# Generate provenance
.github/skills/scripts/skill-runner.sh security-slsa-provenance generate charon-binary

# Verify provenance
.github/skills/scripts/skill-runner.sh security-slsa-provenance verify charon-binary

### Appendix C: SBOM Verification Skill Implementation

#### C1: SKILL.md Specification

```markdown
---
name: "security-verify-sbom"
version: "1.0.0"
description: "Verify SBOM completeness and check for vulnerabilities"
author: "Charon Project"
license: "MIT"
tags: ["security", "sbom", "verification", "supply-chain"]
---

# Security: Verify SBOM

Verify Software Bill of Materials (SBOM) for Docker images and releases.

## Usage

```bash
# Verify Docker image SBOM
.github/skills/scripts/skill-runner.sh security-verify-sbom ghcr.io/user/charon:latest

# Verify local image
.github/skills/scripts/skill-runner.sh security-verify-sbom charon:local

---

## Conclusion

This implementation plan provides a comprehensive, phased approach to integrating supply chain security into Charon. By following this plan, the DevOps agent will:

1. **Sign all artifacts** with Cosign for tamper detection
2. **Generate SLSA provenance** for build transparency
3. **Verify SBOMs** for dependency tracking
4. **Enable local testing** via GitHub Skills
5. **Update processes** to include verification in DoD

**Estimated Effort**: 3-4 weeks (1 week per phase + testing)
**Complexity**: Medium (existing infrastructure, well-documented tools)
**Risk**: Low (non-breaking, incremental rollout)

**Ready for delegation to DevOps agent.**