From security
Scaffold OpenSSF Scorecard GitHub Action on a public repo with a safe two-phase rollout — first run with publish_results false so SARIF findings can be triaged before any score reaches the public dashboard, then flip to true and add a badge once the score is acceptable. Refuses to install on private/internal repos. Subcommand `fix` turns a Scorecard report into a remediation plan and applies it. Use when the user says "add OpenSSF", "set up Scorecard", "OpenSSF boilerplate", "fix the scorecard findings", or "/security:openssf".
How this skill is triggered — by the user, by Claude, or both
Slash command
/security:openssf [install | fix] [args][install | fix] [args]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are managing the [OpenSSF Scorecard](https://github.com/ossf/scorecard) GitHub Action for the current repo, via `/security:openssf [subcommand]`.
You are managing the OpenSSF Scorecard GitHub Action for the current repo, via /security:openssf [subcommand].
| Subcommand | Reference | What it does |
|---|---|---|
install | this file (below) | Scaffold the Scorecard workflow with a safe two-phase rollout (phase 1 publish_results: false, then phase 2 flip + badge). Default subcommand. |
fix | references/fix.md | Take the findings from a Scorecard run, write a bucketed remediation plan, then apply the file-based fixes and offer the settings-based ones. |
Parse the first whitespace-separated token of the arguments:
fix → read references/fix.md and follow it with the remaining arguments.- (--help/-h) → print the subcommand table and stop.install, empty, or anything else → run the install workflow in this file (/security:openssf ≡ /security:openssf install).fix; "add OpenSSF"/"set up Scorecard" → install. If ambiguous, ask.installYou are adding the OpenSSF Scorecard GitHub Action to the current repo and walking the user through a two-phase rollout so a poor first score never lands on the public dashboard:
publish_results: false. Results stay private in the repo's Security tab (SARIF). The user triages findings without anyone outside the repo seeing the score.publish_results: true and add the scorecard badge to the README so the live score is visible at scorecard.dev.This skill stops between phases. Do not flip to phase 2 in the same session unless the user explicitly asks — the gap is the whole point.
# 1. We're in a git repo with a GitHub remote
gh repo view --json visibility,defaultBranchRef,nameWithOwner 2>/dev/null \
|| { echo "Not a GitHub repo (or gh not authed). Abort."; exit 1; }
Capture:
VISIBILITY (PUBLIC / PRIVATE / INTERNAL)DEFAULT_BRANCH (most often main)REPO (owner/name)Visibility gate — refuse on private/internal repos. No exceptions.
| Repo visibility | Action |
|---|---|
| Public | Proceed with phase 1. |
| Private / Internal | Refuse. Stop. |
Empirically verified on a real private repo: the Scorecard action hard-fails before producing any SARIF —
scorecard had an error: internal error: ListCommits:
error during graphqlHandler.setup:
internal error: githubv4.Query: Resource not accessible by integration
The default GITHUB_TOKEN can't run the GraphQL queries Scorecard needs against a private repository. A fine-grained PAT via the action's repo_token input works around this, but adding that complexity defeats the point of a boilerplate, and the public-score outcome still doesn't apply. Don't install it.
If the repo is private/internal, say:
This repo is private. Scorecard hard-fails on private repos under the default GitHub token (
Resource not accessible by integration), and the public scorecard.dev dashboard refuses private repos either way — installing the workflow now would just generate weekly failure emails. Re-run /security:openssf after you flip the repo to public.
That's it — no install, no escape hatches, end the session.
Tag-pinning (@v2) is the Scorecard tutorial default but is itself a low-Pinned-Dependencies finding that the workflow you're installing will flag. Resolve a recent release SHA up front:
gh release view --repo ossf/scorecard-action --json tagName,targetCommitish
# Then resolve the tag to its full SHA:
gh api repos/ossf/scorecard-action/git/refs/tags/<tagName> --jq '.object.sha'
Record both <SHA> and <tagName> — write the SHA into the workflow and the tag as a comment so Dependabot can still recognize and bump it.
If the user pushes back on SHA-pinning (some teams prefer the tag), respect that — note the trade-off and use the tag.
.github/workflows/scorecard.ymlUse the template at assets/scorecard.yml. Substitute:
__DEFAULT_BRANCH__ → captured default branch (e.g. main)__SCORECARD_SHA__ → resolved commit SHA__SCORECARD_TAG__ → human-readable tag (in the trailing comment)publish_results stays false for phase 1Create the directory if needed:
mkdir -p .github/workflows
Show the user the file you're about to write, then write it. Do NOT commit — let the user commit when they're ready. (Their commit hook may run lint/format first; respect that.)
After the user pushes the workflow, on the next push to the default branch and weekly thereafter:
results_format: sarif, and SARIF carries per-check scores (embedded in each finding's message) but not the rolled-up Aggregate score: X/10 number — that line only appears under the default/json formats. To see a readable per-check breakdown, point the user at scripts/scorecard-report.sh (see step 5 / Triage below) rather than telling them to hunt in the log.End the session with a short summary and a clear "next step" for the user:
Wrote .github/workflows/scorecard.yml (publish_results: false)
What to do next:
1. Commit & push the workflow on a branch.
2. Merge to <default-branch> — Scorecard only runs on the default branch.
3. Wait for the first run to finish on <default-branch>.
4. See a readable per-check report:
${CLAUDE_PLUGIN_ROOT}/skills/openssf/scripts/scorecard-report.sh --fetch <owner>/<repo>
(or open Security → Code scanning for the same findings in the UI.)
5. Triage the findings (this skill can help in a second session).
6. When the score is acceptable, re-invoke /security:openssf and ask to go public.
Do not loop into phase 2 the same session. The whole point is to let the workflow actually run and the user actually look at the output.
Start by showing the user a readable report. Don't make them parse SARIF or hunt the Actions log. Run the bundled renderer, which downloads the latest run's SARIF artifact and prints failing checks (score + severity + reason, highest severity first) above the passing ones:
${CLAUDE_PLUGIN_ROOT}/skills/openssf/scripts/scorecard-report.sh --fetch <owner>/<repo>
# or render a SARIF file you already have:
${CLAUDE_PLUGIN_ROOT}/skills/openssf/scripts/scorecard-report.sh path/to/results.sarif
It needs jq (and gh for --fetch). It deliberately does not print an
aggregate score — SARIF doesn't contain one. If the user specifically wants the
weighted 0-10 number before publishing, run Scorecard locally with a non-SARIF
format (scorecard --repo=github.com/<owner>/<repo> --format=default, needs a
$GITHUB_TOKEN); the report footer repeats this hint.
If the user comes back mid-rollout asking "what does this finding mean" or "how do I fix Token-Permissions", help them on a per-check basis. The high-impact, low-effort fixes — in roughly the order users want to tackle them:
| Finding | Typical fix |
|---|---|
| Token-Permissions | Add permissions: read-all (or scoped per-job) to every workflow. One line, no behavior change. |
| Pinned-Dependencies | Pin Actions to commit SHAs. Dependabot can do this with package-ecosystem: github-actions. |
| Dangerous-Workflow | Audit for pull_request_target + checkout of PR head. Replace with pull_request or split into two workflows. |
| Branch-Protection | Enable required reviews + status checks on the default branch via repo settings. |
| Code-Review | Enforce 1+ reviewer in branch protection. Solo-maintainer repos legitimately can't pass this; that's OK. |
| Security-Policy | Add a SECURITY.md at repo root with a contact channel. |
| Signed-Releases | Sign release artifacts via cosign or use gh release create with attestation. Skip if the repo doesn't publish releases. |
| Dependency-Update-Tool | Add a one-file .github/dependabot.yml with the relevant package-ecosystems. |
| CII-Best-Practices | Self-attestation at bestpractices.coreinfrastructure.org. Easy +score if the project is mature. |
| Fuzzing / SAST | These are high-effort and often legitimately not applicable. Don't push the user to fake them. |
Some checks (Maintained, Vulnerabilities, License, Contributors, Binary-Artifacts, Packaging, Webhooks) are derived from repo state, not workflow config — they're either passing or they aren't, and the fix is project-shape work, not a YAML edit.
When advising on fixes, separate the score-improving change from the security-improving change. Enabling permissions: read-all actually makes the workflow safer. "Adding a SECURITY.md so the check passes" is paperwork. The user is entitled to both, but they should know which is which.
Only enter this phase when the user explicitly asks (e.g. "go public", "publish results", "phase 2"). Confirm three things before editing:
Repo is public. Re-check gh repo view --json visibility. If it's flipped to private since phase 1, refuse — publish_results: true will fail the job.
At least one phase-1 run completed. gh run list --workflow=scorecard.yml --limit 1 should show a successful run. If it never ran, the phase-1 install is broken; fix that before publishing.
The user is OK with what will land on scorecard.dev. Show them the per-check report from the most recent run — not an aggregate-score grep of the log, which returns nothing under results_format: sarif:
${CLAUDE_PLUGIN_ROOT}/skills/openssf/scripts/scorecard-report.sh --fetch <owner>/<repo>
Walk through the "NEEDS ATTENTION" checks (especially the high-severity ones) so the user sees exactly what the public score reflects. If several high-severity checks are failing, ask explicitly: "This — including these failing checks — will be publicly visible at scorecard.dev/viewer/?uri=github.com/. Proceed?" If the user wants the exact weighted 0-10 number first, run Scorecard locally with --format=default (the report footer shows the command); otherwise the per-check view is enough to make an informed call.
Two changes to .github/workflows/scorecard.yml:
publish_results: false → publish_results: trueid-token: write is present under permissions: (the template already has it — verify it wasn't removed during triage). This is required for OIDC signing of the published result.Show the diff before writing.
After the next workflow run on the default branch publishes results, the badge URL is:
[](https://scorecard.dev/viewer/?uri=github.com/__REPO_OWNER__/__REPO_NAME__)
Substitute the captured <owner>/<name>. Drop it near the top of the README, alongside any existing CI/license badges. Show the diff; let the user commit.
Note: the badge will 404 until the first published run completes — usually a few minutes after merge. Tell the user this so they don't think the badge is broken.
Flipped publish_results → true.
Badge added to README.
After your next push to <default-branch>:
- Scorecard publishes to https://scorecard.dev/viewer/?uri=github.com/<repo>
- Badge in README will resolve once the published run completes (~5 min after the workflow finishes)
To roll back: revert this commit. The dashboard entry will go stale (no new
data) but old scores remain visible — you cannot un-publish historical scores.
The irreversibility of historical publication is the single thing the user most needs to know before they merge phase 2.
main first.publish_results: true is wasted effort — scorecard.dev keys on the canonical repo. Recommend skipping; if the user insists, phase 1 only.scorecard.yml under .github/workflows/. Read it, diff against the template, and ask before overwriting. The user may have customized it.--fix automation to address findings. Out of scope for this skill — point at the per-check fixes above and let them open PRs.publish_results: true without the gates in phase 2. A bad first public score is hard to unwind because old scores remain in the dashboard history.npx claudepluginhub zcaceres/skills --plugin securityProvides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.