| # AegisLM CI/CD Security | |
| ## Overview | |
| This document defines the security requirements and controls for the AegisLM CI/CD pipeline. All pipeline changes must comply with these security standards. | |
| ## CI/CD Security Architecture | |
| ``` | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β CI/CD Pipeline Security Flow β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ | |
| β β | |
| β ββββββββββββββββ β | |
| β β GitHub β β | |
| β β Push/PR β β | |
| β ββββββββ¬ββββββββ β | |
| β β β | |
| β βΌ β | |
| β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β | |
| β β GitHub Actions Workflow β β | |
| β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β | |
| β β β | |
| β ββββΊ Lint & Type Check β | |
| β β βββ Ruff, MyPy β | |
| β β β | |
| β ββββΊ Schema Validation β | |
| β β βββ Pydantic validation β | |
| β β β | |
| β ββββΊ Unit Tests β | |
| β β βββ pytest with coverage β | |
| β β β | |
| β ββββΊ Docker Build β | |
| β β βββ Multi-stage build β | |
| β β β | |
| β ββββΊ Security Scan ββββββββββββββββββββββββββββββββββββββ β | |
| β β βββ Dependency scan (safety) β β | |
| β β βββ Secret detection (trufflehog) β β | |
| β β βββ Container scan (trivy) β β | |
| β β βββ SAST (bandit) β β | |
| β β β β | |
| β ββββΊ Artifact Signing βββββββββββββββββββββββββββββββββββββ β | |
| β βββ Cosign, GPG β | |
| β β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ``` | |
| --- | |
| ## Security Controls | |
| ### β Required Security Checks | |
| | Check | Tool | Severity | Status | | |
| |-------|------|----------|--------| | |
| | Dependency vulnerability scan | `safety`, `pip-audit` | Critical | β Implemented | | |
| | Secret detection | `trufflehog`, `gitleaks` | Critical | π To Implement | | |
| | Container image scan | `trivy`, `clair` | High | π To Implement | | |
| | SAST (Static Analysis) | `bandit`, `semgrep` | High | π To Implement | | |
| | Code linting | `ruff` | Medium | β Implemented | | |
| | Type checking | `mypy` | Medium | β Implemented | | |
| | Artifact signing | `cosign`, `GPG` | High | π To Implement | | |
| --- | |
| ## Enhanced GitHub Actions Workflow | |
| Update `.github/workflows/ci.yml` with enhanced security: | |
| ``` | |
| yaml | |
| # AegisLM CI/CD Pipeline - Enhanced Security Version | |
| # GitHub Actions workflow with comprehensive security scanning | |
| name: CI | |
| on: | |
| push: | |
| branches: [main, develop] | |
| pull_request: | |
| branches: [main, develop] | |
| env: | |
| # Security settings | |
| TRUFFLEHOG_VERSION: "3.63.1" | |
| TRIVY_VERSION: "0.49.1" | |
| SEMGREP_VERSION: "1.64.0" | |
| jobs: | |
| # =========================================================================== | |
| # Secret Detection - Fail on secrets | |
| # =========================================================================== | |
| secret-detection: | |
| name: Secret Detection | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Full history for trufflehog | |
| - name: Run Trufflehog | |
| uses: trufflesecurity/trufflehog@main | |
| with: | |
| path: ./ | |
| base: ${{ github.event.repository.default_branch }} | |
| head: HEAD | |
| extra_args: --fail --verified-only | |
| - name: Run Gitleaks | |
| uses: gitleaks/gitleaks-action@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITLEAKS_ENABLE_UPDATES: "false" | |
| # =========================================================================== | |
| # SAST - Static Application Security Testing | |
| # =========================================================================== | |
| sast: | |
| name: SAST Analysis | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Run Semgrep | |
| uses: returntocorp/semgrep-action@v1 | |
| with: | |
| config: auto | |
| generateSarif: true | |
| - name: Upload Semgrep results | |
| uses: github/codeql-action/upload-sarif@v3 | |
| with: | |
| sarif_file: semgrep.sarif | |
| - name: Run Bandit | |
| run: | | |
| pip install bandit | |
| bandit -r backend/ -f sarif -o bandit.sarif || true | |
| continue-on-error: true | |
| # =========================================================================== | |
| # Lint and Type Check | |
| # =========================================================================== | |
| lint: | |
| name: Lint & Type Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| pip install -r requirements.txt | |
| pip install ruff mypy | |
| - name: Run Ruff linter | |
| run: ruff check . --output-format=github | |
| - name: Run MyPy type checker | |
| run: mypy backend --ignore-missing-imports --no-error-summary | |
| continue-on-error: true | |
| # =========================================================================== | |
| # Validate Pydantic Schemas | |
| # =========================================================================== | |
| schema-validation: | |
| name: Validate Pydantic Schemas | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: pip install -r requirements.txt | |
| - name: Validate Pydantic schemas | |
| run: | | |
| python -c " | |
| from backend.benchmarking.schemas import BenchmarkConfig, BenchmarkWeights | |
| from backend.core.config import settings | |
| from backend.db.models import EvaluationRun | |
| print('All Pydantic schemas imported successfully') | |
| " | |
| - name: Validate weights sum to 1 | |
| run: | | |
| python -c " | |
| from backend.benchmarking.schemas import BenchmarkWeights | |
| weights = BenchmarkWeights() | |
| total = weights.hallucination + weights.toxicity + weights.bias + weights.confidence | |
| if abs(total - 1.0) > 1e-6: | |
| raise ValueError(f'Weights must sum to 1.0, got {total}') | |
| print(f'Weights validation passed: sum = {total}') | |
| " | |
| # =========================================================================== | |
| # Unit Tests | |
| # =========================================================================== | |
| tests: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| pip install -r requirements.txt | |
| pip install pytest pytest-asyncio pytest-cov | |
| - name: Run unit tests | |
| run: pytest tests/ -v --cov=backend --cov-report=xml --cov-report=term-missing | |
| continue-on-error: true | |
| - name: Upload coverage | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-report | |
| path: coverage.xml | |
| # =========================================================================== | |
| # Docker Build with Security Scanning | |
| # =========================================================================== | |
| docker: | |
| name: Docker Build & Scan | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build Docker image | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| push: false | |
| tags: aegislm:test | |
| load: true | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - name: Run Trivy scanner | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: 'aegislm:test' | |
| format: sarif | |
| output: 'trivy-results.sarif' | |
| severity: 'CRITICAL,HIGH' | |
| exit-code: '1' | |
| ignore-unfixed: true | |
| - name: Upload Trivy results | |
| uses: github/codeql-action/upload-sarif@v3 | |
| with: | |
| sarif_file: 'trivy-results.sarif' | |
| # =========================================================================== | |
| # Dependency Security Scan | |
| # =========================================================================== | |
| dependency-security: | |
| name: Dependency Security | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: pip install -r requirements.txt | |
| - name: Run pip-audit | |
| uses: pypa/pip-audit@main | |
| with: | |
| pip-audit-args: --exclude-editable --require-hashes | |
| - name: Run safety | |
| run: | | |
| pip install safety | |
| safety check --json > safety-results.json || true | |
| continue-on-error: true | |
| - name: Upload security results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: security-results | |
| path: | | |
| safety-results.json | |
| trivy-results.sarif | |
| # =========================================================================== | |
| # Build Summary | |
| # =========================================================================== | |
| summary: | |
| name: Build Summary | |
| needs: [secret-detection, sast, lint, schema-validation, tests, docker, dependency-security] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| steps: | |
| - name: Summary | |
| run: | | |
| echo "## Build Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY | |
| echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Secret Detection | ${{ needs.secret-detection.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| SAST Analysis | ${{ needs.sast.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Lint & Type Check | ${{ needs.lint.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Schema Validation | ${{ needs.schema-validation.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Unit Tests | ${{ needs.tests.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Docker Build & Scan | ${{ needs.docker.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Dependency Security | ${{ needs.dependency-security.result }} |" >> $GITHUB_STEP_SUMMARY | |
| # Fail if critical security issues found | |
| if [ "${{ needs.secret-detection.result }}" == "failure" ]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "β **SECURITY FAILURE**: Secrets detected in code" >> $GITHUB_STEP_SUMMARY | |
| exit 1 | |
| fi | |
| # =========================================================================== | |
| # Artifact Signing (for releases) | |
| # =========================================================================== | |
| sign: | |
| name: Sign Artifacts | |
| needs: [lint, tests, docker] | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'release' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Cosign | |
| uses: sigstore/cosign-installer@v3 | |
| - name: Sign Docker image | |
| run: | | |
| cosign sign --yes aegislm/test:latest | |
| - name: Sign Python packages | |
| run: | | |
| # Generate key pair | |
| cosign generate-key-pair | |
| # Sign wheel files | |
| for wheel in dist/*.whl; do | |
| cosign sign-file --key cosign.key "$wheel" | |
| done | |
| - name: Upload signatures | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: signatures | |
| path: | | |
| *.sig | |
| cosign.pub | |
| ``` | |
| --- | |
| ## Security Scanning Configuration | |
| ### TruffleHog Configuration | |
| Create `.trufflehog.yaml`: | |
| ``` | |
| yaml | |
| # TruffleHog configuration | |
| directories: | |
| - . | |
| exclude: | |
| - .git | |
| - node_modules | |
| - venv | |
| - __pycache__ | |
| rules: | |
| - name: AWS Access Key | |
| pattern: 'AKIA[0-9A-Z]{16}' | |
| entropy: true | |
| - name: GitHub Token | |
| pattern: 'gh[pousr]_[A-Za-z0-9_]{36,255}' | |
| entropy: true | |
| - name: JWT Token | |
| pattern: 'eyJ[A-Za-z0-9-_=]+\.eyJ[A-Za-z0-9-_=]+\.[A-Za-z0-9-_.+/=]*' | |
| entropy: true | |
| - name: Private Key | |
| pattern: '-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----' | |
| entropy: false | |
| - name: Generic API Key | |
| pattern: '(?i)(api[_-]?key|apikey|secret[_-]?key)[\s:=]+["\']?[a-zA-Z0-9]{16,}' | |
| entropy: true | |
| ``` | |
| ### Semgrep Configuration | |
| Create `.semgrep.yaml`: | |
| ``` | |
| yaml | |
| rules: | |
| - id: python-secrets | |
| pattern: | | |
| os.environ["$KEY"] | |
| message: Hardcoded secrets in environment variables | |
| languages: | |
| - python | |
| severity: ERROR | |
| metadata: | |
| cwe: "CWE-798: Use of Hard-coded Credentials" | |
| owasp: "A2:2017-Broken Authentication" | |
| - id: python-sql-injection | |
| pattern: | | |
| cursor.execute("SELECT ..." + $USER_INPUT) | |
| message: Potential SQL injection | |
| languages: | |
| - python | |
| severity: ERROR | |
| metadata: | |
| cwe: "CWE-89: SQL Injection" | |
| owasp: "A1:2017-Injection" | |
| - id: python-path-traversal | |
| pattern: | | |
| open($FILE, ...) | |
| message: Potential path traversal | |
| languages: | |
| - python | |
| severity: WARNING | |
| metadata: | |
| cwe: "CWE-22: Path Traversal" | |
| ``` | |
| --- | |
| ## Dependency Vulnerability Policy | |
| ### Severity Thresholds | |
| | Severity | Action | Pipeline Result | | |
| |----------|--------|-----------------| | |
| | Critical | Fail build | β Fail | | |
| | High | Fail build | β Fail | | |
| | Medium | Warning only | β οΈ Warn | | |
| | Low | Info only | βΉοΈ Info | | |
| ### Allowed Vulnerabilities | |
| For legitimate exceptions, create `.vuln-allowlist.json`: | |
| ``` | |
| json | |
| { | |
| "allowed_vulnerabilities": [ | |
| { | |
| "cve": "CVE-2024-12345", | |
| "package": "some-library", | |
| "reason": "False positive - not used in our code path", | |
| "expires": "2024-12-31" | |
| } | |
| ] | |
| } | |
| ``` | |
| --- | |
| ## Artifact Signing | |
| ### Cosign Setup | |
| ``` | |
| bash | |
| # Install cosign | |
| brew install cosign | |
| # Generate key pair | |
| cosign generate-key-pair | |
| # Sign a container image | |
| cosign sign aegislm/api:v1.0.0 | |
| # Verify signature | |
| cosign verify aegislm/api:v1.0.0 --key cosign.pub | |
| ``` | |
| ### Python Package Signing | |
| ``` | |
| yaml | |
| # In release workflow | |
| - name: Build Python package | |
| run: | | |
| python -m build | |
| - name: Sign packages | |
| run: | | |
| for file in dist/*.whl; do | |
| cosign sign-file --key cosign.key "$file" | |
| done | |
| ``` | |
| --- | |
| ## Pipeline Security Best Practices | |
| ### 1. Secrets Management | |
| ``` | |
| yaml | |
| # Use GitHub Secrets for sensitive values | |
| env: | |
| # Don't use secrets directly in env! | |
| # Instead, use the secrets context | |
| API_TOKEN: ${{ secrets.API_TOKEN }} | |
| ``` | |
| ### 2. Permission Minimization | |
| ``` | |
| yaml | |
| # Use minimal permissions | |
| permissions: | |
| contents: read | |
| security-events: write | |
| actions: read | |
| checks: write | |
| ``` | |
| ### 3. Cache Security | |
| ``` | |
| yaml | |
| # Use secure cache | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| cache: 'pip' # Uses hash of requirements.txt | |
| ``` | |
| --- | |
| ## Compliance Mapping | |
| | Control | Implementation | Standard | | |
| |---------|---------------|----------| | |
| | Secret scanning | TruffleHog, Gitleaks | PCI DSS 6.5.10 | | |
| | SAST | Semgrep, Bandit | OWASP Top 10 | | |
| | Dependency scanning | pip-audit, Safety | NIST 800-53 | | |
| | Container scanning | Trivy | CIS Docker | | |
| | Code signing | Cosign | NIST 800-53 | | |
| --- | |
| ## Emergency Procedures | |
| ### Handling Security Vulnerabilities | |
| 1. **Immediate**: Block vulnerable images in registry | |
| 2. **Short-term**: Patch vulnerable dependencies | |
| 3. **Long-term**: Update to secure alternatives | |
| ### Pipeline Failure Response | |
| ``` | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β Security Failure Response β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ | |
| β β | |
| β Security Scan Fails β | |
| β β β | |
| β βΌ β | |
| β βββββββββββββββ β | |
| β β Identify β β Review vulnerability details β | |
| β β Issue β β Check if applicable to our code β | |
| β ββββββββ¬βββββββ β | |
| β β β | |
| β βΌ β | |
| β βββββββββββββββ β | |
| β β Decide β β Patch available? Use it β | |
| β β Action β β No patch? Add to allowlist (temp) β | |
| β ββββββββ¬βββββββ β Critical? Block deployment β | |
| β β β | |
| β βΌ β | |
| β βββββββββββββββ β | |
| β β Document β β Create security issue β | |
| β β & Notify β β Notify security team β | |
| β βββββββββββββββ β | |
| β β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ``` | |
| --- | |
| ## References | |
| - [GitHub Actions Security](https://docs.github.com/en/actions/security-guides) | |
| - [OWASP Top 10](https://owasp.org/www-project-top-ten/) | |
| - [NIST 800-53 Security Controls](https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final) | |
| - [Cosign Documentation](https://docs.sigstore.dev/cosign/signing/overview/) | |
| - [TruffleHog](https://trufflesecurity.com/trufflehog/) | |