1 Commits
v1 .. v2
2 changed files with 176 additions and 0 deletions

No files matched your search

+12
View File
@@ -29,3 +29,15 @@ Both inputs are required so the consumer is explicit about source. Wire them to
## Versioning
The repo follows lightweight tags: `v1`, `v1.0.0`, etc. Consumers pin to `@v1` for in-major updates, or `@<sha>` for full pinning.
## `scan` — SBOM, osv-scanner and the triage report (v2)
`uses: https://git.janhouse.lv/janhouse/sbom-tools-action/scan@v2` uploads the
repo's source SBOM to Dependency-Track, runs osv-scanner over the repo, and
reports to dtrack-panel which images the repo builds and its
`osv-scanner.toml` `[[IgnoredVulns]]`. The panel's auto-triage then marks
those NOT_AFFECTED in Dependency-Track — for the CI project and for the app's
own dependency tree in the running images — and closes CI-project findings for
dependencies that never reach the image (dev/build-time). Inputs and an example
are in `scan/action.yml`. Authenticates with the same
`DEPENDENCY_TRACK_API_KEY` the upload uses; no extra secret.
+164
View File
@@ -0,0 +1,164 @@
name: 'SBOM + triage report'
description: >
Source SBOM to Dependency-Track, osv-scanner over the repo, and a report to
dtrack-panel (the images this repo builds + its osv-scanner.toml decisions)
so the panel's auto-triage can apply them to the CI project and the running
images.
author: 'janhouse'
# Usage (a repo's .gitea/workflows/sbom.yml):
# - uses: actions/checkout@v4
# - uses: https://git.janhouse.lv/janhouse/sbom-tools-action/scan@v2
# with:
# project: Janhouse-Web
# images: git.janhouse.lv/private-docker/janhouse-cms
# dtrack-url: ${{ secrets.DEPENDENCY_TRACK_URL }}
# dtrack-api-key: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
#
# osv-scanner.toml [[IgnoredVulns]] are NOT_AFFECTED decisions: dtrack-panel
# writes them to Dependency-Track for this repo's own dependencies (the CI
# project, and the app's dependency tree in the images). A reason may start
# with a CycloneDX justification: "code_not_reachable: we never parse XML".
# They don't expire unless ignoreUntil says so — re-check them when the code
# that uses the package changes (see the repo's AGENTS.md).
inputs:
project:
description: 'Dependency-Track project name for this repo (the CI project)'
required: true
project-version:
description: 'Dependency-Track project version'
default: 'latest'
images:
description: 'Images this repo builds, comma or newline separated, without tag (git.janhouse.lv/janhouse/app)'
default: ''
container-image:
description: 'Optional: also include this image''s OS packages in the CI SBOM (merged)'
default: ''
container-skip-files:
description: 'With container-image: trivy --skip-files glob for the app dir already covered by the lockfile scan'
default: '/app/**'
path:
description: 'Directory to scan'
default: '.'
dtrack-url:
description: 'Dependency-Track base URL (secrets.DEPENDENCY_TRACK_URL)'
required: true
dtrack-api-key:
description: 'Dependency-Track API key with BOM upload (secrets.DEPENDENCY_TRACK_API_KEY)'
required: true
panel-url:
description: 'dtrack-panel CI report URL (default: <dtrack-url>/panel-ci/report)'
default: ''
trivy-version:
# 0.70.0 is the newest Trivy emitting CycloneDX 1.6 (see dtrack-docker-scanner's Dockerfile)
default: 'v0.70.0'
cyclonedx-version:
default: 'v0.27.2'
osv-scanner-version:
default: 'v2.7.0'
runs:
using: composite
steps:
- name: Cache SBOM tools
id: cache
uses: actions/cache@v4
with:
path: ~/.local/sbom-tools
key: sbom-scan-${{ runner.os }}-trivy-${{ inputs.trivy-version }}-cdx-${{ inputs.cyclonedx-version }}-osv-${{ inputs.osv-scanner-version }}
- name: Install Trivy, CycloneDX CLI, osv-scanner
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
env:
TRIVY_VERSION: ${{ inputs.trivy-version }}
CDX_VERSION: ${{ inputs.cyclonedx-version }}
OSV_VERSION: ${{ inputs.osv-scanner-version }}
run: |
set -euo pipefail
d=~/.local/sbom-tools; mkdir -p "$d"
curl -sSfL "https://raw.githubusercontent.com/aquasecurity/trivy/${TRIVY_VERSION}/contrib/install.sh" | sh -s -- -b "$d" "${TRIVY_VERSION}"
curl -sSfL "https://github.com/CycloneDX/cyclonedx-cli/releases/download/${CDX_VERSION}/cyclonedx-linux-x64" -o "$d/cyclonedx-cli"
curl -sSfL "https://github.com/google/osv-scanner/releases/download/${OSV_VERSION}/osv-scanner_linux_amd64" -o "$d/osv-scanner"
chmod +x "$d"/*
- name: Add tools to PATH
shell: bash
run: echo "$HOME/.local/sbom-tools" >> "$GITHUB_PATH"
- name: Source SBOM (lockfiles)
shell: bash
env:
SCAN_PATH: ${{ inputs.path }}
CONTAINER_IMAGE: ${{ inputs.container-image }}
CONTAINER_SKIP: ${{ inputs.container-skip-files }}
run: |
set -euo pipefail
trivy fs "$SCAN_PATH" --quiet --timeout 20m --format cyclonedx --output source-sbom.json
if [ -n "$CONTAINER_IMAGE" ]; then
trivy image "$CONTAINER_IMAGE" --quiet --timeout 20m --skip-files "$CONTAINER_SKIP" \
--format cyclonedx --output container-sbom.json
cyclonedx-cli merge --input-files container-sbom.json source-sbom.json \
--output-file sbom.json --output-format json
else
cp source-sbom.json sbom.json
fi
echo "SBOM: $(jq '.components | length' sbom.json) components"
- name: Upload SBOM to Dependency-Track
shell: bash
env:
DTRACK_URL: ${{ inputs.dtrack-url }}
DTRACK_API_KEY: ${{ inputs.dtrack-api-key }}
PROJECT: ${{ inputs.project }}
PROJECT_VERSION: ${{ inputs.project-version }}
run: |
set -euo pipefail
tag=$(git describe --exact-match --tags 2>/dev/null || git rev-parse --short HEAD)
jq -n --arg n "$PROJECT" --arg v "$PROJECT_VERSION" --arg t "$tag" --rawfile bom <(base64 -w0 sbom.json) \
'{projectName: $n, projectVersion: $v, autoCreate: true, isLatestProjectVersion: true,
projectTags: [{name: $t}], bom: $bom}' > payload.json
curl -fsS -X PUT "${DTRACK_URL%/}/api/v1/bom" \
-H "X-Api-Key: ${DTRACK_API_KEY}" -H "Content-Type: application/json" \
--data-binary @payload.json
echo; echo "Uploaded ${PROJECT} @ ${PROJECT_VERSION} (${tag})"
- name: osv-scanner (informational)
shell: bash
continue-on-error: true
env:
SCAN_PATH: ${{ inputs.path }}
run: |
# Exit 1 = vulnerabilities found; this step only reports. Go call
# analysis runs when the Go toolchain is on the runner.
osv-scanner scan source -r "$SCAN_PATH" --format table || true
- name: Report to dtrack-panel (images + osv-scanner.toml)
shell: bash
continue-on-error: true
env:
DTRACK_URL: ${{ inputs.dtrack-url }}
DTRACK_API_KEY: ${{ inputs.dtrack-api-key }}
PANEL_URL: ${{ inputs.panel-url }}
PROJECT: ${{ inputs.project }}
IMAGES: ${{ inputs.images }}
SCAN_PATH: ${{ inputs.path }}
REPO: ${{ github.repository }}
COMMIT: ${{ github.sha }}
run: |
set -euo pipefail
url=${PANEL_URL:-${DTRACK_URL%/}/panel-ci/report}
images=$(printf '%s' "$IMAGES" | tr ',' '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep -v '^$' | jq -R . | jq -s .)
tomls='[]'
while IFS= read -r f; do
tomls=$(jq --arg p "$f" --rawfile c "$f" '. + [{path: $p, content: $c}]' <<<"$tomls")
done < <(find "$SCAN_PATH" -name osv-scanner.toml -not -path '*/node_modules/*' -not -path '*/.git/*' | head -20)
jq -n --arg repo "$REPO" --arg commit "$COMMIT" --arg project "$PROJECT" \
--argjson images "$images" --argjson tomls "$tomls" \
'{repo: $repo, commit: $commit, project: $project, images: $images, osvScannerToml: $tomls}' > report.json
echo "Reporting $(jq '.images | length' report.json) image(s), $(jq '.osvScannerToml | length' report.json) osv-scanner.toml file(s) to ${url}"
curl -fsS -X POST "$url" -H "X-Api-Key: ${DTRACK_API_KEY}" -H "Content-Type: application/json" \
--data-binary @report.json -o response.json
echo "Applied on the panel's next sync. Still open (not triaged):"
jq -r '.open[] | " \(.project): \(.n) \(.severity)"' response.json || true