Skip to content

Scope releaser permissions and bind the tag expression #12998

Scope releaser permissions and bind the tag expression

Scope releaser permissions and bind the tag expression #12998

Workflow file for this run

name: Security Scan
on:
# Called by run-on-main.yml on push to main, where image-build-and-push gates
# on the result. There is deliberately no `push:` trigger here as well — that
# would run every scan twice for each push to main.
workflow_call:
workflow_dispatch:
# PRs trigger this directly rather than through run-on-pr.yml, for the same
# reason. Unfiltered by branch, to match the coverage run-on-pr.yml gave.
pull_request:
schedule:
# Run daily at 2 AM UTC
- cron: '0 2 * * *'
# security-events: write is granted per job rather than here, so only the two
# jobs that upload SARIF can write security events.
permissions:
contents: read
jobs:
grype-repo-scan:
name: Grype Repository Scan
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false
- name: Run Grype vulnerability scanner
id: grype-scan
uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7.4.0
with:
path: "."
output-format: "sarif"
fail-build: false
- name: Upload Grype scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
if: always()
with:
sarif_file: ${{ steps.grype-scan.outputs.sarif }}
category: "grype"
zizmor:
name: GitHub Actions Static Analysis
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
# --no-exit-codes stops *findings* failing the job; this stops a tool or
# network failure doing so. Both come off when the gate goes blocking.
continue-on-error: true
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
# This job only reads the workflow files; it never pushes.
persist-credentials: false
# Advisory only for now: --no-exit-codes keeps the job green while the
# existing backlog is worked through, so this reports without blocking.
# Remove it (and add --min-severity) once the backlog is clear.
#
# Results are written straight to SARIF and never echoed. Workflow logs
# and job summaries are world-readable on a public repository, so
# printing findings would publish them; the SARIF upload keeps them in
# the Security tab, which requires write access to read.
- name: Run zizmor
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
pipx run zizmor==1.29.0 \
--persona=regular \
--format=sarif \
--no-exit-codes \
--no-progress \
.github/ > zizmor.sarif
# Pull requests from forks get a read-only token, so the upload is
# skipped there; those workflows are still scanned on push to main.
- name: Upload zizmor results to GitHub Security tab
uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
if: always() && !github.event.pull_request.head.repo.fork
with:
sarif_file: zizmor.sarif
category: "zizmor"
govulncheck:
name: Go Vulnerability Check
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false
- name: Run govulncheck
uses: golang/govulncheck-action@032d45514ae346b1db93c04b0c90b841c370344f # v1
with:
go-version-input: 'stable'
go-package: ./...
repo-checkout: false
output-format: json
output-file: govulncheck-output.json
- name: Check for vulnerabilities (with exclusions)
run: |
# Ignored vulnerabilities with justification:
# Go stdlib advisories published 2026-06-02, all fixed in go1.26.4 /
# go1.25.11 (DoS / log-injection class, no RCE):
# GO-2026-5037 (CVE-2026-27145, crypto/x509 VerifyHostname)
# GO-2026-5038 (CVE-2026-42504, mime WordDecoder.DecodeHeader)
# GO-2026-5039 (CVE-2026-42507, net/textproto error messages)
# CI's `setup-go: stable` still resolves to go1.26.3 because the
# actions/go-versions manifest lags the Go release. Temporary
# exclusion; remove once CI builds on go1.26.4 or later.
#
# GO-2026-5932: golang.org/x/crypto/openpgp is deprecated-by-design
# ("unsafe, not maintained, should not be used"). No fixed version
# exists and none is planned. ToolHive does not import openpgp
# directly; it is pulled transitively via sigstore (rekor/sigstore-go)
# for backward-compatible OpenPGP verification. Remove when sigstore
# drops the openpgp dependency.
IGNORED_VULNS="GO-2026-5037 GO-2026-5038 GO-2026-5039 GO-2026-5932"
# Show the raw output for debugging
echo "::group::govulncheck raw output"
cat govulncheck-output.json
echo "::endgroup::"
# Extract vulnerability IDs that have actual findings (called symbols)
# The JSON has "finding" objects with "osv" field only for vulnerabilities
# where vulnerable code paths are actually called
FOUND_VULNS=$(jq -r 'select(.finding != null) | .finding.osv' govulncheck-output.json | sort -u | grep -E '^GO-' || true)
if [ -z "$FOUND_VULNS" ]; then
echo "✅ No vulnerabilities found"
exit 0
fi
echo "Found vulnerabilities: $FOUND_VULNS"
# Check if all found vulnerabilities are in the ignore list
UNIGNORED=""
for vuln in $FOUND_VULNS; do
if ! echo "$IGNORED_VULNS" | grep -qw "$vuln"; then
UNIGNORED="$UNIGNORED $vuln"
fi
done
UNIGNORED=$(echo "$UNIGNORED" | xargs)
if [ -z "$UNIGNORED" ]; then
echo "⚠️ All vulnerabilities are ignored: $FOUND_VULNS"
exit 0
fi
echo "❌ Vulnerabilities need attention: $UNIGNORED"
exit 1