Skip to content

Branch Protection & CI Gating

This document describes the strict CI gating strategy implemented for the solve-it-mcp repository to ensure code quality and prevent broken releases for forensic software.


๐Ÿ›ก๏ธ Overview

Goal: Prevent merging code to main and publishing Docker images unless all quality, security, and build validation checks pass.

Strategy: Multi-layered protection using: 1. GitHub Branch Protection Rules (required checks) 2. Separate focused workflows (parallel execution for speed) 3. Docker-only builds on main branch (no PR noise) 4. Forensic integrity features (SBOM, image signing, provenance)


๐Ÿ“‹ Branch Protection Rules

Configuring Branch Protection for main

Navigate to: Settings โ†’ Branches โ†’ Branch protection rules โ†’ Add rule

Required Settings:

Branch name pattern: main

โ˜‘ Require a pull request before merging
  โ˜‘ Require approvals: 0 (or 1+ for team review)
  โ˜‘ Dismiss stale pull request approvals when new commits are pushed
  โ˜‘ Require review from Code Owners: โ˜ (optional)

โ˜‘ Require status checks to pass before merging
  โ˜‘ Require branches to be up to date before merging

  Required status checks (add these exact names):
    - CI Summary              (from ci.yml)
    - Security Summary        (from security.yml)
    - PR Validation Summary   (from docker-pr-validation.yml)

  Note: These are the summary jobs that depend on all other checks passing.

โ˜‘ Require conversation resolution before merging

โ˜‘ Require linear history (recommended for forensic audit trail)

โ˜‘ Do not allow bypassing the above settings
  โ˜ Allow specific actors to bypass (optional - for emergencies only)

โ˜ Restrict who can push to matching branches (optional)

โ˜‘ Allow force pushes: โ˜ DISABLED (protects git history)
โ˜‘ Allow deletions: โ˜ DISABLED (prevents branch deletion)

๐Ÿ”„ Workflow Architecture

New Modular Workflow Structure

The repository now uses 4 separate focused workflows instead of one monolithic CI:

1. ci.yml - Code Quality & Tests (~5 min)

  • Ruff linting & formatting
  • MyPy type checking
  • Pytest with coverage (Python 3.11 & 3.12)
  • YAML validation
  • Runs on: PR + Main push

2. security.yml - Vulnerability Scanning (~3 min)

  • Bandit (Python security)
  • pip-audit & Safety (dependency vulnerabilities)
  • Hadolint (Dockerfile security)
  • TruffleHog (secret scanning)
  • Runs on: PR + Main push + Daily schedule

3. docker-pr-validation.yml - Build Validation (~12 min)

  • Single-arch Docker build (linux/amd64)
  • Health check tests (/healthz, /readyz)
  • Multi-arch build verification
  • Trivy security scan
  • Runs on: PR only
  • Does NOT publish images

4. docker-publish.yml - Production Build (~20 min)

  • Multi-arch builds (amd64, arm64, arm/v7)
  • SBOM generation (SPDX, CycloneDX)
  • Image signing with Cosign (keyless)
  • Provenance attestation
  • Push to Docker Hub
  • Full Trivy scans
  • Runs on: Main push + Git tags only

Workflow Execution Flow

graph TD
    A[PR Created/Updated] --> B[ci.yml]
    A --> C[security.yml]
    A --> D[docker-pr-validation.yml]

    B --> E{All Jobs Pass?}
    C --> E
    D --> E

    E -->|Yes| F[PR Can Be Merged]
    E -->|No| G[PR Blocked]

    F --> H[Merge to Main]
    H --> I[ci.yml on Main]
    H --> J[security.yml on Main]

    I --> K{Both Pass?}
    J --> K

    K -->|Yes| L[docker-publish.yml]
    K -->|No| M[No Docker Build]

    L --> N[Build & Publish Images]
    N --> O[Sign Images + Attach SBOM]

Benefits of This Architecture

For Pull Requests: - โœ… Fast parallel feedback (~12 min total) - โœ… Clear separation of concerns - โœ… Build validation without publishing - โœ… Security checks before merge

For Main Branch: - โœ… Production builds only after all checks pass - โœ… No wasted Docker builds on PRs - โœ… Complete forensic audit trail - โœ… SBOM and signatures for compliance

For Forensic Software: - โœ… Every image traceable to source commit - โœ… SBOM lists all dependencies - โœ… Cryptographic signatures verify integrity - โœ… Provenance attestation proves build source


๐Ÿ” Workflow Gating Strategy

How CI Gating Works

Branch Protection enforces that all required status checks pass before allowing merge:

  1. CI Summary - Must pass (from ci.yml)
  2. Security Summary - Must pass (from security.yml)
  3. PR Validation Summary - Must pass (from docker-pr-validation.yml)

Each summary job only succeeds if all its dependent jobs pass.

Docker Publish Gating

The docker-publish.yml workflow: - โœ… Only triggered by main branch push or git tags - โœ… Never runs on PRs (no wasted builds) - โœ… Relies on GitHub branch protection (CI must pass before merge allowed) - โœ… Includes verify-ci job as safety check


๐ŸŽฏ Required Checks Breakdown

Workflow: ci.yml (Code Quality & Tests)

Must Pass Before Merge:

1. Code Quality Job

  • Checks: Ruff linting, Ruff formatting, MyPy type checking
  • Duration: ~2 minutes
  • Failure: Blocks merge

2. Unit Tests (Python 3.11 & 3.12)

  • Jobs: Matrix across Python versions
  • Checks: pytest with coverage, Codecov upload
  • Duration: ~3 minutes per version
  • Failure: Blocks merge

3. YAML Linting

  • Checks: yamllint on workflow files
  • Duration: ~1 minute
  • Failure: Blocks merge

4. CI Summary

  • Checks: Aggregates all ci.yml job results
  • Duration: ~10 seconds
  • Failure: Blocks merge if any ci.yml job failed

Workflow: security.yml (Vulnerability Scanning)

Must Pass Before Merge:

1. Code Security (Bandit)

  • Checks: Python code security issues
  • Duration: ~1 minute
  • Failure: Blocks merge

2. Dependency Security

  • Checks: pip-audit & Safety for vulnerable dependencies
  • Duration: ~1 minute
  • Failure: Blocks merge

3. Dockerfile Security (Hadolint)

  • Checks: Dockerfile best practices and security
  • Duration: ~1 minute
  • Failure: Blocks merge

4. Secret Scanning

  • Checks: TruffleHog for exposed secrets
  • Duration: ~1 minute
  • Failure: Warning (doesn't block, but should be reviewed)

5. Security Summary

  • Checks: Aggregates all security.yml job results
  • Duration: ~10 seconds
  • Failure: Blocks merge if any security job failed

Workflow: docker-pr-validation.yml (Build Validation)

Must Pass Before Merge:

1. Build & Test (AMD64)

  • Checks: Docker build, health checks (/healthz, /readyz), multi-arch capability
  • Duration: ~8 minutes
  • Failure: Blocks merge

2. Trivy Security Scan

  • Checks: Container image vulnerabilities
  • Duration: ~3 minutes
  • Failure: Blocks merge if CRITICAL vulnerabilities found

3. PR Validation Summary

  • Checks: Aggregates all docker-pr-validation.yml job results
  • Duration: ~10 seconds
  • Failure: Blocks merge if any validation job failed

โš™๏ธ How It Works

Scenario 1: Normal PR Flow

1. Developer creates PR
   โ†“
2. Three workflows run in PARALLEL:
   โ”œโ”€ ci.yml (~5 min)
   โ”‚  โ”œโ”€ Code Quality โœ…
   โ”‚  โ”œโ”€ Tests (3.11) โœ…
   โ”‚  โ”œโ”€ Tests (3.12) โœ…
   โ”‚  โ””โ”€ YAML Lint โœ…
   โ”‚
   โ”œโ”€ security.yml (~3 min)
   โ”‚  โ”œโ”€ Bandit โœ…
   โ”‚  โ”œโ”€ pip-audit โœ…
   โ”‚  โ”œโ”€ Hadolint โœ…
   โ”‚  โ””โ”€ Secret Scan โœ…
   โ”‚
   โ””โ”€ docker-pr-validation.yml (~12 min)
      โ”œโ”€ Build & Test โœ…
      โ””โ”€ Trivy Scan โœ…
   โ†“
3. Total time: ~12 minutes (parallel execution)
   โ†“
4. All 3 summary jobs pass:
   โ”œโ”€ CI Summary โœ…
   โ”œโ”€ Security Summary โœ…
   โ””โ”€ PR Validation Summary โœ…
   โ†“
5. "Merge" button ENABLED
   โ†“
6. Maintainer merges PR
   โ†“
7. ci.yml + security.yml run on main
   โ†“
8. Both pass โ†’ docker-publish.yml triggered
   โ”œโ”€ verify-ci job โœ…
   โ”œโ”€ Multi-arch builds (amd64, arm64, arm/v7)
   โ”œโ”€ SBOM generation
   โ”œโ”€ Image signing
   โ”œโ”€ Full Trivy scans
   โ””โ”€ Push to Docker Hub

Scenario 2: Tests Fail on PR

1. Developer creates PR
   โ†“
2. Workflows run
   โ”œโ”€ ci.yml
   โ”‚  โ”œโ”€ Code Quality โœ…
   โ”‚  โ””โ”€ Tests (3.11) โŒ FAILED
   โ”œโ”€ security.yml โœ…
   โ””โ”€ docker-pr-validation.yml โœ…
   โ†“
3. CI Summary โŒ FAILED
   โ†“
4. "Merge" button DISABLED
   โ†“
5. Developer fixes tests, pushes commit
   โ†“
6. Workflows run again
   โ””โ”€ All checks โœ…
   โ†“
7. "Merge" button ENABLED

Scenario 3: Security Vulnerability Found

1. Developer creates PR
   โ†“
2. security.yml runs
   โ”œโ”€ Bandit โœ…
   โ”œโ”€ pip-audit โœ…
   โ”œโ”€ Hadolint โŒ CRITICAL issue found
   โ””โ”€ Secret Scan โœ…
   โ†“
3. Security Summary โŒ FAILED
   โ†“
4. "Merge" button DISABLED
   โ†“
5. Developer fixes Dockerfile, updates PR
   โ†“
6. security.yml runs again
   โ””โ”€ All checks โœ…
   โ†“
7. "Merge" button ENABLED

Scenario 4: Release Tag Created

1. Maintainer creates tag: v0.2025-10-0.1.0
   โ†“
2. Tag pushed to GitHub
   โ†“
3. docker-publish.yml triggered by tag
   โ”œโ”€ verify-ci job โœ… (checks main branch CI)
   โ”œโ”€ Multi-arch builds
   โ”œโ”€ SBOM generation
   โ”œโ”€ Image signing
   โ”œโ”€ Version tags: v0.2025-10-0.1.0, latest
   โ”œโ”€ Full Trivy scans
   โ””โ”€ Push to Docker Hub

Scenario 5: Monthly SOLVE-IT Update

1. Monthly cron trigger (1st of month, 3 AM UTC)
   โ†“
2. docker-monthly.yml runs
   โ”œโ”€ Check SOLVE-IT latest release
   โ”œโ”€ Compare with published version
   โ””โ”€ New version found? v0.2025-11
   โ†“
3. Calls docker-publish.yml workflow
   โ”œโ”€ Create new release tag
   โ”œโ”€ Build with new SOLVE-IT data
   โ”œโ”€ Full security scans
   โ””โ”€ Publish

๐Ÿšจ Bypassing Protection (Emergency Only)

When to Bypass:

  • โœ… Critical security hotfix needed immediately
  • โœ… Known flaky test, but code is verified manually
  • โœ… CI infrastructure issue (GitHub Actions outage)

How to Bypass:

# Go to Actions โ†’ Docker Build and Publish โ†’ Run workflow
# Select branch: main
# Run manually (skips verify-ci for workflow_dispatch events)

Method 2: Temporarily Disable Branch Protection

# Settings โ†’ Branches โ†’ Edit rule for main
# Temporarily uncheck "Require status checks to pass"
# Merge PR
# RE-ENABLE protection immediately!

Method 3: Admin Override (If enabled)

# Only if "Allow specific actors to bypass" is configured
# Admin can merge despite failing checks
# Should be logged and reviewed

โš ๏ธ IMPORTANT: Document all bypasses in a GitHub Issue with: - Reason for bypass - Timestamp - Who authorized it - Follow-up action to fix root cause


๐Ÿ“Š Monitoring & Alerts

Check Workflow Status

GitHub Actions Page: - https://github.com/3soos3/solve-it-mcp/actions

Workflow Badges (add to README):

[![CI Status](https://github.com/3soos3/solve-it-mcp/workflows/CI%20-%20Code%20Quality%20%26%20Tests/badge.svg)](https://github.com/3soos3/solve-it-mcp/actions)
[![Docker Build](https://github.com/3soos3/solve-it-mcp/workflows/Docker%20Build%20and%20Publish/badge.svg)](https://github.com/3soos3/solve-it-mcp/actions)

Email Notifications

Configure in: Settings โ†’ Notifications โ†’ Actions - โ˜‘ Send notifications for failed workflows - โ˜‘ Include workflow logs


๐Ÿงช Testing the Setup

Test 1: Verify Branch Protection

# Try to push directly to main (should fail)
git checkout main
git commit --allow-empty -m "test: direct push"
git push origin main
# Expected: remote rejected (branch protected)

Test 2: Verify CI Gating

# Create PR with failing test
# 1. Add a failing test to tests/
# 2. Create PR
# 3. Verify "Merge" button is disabled
# 4. Check "Required" status checks section

Test 3: Verify Docker Workflow Gating

# Check workflow file
cat .github/workflows/docker-publish.yml | grep -A5 "verify-ci"

# Expected: Job exists and checks CI status

๐Ÿ“ Step-by-Step Setup Instructions

1. Enable Branch Protection

1. Go to: https://github.com/3soos3/solve-it-mcp/settings/branches
2. Click "Add rule" or "Edit" for existing main rule
3. Branch name pattern: main
4. Enable these checkboxes:
   โ˜‘ Require a pull request before merging
   โ˜‘ Require status checks to pass before merging
   โ˜‘ Require branches to be up to date before merging
5. In "Status checks that are required", search and add:
   - CI Summary
   - Security Summary
   - PR Validation Summary
6. Click "Create" or "Save changes"

2. Verify Workflow Files

# Ensure workflows are in place
ls -la .github/workflows/
# Should show:
# - ci.yml (Code Quality & Tests)
# - security.yml (Vulnerability Scanning)
# - docker-pr-validation.yml (PR Build Validation)
# - docker-publish.yml (Production Build & Publish)
# - docker-monthly.yml (Smart Monthly Rebuilds)

3. Test the Setup

# Create a test PR
git checkout -b test/branch-protection
echo "# Test" >> TEST.md
git add TEST.md
git commit -m "test: branch protection"
git push -u origin test/branch-protection

# Create PR on GitHub
# Verify CI runs automatically
# Verify merge button state

4. Monitor First Real PR

# After setup, monitor first real PR:
# 1. Check all CI jobs run
# 2. Check status checks appear in PR
# 3. Verify merge button behavior
# 4. Check Docker workflow triggers after merge

๐Ÿ”ง Troubleshooting

Issue: "Merge" button enabled despite failing CI

Cause: Status checks not configured correctly in branch protection

Fix: 1. Go to branch protection settings 2. Ensure "Require status checks to pass" is checked 3. Verify exact job names match what appears in Actions tab 4. Job names are case-sensitive!

Issue: Docker workflow runs even though CI failed

Cause: verify-ci job not working correctly

Fix:

# Check workflow logs
# Look for "Verify CI Status" job
# Check if it's being skipped incorrectly
# Verify the if conditions in the job

Issue: CI checks not appearing in PR

Cause: CI workflow not triggering on PRs

Fix:

# In .github/workflows/ci.yml, verify:
on:
  pull_request:
    branches:
      - main

Issue: Status check names don't match

Cause: Job names in workflow don't match configured status checks

Fix:

# Job name in workflow file MUST match status check name
# Example:
# Workflow: name: "Code Quality"
# Branch protection: Add status check "Code Quality" (exact match)


๐Ÿ“š Additional Resources


๐Ÿ” Forensic Software Features

SBOM (Software Bill of Materials)

Every published Docker image includes an SBOM for complete dependency transparency:

Formats Generated: - SPDX JSON - Industry standard, ISO/IEC 5962:2021 compliant - CycloneDX JSON - OWASP standard for software supply chain - Syft JSON - Anchore's detailed format

How to Access:

# Download SBOM from GitHub artifacts
gh run download <run-id> --name sbom-<commit-sha>

# View SBOM attached to image (requires cosign)
cosign download sbom ghcr.io/3soos3/solve-it-mcp:latest

# View SBOM in container
docker run --rm ghcr.io/3soos3/solve-it-mcp:latest cat /sbom/sbom.spdx.json

Use Cases: - Compliance audits (GDPR, HIPAA, PCI-DSS) - Vulnerability tracking across fleet - License compliance verification - Evidence chain of custody

Image Signing with Cosign

All images are cryptographically signed using Sigstore Cosign (keyless signing):

Verification:

# Verify image signature
cosign verify ghcr.io/3soos3/solve-it-mcp:latest \
  --certificate-identity-regexp=github \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com

# Expected output:
# โœ“ Verified signature
# โœ“ Certificate identity matches
# โœ“ OIDC issuer matches

Provenance:

# View build provenance
cosign download attestation ghcr.io/3soos3/solve-it-mcp:latest | jq

# Shows:
# - Source repository
# - Commit SHA
# - Build workflow
# - Build timestamp
# - Builder identity

Forensic Benefits: - Integrity: Prove image hasn't been tampered with - Authenticity: Verify image source and builder - Non-repudiation: Signatures are tied to GitHub identity - Transparency: Public Sigstore transparency log (Rekor)

Audit Trail

Complete traceable history for every Docker image:

Image Tags Include: - sha-<commit> - Exact source commit - v<version> - Release version - latest - Current stable

Metadata in Image Labels:

docker inspect ghcr.io/3soos3/solve-it-mcp:latest | jq '.[0].Config.Labels'

# Shows:
# - org.opencontainers.image.created
# - org.opencontainers.image.revision (git commit)
# - org.opencontainers.image.source (repo URL)
# - org.opencontainers.image.version

CI/CD Artifacts: - Workflow logs (retained 90 days) - Security scan results (SARIF format) - Test coverage reports - SBOM files

GitHub Audit: - All commits signed/verified - PR reviews required - Branch protection enforced - Workflow runs logged


โœ… Checklist for New Repositories

  • Enable branch protection for main
  • Configure required status checks (CI Summary, Security Summary, PR Validation Summary)
  • Add all 4 workflows (ci, security, docker-pr-validation, docker-publish)
  • Set up Docker Hub secrets (DOCKERHUB_USERNAME, DOCKERHUB_TOKEN)
  • Test with a failing PR (verify blocked)
  • Test with a passing PR (verify can merge)
  • Verify Docker workflow only runs on main
  • Verify SBOM generation works
  • Verify image signing works
  • Document bypass procedures
  • Set up monitoring/alerts
  • Add workflow badges to README

๐ŸŽฏ Summary

What This Setup Provides: - โœ… No broken code can be merged to main - โœ… No Docker images built from failing checks - โœ… Fast parallel feedback (~12 min for PRs) - โœ… Automated quality gates at every step - โœ… Clear separation of concerns - โœ… Complete forensic audit trail - โœ… SBOM for compliance - โœ… Cryptographic image signatures - โœ… Provenance attestation

Forensic Software Benefits: - โœ… Every image traceable to source commit - โœ… Complete dependency transparency (SBOM) - โœ… Cryptographic integrity verification - โœ… Non-repudiatable build provenance - โœ… Compliance-ready audit trail - โœ… Court-defensible evidence chain

Maintenance Required: - Review status check names when workflows change - Update branch protection rules if adding new critical checks - Monitor security scans for new vulnerabilities - Rotate Docker Hub tokens annually - Document any bypass usage

Questions or Issues? - File an issue: https://github.com/3soos3/solve-it-mcp/issues - Workflow docs: .github/workflows/README.md