Skip to content

Minimally scope permissions in GitHub Actions workflows - #261

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

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

Conversation

@desrosj

@desrosj desrosj commented May 14, 2026

Copy link
Copy Markdown
Member

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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).
@circlecube
circlecube marked this pull request as ready for review September 8, 2026 14:58
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

AI code review

✅ Strengths

  • Principle of least privilege applied consistently: top-level permissions: {} added across workflows with job-scoped overrides where needed.
  • Clear, contextual inline comments on each permission explaining why it’s required; improves future maintainability and reviews.
  • Sensible timeout-minutes caps per job (lightweight 10–30 mins for metadata/lint/webhook, 60–120 mins for heavier reusable workflows) to prevent runaway jobs while allowing realistic headroom.
  • Removed unnecessary permissions (e.g., setup jobs now use permissions: {}) and avoided granting write broadly at the workflow level.
  • Concurrency guards retained; cancel-in-progress behavior avoids wasting CI minutes on superseded runs.

⚠️ Suggestions (non-blocking)

  • Pin reusable workflows to a tag or commit SHA instead of @main for supply-chain safety: newfold-labs/workflows/.github/workflows/*@main. This avoids unexpected behavior if the reusable workflow changes upstream.
  • Verify that timeout-minutes on jobs that uses: reusable workflows propagate as expected to all called jobs. If not, consider setting timeouts inside the reusable workflows as well.
  • Lint workflow: ensure any auto-fix/auto-commit step is guarded (e.g., only on main or an explicit dispatch) so PR runs don’t unintentionally push. The job already has contents: write by design; just double-check step-level if: conditions.
  • If any reusable workflows pull from GitHub Packages/Container Registry, you may need packages: read on those jobs; looks unnecessary here, but worth confirming against the reusable definitions.

❌ Issues (blocking/critical)

  • None identified in this diff. Permissions are appropriately minimized and aligned with the described reusable workflows; timeouts are reasonable. No obvious security, correctness, or reliability regressions.

Verdict

⚠️ Verdict: Looks good to merge with minor follow-ups (pin reusable workflow refs and confirm timeout behavior). The repo setting can be switched to "Read repository contents and packages" after merge as noted in the PR description.


Automation note (for everyone)

This AI review is posted as one regular pull-request conversation comment that GitHub Actions updates in place on each successful workflow run (same comment URL). New commits do not “close” an earlier AI edition in the GitHub sense—the text is replaced. This automation does not dismiss or complete formal GitHub Reviews, resolve review threads, or change review-request state; those still require normal GitHub review actions.

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