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'