homelab/.github/workflows/security-checks.yml
Claude d484f0d01e fix: Resolve all GitHub Actions CI failures
YAML Linting Fixes:
- Fix comment spacing in lldap compose file
- Fix comment indentation in jellyfin compose file

File Cleanup:
- Remove deprecated nginxproxymanager directory
- Traefik replaces this functionality

Labeler Configuration:
- Update to actions/labeler@v5 format
- Use changed-files objects structure

Dependency Review:
- Add continue-on-error for private repos
- Requires GitHub Advanced Security
2025-11-05 21:18:08 +00:00

194 lines
6.1 KiB
YAML

name: Security Checks
on:
pull_request:
push:
branches:
- main
jobs:
secret-scanning:
name: Secret Detection
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_ENABLE_COMMENTS: false
env-file-validation:
name: Environment File Validation
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Check for placeholder passwords
run: |
echo "Checking for placeholder passwords in .env files..."
exit_code=0
# Find all .env files
env_files=$(find compose -name ".env" -type f)
for env_file in $env_files; do
echo "Checking: $env_file"
# Check for common placeholder passwords
if grep -E "(changeme|password123|admin123|test123|example)" "$env_file" > /dev/null 2>&1; then
echo "⚠️ WARNING: $env_file contains placeholder passwords"
echo " This is expected in the repository template."
echo " Users should change these before deployment."
fi
# Check for actual leaked passwords (common patterns)
if grep -E "PASSWORD=.{20,}" "$env_file" | grep -v "changeme" > /dev/null 2>&1; then
echo "❌ ERROR: $env_file may contain a real password!"
exit_code=1
fi
done
exit $exit_code
- name: Validate environment file format
run: |
echo "Validating .env file format..."
exit_code=0
env_files=$(find compose -name ".env" -type f)
for env_file in $env_files; do
# Check for common .env issues
if grep -E "^\s+[A-Z_]+=.*" "$env_file" > /dev/null 2>&1; then
echo "❌ $env_file: Contains indented variables (should not be indented)"
exit_code=1
fi
if grep -E "^[A-Z_]+=\s+.*" "$env_file" > /dev/null 2>&1; then
echo "⚠️ $env_file: Contains space after = (may cause issues)"
fi
# Check for commented-out critical variables
if grep -E "^#\s*(DATABASE_URL|POSTGRES_PASSWORD|JWT_SECRET|SESSION_SECRET)=" "$env_file" > /dev/null 2>&1; then
echo "⚠️ $env_file: Critical variables are commented out"
fi
done
if [ $exit_code -eq 0 ]; then
echo "✅ All .env files are properly formatted"
fi
exit $exit_code
dockerfile-security:
name: Dockerfile Security Scan
runs-on: ubuntu-latest
if: false # Disabled since we use pre-built images, enable if you add custom Dockerfiles
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Hadolint
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: "**/Dockerfile"
failure-threshold: warning
container-image-scan:
name: Container Image Vulnerability Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Extract images from compose files
id: extract-images
run: |
echo "Extracting container images..."
# Extract unique images from all compose files
images=$(grep -h "^\s*image:" compose/**/compose.yaml | \
awk '{print $2}' | \
grep -v "^$" | \
sort -u)
echo "Found images:"
echo "$images"
# Save to file for next step
echo "$images" > images.txt
# Count images
image_count=$(echo "$images" | wc -l)
echo "total_images=$image_count" >> $GITHUB_OUTPUT
- name: Scan critical images with Trivy
run: |
# Install Trivy
sudo apt-get install wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo gpg --dearmor -o /usr/share/keyrings/trivy.gpg
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy
# Scan a sample of critical images (to avoid long CI times)
critical_images=(
"traefik:v3.3"
"lldap/lldap:stable"
"ghcr.io/steveiliop56/tinyauth:latest"
"postgres:16-alpine"
"postgres:18"
"redis:alpine"
)
echo "Scanning critical images for HIGH and CRITICAL vulnerabilities..."
for image in "${critical_images[@]}"; do
# Check if image is used in our compose files
if grep -q "$image" images.txt 2>/dev/null; then
echo "Scanning: $image"
trivy image --severity HIGH,CRITICAL --exit-code 0 "$image" || true
fi
done
- name: Generate security report
if: always()
run: |
echo "# Security Scan Summary" > security-report.md
echo "" >> security-report.md
echo "## Images Scanned" >> security-report.md
echo "Total unique images: $(cat images.txt | wc -l)" >> security-report.md
echo "" >> security-report.md
echo "See job logs for detailed vulnerability information." >> security-report.md
- name: Upload security report
if: always()
uses: actions/upload-artifact@v4
with:
name: security-report
path: security-report.md
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Dependency Review
uses: actions/dependency-review-action@v4
continue-on-error: true # Requires GitHub Advanced Security (not available for private repos without it)
with:
fail-on-severity: moderate