Skip to content

ci: pin every GitHub Action to a commit SHA - #295

Merged
mergify[bot] merged 1 commit into
mainfrom
devs/jd/jd/sql-compare-action-pinning/pin-github-action-commit-sha--ca52caa9
Aug 5, 2026
Merged

ci: pin every GitHub Action to a commit SHA#295
mergify[bot] merged 1 commit into
mainfrom
devs/jd/jd/sql-compare-action-pinning/pin-github-action-commit-sha--ca52caa9

Conversation

@jd

@jd jd commented Aug 5, 2026

Copy link
Copy Markdown
Member

CI has failed on every pull request since 2026-07-01. The last green run
was 2026-06-30 (run 28426521860). Nothing in this repo changed: the only
commits touching .github/workflows/ since then are Dependabot tag bumps,
and the uses: refs have looked like this for the repo's whole life.

What changed is outside the repo. tools/semgrep runs
semgrep --config=auto, which resolves the Community rule registry at
run time
, and that registry now carries
yaml.github-actions.security.github-actions-mutable-action-tag. It
reports 7 blocking findings — every uses: names a mutable tag instead of
a 40-character commit SHA:

file lines
.github/workflows/ci.yaml 19, 20, 27, 43
.github/workflows/release.yml 16, 17, 25

That single red job is why ruff 0.15.19 → 0.16.0, actions/checkout,
actions/setup-python and even Mergify's own configuration-deprecation PRs
are all stuck. The loop is self-sustaining: Dependabot writes mutable
tags
when it bumps an action, so its own GHA bumps trip the rule they
just re-introduced. #291 is literally "bump actions/checkout from 7.0.0 to
7.0.1" failing on the tag it wrote.

The one that is not a lint nit

release.yml:25 was pypa/gh-action-pypi-publish@release/v1 — a mutable
branch, not even a tag, on the job that holds this project's PyPI
publish rights (environment: release, id-token: write). A push to that
branch upstream — by its owner or by anyone who compromises the
repository — runs with permission to publish sql-compare to PyPI on the
next release, and there is no version number to notice it by. This is the
real supply-chain exposure here; it is pinned deliberately, not
incidentally.

What this does and does not cost

Every ref is pinned to the SHA its current tag resolves to, so behaviour
is unchanged today — including gh-action-pypi-publish, where
dc37677 (v1.14.2) is exactly where release/v1 points right now. The
trailing # vX.Y.Z comment keeps the file readable and is the field
Dependabot rewrites. No new maintenance: Dependabot updates SHA-pinned
actions natively and .github/dependabot.yml already enables the
github-actions ecosystem.

Verified locally against the exact CI image — semgrep/semgrep:1.138.0
running semgrep --config=auto --error --timeout=15 . over the same 18
targets with the same 329 rules: 7 blocking findings before, 0 after.

What this does NOT fix — a call for @jd

Pinning the semgrep image pins the engine, not the rules.
--config=auto still resolves the registry live, which is precisely how
this repo went red with zero commits, and it will happen again the next
time the Community ruleset gains a rule this repo trips. Green today does
not mean green tomorrow. Three options, none of them free:

  1. Pin a ruleset--config=p/<ruleset> or a versioned registry
    pin. Keeps CI reproducible; new upstream rules only arrive when someone
    bumps them, which is also the downside.
  2. Vendor the rules — copy the rule YAML into the repo. Fully
    reproducible and diffable; someone has to own refreshing it.
  3. Accept the drift — status quo. Zero effort, and the fleet
    occasionally goes red with no local cause. Note the monorepo has
    explicitly made this choice and recorded it in its root CLAUDE.md.

Changing the security posture is a maintainer call, so this PR does not
make it. It only unblocks CI.

CI has failed on every pull request since 2026-07-01. The last green run
was 2026-06-30 (run 28426521860). Nothing in this repo changed: the only
commits touching `.github/workflows/` since then are Dependabot tag bumps,
and the `uses:` refs have looked like this for the repo's whole life.

What changed is outside the repo. `tools/semgrep` runs
`semgrep --config=auto`, which resolves the Community rule registry **at
run time**, and that registry now carries
`yaml.github-actions.security.github-actions-mutable-action-tag`. It
reports 7 blocking findings — every `uses:` names a mutable tag instead of
a 40-character commit SHA:

| file | lines |
|---|---|
| `.github/workflows/ci.yaml` | 19, 20, 27, 43 |
| `.github/workflows/release.yml` | 16, 17, 25 |

That single red job is why ruff 0.15.19 → 0.16.0, actions/checkout,
actions/setup-python and even Mergify's own configuration-deprecation PRs
are all stuck. The loop is self-sustaining: Dependabot writes *mutable
tags* when it bumps an action, so its own GHA bumps trip the rule they
just re-introduced. #291 is literally "bump actions/checkout from 7.0.0 to
7.0.1" failing on the tag it wrote.

## The one that is not a lint nit

`release.yml:25` was `pypa/gh-action-pypi-publish@release/v1` — a mutable
**branch**, not even a tag, on the job that holds this project's PyPI
publish rights (`environment: release`, `id-token: write`). A push to that
branch upstream — by its owner or by anyone who compromises the
repository — runs with permission to publish `sql-compare` to PyPI on the
next release, and there is no version number to notice it by. This is the
real supply-chain exposure here; it is pinned deliberately, not
incidentally.

## What this does and does not cost

Every ref is pinned to the SHA its current tag resolves to, so behaviour
is unchanged today — including `gh-action-pypi-publish`, where
`dc37677` (v1.14.2) is exactly where `release/v1` points right now. The
trailing `# vX.Y.Z` comment keeps the file readable and is the field
Dependabot rewrites. No new maintenance: Dependabot updates SHA-pinned
actions natively and `.github/dependabot.yml` already enables the
`github-actions` ecosystem.

Verified locally against the exact CI image — `semgrep/semgrep:1.138.0`
running `semgrep --config=auto --error --timeout=15 .` over the same 18
targets with the same 329 rules: **7 blocking findings before, 0 after.**

## What this does NOT fix — a call for @jd

Pinning the semgrep *image* pins the **engine**, not the **rules**.
`--config=auto` still resolves the registry live, which is precisely how
this repo went red with zero commits, and it will happen again the next
time the Community ruleset gains a rule this repo trips. Green today does
not mean green tomorrow. Three options, none of them free:

1. **Pin a ruleset** — `--config=p/<ruleset>` or a versioned registry
   pin. Keeps CI reproducible; new upstream rules only arrive when someone
   bumps them, which is also the downside.
2. **Vendor the rules** — copy the rule YAML into the repo. Fully
   reproducible and diffable; someone has to own refreshing it.
3. **Accept the drift** — status quo. Zero effort, and the fleet
   occasionally goes red with no local cause. Note the monorepo has
   explicitly made this choice and recorded it in its root `CLAUDE.md`.

Changing the security posture is a maintainer call, so this PR does not
make it. It only unblocks CI.

Change-Id: Ica52caa915bdbf1cde52e1849ca89f8fad0537db
Copilot AI lite review requested due to automatic review settings August 5, 2026 12:33
@mergify

mergify Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 All 6 merge protections satisfied — ready to merge.

Show 6 satisfied protections

🟢 🤖 Continuous Integration

  • all of:
    • check-success=Test with Python 3.10
    • check-success=Test with Python 3.11
    • check-success=Test with Python 3.12
    • check-success=Test with Python 3.9
    • check-success=semgrep

🟢 👀 Review Requirements

  • any of:
    • #approved-reviews-by>=1
    • author = dependabot[bot]

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|internal|docs|style|refactor|perf|test|build|ci|chore|revert|ui)(?:\(.+\))?!?:

🟢 🔎 Reviews

  • #changes-requested-reviews-by = 0
  • #review-requested = 0
  • #review-threads-unresolved = 0

🟢 📕 PR description

  • body ~= (?ms:.{48,})

🟢 🚦 Auto-queue

When all merge protections are satisfied, this pull request will be queued automatically.

@mergify
mergify Bot deployed to Mergify Merge Protections August 5, 2026 12:33 Active
@mergify
mergify Bot requested a review from a team August 5, 2026 12:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Pins all GitHub Actions uses: references in this repository’s CI and release workflows to immutable commit SHAs to satisfy Semgrep’s yaml.github-actions.security.github-actions-mutable-action-tag rule and unblock CI.

Changes:

  • Replace actions/checkout@v7.0.0 with actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 (with # v7.0.0 comment).
  • Replace actions/setup-python@v6.3.0 with actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 (with # v6.3.0 comment).
  • Replace pypa/gh-action-pypi-publish@release/v1 with pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 (with # v1.14.2 comment).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
.github/workflows/ci.yaml Pins checkout/setup-python action refs to commit SHAs in test + semgrep jobs.
.github/workflows/release.yml Pins checkout/setup-python and PyPI publish action refs to commit SHAs for release publishing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@jd
jd marked this pull request as ready for review August 5, 2026 13:43
@mergify

mergify Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-08-05 13:49 UTC · Rule: default · triggered by merge protections
  • Checks skipped · PR is already up-to-date
  • Merged2026-08-05 13:50 UTC · at 6e3e434b68a60191a39f4f24315cce0bcb73e355 · squash

This pull request spent 34 seconds in the queue, including 9 seconds running CI.

Required conditions to merge

@mergify
mergify Bot merged commit 0d26e6c into main Aug 5, 2026
8 checks passed
@mergify
mergify Bot deleted the devs/jd/jd/sql-compare-action-pinning/pin-github-action-commit-sha--ca52caa9 branch August 5, 2026 13:50
@mergify mergify Bot added queued and removed queued labels Aug 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants