Skip to content

container-scanning.yml

# Container Security Scanning for GitHub Enterprise Server
#
# This workflow scans container images for vulnerabilities.
# Supports both local Dockerfile builds and remote registry images.
#
# Scanners included:
# - Trivy (Comprehensive vulnerability scanner)
# - Grype (Fast CVE detection)
# - Syft (SBOM generation)

name: Container Security Scan

on:
  push:
    branches: [main, master]
    paths:
      - '**/Dockerfile*'
      - 'docker-compose*.yml'
      - '.github/workflows/container-scanning.yml'
  pull_request:
    branches: [main, master]
    paths:
      - '**/Dockerfile*'
      - 'docker-compose*.yml'
  # Manual trigger for ad-hoc scans
  workflow_dispatch:
    inputs:
      image_ref:
        description: 'Container image to scan (e.g., nginx:latest)'
        required: false
        type: string
        default: ''

permissions:
  contents: read
  security-events: write
  pull-requests: write
  actions: read
  packages: read # For GHCR access

env:
  # Default image to scan if not specified
  DEFAULT_IMAGE: 'ghcr.io/${{ github.repository }}:latest'

jobs:
  # ============================================
  # Option 1: Scan a remote/existing image
  # ============================================
  scan-remote-image:
    name: Scan Container Image
    runs-on: ubuntu-latest
    if: github.event.inputs.image_ref != '' || github.event_name != 'workflow_dispatch'
    steps:
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

      - name: Determine image to scan
        id: image
        run: |
          if [ -n "${{ github.event.inputs.image_ref }}" ]; then
            IMAGE="${{ github.event.inputs.image_ref }}"
          else
            IMAGE="${{ env.DEFAULT_IMAGE }}"
          fi
          echo "image=$IMAGE" >> $GITHUB_OUTPUT
          echo "Scanning image: $IMAGE"

      # Authenticate to registry if needed (example for GHCR)
      - name: Login to GitHub Container Registry
        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
        continue-on-error: true

      - name: Run Container Security Scan
        uses: huntridge-labs/argus/.github/actions/scanner-container@1.1.0
        with:
          image_ref: ${{ steps.image.outputs.image }}
          container_name: 'app'
          scanners: 'trivy,grype,syft'
          fail_on_severity: 'high'
          enable_code_security: 'true'
          # For private registries:
          # registry_username: ${{ github.actor }}
          # registry_password: ${{ secrets.GITHUB_TOKEN }}

  # ============================================
  # Option 2: Build and scan local Dockerfile
  # ============================================
  build-and-scan:
    name: Build and Scan
    runs-on: ubuntu-latest
    if: github.event_name != 'workflow_dispatch'
    steps:
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3

      - name: Build container image
        id: build
        run: |
          IMAGE_NAME="scan-target"
          IMAGE_TAG="$GITHUB_SHA"

          # Build the image (adjust path to your Dockerfile)
          if [ -f "Dockerfile" ]; then
            docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" .
            echo "image=${IMAGE_NAME}:${IMAGE_TAG}" >> $GITHUB_OUTPUT
            echo "Built image: ${IMAGE_NAME}:${IMAGE_TAG}"
          else
            echo "No Dockerfile found, skipping build"
            echo "image=" >> $GITHUB_OUTPUT
          fi

      - name: Run Container Security Scan
        if: steps.build.outputs.image != ''
        uses: huntridge-labs/argus/.github/actions/scanner-container@1.1.0
        with:
          image_ref: ${{ steps.build.outputs.image }}
          container_name: 'local-build'
          scanners: 'trivy,grype,syft'
          fail_on_severity: 'high'
          enable_code_security: 'true'

  # ============================================
  # Generate standalone SBOM for source code
  # ============================================
  generate-sbom:
    name: Generate Source SBOM
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

      - name: Generate SBOM
        uses: huntridge-labs/argus/.github/actions/scanner-syft@1.1.0
        with:
          scan_path: '.'
          output_format: 'cyclonedx-json'