Skip to content

ci: harden CI workflow and disable npm install scripts#290

Merged
epeicher merged 1 commit into
trunkfrom
ci/harden-ci-workflow
Jun 3, 2026
Merged

ci: harden CI workflow and disable npm install scripts#290
epeicher merged 1 commit into
trunkfrom
ci/harden-ci-workflow

Conversation

@epeicher

@epeicher epeicher commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Why

Security hardening for the public repo's CI workflow. Because the repo is public and ci.yml triggers on pull_request, any fork PR runs the build/test steps on a runner. The workflow was also the only one in the repo without an explicit permissions: block.

These are hardening gaps, not active vulnerabilities. The workflow already uses the safe pull_request trigger (not pull_request_target), npm ci (lockfile-pinned), and interpolates no PR-controlled data into run: blocks (no script-injection vector).

What

  • permissions: contents: read at the top level. The workflow only reads the repo to lint, build, and test; it never writes commits, comments, or releases. Previously it inherited the repo/org default token scopes, which can be read-write. This also brings ci.yml in line with the other workflows, which all set explicit permissions.
  • persist-credentials: false on all three actions/checkout steps. The default leaves GITHUB_TOKEN in .git/config, and later steps execute PR-authored code (npm scripts, build). The job never needs git auth after checkout.
  • .npmrc with ignore-scripts=true to block dependency lifecycle scripts (pre/install/post) on npm ci, neutralizing the compromised-transitive-dependency supply-chain vector.

Why ignore-scripts is safe here

  • No dependency in package-lock.json declares an install script (hasInstallScript appears nowhere).
  • esbuild 0.21.5 delivers its binary via the @esbuild/<platform> optional packages, not a postinstall download.
  • npm still runs explicitly-invoked npm run scripts; only pre/post/install lifecycle hooks are blocked. build, test:js, vendor:pixi, and test:php:install are unaffected.

The .npmrc is repo-wide, so it also applies to contributors' local npm ci/npm install as defense-in-depth (a no-op functionally given the above).

Out of scope

SHA-pinning the actions (currently @v6/@v1) plus a Dependabot config for github-actions was identified as a lower-priority follow-up and intentionally left out to keep this diff focused.

Open WordPress Playground Preview

Security hardening for the public repo's CI, where any fork PR runs the
build/test steps:

- Add an explicit `permissions: contents: read` block. The workflow only
  reads the repo to lint, build, and test; it never writes. Previously it
  inherited the repo/org default token scopes, which can be read-write.
  Brings ci.yml in line with the other workflows, which all set permissions.
- Set `persist-credentials: false` on all three checkouts. The default
  leaves GITHUB_TOKEN in .git/config, and later steps execute PR-authored
  code (npm scripts, build). The job never needs git auth after checkout.
- Add .npmrc with `ignore-scripts=true` to block dependency lifecycle
  scripts (pre/install/post) on npm ci, neutralizing the compromised-
  transitive-dependency supply-chain vector. No dependency in the lockfile
  declares an install script and esbuild ships its binary via @esbuild/*
  optional packages, so this changes nothing functionally; explicitly
  invoked `npm run` scripts are unaffected.
@epeicher epeicher enabled auto-merge (squash) June 3, 2026 08:09
@epeicher epeicher merged commit 4a30ce8 into trunk Jun 3, 2026
5 checks passed
@epeicher epeicher deleted the ci/harden-ci-workflow branch June 3, 2026 08:11
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.

1 participant