Skip to content

Float first-party actions, advance the OSV pin, scope the token - #28

Merged
imanimanyara merged 1 commit into
mainfrom
fix/security-workflow-pins-and-permissions
Nov 13, 2026
Merged

imanimanyara merged 1 commit into
mainfrom
fix/security-workflow-pins-and-permissions

Conversation

@imanimanyara

@imanimanyara imanimanyara commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

Summary

Five defects in the reusable security.yml, found by comparing it against the org's own action-pinning and CI rules. Each is cited to the rule it breaks.

Defect Rule it breaks
actions/checkout SHA-pinned at 3 call sites "actions/*, docker/*, github/* — float on the major tag"
shivammathur/setup-php comment reads # v2 (2 sites) "# v2 names a mutable tag, which is the thing the pin exists to escape; the comment must name the release"
google/osv-scanner-action pinned to v2.7.0 "Always latest, never a held-back version — a stale pin is strictly worse than a floating tag"
no permissions: block least privilege; jobs inherited the calling repository's default token scope
a step named "Install dependencies (generate composer.lock)" that sets up PHP it is the next step that installs

Measurements

Every pin re-resolved 2026-11-13 by dereferencing the tag object, because every one of these upstreams uses annotated tags and a naive read of git/ref/tags/<tag> returns a tag object that uses: cannot resolve:

action latest pinned here
actions/checkout v7.0.1 now floats @v7 (first-party)
shivammathur/setup-php 2.40.0 eb7c497e… — already correct, comment fixed
google/osv-scanner-action v2.7.1 advanced to 32d3cd48…
GitGuardian/ggshield-action v1.56.1 current
1password/load-secrets-action v5.0.1 current

Why permissions matters here specifically

A reusable workflow with no permissions: block runs under the calling repository's default token scope. On a repository created before GitHub changed that default, it is read/write across the board — so the most privileged token in the estate was being handed to the job whose entire purpose is to look for leaked credentials. Every job here only reads the tree, and the ggshield step authenticates with its own key rather than GITHUB_TOKEN.

Verified

  • YAML parses; all three jobs (composer-audit, osv-scan, secret-scan) intact, permissions: {contents: read}, OP_SERVICE_ACCOUNT_TOKEN still declared optional.
  • Each edit asserted by count before writing, and re-counted after.

Context

Of 88 laranail packages that call a reusable laranail/.github workflow, this one has 1 caller against tests.yml's 39 — while 23 packages ship their own standalone security.yml that runs composer audit and nothing else. So the estate is not unscanned, it is unshared, and 20 packages get no OSV scan and no secret scan. Fixing the shared workflow first is the prerequisite for that adoption, not a substitute for it.

Copilot AI balanced review requested due to automatic review settings November 13, 2026 16:24

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.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@imanimanyara
imanimanyara merged commit 65e018c into main Nov 13, 2026
3 checks passed
@imanimanyara
imanimanyara deleted the fix/security-workflow-pins-and-permissions branch November 13, 2026 16:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants