CI:
This commit is contained in:
+34
-31
@@ -35,46 +35,49 @@ jobs:
|
||||
set -e
|
||||
docker build -t "${IMAGE}:${GITHUB_SHA}" -t "${IMAGE}:latest" .
|
||||
|
||||
# --- Feature 4: Trivy vulnerability scan (gate) --------------------------
|
||||
# Install the Trivy binary from the official script (the runner reaches the
|
||||
# internet; a pinned binary is more reproducible here than the
|
||||
# trivy-action, which resolves from github.com/master). The scan runs
|
||||
# against the locally-built image over the runner's docker.sock.
|
||||
- name: Install Trivy
|
||||
run: |
|
||||
set -e
|
||||
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh \
|
||||
| sh -s -- -b /usr/local/bin v0.58.1
|
||||
trivy --version
|
||||
|
||||
# Gate: fail ci on any fixable CRITICAL/HIGH so a vulnerable image never
|
||||
# gets pushed or deployed. ignore-unfixed keeps the gate real but avoids
|
||||
# failing on distro CVEs with no available fix (nginx:alpine currently has
|
||||
# zero fixable CRITICAL/HIGH — the gate passes clean but is genuinely
|
||||
# enforcing). --scanners vuln keeps it to CVEs (no secret/misconfig noise).
|
||||
# --- Feature 4: Trivy vulnerability scan (gate) + SBOM ------------------
|
||||
# Trivy runs from its official container over the runner's docker.sock, so
|
||||
# there is no fragile binary install and it can scan the locally-built
|
||||
# image. A shared cache + shared workdir are bind-mounted; the SBOM is
|
||||
# written to the job workspace so the upload step can find it. A single
|
||||
# `docker run` per action keeps the runner-in-runner path simple.
|
||||
- name: Trivy scan (gate CRITICAL,HIGH)
|
||||
run: |
|
||||
set -e
|
||||
trivy image \
|
||||
--exit-code 1 \
|
||||
--severity CRITICAL,HIGH \
|
||||
--ignore-unfixed \
|
||||
--scanners vuln \
|
||||
--no-progress \
|
||||
"${IMAGE}:${GITHUB_SHA}"
|
||||
# Gate: fail ci on any fixable CRITICAL/HIGH so a vulnerable image never
|
||||
# gets pushed or deployed. ignore-unfixed keeps the gate real but avoids
|
||||
# failing on distro CVEs with no available fix (nginx:alpine currently
|
||||
# has zero fixable CRITICAL/HIGH — the gate passes clean but is
|
||||
# genuinely enforcing). --scanners vuln keeps it to CVEs.
|
||||
docker run --rm \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v trivy-cache:/root/.cache/ \
|
||||
aquasec/trivy:0.58.1 image \
|
||||
--exit-code 1 \
|
||||
--severity CRITICAL,HIGH \
|
||||
--ignore-unfixed \
|
||||
--scanners vuln \
|
||||
--no-progress \
|
||||
"${IMAGE}:${GITHUB_SHA}"
|
||||
echo "trivy gate passed (no fixable CRITICAL/HIGH)"
|
||||
|
||||
# --- Feature 4: SBOM (CycloneDX) generation + artifact upload -----------
|
||||
- name: Generate SBOM (CycloneDX)
|
||||
if: always()
|
||||
run: |
|
||||
set -e
|
||||
trivy image \
|
||||
--format cyclonedx \
|
||||
--scanners vuln \
|
||||
--no-progress \
|
||||
--output sbom.cdx.json \
|
||||
"${IMAGE}:${GITHUB_SHA}"
|
||||
# Write the SBOM to trivy's stdout and redirect it into the job
|
||||
# workspace. A bind-mounted --output would land on the HOST path
|
||||
# (docker.sock is the host daemon, so a sibling container's -v resolves
|
||||
# host-side, not inside this job container); the stdout redirect writes
|
||||
# straight into the job filesystem where the upload step can find it.
|
||||
docker run --rm \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v trivy-cache:/root/.cache/ \
|
||||
aquasec/trivy:0.58.1 image \
|
||||
--format cyclonedx \
|
||||
--scanners vuln \
|
||||
--no-progress \
|
||||
"${IMAGE}:${GITHUB_SHA}" > sbom.cdx.json
|
||||
echo "SBOM components: $(python3 -c 'import json; print(len(json.load(open("sbom.cdx.json")).get("components",[])))' 2>/dev/null || echo n/a)"
|
||||
ls -l sbom.cdx.json
|
||||
|
||||
|
||||
Reference in New Issue
Block a user