|
| 1 | +name: Security |
| 2 | + |
| 3 | +# Action SHAs are pinned, not floating tags. To bump: |
| 4 | +# gh api repos/<owner>/<repo>/commits/<tag> --jq .sha |
| 5 | +# (use /commits/<tag>, NOT /git/refs/tags/<tag> — annotated tags would |
| 6 | +# return the tag-object SHA, which Actions can't resolve.) |
| 7 | + |
| 8 | +on: |
| 9 | + push: |
| 10 | + branches: [develop, main] |
| 11 | + pull_request: |
| 12 | + branches: [develop, main] |
| 13 | + schedule: |
| 14 | + # Weekly Monday 06:00 UTC — re-runs the suite against the latest |
| 15 | + # vulnerability databases even when the repo is quiet. |
| 16 | + - cron: "0 6 * * 1" |
| 17 | + |
| 18 | +permissions: |
| 19 | + contents: read |
| 20 | + |
| 21 | +jobs: |
| 22 | + gitleaks: |
| 23 | + name: Secret scan (gitleaks) |
| 24 | + runs-on: ubuntu-latest |
| 25 | + steps: |
| 26 | + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 |
| 27 | + with: |
| 28 | + fetch-depth: 0 # full history so gitleaks can scan every commit |
| 29 | + # Install and run the binary directly — the v2 action attempts to upload |
| 30 | + # a SARIF artifact, which trips the account-wide artifact storage quota |
| 31 | + # on this repo. Running the CLI keeps us to a single blocking step with |
| 32 | + # no artifact output. |
| 33 | + - name: Install gitleaks |
| 34 | + run: | |
| 35 | + VERSION=8.24.3 |
| 36 | + curl -sSL "https://github.com/zricethezav/gitleaks/releases/download/v${VERSION}/gitleaks_${VERSION}_linux_x64.tar.gz" \ |
| 37 | + | tar -xz -C /usr/local/bin gitleaks |
| 38 | + gitleaks version |
| 39 | + - name: Run gitleaks |
| 40 | + run: gitleaks detect --source . --redact --verbose --no-banner --exit-code 1 |
| 41 | + |
| 42 | + pip-audit: |
| 43 | + name: Python deps (pip-audit) |
| 44 | + runs-on: ubuntu-latest |
| 45 | + steps: |
| 46 | + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 |
| 47 | + - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8 |
| 48 | + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 |
| 49 | + with: |
| 50 | + python-version: "3.14" |
| 51 | + - run: uv sync --frozen --extra dev |
| 52 | + - name: Audit production deps |
| 53 | + # --strict fails on ANY surfaced CVE, not just HIGH/CRITICAL. We don't |
| 54 | + # have a volume problem and any CVE in pinned deps is worth a |
| 55 | + # conscious accept-or-upgrade decision. |
| 56 | + # |
| 57 | + # Per-CVE ignores live in .github/security/pip-audit-ignore.txt with |
| 58 | + # a comment per ignore. xargs ferries them onto the command line so |
| 59 | + # the policy stays in version control rather than buried in this YAML. |
| 60 | + run: | |
| 61 | + uv pip install pip-audit |
| 62 | + IGNORES=$(grep -v '^\s*#' .github/security/pip-audit-ignore.txt 2>/dev/null \ |
| 63 | + | grep -v '^\s*$' \ |
| 64 | + | sed 's/^/--ignore-vuln /' \ |
| 65 | + | tr '\n' ' ') |
| 66 | + uv run pip-audit --strict --progress-spinner off \ |
| 67 | + --vulnerability-service osv \ |
| 68 | + $IGNORES |
| 69 | +
|
| 70 | + npm-audit: |
| 71 | + name: Frontend deps (npm audit) |
| 72 | + runs-on: ubuntu-latest |
| 73 | + # Skips cleanly until #21 lands frontend/package.json. |
| 74 | + if: hashFiles('frontend/package-lock.json') != '' |
| 75 | + steps: |
| 76 | + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 |
| 77 | + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 |
| 78 | + with: |
| 79 | + node-version: "24" |
| 80 | + cache: npm |
| 81 | + cache-dependency-path: frontend/package-lock.json |
| 82 | + - run: cd frontend && npm ci |
| 83 | + # --audit-level=high — fail only on high/critical; moderate/low noted |
| 84 | + # but not blocking. |
| 85 | + - run: cd frontend && npm audit --audit-level=high |
| 86 | + |
| 87 | + trivy-image: |
| 88 | + name: Container image scan (trivy) |
| 89 | + runs-on: ubuntu-latest |
| 90 | + # Blocking: any fixable HIGH/CRITICAL CVE in the built image fails the PR. |
| 91 | + steps: |
| 92 | + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 |
| 93 | + - name: Build image |
| 94 | + run: docker build -t harness-python-react:ci . |
| 95 | + - name: Run Trivy vulnerability scanner |
| 96 | + # Pinned to a SHA — never @master. A moving branch in a |
| 97 | + # supply-chain workflow defeats the point of the scan. |
| 98 | + uses: aquasecurity/trivy-action@a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 # v0.36.0 |
| 99 | + with: |
| 100 | + image-ref: harness-python-react:ci |
| 101 | + format: table |
| 102 | + severity: HIGH,CRITICAL |
| 103 | + exit-code: "1" |
| 104 | + ignore-unfixed: true |
| 105 | + vuln-type: os,library |
0 commit comments