149 lines
5.8 KiB
YAML
149 lines
5.8 KiB
YAML
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Aegis — Security Scan pipeline.
|
|
# Milestone M0: Trivy (SCA/IaC/secrets gate) + Gitleaks (secrets).
|
|
# This is the CANONICAL workflow; it is mirrored (copy) into target app repos
|
|
# (CannaManage first, then plate-auth / Sparkboard / InspectFlow). Repo-specific
|
|
# differences are repo-type (image vs source), not scanner config.
|
|
#
|
|
# P0 fixes applied (from docs/planning/12 + 14):
|
|
# F-05 scanner actions pinned to exact versions (never @master)
|
|
# EP-W2 timeout-minutes: 10 on every job (prevents stalled DB downloads)
|
|
# EP-W1 Trivy DefectDojo-bound run uses --scanners vuln (no secret values in JSON)
|
|
#
|
|
# Deferred to later milestones:
|
|
# M1 Semgrep (SAST) + Syft (SBOM) + Checkov (IaC) jobs
|
|
# M3 DefectDojo push steps (needs DefectDojo running — deployed in M2)
|
|
# M5 Cosign image signing + SBOM attestation
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
name: Security Scan
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
schedule:
|
|
- cron: '0 2 * * *' # 02:00 UTC daily — nightly deep scan
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
# ── Trivy: SCA + IaC + secrets. GATE blocks on HIGH/CRITICAL. ──────────────
|
|
trivy:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10 # EP-W2
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
# GATE — block the build on HIGH/CRITICAL findings (defense in depth).
|
|
# Human-readable table in the CI log. Suppressions: .trivyignore (CVE IDs).
|
|
- name: Trivy gate (block HIGH/CRITICAL)
|
|
uses: aquasecurity/trivy-action@0.24.0 # F-05: pinned, never @master
|
|
with:
|
|
scan-type: fs
|
|
scan-ref: .
|
|
severity: HIGH,CRITICAL
|
|
exit-code: '1'
|
|
format: table
|
|
|
|
# REPORT — full JSON for DefectDojo (M3). EP-W1: --scanners vuln SKIPS the
|
|
# secret scanner so real secret values are never written to the artifact.
|
|
# (Secret detection is Gitleaks' job below; Trivy's would leak values.)
|
|
- name: Trivy full report (vulns only — safe for DefectDojo)
|
|
if: always()
|
|
uses: aquasecurity/trivy-action@0.24.0
|
|
with:
|
|
scan-type: fs
|
|
scan-ref: .
|
|
scanners: vuln
|
|
format: json
|
|
output: trivy-report.json
|
|
|
|
- name: Upload Trivy report
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: trivy-report
|
|
path: trivy-report.json
|
|
retention-days: 30
|
|
|
|
# M3 will add: "Push to DefectDojo" step here
|
|
# (curl --fail --retry 3 --retry-delay 5 ... /api/v2/import-scan/).
|
|
|
|
# ── Gitleaks: hardcoded secrets. BLOCK on any leak (exit-code 1). ───────────
|
|
gitleaks:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10 # EP-W2
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0 # full history — leaks can be in any commit
|
|
|
|
- name: Gitleaks scan
|
|
uses: gitleaks/gitleaks-action@v2 # F-05: pinned
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Gitea provides this
|
|
# Blocks (exit-code 1) on any detected secret. Suppress individual
|
|
# false positives in .gitleaksignore (rule IDs only — never real values).
|
|
|
|
# M3 will add: upload gitleaks-report + DefectDojo push.
|
|
|
|
# ── Semgrep: SAST. WARN (report only — tune rules before gating). ──────────
|
|
semgrep:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10 # EP-W2
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Semgrep SAST scan
|
|
# F-01: the DefectDojo-bound run emits JSON (semgrep ci --json), NOT SARIF
|
|
# — DD's "Semgrep JSON Report" parser expects semgrep's native --json schema.
|
|
uses: returntocorp/semgrep-action@v1.80.0 # F-05: pinned (R-05)
|
|
with:
|
|
config: >-
|
|
p/owasp-top-ten p/python p/java p/typescript
|
|
scanners/semgrep-rules.yml
|
|
- name: Semgrep JSON report (for DefectDojo, M3)
|
|
if: always()
|
|
run: |
|
|
semgrep ci --json \
|
|
--output=semgrep-results.json \
|
|
--config "p/owasp-top-ten p/python p/java p/typescript scanners/semgrep-rules.yml" || true
|
|
- name: Upload Semgrep report
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: semgrep-report
|
|
path: semgrep-results.json
|
|
retention-days: 30
|
|
|
|
# ── Syft: SBOM (CycloneDX JSON). INFO (supply-chain inventory, R-09 retention). ─
|
|
sbom:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10 # EP-W2
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Generate SBOM
|
|
uses: anchor/sbom-action@v0.17.0 # F-05: pinned
|
|
with:
|
|
format: cyclonedx-json
|
|
output-file: sbom.json
|
|
- name: Upload SBOM artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: sbom-cyclonedx
|
|
path: sbom.json
|
|
retention-days: 90 # supply-chain audit trail (R-09)
|
|
|
|
# ── Checkov: IaC scan (Dockerfiles, compose, Kubernetes, Terraform). ────────
|
|
checkov:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10 # EP-W2
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Checkov IaC scan
|
|
uses: bridgecrewio/checkov-action@v12 # F-05: pinned
|
|
with:
|
|
directory: .
|
|
framework: dockerfile,terraform,kubernetes
|
|
output_format: cli,sarif
|
|
output_file_path: console,checkov-results.sarif
|
|
#soft_fail: true # M1 = WARN; flip to block once baselined
|