Skip to content

containerized-web-app.yml

# Containerized Web App Security Pipeline
#
# A comprehensive security scanning workflow for containerized web applications.
# This demonstrates the recommended pattern for securing containerized apps.
#
# Features:
# - Secrets detection (Gitleaks)
# - SAST scanning (Bandit, CodeQL, OpenGrep)
# - Malware detection (ClamAV)
# - Container image scanning (Trivy, Grype, Syft SBOM)
# - DAST web application scanning (ZAP)
# - Consolidated security summary with PR comments
#
# Usage:
# 1. Copy this file to your repository's .github/workflows/ directory
# 2. Adjust the Dockerfile path, port, and health endpoint for your application
# 3. Configure CodeQL language(s) for your codebase
# 4. For air-gapped GHES, update action references to your internal mirror
#
# Note: All individual scanners disable PR comments - the security-summary
# action generates a single consolidated comment for cleaner PR reviews.

# yamllint disable rule:brackets
name: Security Pipeline

on:
  workflow_dispatch:
  pull_request:
    branches: [main]

permissions:
  contents: read
  pull-requests: write
  security-events: write
  actions: read
  checks: write
  id-token: write
  packages: read

jobs:
  # ============================================
  # Secrets Detection
  # ============================================
  gitleaks:
    name: Gitleaks Secret Scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        with:
          fetch-depth: 0
      - uses: huntridge-labs/argus/.github/actions/scanner-gitleaks@1.1.0
        with:
          fail_on_severity: 'high'
          post_pr_comment: false  # Let security-summary handle comments
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}

  # ============================================
  # SAST - Static Application Security Testing
  # ============================================
  bandit:
    name: Bandit Python SAST
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
      - uses: huntridge-labs/argus/.github/actions/scanner-bandit@1.1.0
        with:
          fail_on_severity: 'high'
          post_pr_comment: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  codeql:
    name: CodeQL SAST
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
      - uses: huntridge-labs/argus/.github/actions/scanner-codeql@1.1.0
        with:
          language: 'python'  # Adjust: python, javascript, java, go, etc.
          fail_on_severity: 'high'
          # Optional: Use a custom CodeQL config file
          # config_file: '.github/codeql/codeql-config.yml'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  opengrep:
    name: OpenGrep SAST
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
      - uses: huntridge-labs/argus/.github/actions/scanner-opengrep@1.1.0
        with:
          config: 'auto'
          fail_on_severity: 'high'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  # ============================================
  # Malware Detection
  # ============================================
  clamav:
    name: ClamAV Malware Scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
      - uses: huntridge-labs/argus/.github/actions/scanner-clamav@1.1.0
        with:
          scan_path: '.'
          fail_on_severity: 'high'
          post_pr_comment: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  # ============================================
  # Container Scanning - Build and Scan Application Image
  # ============================================
  container-scan:
    name: Container Security Scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

      - name: Build container image
        run: |
          docker build -t my-app:${{ github.sha }} .
          echo "✅ Built image: my-app:${{ github.sha }}"

      - uses: huntridge-labs/argus/.github/actions/scanner-container@1.1.0
        with:
          image_ref: 'my-app:${{ github.sha }}'
          container_name: 'my-app'
          scanners: 'trivy,grype,syft'
          fail_on_severity: 'high'

  # ============================================
  # DAST - Dynamic Application Security Testing
  # ============================================
  zap-dast:
    name: ZAP DAST Scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

      - name: Build and start container
        run: |
          docker build -t my-app:${{ github.sha }} .
          docker run -d --name my-app -p 8080:8080 my-app:${{ github.sha }}
          echo "⏳ Waiting for application to be healthy..."
          # Poll health endpoint until ready (adjust /health to your app's endpoint)
          for i in {1..30}; do
            if curl -sf http://localhost:8080/health > /dev/null 2>&1; then
              echo "✅ Application is healthy"
              exit 0
            fi
            echo "  Attempt $i/30 - waiting..."
            sleep 1
          done
          echo "❌ Application failed to start"
          docker logs my-app
          exit 1

      - uses: huntridge-labs/argus/.github/actions/scanner-zap@1.1.0
        with:
          target_url: 'http://localhost:8080'
          scan_name: 'my-app'
          fail_on_severity: 'high'
          post_pr_comment: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Stop container
        if: always()
        run: |
          docker stop my-app || true
          docker rm my-app || true

  # ============================================
  # Security Summary - Consolidated PR Comment
  # ============================================
  security-summary:
    name: Security Summary
    needs: [gitleaks, bandit, codeql, opengrep, clamav, container-scan, zap-dast]
    if: always()
    runs-on: ubuntu-latest
    steps:
      - name: Download scanner summaries
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          pattern: scanner-summary-*
          path: scanner-summaries
          merge-multiple: true
        continue-on-error: true

      - uses: huntridge-labs/argus/.github/actions/security-summary@1.1.0
        with:
          title: '🔒 Security Pipeline Summary'
          post_pr_comment: 'true'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}