Skip to content

Instantly share code, notes, and snippets.

@initcron
Last active September 23, 2025 07:07
Show Gist options
  • Save initcron/a89d266ba85fae93d9de71b55f788d86 to your computer and use it in GitHub Desktop.
Save initcron/a89d266ba85fae93d9de71b55f788d86 to your computer and use it in GitHub Desktop.
.github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [ "main", "develop" ]
env:
REGISTRY: docker.io
IMAGE_NAME: ${{ secrets.DOCKERHUB_USERNAME }}/tech-stack-advisor
permissions:
contents: read
security-events: write
actions: read
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Train model
run: python train.py
- name: Test application
run: |
# Check if model files were created
if [ -f "model.pkl" ] && [ -f "encoders.pkl" ]; then
echo "βœ… Model files created successfully"
else
echo "❌ Model files missing"
exit 1
fi
- name: Upload model artifacts
uses: actions/upload-artifact@v4
with:
name: trained-models
path: |
model.pkl
encoders.pkl
docker-build:
needs: build-and-test
runs-on: ubuntu-latest
outputs:
image-digest: ${{ steps.build.outputs.digest }}
image-tags: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download model artifacts
uses: actions/download-artifact@v5
with:
name: trained-models
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push multi-architecture image
uses: docker/build-push-action@v6
id: build
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Generate build summary
run: |
echo "## 🐳 Docker Build Summary" >> $GITHUB_STEP_SUMMARY
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Image | \`${{ env.IMAGE_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Platforms | linux/amd64, linux/arm64 |" >> $GITHUB_STEP_SUMMARY
echo "| Tags | ${{ steps.meta.outputs.tags }} |" >> $GITHUB_STEP_SUMMARY
echo "| Registry | Docker Hub |" >> $GITHUB_STEP_SUMMARY
security-scan:
needs: docker-build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Trivy
run: |
sudo apt-get update
sudo apt-get install wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Run Trivy vulnerability scan
run: |
echo "πŸ” Running Trivy vulnerability scan..."
trivy image \
--format sarif \
--output trivy-results.sarif \
${{ env.IMAGE_NAME }}:latest
- name: Run Trivy vulnerability scan (table format)
run: |
echo "πŸ” Running Trivy scan for human-readable output..."
trivy image \
--format table \
--output trivy-results.txt \
${{ env.IMAGE_NAME }}:latest
- name: Generate SBOM with Trivy
run: |
echo "πŸ“‹ Generating SBOM with Trivy..."
trivy image \
--format spdx-json \
--output sbom.spdx.json \
${{ env.IMAGE_NAME }}:latest
- name: Check for HIGH and CRITICAL vulnerabilities
id: vuln-check
run: |
echo "🚨 Checking for HIGH/CRITICAL vulnerabilities..."
# Count HIGH and CRITICAL vulnerabilities
HIGH_COUNT=$(trivy image --format json ${{ env.IMAGE_NAME }}:latest | jq '[.Results[]?.Vulnerabilities[]? | select(.Severity == "HIGH")] | length')
CRITICAL_COUNT=$(trivy image --format json ${{ env.IMAGE_NAME }}:latest | jq '[.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL")] | length')
echo "high-count=$HIGH_COUNT" >> $GITHUB_OUTPUT
echo "critical-count=$CRITICAL_COUNT" >> $GITHUB_OUTPUT
echo "Found $CRITICAL_COUNT CRITICAL and $HIGH_COUNT HIGH severity vulnerabilities"
# Display summary
echo "## πŸ”’ Security Scan Results" >> $GITHUB_STEP_SUMMARY
echo "| Severity | Count |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| CRITICAL | $CRITICAL_COUNT |" >> $GITHUB_STEP_SUMMARY
echo "| HIGH | $HIGH_COUNT |" >> $GITHUB_STEP_SUMMARY
- name: Security gate - Fail on CRITICAL vulnerabilities
if: steps.vuln-check.outputs.critical-count > 5
run: |
echo "❌ SECURITY GATE FAILED: Found ${{ steps.vuln-check.outputs.critical-count }} CRITICAL vulnerabilities"
echo "🚨 Build blocked due to critical security issues"
exit 1
- name: Security gate - Warn on HIGH vulnerabilities
if: steps.vuln-check.outputs.high-count > 5
run: |
echo "⚠️ WARNING: Found ${{ steps.vuln-check.outputs.high-count }} HIGH severity vulnerabilities"
echo "πŸ’‘ Consider reviewing and addressing these vulnerabilities"
- name: Upload security artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: security-reports
path: |
trivy-results.sarif
trivy-results.txt
sbom.spdx.json
- name: Upload SARIF results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
category: trivy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment