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
34 changes: 31 additions & 3 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Scorecard

# OpenSSF Scorecard — scores the repo's supply-chain security posture and (for a
# PUBLIC repo) publishes results + a badge. Results land in the Security tab.
# Delete this file if you don't want it.
# Private forks skip automatically (the visibility gate below); delete if unwanted.

on:
branch_protection_rule:
Expand All @@ -14,12 +14,40 @@ on:
permissions: {}

jobs:
# Publish + SARIF upload need a public repo. Resolve visibility via the API
# (works on every trigger, unlike the schedule event payload) so a private fork
# skips cleanly. Private repo with GitHub Advanced Security? Drop the gate and
# set publish_results: false below (publishing is a public-only path).
visibility:
name: Check repo visibility
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions: {} # gh needs only metadata:read, always granted to GITHUB_TOKEN
outputs:
public: ${{ steps.check.outputs.public }}
steps:
- id: check
env:
GH_TOKEN: ${{ github.token }}
run: |
visibility="$(gh api "repos/$GITHUB_REPOSITORY" --jq '.visibility')" || true
case "$visibility" in
public) echo "public=true" >> "$GITHUB_OUTPUT" ;;
private|internal) echo "public=false" >> "$GITHUB_OUTPUT" ;; # intended clean skip, silent
*)
echo "::warning::Could not resolve repo visibility (got '$visibility') — Scorecard skipped"
echo "public=false" >> "$GITHUB_OUTPUT"
;;
esac

analysis:
name: Scorecard analysis
needs: visibility
if: needs.visibility.outputs.public == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: read # checkout (required on private forks)
contents: read
security-events: write # upload SARIF to code scanning
id-token: write # publish results to OpenSSF
steps:
Expand All @@ -31,7 +59,7 @@ jobs:
with:
results_file: results.sarif
results_format: sarif
# Needs a PUBLIC repo; set false on a private fork (or delete this workflow).
# Publishes results + badge to OpenSSF.
publish_results: true

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ If you prefer to set up manually instead of using `/onboard`:
- All trigger on `v*` tags. `publish-pypi.yml` still fails until you rename the package and configure PyPI Trusted Publishing; delete whichever publish workflow (and its stub) you don't need.
- [ ] Enable GitHub Discussions (Settings > General > Features) — issue template config links to it
- [ ] Enable CodeQL default setup (Settings > Security > Code scanning)
- [ ] OpenSSF Scorecard (`.github/workflows/scorecard.yml`) needs a **public** repo to publish its score/badge — delete the workflow if the repo is private
- [ ] OpenSSF Scorecard (`.github/workflows/scorecard.yml`) needs a **public** repo to publish its score/badge — on a private fork it skips automatically, so delete it only if you don't want it at all
- [ ] Publish docs (optional) — **GitHub Pages**: set Settings > Pages > Source = "GitHub Actions", then rename `.github/workflows/pages.yml.example` → `pages.yml` (single-version). **Versioned**: rename `.readthedocs.yaml.example` → `.readthedocs.yaml` and import the repo at readthedocs.org. Pick one; the docs *build* is already checked on every PR either way
- [ ] Enable secret scanning with push protection (Settings > Security > Secret Protection)
- [ ] Configure branch ruleset for `main` — require PR reviews, require CI to pass, block force pushes
Expand Down