Skip to content

ci(workflows): catch & auto-fix Dependabot pnpm.overrides drift#253

Open
miguelpeixe wants to merge 5 commits into
mainfrom
ci/dependabot-lockfile-sync
Open

ci(workflows): catch & auto-fix Dependabot pnpm.overrides drift#253
miguelpeixe wants to merge 5 commits into
mainfrom
ci/dependabot-lockfile-sync

Conversation

@miguelpeixe

Copy link
Copy Markdown
Member

All Submissions:

Changes proposed in this Pull Request:

Follow-up to #252. Adds two independent layers of defense against the lockfile/package.json pnpm.overrides drift that broke main in run 27210804365:

1. CI safety net — .github/workflows/ci.yml

The changed-packages detector currently skips Install deps when no source package is affected. That misses a class of PRs that only modify root dependency files (the Dependabot lockfile-only case, but also any manual root edit). The detector now additionally checks git diff for changes to pnpm-lock.yaml, root package.json, or pnpm-workspace.yaml; if any are touched, any=true so Install deps runs. The JS / PHPCS / PHPUnit matrix jobs continue to skip cleanly because their matrices stay empty.

2. Dependabot auto-fix — .github/workflows/dependabot-sync-overrides.yml (new)

Runs on every Dependabot PR via pull_request_target. When the PR diff touches pnpm-lock.yaml, it compares the lockfile's overrides: block against package.json's pnpm.overrides and, for any key already present in package.json whose value differs, updates package.json to match. Commits and pushes via the same GH_TOKEN PAT pattern used by dependabot-branch-auto-update.yml, so CI re-fires against the synced state and the existing auto-merge can complete.

Safety:

  • Gated on github.actor == 'dependabot[bot]'.
  • pull_request_target runs the workflow definition from main, not from the PR, so a hostile PR cannot modify the workflow that holds the PAT.
  • The Python sync only updates existing keys in package.json.pnpm.overrides; it never adds or removes entries. So a hostile lockfile diff cannot inject arbitrary overrides into package.json.
  • Commit author is dependabot[bot] so the existing auto-merge.yml (which checks PR author) continues to treat the PR as auto-mergeable. The repo does not dismiss stale reviews, so the prior approval survives the sync commit.

How to test the changes in this Pull Request:

  1. Confirm both workflow files parse (python3 -c "import yaml; yaml.safe_load(open('.github/workflows/ci.yml')); yaml.safe_load(open('.github/workflows/dependabot-sync-overrides.yml'))").
  2. After merge, the next Dependabot PR that bumps a pinned override exercises the auto-fix path end-to-end. Expected behaviour: Dependabot opens the PR, sync workflow runs, detects the package.json mismatch, pushes a follow-up commit, CI re-runs and passes, auto-merge completes.
  3. (Out-of-band) Manually open a no-op PR that only edits pnpm-lock.yaml (e.g. add then immediately revert a whitespace change) and confirm Install deps runs in CI on that PR rather than being skipped.

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes, as applicable? — N/A, CI workflow change. Verified locally that the sync logic correctly classifies the three current overrides as matching against the post-fix(deps): sync @typescript-eslint/parser override with lockfile #252 state.
  • Have you successfully run tests with your changes locally? — YAML validated; sync script dry-run executed against current repo state.

What this does not cover:

  • Composer overrides — out of scope; Dependabot's composer support is separate.
  • Overrides Dependabot adds that don't exist in package.json — by design we don't touch new keys. If we ever start tracking a new transitive override, a human still adds it to package.json first.

@miguelpeixe miguelpeixe requested a review from a team as a code owner June 9, 2026 15:25
@miguelpeixe miguelpeixe requested a review from Copilot June 9, 2026 15:27

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 CI against pnpm override drift (especially from lockfile-only Dependabot PRs) by ensuring dependency installs run when root dependency files change, and by automatically syncing package.json’s pnpm.overrides to match pnpm-lock.yaml on Dependabot PRs.

Changes:

  • Update the CI change detector to treat edits to pnpm-lock.yaml, root package.json, or pnpm-workspace.yaml as requiring the Install deps job.
  • Add a new pull_request_target workflow that, for Dependabot PRs touching pnpm-lock.yaml, updates only existing pnpm.overrides keys in package.json to match the lockfile and pushes the fix commit.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
.github/workflows/dependabot-sync-overrides.yml New workflow to auto-sync existing pnpm.overrides entries in package.json with pnpm-lock.yaml on Dependabot PRs and push a fix commit.
.github/workflows/ci.yml Ensure Install deps runs when root dependency files change, preventing lockfile/config mismatches from merging undetected.

Without `install` in ci-ok's needs, a `--frozen-lockfile` failure on a
root-deps-only PR (empty js/php matrices) is masked by the skipped
matrix jobs and ci-ok passes green -- silently defeating the path-trigger
safety net added earlier in this branch.

Also: drop `2>/dev/null` from the new diff so a bad BASE_REF fails loudly
instead of silently flipping ROOT_DEPS_CHANGED to false, and collapse the
any=true/false if/else into one echo against the already-true/false var.
Address review findings on the Dependabot sync workflow:

- Add per-PR concurrency group (cancel-in-progress) so racing events
  on the same PR don't push and fail non-fast-forward.
- Gate on pull_request.user.login (stable PR author) instead of
  github.actor (per-event pusher) so a human pushing a fix to a
  Dependabot PR still triggers the sync.
- Belt-and-braces loop-break: skip when HEAD already is the sync's
  own commit subject (the actor change above removed the incidental
  loop-break the original gate relied on).
- Fetch base.sha before diffing so a post-event Dependabot rebase
  doesn't make the diff error out with `fatal: bad revision`.
- Use grep -Fqx so the `.` in `pnpm-lock.yaml` isn't treated as a
  regex metachar (matches ci.yml's escaped form).
- Python: coerce both sides of the compare/assign with str() so a
  future numeric-looking override (`foo: 8`, `foo: 5.3`) doesn't end
  up written as an unquoted JSON number.
- Python: pass ensure_ascii=False so non-ASCII in package.json isn't
  rewritten as \uXXXX, producing massive unrelated diff noise.
- Python: defensive `(pkg.get('pnpm') or {})` for `"pnpm": null`.
- Python: warn (don't silently no-op) when package.json has override
  keys missing from the lockfile -- `--frozen-lockfile` still rejects
  that mismatch and the sync can't fix it (removal is a human change).
- Explicit `git push origin HEAD:$HEAD_REF` so the push target is
  unambiguous if checkout left no upstream.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants