Skip to content

Minimally scope permissions in GitHub Actions workflows#261

Draft
desrosj wants to merge 3 commits into
mainfrom
add/scoped-workflow-permissions
Draft

Minimally scope permissions in GitHub Actions workflows#261
desrosj wants to merge 3 commits into
mainfrom
add/scoped-workflow-permissions

Conversation

@desrosj
Copy link
Copy Markdown
Member

@desrosj desrosj commented May 14, 2026

This updates the GitHub Actions workflow files to:

  • Grant minimally-scoped permissions to each job to adhere to the principle of least privilege
  • Specify a timeout on each job to prevent runaway processes consuming too many minutes (the default is 360)

Once this PR is merged, the Settings -> Actions -> Workflow permissions setting can be changed by a repo admin to "Read repository contents and packages permissions".

For more information, see PRESS11-470.

References

Use of AI

Cursor was used with (Claude Opus 4.7 and Composer 2.0 at varying points) to analyze the repository and make the initial changes.

When this PR is marked "ready for review" it means that I have manually reviewed all permissions and timeouts that were changed and made any necessary adjustments.

As a part of the analysis, the following summary was created:

Status

Field Value
Workflows scanned 6 (auto-translate.yml, brand-plugin-test-playwright.yml, lint.yml, newfold-prep-release.yml, satis-webhook.yml, unit-tests-and-coverage-report.yml)
Branch add/scoped-workflow-permissions (created)
Permissions commit 1c2fe7b6
Timeouts commit fa2474a2

Top-level permissions: {}

Category Entry
Workflows that were missing the top-level permissions: {} directive (added in this run): unit-tests-and-coverage-report.yml
Workflows that were missing the top-level permissions: {} directive (added in this run): satis-webhook.yml
Workflows that were missing the top-level permissions: {} directive (added in this run): lint.yml
Workflows that were missing the top-level permissions: {} directive (added in this run): brand-plugin-test-playwright.yml (replaced prior top-level permissions: contents: read and relocated the block to immediately precede jobs:)
Workflows that were missing the top-level permissions: {} directive (added in this run): auto-translate.yml (inserted the required two-line comment immediately above the existing permissions: {})

Job-level permissions: additions

Workflow file Summary Job Permissions / notes
unit-tests-and-coverage-report.yml 1 job was missing a scoped permissions: directive get-repo-name permissions: {} [3]
satis-webhook.yml 1 job was missing a scoped permissions: directive webhook contents: read [3]
lint.yml 1 job was missing a scoped permissions: directive phpcs contents: write [3]

Permissions corrections (previously incorrect)

# Correction
1 brand-plugin-test-playwright.yml :: top-level (workflow): BEFORE permissions: contents: read -> AFTER # Disable permissions... / # Any needed... + permissions: {} immediately before jobs: -- align with required default-deny workflow baseline; previously granted contents: read to the whole workflow -- [3]
2 brand-plugin-test-playwright.yml :: setup: BEFORE contents: read -> AFTER permissions: {} -- job only derives a branch name from ref env vars and does not use actions/checkout or other token-backed GitHub API calls -- [3]
3 auto-translate.yml :: translate: added aligned inline comments for existing contents: write / pull-requests: write, and moved the permissions block to immediately follow uses: per the audit’s job layout rule -- [3]
4 newfold-prep-release.yml :: prep-release: added aligned inline comments for existing contents: write / pull-requests: write, and moved the permissions block to immediately follow uses: per the audit’s job layout rule -- [3]
5 unit-tests-and-coverage-report.yml :: unit-tests: added aligned inline comments for existing contents: write / pull-requests: write, and moved the permissions block to immediately follow uses: per the audit’s job layout rule -- [3]

timeout-minutes additions

Workflow Job Minutes / action Rationale
unit-tests-and-coverage-report.yml get-repo-name 10 lightweight metadata-only job; short cap prevents a stuck runner without impacting realistic runtime.
unit-tests-and-coverage-report.yml unit-tests 120 reusable codecoverage workflow runs a broad PHP matrix plus coverage merge/Pages push steps that can be slow on cold caches.
satis-webhook.yml webhook 30 checkout, local grep validation, and a single repository-dispatch call should finish quickly; 30 minutes matches common guardrails for small release hook workflows.
lint.yml phpcs 30 Composer install, PHPCS, diff-based changed-files, and occasional auto-commit on main are typically well under this cap.
brand-plugin-test-playwright.yml setup 10 only computes branch metadata from environment variables.
brand-plugin-test-playwright.yml bluehost 120 reusable Playwright + wp-env installs can be long-running; needs a higher ceiling than lint-style jobs.
brand-plugin-test-playwright.yml bluehost-dev 120 same rationale as bluehost, plus an alternate plugin branch may change dependency resolution timing.
auto-translate.yml translate 120 reusable translations pipeline may run i18n tooling, optional Azure translation, artifact handoffs, and PR operations.
newfold-prep-release.yml prep-release 60 reusable release prep runs Composer/npm installs and may execute build/i18n scripts before branching/PR steps.

Notes / blockers

# Note
1 Callable workflows in newfold-labs/workflows were reviewed at main for expected GITHUB_TOKEN usage (e.g., reusable-codecoverage.yml pushing gh-pages and PR comments; reusable-translations.yml using gh pr and git pushes; module-plugin-test-playwright.yml cloning multiple private repos; reusable-module-prep-release.yml using gh pr list). If those reusables change behavior, re-validate the corresponding caller permissions and timeouts.
2 satis-webhook.yml dispatches using secrets.WEBHOOK_TOKEN (not github.token); job permissions only cover actions/checkout with the default token.

desrosj and others added 3 commits May 14, 2026 17:09
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@desrosj desrosj self-assigned this May 14, 2026
@desrosj desrosj requested a review from Copilot May 14, 2026 23:31
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the repository’s GitHub Actions workflows by adopting a default-deny permissions posture (permissions: {}) and explicitly scoping job permissions, while also adding per-job timeouts to prevent runaway CI executions.

Changes:

  • Add top-level permissions: {} to workflows and define least-privilege job-level permissions where needed.
  • Add timeout-minutes to each job across workflows.
  • Document why specific permissions (e.g., contents: write, pull-requests: write) are required for reusable workflows and automation steps.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
.github/workflows/unit-tests-and-coverage-report.yml Default-deny permissions; job-level permissions/timeouts for metadata + reusable code coverage workflow.
.github/workflows/satis-webhook.yml Default-deny permissions; scoped contents: read for checkout; add job timeout.
.github/workflows/newfold-prep-release.yml Default-deny permissions; document scoped write permissions; add job timeout for reusable release prep.
.github/workflows/lint.yml Default-deny permissions; add job timeout; explicitly request contents: write for PHPCBF auto-commit flow.
.github/workflows/brand-plugin-test-playwright.yml Replace workflow-wide permissions with default-deny; scope permissions per job; add timeouts.
.github/workflows/auto-translate.yml Keep default-deny baseline; document scoped permissions; add job timeout for reusable translations workflow.

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

Comment on lines +26 to +28
timeout-minutes: 30
permissions:
contents: write # Required to checkout the repo and push PHPCBF fixes on main via git-auto-commit-action (github.token).
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