From e056df2a8729d1dbeecd5f5f89a49dcdc1f2394f Mon Sep 17 00:00:00 2001 From: ms280690 Date: Fri, 29 May 2026 11:38:59 -0700 Subject: [PATCH 1/3] fix: scorecard publish_results=false; add SECURITY.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scorecard/action.yml: - Change publish_results default from true to false. The scorecard webapp verifies the calling workflow directly invokes ossf/scorecard-action as a job step; composite action wrapping hides that call so publication always fails with 400 "workflow has no job that calls ossf/scorecard-action". SARIF still uploads to GitHub Security tab. Callers wanting public database publication must call ossf/scorecard-action directly. - Update description to document the architectural constraint. README.md: - Add note explaining the publish_results composite-action limitation with workaround instructions. SECURITY.md: - Add security policy satisfying scorecard Security-Policy check criteria: email contact, HTTPS URL, free-form disclosure text, vuln/disclosure keywords, 30/90-day timeline. - Improves scorecard Security-Policy score from 0 → expected 10. Co-Authored-By: Claude Sonnet 4.6 --- .github/actions/scorecard/action.yml | 12 ++++++-- README.md | 5 +++- SECURITY.md | 45 ++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 SECURITY.md diff --git a/.github/actions/scorecard/action.yml b/.github/actions/scorecard/action.yml index 204f1ec..8a274b5 100644 --- a/.github/actions/scorecard/action.yml +++ b/.github/actions/scorecard/action.yml @@ -1,11 +1,17 @@ name: "OpenSSF Scorecard" description: | - Runs OpenSSF Scorecard checks, uploads SARIF to the GitHub Security tab, and publishes results to the OpenSSF database. + Runs OpenSSF Scorecard checks and uploads SARIF to the GitHub Security tab. Required permissions on calling job: id-token: write, security-events: write, actions: read, contents: read + + NOTE: publish_results defaults to false. The scorecard webapp verifies that the + calling workflow directly invokes ossf/scorecard-action as a job step. Composite + action wrapping hides that call, so publication always fails with a 400 error. + To publish to the OpenSSF database, call ossf/scorecard-action directly in your + workflow instead of using this composite action. inputs: publish_results: - description: "Publish results to the public OpenSSF Scorecard database and generate the Scorecard badge. Set to false for private repositories." - default: "true" + description: "Publish results to the public OpenSSF Scorecard database. Only works when ossf/scorecard-action is called directly (not via a composite action). See action description." + default: "false" runs: using: "composite" steps: diff --git a/README.md b/README.md index 6c2d5b8..aad3f8e 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,9 @@ jobs: ### OpenSSF Scorecard -Requires `id-token: write` for OIDC signing. Only runs on public repos with `publish_results: true`. +Requires `id-token: write` for OIDC signing. SARIF is always uploaded to the GitHub Security tab. + +> **Note on `publish_results`:** The scorecard webapp verifies that the calling workflow directly invokes `ossf/scorecard-action` as a job step. Composite action wrapping hides that call, so `publish_results: true` always fails with a 400 error. This composite action therefore defaults `publish_results` to `false`. To publish results to the public OpenSSF database and generate the Scorecard badge, call `ossf/scorecard-action` directly in your workflow. ```yaml jobs: @@ -78,6 +80,7 @@ jobs: with: persist-credentials: false - uses: sparkgeo/github-actions/.github/actions/scorecard@ + # publish_results defaults to false — see note above ``` ### Dependency Review diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..a24ebbd --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,45 @@ +# Security Policy + +## Reporting a Vulnerability + +**Do not open a public GitHub issue for security vulnerabilities.** + +Report vulnerabilities via the [GitHub Security Advisory](../../security/advisories/new) process: + +1. Go to the **Security** tab of this repository. +2. Click **Report a vulnerability**. +3. Fill in the advisory form with a description, affected versions, and reproduction steps. + +Alternatively, email **info@sparkgeo.com** with the subject line `[SECURITY] sparkgeo/github-actions`. + +## Disclosure Timeline + +| Phase | Target | +|---|---| +| Acknowledgement | Within 2 business days of receipt | +| Initial assessment | Within 5 business days | +| Fix or mitigation | Within 30 days for high/critical; 90 days for moderate/low | +| Public disclosure | After fix is released, or 90 days from report (whichever comes first) | + +We follow coordinated vulnerability disclosure. If we cannot ship a fix within 90 days, we will notify the reporter and agree on an extended timeline before any public disclosure. + +## Scope + +This repository contains reusable GitHub Actions composite actions. Vulnerabilities in scope include: + +- Supply chain risks in pinned action SHAs or version references +- Script injection via user-controlled context variables in workflow or action YAML +- Overly permissive `GITHUB_TOKEN` permissions that could be exploited +- Secrets or credentials inadvertently exposed in workflow logs or artifacts +- Logic errors in composite actions that could cause callers to grant unintended access + +Out of scope: vulnerabilities in third-party actions referenced by this repo (report those upstream). We will update our pinned SHA if a referenced action releases a security patch. + +## Supported Versions + +This repo does not use versioned releases. All consumers should pin to a specific commit SHA and update via Dependabot or Renovate (see `docs/approved-actions.md`). Only the current `main` branch is actively maintained. + +## Security Contacts + +- GitHub Security Advisory (preferred): https://github.com/sparkgeo/github-actions/security/advisories/new +- Email: info@sparkgeo.com From 5eec5b9ee75f83706833a3741cfaba827de65bc6 Mon Sep 17 00:00:00 2001 From: ms280690 Date: Fri, 29 May 2026 11:41:41 -0700 Subject: [PATCH 2/3] =?UTF-8?q?fix(ci):=20remove=20paths=20filter=20?= =?UTF-8?q?=E2=80=94=20run=20CI=20on=20all=20pushes=20to=20main?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .github/** paths filter caused CI to skip on doc/README-only pushes. This improved SAST and CI-Tests scorecard checks require CI to run on every commit to main to score higher. Remove the filter so all pushes trigger the full job matrix. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ad4783..52d4e07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,8 +5,6 @@ name: CI on: push: branches: [main] - paths: - - '.github/**' pull_request: schedule: - cron: '0 6 * * 1' # weekly Monday 06:00 UTC — for scorecard From a3134777d2c6ad9dd31ed6eab72566fa2f9b2de1 Mon Sep 17 00:00:00 2001 From: ms280690 Date: Fri, 29 May 2026 12:00:54 -0700 Subject: [PATCH 3/3] fix(scorecard): remove id-token:write, simplify if condition, strengthen publish_results warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ci.yml: - Remove id-token: write from scorecard job — publish_results defaults to false, no OIDC token is ever consumed; permission was dangling over-privilege - Simplify scorecard if: condition — github.ref == 'refs/heads/main' already excludes PRs (they use refs/pull/*/merge), making the event_name check redundant scorecard/action.yml: - Remove id-token: write from required permissions in description - Upgrade publish_results warning from NOTE to WARNING with explicit HTTP 400 error message; input retained for callers who read docs but footgun is clear README.md: - Remove id-token: write from scorecard example and prose - Update table row: publish_results default was incorrectly shown as true - Warn callers explicitly that setting publish_results: true always fails Co-Authored-By: Claude Sonnet 4.6 --- .github/actions/scorecard/action.yml | 18 +++++++++++------- .github/workflows/ci.yml | 3 +-- README.md | 9 ++++----- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.github/actions/scorecard/action.yml b/.github/actions/scorecard/action.yml index 8a274b5..b9383e4 100644 --- a/.github/actions/scorecard/action.yml +++ b/.github/actions/scorecard/action.yml @@ -1,16 +1,20 @@ name: "OpenSSF Scorecard" description: | Runs OpenSSF Scorecard checks and uploads SARIF to the GitHub Security tab. - Required permissions on calling job: id-token: write, security-events: write, actions: read, contents: read + Required permissions on calling job: security-events: write, actions: read, contents: read - NOTE: publish_results defaults to false. The scorecard webapp verifies that the - calling workflow directly invokes ossf/scorecard-action as a job step. Composite - action wrapping hides that call, so publication always fails with a 400 error. - To publish to the OpenSSF database, call ossf/scorecard-action directly in your - workflow instead of using this composite action. + WARNING — publish_results: this input is a known footgun. The OpenSSF scorecard webapp + verifies that the calling workflow directly invokes ossf/scorecard-action as a job step. + Composite action wrapping hides that call. Setting publish_results: true will ALWAYS fail + with HTTP 400 "workflow has no job that calls ossf/scorecard-action". The default is false + and should remain false. To publish to the OpenSSF public database, call + ossf/scorecard-action directly in your workflow instead of using this composite action. inputs: publish_results: - description: "Publish results to the public OpenSSF Scorecard database. Only works when ossf/scorecard-action is called directly (not via a composite action). See action description." + description: | + WARNING: always fails with HTTP 400 when set to true. The scorecard webapp cannot see + through composite action wrapping to verify the ossf/scorecard-action call. Keep false + (default). To actually publish, call ossf/scorecard-action directly in your workflow. default: "false" runs: using: "composite" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52d4e07..441671d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,12 +51,11 @@ jobs: scorecard: name: OpenSSF Scorecard runs-on: ubuntu-latest - if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' permissions: contents: read actions: read security-events: write - id-token: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: diff --git a/README.md b/README.md index aad3f8e..7ad77d3 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ gh api repos/sparkgeo/github-actions/commits/main --jq '.sha' |---|---|---|---| | GitHub Actionlint | [`github-actionlint`](.github/actions/github-actionlint/action.yml) | Lints workflow and action YAML files using actionlint via reviewdog; posts annotations as GitHub Checks | None | | Zizmor | [`zizmor`](.github/actions/zizmor/action.yml) | Runs zizmor static security analysis against workflow and action YAML files; uploads findings as SARIF to the Security tab | None | -| OpenSSF Scorecard | [`scorecard`](.github/actions/scorecard/action.yml) | Runs OpenSSF Scorecard checks; uploads SARIF to the Security tab and publishes results to the OpenSSF database | `publish_results` (default: `true` — set to `false` for private repos) | +| OpenSSF Scorecard | [`scorecard`](.github/actions/scorecard/action.yml) | Runs OpenSSF Scorecard checks; uploads SARIF to the Security tab | `publish_results` (default: `false` — always fails with HTTP 400 if set to `true`; see action description) | | Dependency Review | [`dependency-review`](.github/actions/dependency-review/action.yml) | Blocks PRs introducing dependencies with known vulnerabilities or denied licenses; posts a summary comment | `fail-on-severity` (default: `high`), `deny-licenses` (default: `GPL-2.0,GPL-3.0,AGPL-3.0`), `comment-summary-in-pr` (default: `on-failure`) | | Storage Optimizer | [`storage-optimizer`](.github/actions/storage-optimizer/action.yml) | Frees disk space on GitHub-hosted runners by removing unused toolchains (JDK, .NET, Swift, Android SDK, etc.) and pruning Docker | None | | Terramate + OpenTofu Setup | [`terramate-opentofu-setup`](.github/actions/terramate-opentofu-setup/action.yml) | Installs Terramate and OpenTofu, validates generated files are up to date, initialises changed stacks, and lists changed stacks | `opentofu_version` (default: `1.10.0`), `terramate_version` (default: `0.14.7`) | @@ -62,9 +62,9 @@ jobs: ### OpenSSF Scorecard -Requires `id-token: write` for OIDC signing. SARIF is always uploaded to the GitHub Security tab. +SARIF is always uploaded to the GitHub Security tab. Does not require `id-token: write` — `publish_results` defaults to `false` and no OIDC token is consumed. -> **Note on `publish_results`:** The scorecard webapp verifies that the calling workflow directly invokes `ossf/scorecard-action` as a job step. Composite action wrapping hides that call, so `publish_results: true` always fails with a 400 error. This composite action therefore defaults `publish_results` to `false`. To publish results to the public OpenSSF database and generate the Scorecard badge, call `ossf/scorecard-action` directly in your workflow. +> **Note on `publish_results`:** Setting `publish_results: true` always fails with HTTP 400. The scorecard webapp verifies that the calling workflow directly invokes `ossf/scorecard-action` as a job step — composite action wrapping hides that call. Keep the default (`false`). To publish to the public OpenSSF database, call `ossf/scorecard-action` directly in your workflow. ```yaml jobs: @@ -74,13 +74,12 @@ jobs: contents: read actions: read security-events: write - id-token: write steps: - uses: actions/checkout@ with: persist-credentials: false - uses: sparkgeo/github-actions/.github/actions/scorecard@ - # publish_results defaults to false — see note above + # publish_results defaults to false — do not set to true (always fails with HTTP 400) ``` ### Dependency Review