Skip to content

ci(deploy): scope Pages permissions to the jobs that need them#136

Merged
IgorShevchik merged 1 commit into
mainfrom
claude/deploy-perms-least-privilege
Jun 7, 2026
Merged

ci(deploy): scope Pages permissions to the jobs that need them#136
IgorShevchik merged 1 commit into
mainfrom
claude/deploy-perms-least-privilege

Conversation

@IgorShevchik

@IgorShevchik IgorShevchik commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

Security-review follow-up to #103 / #134 (deferred from that PR by agreement).

Problem

deploy.yml declared the privileged Pages scope at the workflow level, so every job inherited it. The build job (checkout, install, docs:generate, configure-pages, upload-pages-artifact) ran with id-token: write (an OIDC token it never mints) and pages: write (it never publishes).

Change

Confine privilege to deploy; drop build to read-only.

Scope Before After
workflow contents:read, pages:write, id-token:write contents:read
build (inherited write + OIDC) contents:read, pages:read
deploy (inherited) pages:write, id-token:write

build keeps pages: read because actions/configure-pages GETs the Pages site config to derive the base path; upload-pages-artifact needs no pages scope.

Review & checks

Reviewed from five angles (eng / QA / security / CTO / docs) — the diff was assessed correct, no code changes requested on deploy.yml. A dependency-free permission-invariant script confirms: workflow == {contents:read}, build has no id-token/pages:write, deploy scoped to exactly {pages:write, id-token:write}6/6 OK.

⚠️ Draft — verify before marking ready

deploy.yml runs only on push: main / workflow_dispatch, so CI cannot exercise it on a branch.

  1. Preferred: run workflow_dispatch on this branch (Actions → "Deploy to Pages 📰" → Run workflow → claude/deploy-perms-least-privilege) and confirm the build job — especially the configure-pages step — is green.
    • Caveat: if the github-pages environment restricts deployments to main, the deploy job will pause/skip on a non-main run due to environment protection — expected, not a failure of this change. The build result is what matters in this run.
  2. Or: merge and watch the first main deploy.

Rollback path: if configure-pages fails with 403 Resource not accessible by integration, add pages: write to the build job (or restore the workflow-level pages: write). The core win — removing id-token: write from build — holds regardless. A failed build simply skips deploy, so live Pages stay on the last good version (no broken deploy).

Defence-in-depth (repo setting, not in this diff)

Confirm Settings → Environments → github-pages restricts deployments to main.

https://claude.ai/code/session_01977J3EFoxeffXCHS2TE7Kw

Security-review follow-up to #103 / #134. deploy.yml granted pages:write +
id-token:write at the workflow level, so the `build` job (checkout, install,
docs:generate, configure-pages, upload-pages-artifact) ran with an
OIDC-mintable token it never uses. Confine the privileged scope to `deploy`
and drop `build` to read-only:

- workflow: contents: read
- build:    contents: read, pages: read   (configure-pages reads the Pages config)
- deploy:   pages: write, id-token: write (deploy-pages publishes via OIDC)

Needs a verification deploy run before merge (see PR body): deploy.yml only
runs on push to main / workflow_dispatch, so it cannot be exercised from CI
on a branch.

https://claude.ai/code/session_01977J3EFoxeffXCHS2TE7Kw
@IgorShevchik IgorShevchik marked this pull request as ready for review June 7, 2026 05:56
@IgorShevchik IgorShevchik merged commit 8b83794 into main Jun 7, 2026
9 of 10 checks passed
@IgorShevchik IgorShevchik deleted the claude/deploy-perms-least-privilege branch June 7, 2026 05:56
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