Skip to content

security(workflows): add least-privilege permissions blocks to all 14 workflow files#5917

Merged
rtibbles merged 4 commits into
learningequality:unstablefrom
rtibblesbot:issue-5915-8defb9
May 16, 2026
Merged

security(workflows): add least-privilege permissions blocks to all 14 workflow files#5917
rtibbles merged 4 commits into
learningequality:unstablefrom
rtibblesbot:issue-5915-8defb9

Conversation

@rtibblesbot
Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot commented May 16, 2026

Plan: Add top-level permissions: blocks to all 14 GitHub workflow files in .github/workflows/ so that the GITHUB_TOKEN is restricted to only the scopes each workflow actually uses.

  • Add permissions to the 7 delegated call-* shims
  • Add permissions to pre-commit.yml, i18n-download.yml, i18n-upload.yml
  • Add permissions to deploytest.yml, frontendtest.yml, pythontest.yml
  • Add permissions to containerbuild.yml

status

Summary

Adds top-level permissions: blocks to all 14 GitHub workflow files that previously had none. Without explicit permissions, workflows inherit the repository's default GITHUB_TOKEN scope (typically read-all), giving test runners and thin shims far more access than they need. This restricts each token to the minimum the workflow actually uses and resolves 14 outstanding CodeQL actions/missing-workflow-permissions alerts.

Most workflows receive only contents: read (required for actions/checkout). The three CI workflows that use fkirc/skip-duplicate-actions also get actions: read (that action reads prior run state). The container build workflow gets packages: write because it pushes images to ghcr.io using GITHUB_TOKEN directly. All other write operations (PRs, labels, Slack) go through the LE bot app token and need no GITHUB_TOKEN write scope.

References

Closes #5915.

Reviewer guidance

  • containerbuild.yml: packages: write is declared at top level (not job level) — GitHub mints the token before any step's if: guard evaluates. Verify the ghcr.io push succeeds on non-PR runs.
  • deploytest.yml, frontendtest.yml, pythontest.yml: actions: read is included for fkirc/skip-duplicate-actions. Without it the action degrades gracefully (always runs). Watch for any Resource not accessible by integration errors in CI.
  • None of these files had pre-existing job-level permissions: blocks that could conflict with the new top-level declarations.

AI usage

Claude Code implemented the changes following a pre-approved plan. The plan audited each workflow's operations against GitHub permission scope docs and specified the exact minimal scope for each file. YAML and permission values were validated programmatically before committing.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?
  • Ran pre-flight CI checks (lint, format, tests) and verified all pass
  • Rebased onto the target branch and resolved any conflicts
  • Reorganized commit history into clean, logical commits
  • Audited the diff to ensure only issue-relevant files are changed
  • Built PR body from the repository's PR template with evidence blocks

rtibblesbot and others added 4 commits May 16, 2026 10:55
… shims

All write operations in these workflows are performed by the LE bot app
token (LE_BOT_APP_ID / LE_BOT_PRIVATE_KEY). The GITHUB_TOKEN itself
requires only contents:read for the reusable-workflow call to be bounded.

Addresses CodeQL actions/missing-workflow-permissions alerts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nd i18n workflows

pre-commit.yml: fkirc/skip-duplicate-actions degrades gracefully to
always-run when it cannot read workflow runs; the tighter scope is
preferred per the audit.

i18n-download.yml: PR creation uses the LE bot app token, not
GITHUB_TOKEN, so no write scope is needed.

Addresses CodeQL actions/missing-workflow-permissions alerts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…:read

fkirc/skip-duplicate-actions requires actions:read to query prior
workflow runs. contents:read is required for actions/checkout.
No write operations are performed by GITHUB_TOKEN in these workflows.

Addresses CodeQL actions/missing-workflow-permissions alerts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ges:write

The postgres job logs in to ghcr.io with GITHUB_TOKEN and pushes the
image on non-PR runs, requiring packages:write. The nginx job only
test-builds and never pushes, but the scope is declared at workflow
level. contents:read covers actions/checkout.

Addresses CodeQL actions/missing-workflow-permissions alerts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rtibblesbot rtibblesbot marked this pull request as ready for review May 16, 2026 18:24
@rtibbles rtibbles merged commit 979353d into learningequality:unstable May 16, 2026
22 checks passed
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.

Add least-privilege permissions blocks to all GitHub workflows

2 participants