Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/actions.lock
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ dependencies:
owner_id: 47606891
repo_id: 331103973
'github/codeql-action@cdf488f595d80d6e07e03d4674febd5ab45fa938':
ref: 'v4.37.9'
ref: 'cdf488f595d80d6e07e03d4674febd5ab45fa938'
commit: 'sha1-cdf488f595d80d6e07e03d4674febd5ab45fa938'
owner_id: 9919
repo_id: 259445878
Expand All @@ -202,7 +202,7 @@ dependencies:
owner_id: 1841483
repo_id: 220799100
'ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc':
ref: 'v2.4.4'
ref: '2d1146689b8cda280b9bc96326124645441f03bc'
commit: 'sha1-2d1146689b8cda280b9bc96326124645441f03bc'
owner_id: 67707773
repo_id: 421101922
Expand Down
99 changes: 91 additions & 8 deletions .github/workflows/scorecard-reusable.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
name: OSSF Scorecard Reusable Workflow

on:
workflow_call:

# NOTE: This workflow requires security-events: write and id-token: write
# to publish scorecard results. Callers MUST grant these permissions.
# The previous attempt to add only `actions: read` at top-level (0ced540e) failed
# because it exceeded caller grants. The fix is to declare ALL required permissions
# at the top-level so callers know what to grant.
# Callers must grant contents: read, security-events: write and id-token: write.
# Only default-branch publication receives OIDC; PR analysis cannot publish
# unmerged results to the public Scorecard dataset or badge.
permissions:
contents: read
security-events: write
id-token: write

jobs:
scorecard:
if: github.event_name != 'pull_request'
name: Run Scorecard
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
security-events: write
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -34,7 +36,7 @@ jobs:
# publish_results feeds the public OpenSSF API and the badge, and is
# INDEPENDENT of results_format -- so emitting SARIF does not cost us
# the badge. Both outputs are live with this shape.
publish_results: true
publish_results: ${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}

# RESTORED 2026-08-25. Commit 5a93d9d5 (PR #393, "Ci/gitleaks self hosted
# fix", 2026-06-21) deleted this step and switched results_format to json
Expand All @@ -54,3 +56,84 @@ jobs:
name: scorecard-results
path: results.sarif
retention-days: 90

pull-request:
if: github.event_name == 'pull_request'
name: Run Scorecard PR
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
security-events: write
steps:
- name: Checkout pull request
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha }}
# OpenSSF labels pull_request support experimental. Upload actual results;
# a failed scan or upload must fail the workflow, not become a clean gate.
- name: Analyze pull request
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
with:
results_file: results.sarif
results_format: sarif
publish_results: false
# scorecard-action forces Local (filesystem) mode on pull_request events,
# so the PR run only ever produces the supply-chain/local category. The
# code-scanning ruleset evaluates Scorecard per category and main's
# scheduled run also carries supply-chain/branch-protection and
# supply-chain/online-scm, so a PR is "expecting 2 results" forever.
# Those two categories are repo-state properties (branch protection, CI,
# code review, maintenance), not properties of a commit, and scorecard
# refuses to compute them for a non-HEAD --commit. So measure them at
# repository HEAD with the pinned scorecard CLI, restricted to exactly the
# repo-level checks, and merge the runs into the same SARIF. The local
# category stays the scorecard-action measurement of the PR tree.
- name: Install scorecard CLI (pinned + checksum-verified)
run: |
set -euo pipefail
SCORECARD_VERSION=5.5.0
SHA256=83b90a05c1540ef1390db1cd5711e5fd04be9c1d8537fb84d39d02092d6a8dff
cd "$RUNNER_TEMP"
curl -fsSL --proto "=https" --proto-redir "=https" -o scorecard.tar.gz \
"https://github.com/ossf/scorecard/releases/download/v${SCORECARD_VERSION}/scorecard_${SCORECARD_VERSION}_linux_amd64.tar.gz"
echo "${SHA256} scorecard.tar.gz" | sha256sum -c -
tar -xzf scorecard.tar.gz scorecard
chmod +x scorecard
./scorecard version
- name: Measure repo-level checks at HEAD
env:
ENABLE_SARIF: "1"
GITHUB_AUTH_TOKEN: ${{ github.token }}
# Policy file from scorecard-action at the same pinned SHA as above.
POLICY_URL: https://raw.githubusercontent.com/ossf/scorecard-action/2d1146689b8cda280b9bc96326124645441f03bc/policies/template.yml
POLICY_SHA256: 6e75dcc0df989d333492c0e1f6e484fc5b4d26ab768333ddcd0e3788539689b0
run: |
set -euo pipefail
curl -fsSL --proto "=https" --proto-redir "=https" -o "$RUNNER_TEMP/policy.yml" "$POLICY_URL"
echo "${POLICY_SHA256} $RUNNER_TEMP/policy.yml" | sha256sum -c -
"$RUNNER_TEMP/scorecard" \
--repo="github.com/${GITHUB_REPOSITORY}" \
--checks=Branch-Protection,CI-Tests,CII-Best-Practices,Code-Review,Contributors,Maintained,Signed-Releases \
--format=sarif --policy="$RUNNER_TEMP/policy.yml" --show-details \
> "$RUNNER_TEMP/repo-state.sarif"
# Merge: keep every run from the PR-tree scan, append the repo-level
# runs. Fail if the result is not exactly the three categories.
jq -s '.[0] as $pr | .[1] as $head | $pr | .runs += $head.runs' \
results.sarif "$RUNNER_TEMP/repo-state.sarif" > merged.sarif
mv merged.sarif results.sarif
jq -r '.runs[].automationDetails.id' results.sarif
n=$(jq '[.runs[].automationDetails.id | split("/")[0:2] | join("/")] | unique | length' results.sarif)
test "$n" -eq 3 || { echo "expected 3 Scorecard categories, got $n" >&2; exit 1; }
- name: Upload SARIF to code scanning
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
with:
sarif_file: results.sarif
- name: Retain scan evidence
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: scorecard-pr-results
path: results.sarif
if-no-files-found: error
retention-days: 14
12 changes: 9 additions & 3 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
name: Scorecard

on:
push:
branches: [main]
pull_request:
schedule:
- cron: '0 0 * * 0'
workflow_dispatch:
Expand All @@ -15,11 +19,13 @@ concurrency:
# id-token: write is the OIDC token Scorecard uses to publish results;
# security-events: write uploads the SARIF.
permissions:
actions: read
contents: read
security-events: write
id-token: write

jobs:
scorecard:
permissions:
actions: read
contents: read
security-events: write
Comment thread
hyperpolymath marked this conversation as resolved.
Dismissed
id-token: write
uses: ./.github/workflows/scorecard-reusable.yml
Loading