Skip to content

CI: Remove issues read permission from scan jobs - #52

Merged
ModeSevenIndustrialSolutions merged 1 commit into
lfreleng-actions:mainfrom
modeseven-lfreleng-actions:ci/drop-issues-read-permission
Sep 2, 2026
Merged

CI: Remove issues read permission from scan jobs#52
ModeSevenIndustrialSolutions merged 1 commit into
lfreleng-actions:mainfrom
modeseven-lfreleng-actions:ci/drop-issues-read-permission

Conversation

@ModeSevenIndustrialSolutions

Copy link
Copy Markdown
Contributor

Problem

The Grype scan migration (python-workflows PR #65 and its siblings across the
workflow families) replaced the inline Grype shell with
lfreleng-actions/grype-scan-action, adding a new capability — maintainer-approved
CVE bypass issues — and requesting issues: read on the jobs that host the scan.

A called workflow cannot hold a permission its caller has not granted. Every
consumer whose caller workflow does not grant issues: read therefore fails with
startup_failure: 0 jobs, no check runs, no annotation. The consumer's pull
request looks green, because the checks that would fail are simply absent. That is
what makes this outage so easy to miss.

The change shipped as a patch release, with no mention of permissions in the
release notes and no breaking-change marker.

This PR is one of six applying the identical fix across python-, node-, go-,
docker-, java-workflows and workflows-template.

Why remove the permission rather than grant it estate-wide

Granting it in consumers means 40+ changes across the estate to restore a
capability none of these repositories use. Removing it upstream is 6 changes.

Evidence that the permission is unnecessary here — every consumer in this estate
is a public repository:

ClaimHow it was verified
Public issues are readable with no token and no scopeUnauthenticated curl against a public repo's issues API → HTTP 200, 3 issues returned
Private repositories genuinely differSame unauthenticated request against a private repo → HTTP 404
A failed bypass lookup never fails the scanRan the real collect_bypasses.py: with no token → exit=0; with an invalid token → ::warning:: …continuing with no bypasses applied, bypasses=[], exit=0
The step cannot turn that into a hard failureThe script runs under set -uo pipefail (no -e); the Evaluate findings step is if: always() and, with an empty bypass list, the vulnerability gate stays closed

Losing bypass data can only make a scan stricter, never laxer. The failure mode
is safe in the security-relevant direction.

Known gap, stated plainly

In production the action passes secrets.GITHUB_TOKENwithoutissues: read. I
could not reproduce a scope-restricted Actions token outside Actions, so I cannot
say whether GitHub returns 200 (the permission is ceremony) or 403 (the feature
genuinely needs it for this token type).

Either outcome is safe: a 403 takes the documented warn-and-continue path shown
in the table above, leaving the gate closed.

Scope of this change

Deletion only. The request is dropped from the two reusable workflows
(maven-build-test.yaml, gradle-build-test.yaml), and the matching grants are
dropped from the Maven and Gradle examples and the self-test workflow, symmetric
with the change that added them together. Leaving the grants behind would document
a requirement that no longer exists.

No permissions: block is left empty: every deleted line sat beside at least one
other permission. I verified this by parsing all 81 workflow and example files
across the six repositories and asserting that no permissions key resolves to
null.

Validation

  • prek run --files <changed>all hooks pass (yamllint, actionlint, zizmor, markdownlint, write-good, codespell, reuse, workflow validators)
  • zizmor .github/workflows/base and head report the same 2 pre-existing low findings (self-repository, unrelated to permissions). This change adds nothing.
  • All workflow/example files parse; 0 null permissions blocks

How to confirm the fix

Confirmation here is indirect. This PR touches only .github/**, which the
build/test workflow path-filters out ('!.github/**'), so the build/test check will
not appear on this PR — its absence is the path filter, not the bug.

Real proof comes from the next PR in a consumer repository that touches a
non-.github path, once a release carrying this change is picked up.

Follow-up

After merge this repository needs a new release so consumers pick the fix up via
Dependabot. Repos still pinned to the pre-migration release will otherwise break on
their next bump.

Existing tags should not be deleted — SHA pins still resolve through them, so
deletion breaks reproducibility without fixing anything. Consider annotating the
affected releases as known-broken instead.

The Grype scan jobs requested "issues: read" so the CVE bypass lookup
could find maintainer-approved bypass issues. A called workflow cannot
hold a permission its caller withheld, so every consumer that does not
grant "issues: read" fails before it starts. GitHub reports that as a
startup failure: zero jobs, no check runs and no annotation. The pull
request then looks green because the checks that would fail never run.
This estate publishes only public repositories, whose issues any
client can read without a token or a scope. The bypass lookup also
tolerates failure. It warns, returns an empty bypass list and exits
zero, which leaves the vulnerability gate closed. Missing bypass data
can only make a scan stricter, never weaker.
Drop the request from the reusable workflows, along with the matching
grants wherever this repository documents or exercises them, so that
consumers no longer need to grant a permission that nothing requires.
Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Matthew Watkins <mwatkins@linuxfoundation.org>
@ModeSevenIndustrialSolutions
ModeSevenIndustrialSolutions requested review from a team and a balanced review from CopilotSeptember 1, 2026 18:41
@github-actionsgithub-actionsBot added the CI CI and tests updates label Sep 1, 2026

CopilotAI 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.

🟢 Approval recommended

Pull request overview

Removes the unnecessary issues: read permission to restore compatibility for callers of reusable Java workflows.

Changes:

  • Removes the permission from Maven and Gradle Grype jobs.
  • Updates self-tests and consumer examples accordingly.
File summaries
FileDescription
examples/maven/build-test/github.yamlRemoves the obsolete caller grant.
examples/maven/build-test/gerrit.yamlRemoves the obsolete caller grant.
examples/gradle/build-test/github.yamlRemoves the obsolete caller grant.
examples/gradle/build-test/gerrit.yamlRemoves the obsolete caller grant.
.github/workflows/testing.yamlUpdates Maven and Gradle self-test permissions.
.github/workflows/maven-build-test.yamlRemoves issue access from the Grype job.
.github/workflows/gradle-build-test.yamlRemoves issue access from the Grype job.
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

askb
askb approved these changes Sep 2, 2026
@ModeSevenIndustrialSolutions
ModeSevenIndustrialSolutions merged commit b415dbf into lfreleng-actions:mainSep 2, 2026
11 checks passed
@ModeSevenIndustrialSolutions
ModeSevenIndustrialSolutions deleted the ci/drop-issues-read-permission branch September 2, 2026 08:03
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICI and tests updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@ModeSevenIndustrialSolutions@askb