Skip to content

fix(ci): skip docs-only changes for R-CMD-check, test-fast, test-suite #2

fix(ci): skip docs-only changes for R-CMD-check, test-fast, test-suite

fix(ci): skip docs-only changes for R-CMD-check, test-fast, test-suite #2

# Runs a supplemental OpenSSF Scorecard analysis on every PR and preserves its
# filtered SARIF as an artifact. The central Security Scan workflow owns the
# PR code-scanning upload so this workflow does not duplicate installation API
# calls or fail a clean PR when GitHub's upload quota is spent.
#
# NOTE: Scorecard reports repository-posture findings (branch protection, token
# permissions, dependency pinning, ...) that are unrelated to the PR diff. The
# central Security Scan job therefore treats Scorecard as soft visibility and
# delegates PR-only SAST/vulnerability posture findings to the dedicated
# CodeQL, OSV, Trivy, and dependency-review hard gates.
name: Scorecard PR
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, closed]
branches: [main, master, develop]
concurrency:
group: >-
scorecard-pr-${{
github.event_name == 'pull_request' && github.event.pull_request.base.repo.full_name || github.repository }}-${{
github.event_name == 'pull_request' && github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
analysis:
name: Scorecard
if: github.event.action != 'closed'
runs-on: ubuntu-24.04
permissions:
contents: read
actions: read
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Run analysis
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
# publish_results is only valid on the default branch; PR runs upload
# SARIF to code scanning without publishing to the public OpenSSF API.
publish_results: false
- name: Filter delegated PR-only Scorecard SARIF findings
run: |
python3 <<'PY'
import json
import pathlib
PR_HARD_GATE_RULE_IDS = {"SASTID", "VulnerabilitiesID"}
PR_GOVERNANCE_RULE_IDS = {"FuzzingID"}
PR_DELEGATED_RULE_IDS = PR_HARD_GATE_RULE_IDS | PR_GOVERNANCE_RULE_IDS
sarif_path = pathlib.Path("results.sarif")
sarif = json.loads(sarif_path.read_text(encoding="utf-8"))
hard_gate_delegated = 0
governance_delegated = 0
for run in sarif.get("runs", []):
kept = []
for result in run.get("results", []):
rule_id = result.get("ruleId")
if rule_id in PR_DELEGATED_RULE_IDS:
if rule_id in PR_HARD_GATE_RULE_IDS:
hard_gate_delegated += 1
if rule_id in PR_GOVERNANCE_RULE_IDS:
governance_delegated += 1
continue
kept.append(result)
run["results"] = kept
filtered_path = sarif_path.with_name(f"{sarif_path.name}.filtered")
filtered_path.write_text(json.dumps(sarif, indent=2), encoding="utf-8")
filtered_path.replace(sarif_path)
print(
"Delegated "
f"{hard_gate_delegated} PR-only Scorecard SAST/vulnerability finding(s) to "
"CodeQL, OSV, Trivy, and dependency-review hard gates."
)
print(
"Delegated "
f"{governance_delegated} PR-only Scorecard fuzzing posture finding(s) "
"to default-branch governance tracking."
)
PY
- name: Preserve Scorecard PR SARIF evidence
if: always() && hashFiles('results.sarif') != ''
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: scorecard-pr-sarif-${{ github.run_id }}-${{ github.run_attempt }}
path: results.sarif
retention-days: 7