From 74f6f3538d0eccdd987b4bfeec2dbd9ef44d1a47 Mon Sep 17 00:00:00 2001 From: ms280690 Date: Mon, 1 Jun 2026 11:22:06 -0700 Subject: [PATCH 1/3] feat: run all CI jobs on push to main; add CI status badge to README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ci.yml: - dependency-review: also run on push to main. Passes base-ref/head-ref from push event context (event.before → sha) so the composite action can compare the pushed range. On PRs, base-ref is empty and the action reads PR context. - storage-optimizer: also run on push to main to demonstrate end-to-end. Previously gated to workflow_dispatch only. dependency-review/action.yml: - Add base-ref and head-ref inputs (default empty) for non-PR invocation. - Two conditional steps: PR path (base-ref == '') uses built-in PR context; push path (base-ref != '') passes explicit commit range. scorecard/action.yml: - Add Print scorecard summary step that emits findings to the Actions log so maintainers do not need to download the SARIF artifact to see scores. README.md: - Add CI workflow status badge linking to the latest main branch run. Co-Authored-By: Claude Sonnet 4.6 --- .github/actions/dependency-review/action.yml | 15 +++++++++++++++ .github/actions/scorecard/action.yml | 15 +++++++++++++++ .github/workflows/ci.yml | 14 +++++++++----- README.md | 2 ++ 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/.github/actions/dependency-review/action.yml b/.github/actions/dependency-review/action.yml index 6d2ee88..24f71ec 100644 --- a/.github/actions/dependency-review/action.yml +++ b/.github/actions/dependency-review/action.yml @@ -10,11 +10,26 @@ inputs: comment-summary-in-pr: description: "Post a summary comment on the PR: always|on-failure|never" default: "on-failure" + base-ref: + description: "Base commit SHA for non-PR events (e.g. github.event.before on push). Leave empty on pull_request — the action reads PR context automatically." + default: "" + head-ref: + description: "Head commit SHA for non-PR events (e.g. github.sha on push). Leave empty on pull_request." + default: "" runs: using: "composite" steps: - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 + if: ${{ inputs.base-ref == '' }} with: fail-on-severity: ${{ inputs.fail-on-severity }} deny-licenses: ${{ inputs.deny-licenses }} comment-summary-in-pr: ${{ inputs.comment-summary-in-pr }} + - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 + if: ${{ inputs.base-ref != '' }} + with: + base-ref: ${{ inputs.base-ref }} + head-ref: ${{ inputs.head-ref }} + fail-on-severity: ${{ inputs.fail-on-severity }} + deny-licenses: ${{ inputs.deny-licenses }} + comment-summary-in-pr: ${{ inputs.comment-summary-in-pr }} diff --git a/.github/actions/scorecard/action.yml b/.github/actions/scorecard/action.yml index b9383e4..04d3ffb 100644 --- a/.github/actions/scorecard/action.yml +++ b/.github/actions/scorecard/action.yml @@ -34,6 +34,21 @@ runs: retention-days: 5 if-no-files-found: ignore + - name: Print scorecard summary + if: always() && hashFiles('scorecard-results.sarif') != '' + shell: bash + run: | + echo "=== OpenSSF Scorecard Results ===" + findings=$(jq -r ' + .runs[].results[]? | + " [\(.ruleId | gsub("ID$";""))] \(.message.text | split("\n")[0])" + ' scorecard-results.sarif) + if [[ -z "$findings" ]]; then + echo " All checks passed" + else + echo "$findings" + fi + - uses: github/codeql-action/upload-sarif@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 if: always() && hashFiles('scorecard-results.sarif') != '' with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 441671d..e796103 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,11 +64,13 @@ jobs: - uses: ./.github/actions/scorecard # Review dependency changes for vulnerabilities and license issues. - # Only meaningful on pull_request — requires PR base/head context. + # On pull_request: compares PR base/head via built-in event context. + # On push to main: compares the pushed range (event.before → sha) so maintainers + # can see the action work end-to-end without opening a PR. dependency-review: name: Dependency Review runs-on: ubuntu-latest - if: github.event_name == 'pull_request' + if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main') permissions: contents: read pull-requests: write @@ -78,6 +80,9 @@ jobs: persist-credentials: false - uses: ./.github/actions/dependency-review + with: + base-ref: ${{ github.event_name == 'push' && github.event.before || '' }} + head-ref: ${{ github.event_name == 'push' && github.sha || '' }} # Verify Terramate and OpenTofu are installed correctly. # Terramate stack steps are no-ops in this repo (no stacks defined). @@ -95,12 +100,11 @@ jobs: - uses: ./.github/actions/terramate-opentofu-setup # Verify the storage optimizer composite action runs without error. - # Gated to workflow_dispatch: storage-optimizer is only useful when a job does - # heavy disk work on the same runner; running it on a throwaway CI runner wastes minutes. + # Runs on push to main (demonstration) and workflow_dispatch (on-demand). storage-optimizer: name: Storage Optimizer runs-on: ubuntu-latest - if: github.event_name == 'workflow_dispatch' + if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main') permissions: contents: read steps: diff --git a/README.md b/README.md index 7ad77d3..82e2738 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # sparkgeo/github-actions +[![CI](https://github.com/sparkgeo/github-actions/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/sparkgeo/github-actions/actions/workflows/ci.yml) + Reusable GitHub Actions composite actions and CI workflow for the Sparkgeo organisation. All action references in this repo are pinned to full commit SHAs. See [CONTRIBUTING.md](CONTRIBUTING.md) for authoring standards and how to add new actions. From 358910d29739e742ac5591b8d5d1abf606de410c Mon Sep 17 00:00:00 2001 From: ms280690 Date: Mon, 1 Jun 2026 11:34:17 -0700 Subject: [PATCH 2/3] fix(dependency-review): replace deny-licenses with allow-licenses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit deny-licenses is deprecated for removal in the next major release of actions/dependency-review-action (see upstream issue #997). Switch to the allow-licenses allowlist approach which is more robust — it catches unlisted copyleft and commercial licenses automatically rather than requiring all problem licenses to be enumerated explicitly. Default allow-list: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, Unlicense, CC0-1.0 — permissive licences appropriate for a commercial org. Update composite action inputs and both conditional steps (PR path and push path). Update README table and example snippet. Co-Authored-By: Claude Sonnet 4.6 --- .github/actions/dependency-review/action.yml | 12 ++++++------ README.md | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/actions/dependency-review/action.yml b/.github/actions/dependency-review/action.yml index 24f71ec..a5f208d 100644 --- a/.github/actions/dependency-review/action.yml +++ b/.github/actions/dependency-review/action.yml @@ -1,12 +1,12 @@ name: "Dependency Review" -description: "Blocks PRs that introduce dependencies with known vulnerabilities or denied licenses; posts a summary comment on the PR." +description: "Blocks PRs that introduce dependencies with known vulnerabilities or non-permitted licenses; posts a summary comment on the PR." inputs: fail-on-severity: description: "Minimum vulnerability severity to fail: critical|high|moderate|low" default: "high" - deny-licenses: - description: "Comma-separated list of SPDX license identifiers to deny" - default: "GPL-2.0,GPL-3.0,AGPL-3.0" + allow-licenses: + description: "Comma-separated list of SPDX license identifiers that are permitted. Dependencies using any other license will fail the check." + default: "MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, Unlicense, CC0-1.0" comment-summary-in-pr: description: "Post a summary comment on the PR: always|on-failure|never" default: "on-failure" @@ -23,7 +23,7 @@ runs: if: ${{ inputs.base-ref == '' }} with: fail-on-severity: ${{ inputs.fail-on-severity }} - deny-licenses: ${{ inputs.deny-licenses }} + allow-licenses: ${{ inputs.allow-licenses }} comment-summary-in-pr: ${{ inputs.comment-summary-in-pr }} - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 if: ${{ inputs.base-ref != '' }} @@ -31,5 +31,5 @@ runs: base-ref: ${{ inputs.base-ref }} head-ref: ${{ inputs.head-ref }} fail-on-severity: ${{ inputs.fail-on-severity }} - deny-licenses: ${{ inputs.deny-licenses }} + allow-licenses: ${{ inputs.allow-licenses }} comment-summary-in-pr: ${{ inputs.comment-summary-in-pr }} diff --git a/README.md b/README.md index 82e2738..e8ccef0 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,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 | `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`) | +| Dependency Review | [`dependency-review`](.github/actions/dependency-review/action.yml) | Blocks PRs introducing dependencies with known vulnerabilities or non-permitted licenses; posts a summary comment | `fail-on-severity` (default: `high`), `allow-licenses` (default: `MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, Unlicense, CC0-1.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`) | @@ -102,9 +102,9 @@ jobs: persist-credentials: false - uses: sparkgeo/github-actions/.github/actions/dependency-review@ with: - fail-on-severity: high # critical | high | moderate | low - deny-licenses: GPL-2.0,AGPL-3.0 # SPDX identifiers - comment-summary-in-pr: always # always | on-failure | never + fail-on-severity: high # critical | high | moderate | low + allow-licenses: MIT, Apache-2.0, BSD-2-Clause # SPDX identifiers; deps with other licenses fail + comment-summary-in-pr: always # always | on-failure | never ``` ### Storage Optimizer From e046fb1ac4cd41b1efc451e6c317e7a4082d30d7 Mon Sep 17 00:00:00 2001 From: ms280690 Date: Mon, 1 Jun 2026 11:45:40 -0700 Subject: [PATCH 3/3] fix: address PR review findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ci.yml: - Skip dependency-review on push when event.before is the zero SHA (first push to branch — no base commit to compare against). dependency-review/action.yml: - Add validation step: fail fast with a clear error if exactly one of base-ref / head-ref is set. Both must be provided or both must be empty. - Pass ref values via env vars (not direct template expansion) to avoid script injection flagged by zizmor. scorecard/action.yml: - Add set -euo pipefail to print-summary step so jq parse failures do not silently print "All checks passed". - Guard against missing jq binary with an explicit check and warning. README.md: - Add base-ref / head-ref inputs to Dependency Review table row so consumers know how to invoke the action outside pull_request context. - Update Dependency Review section prose and example snippet to reflect non-PR support; replace stale "only meaningful on pull_request" note. Co-Authored-By: Claude Sonnet 4.6 --- .github/actions/dependency-review/action.yml | 9 +++++++++ .github/actions/scorecard/action.yml | 7 ++++++- .github/workflows/ci.yml | 3 ++- README.md | 8 +++++--- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.github/actions/dependency-review/action.yml b/.github/actions/dependency-review/action.yml index a5f208d..488723c 100644 --- a/.github/actions/dependency-review/action.yml +++ b/.github/actions/dependency-review/action.yml @@ -19,6 +19,15 @@ inputs: runs: using: "composite" steps: + - name: Validate ref inputs + if: ${{ (inputs.base-ref != '' && inputs.head-ref == '') || (inputs.base-ref == '' && inputs.head-ref != '') }} + shell: bash + env: + BASE_REF: ${{ inputs.base-ref }} + HEAD_REF: ${{ inputs.head-ref }} + run: | + echo "::error::dependency-review: base-ref and head-ref must both be set or both be empty. Got base-ref='${BASE_REF}' head-ref='${HEAD_REF}'." + exit 1 - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 if: ${{ inputs.base-ref == '' }} with: diff --git a/.github/actions/scorecard/action.yml b/.github/actions/scorecard/action.yml index 04d3ffb..4e9f64c 100644 --- a/.github/actions/scorecard/action.yml +++ b/.github/actions/scorecard/action.yml @@ -38,13 +38,18 @@ runs: if: always() && hashFiles('scorecard-results.sarif') != '' shell: bash run: | + set -euo pipefail + if ! command -v jq &>/dev/null; then + echo "::warning::jq not found — skipping scorecard summary" + exit 0 + fi echo "=== OpenSSF Scorecard Results ===" findings=$(jq -r ' .runs[].results[]? | " [\(.ruleId | gsub("ID$";""))] \(.message.text | split("\n")[0])" ' scorecard-results.sarif) if [[ -z "$findings" ]]; then - echo " All checks passed" + echo " All checks passed (no findings in SARIF)" else echo "$findings" fi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e796103..4a7b7fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,10 +67,11 @@ jobs: # On pull_request: compares PR base/head via built-in event context. # On push to main: compares the pushed range (event.before → sha) so maintainers # can see the action work end-to-end without opening a PR. + # Skipped on first push to a branch (event.before = zero SHA) — no base to compare. dependency-review: name: Dependency Review runs-on: ubuntu-latest - if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main') + if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main' && github.event.before != '0000000000000000000000000000000000000000') permissions: contents: read pull-requests: write diff --git a/README.md b/README.md index e8ccef0..4187361 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,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 | `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 non-permitted licenses; posts a summary comment | `fail-on-severity` (default: `high`), `allow-licenses` (default: `MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, Unlicense, CC0-1.0`), `comment-summary-in-pr` (default: `on-failure`) | +| Dependency Review | [`dependency-review`](.github/actions/dependency-review/action.yml) | Blocks PRs introducing dependencies with known vulnerabilities or non-permitted licenses; posts a summary comment. Also supports non-PR invocation via `base-ref`/`head-ref`. | `fail-on-severity` (default: `high`), `allow-licenses` (default: `MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, Unlicense, CC0-1.0`), `comment-summary-in-pr` (default: `on-failure`), `base-ref` (default: `""`), `head-ref` (default: `""`) | | 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`) | @@ -86,13 +86,13 @@ jobs: ### Dependency Review -Only meaningful on `pull_request` events — requires PR base/head context. +Works on `pull_request` events (automatic base/head from PR context) and on push/non-PR events by passing `base-ref`/`head-ref` explicitly. Skip on initial branch push (`event.before` = zero SHA — no base to compare). ```yaml jobs: dependency-review: runs-on: ubuntu-latest - if: github.event_name == 'pull_request' + if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main' && github.event.before != '0000000000000000000000000000000000000000') permissions: contents: read pull-requests: write @@ -105,6 +105,8 @@ jobs: fail-on-severity: high # critical | high | moderate | low allow-licenses: MIT, Apache-2.0, BSD-2-Clause # SPDX identifiers; deps with other licenses fail comment-summary-in-pr: always # always | on-failure | never + base-ref: ${{ github.event_name == 'push' && github.event.before || '' }} # leave empty on pull_request + head-ref: ${{ github.event_name == 'push' && github.sha || '' }} # leave empty on pull_request ``` ### Storage Optimizer