Skip to content

feat: security hardening + rewrite README for portfolio #16

feat: security hardening + rewrite README for portfolio

feat: security hardening + rewrite README for portfolio #16

Workflow file for this run

name: CI Pipeline
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches:
- main
jobs:
# ============================================================================
# STAGE 1: Fast Validation (< 2 min)
# ============================================================================
validation:
name: Code Validation
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
# Terraform validation
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
- name: Terraform Format Check
run: terraform fmt -check -recursive terraform/
continue-on-error: false
- name: Terraform Init
run: |
cd terraform
terraform init -backend=false
- name: Terraform Validate
run: |
cd terraform
terraform validate -no-color
# YAML validation
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install yamllint
run: pip install yamllint
- name: YAML Lint
run: |
yamllint -f parsable \
docker/docker-compose.yml \
terraform/cloud-init.yaml \
.github/workflows/*.yml
# Docker Compose validation
- name: Validate docker-compose.yml
run: |
cd docker
docker compose config --quiet
# Markdown validation
- name: Markdown Lint
run: |
FILES=$(find . -name "*.md" -not -path "*/\.terraform/*" -not -path "*/node_modules/*" -not -path "*/.git/*")
if [ -n "$FILES" ]; then
echo "$FILES" | xargs npx markdownlint-cli2
fi
# ShellCheck
- name: ShellCheck
uses: ludeeus/action-shellcheck@master
with:
scandir: './scripts'
severity: warning
ignore_paths: '.git .terraform'
# ============================================================================
# STAGE 2: Security Scans (runs after validation)
# ============================================================================
security:
name: Security Scanning
runs-on: ubuntu-latest
needs: validation
steps:
- name: Checkout code
uses: actions/checkout@v4
# Terraform security
- name: Run tfsec
uses: aquasecurity/tfsec-action@v1.0.3
with:
working_directory: terraform
soft_fail: false
additional_args: --minimum-severity MEDIUM
# IaC security scan
- name: Run Trivy IaC scan
uses: aquasecurity/trivy-action@master
with:
scan-type: 'config'
scan-ref: '.'
format: 'table'
severity: 'MEDIUM,HIGH,CRITICAL'
exit-code: '1'
skip-dirs: '.git,.terraform,node_modules'
# Secret detection
- name: Run Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ============================================================================
# STAGE 3: Docker Checks (runs after validation, parallel with security)
# ============================================================================
docker:
name: Docker Checks
runs-on: ubuntu-latest
needs: validation
steps:
- name: Checkout code
uses: actions/checkout@v4
# Docker Compose security
- name: Trivy Docker Compose scan
uses: aquasecurity/trivy-action@master
with:
scan-type: 'config'
scan-ref: 'docker/docker-compose.yml'
format: 'table'
severity: 'MEDIUM,HIGH,CRITICAL'
exit-code: '1'
# Custom Docker security checks
- name: Check for privileged containers
run: |
if grep -q "privileged.*true" docker/docker-compose.yml; then
echo "❌ ERROR: Privileged containers found!"
exit 1
fi
echo "✅ No privileged containers"
- name: Check Docker socket permissions
run: |
if grep -q "/var/run/docker.sock.*:rw" docker/docker-compose.yml; then
echo "❌ ERROR: Docker socket mounted as read-write!"
exit 1
fi
echo "✅ Docker socket permissions OK"
- name: Check for hardcoded secrets
run: |
PATTERNS="password:|secret:|api_key:|token:"
if grep -iE "$PATTERNS" docker/docker-compose.yml | grep -v "GITHUB_TOKEN\|secrets\."; then
echo "❌ ERROR: Potential hardcoded secrets found!"
exit 1
fi
echo "✅ No hardcoded secrets detected"
# ============================================================================
# STAGE 4: PR Automation (parallel with security/docker)
# ============================================================================
pr-automation:
name: PR Automation
runs-on: ubuntu-latest
needs: validation
if: github.event_name == 'pull_request'
permissions:
pull-requests: write
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
# PR Info
- name: PR Information
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
console.log('PR Information:');
console.log(`- Title: ${pr.title}`);
console.log(`- Author: ${pr.user.login}`);
console.log(`- Base: ${pr.base.ref}`);
console.log(`- Head: ${pr.head.ref}`);
console.log(`- Files changed: ${pr.changed_files}`);
console.log(`- Additions: +${pr.additions}`);
console.log(`- Deletions: -${pr.deletions}`);
# Auto-labeling
- name: Auto Label PR
uses: actions/labeler@v5
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: .github/labeler.yml
# Size labeling
- name: Add Size Label
uses: codelytv/pr-size-labeler@v1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
xs_label: 'size/XS'
xs_max_size: 10
s_label: 'size/S'
s_max_size: 100
m_label: 'size/M'
m_max_size: 500
l_label: 'size/L'
l_max_size: 1000
xl_label: 'size/XL'
# Conventional commits (informational only)
- name: Validate Conventional Commits
uses: wagoid/commitlint-github-action@v6
continue-on-error: true
with:
configFile: .github/commitlint.config.mjs
failOnWarnings: false
failOnErrors: false
helpURL: 'https://www.conventionalcommits.org'
# ============================================================================
# STAGE 5: Summary (runs after all checks)
# ============================================================================
summary:
name: CI Summary
runs-on: ubuntu-latest
needs: [validation, security, docker, pr-automation]
if: always()
steps:
- name: Check Results
run: |
echo "## CI Pipeline Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.validation.result }}" == "success" ] && \
[ "${{ needs.security.result }}" == "success" ] && \
[ "${{ needs.docker.result }}" == "success" ]; then
echo "✅ **All checks passed!**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Code Validation" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Security Scanning" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Docker Checks" >> $GITHUB_STEP_SUMMARY
exit 0
else
echo "❌ **Some checks failed**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- ${{ needs.validation.result == 'success' && '✅' || '❌' }} Code Validation" >> $GITHUB_STEP_SUMMARY
echo "- ${{ needs.security.result == 'success' && '✅' || '❌' }} Security Scanning" >> $GITHUB_STEP_SUMMARY
echo "- ${{ needs.docker.result == 'success' && '✅' || '❌' }} Docker Checks" >> $GITHUB_STEP_SUMMARY
exit 1
fi