From 9f91145a84aff9f67492241fdcb423e7d28a0756 Mon Sep 17 00:00:00 2001 From: Satvik Choudhary Date: Wed, 8 Jul 2026 14:10:17 +0530 Subject: [PATCH 1/2] ci: auto-format dependabot PRs after dependency bumps Dependabot regenerates the lockfile on every bump, which can silently move the resolved prettier/eslint version within the existing semver range and reformat source files. Dependabot never runs project scripts and its commits bypass the husky/lint-staged pre-commit hook, so pnpm check fails on style even when no source was touched (e.g. PR #79, where prettier drifted 3.8.4 -> 3.9.4 and reformatted junitXmlParser.ts). This workflow reformats Dependabot PRs and pushes the fix back. A DEPENDABOT_AUTOFIX_TOKEN secret (PAT or GitHub App token) is needed so the pushed commit retriggers CI; it falls back to GITHUB_TOKEN otherwise. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/dependabot-autoformat.yml | 62 +++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/workflows/dependabot-autoformat.yml diff --git a/.github/workflows/dependabot-autoformat.yml b/.github/workflows/dependabot-autoformat.yml new file mode 100644 index 0000000..e44987a --- /dev/null +++ b/.github/workflows/dependabot-autoformat.yml @@ -0,0 +1,62 @@ +name: Dependabot auto-format + +# Dependabot regenerates the whole lockfile on every bump, which can silently +# move the *resolved* prettier/eslint version (within the existing semver range) +# and reformat source files. Dependabot never runs project scripts, and its +# commits are made via the API so they bypass the local husky/lint-staged hook. +# The result is that `pnpm check` fails on style even though no source was +# touched. This workflow reformats such PRs and pushes the fix back. + +on: + pull_request: + +permissions: + contents: write + +concurrency: + group: dependabot-autoformat-${{ github.ref }} + cancel-in-progress: true + +jobs: + autoformat: + if: github.actor == 'dependabot[bot]' + runs-on: ubuntu-latest + + steps: + - name: Checkout PR branch + uses: actions/checkout@v7 + with: + ref: ${{ github.head_ref }} + # A PAT / GitHub App token is required so the pushed commit retriggers + # CI (commits pushed with the default GITHUB_TOKEN do NOT start new + # workflow runs, so the failing check would stay stale). Falls back to + # GITHUB_TOKEN — the fix still lands, but CI won't re-run on its own. + token: ${{ secrets.DEPENDABOT_AUTOFIX_TOKEN || secrets.GITHUB_TOKEN }} + + - name: Set up pnpm + uses: pnpm/action-setup@v6 + + - name: Use Node.js 24 + uses: actions/setup-node@v6 + with: + node-version: 24 + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Apply formatting and lint fixes + run: | + pnpm format + pnpm lint:fix + + - name: Commit and push if changed + run: | + if [[ -z "$(git status --porcelain)" ]]; then + echo "No formatting changes needed." + exit 0 + fi + git config user.name 'dependabot[bot]' + git config user.email '49699333+dependabot[bot]@users.noreply.github.com' + git commit -am 'chore(deps): apply formatting after dependency bump' + git push From c31a88e9679c495859187c481d39886376885e4a Mon Sep 17 00:00:00 2001 From: Andrian Budantsov Date: Sat, 11 Jul 2026 09:02:55 +0400 Subject: [PATCH 2/2] ci: scope write token to the push step only Running pnpm install / format / lint:fix executes code controlled by the dependency bump, so don't persist a write credential during checkout. Inject the token only in the final push step, which runs no PR code. --- .github/workflows/dependabot-autoformat.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/dependabot-autoformat.yml b/.github/workflows/dependabot-autoformat.yml index e44987a..62b23b0 100644 --- a/.github/workflows/dependabot-autoformat.yml +++ b/.github/workflows/dependabot-autoformat.yml @@ -27,11 +27,11 @@ jobs: uses: actions/checkout@v7 with: ref: ${{ github.head_ref }} - # A PAT / GitHub App token is required so the pushed commit retriggers - # CI (commits pushed with the default GITHUB_TOKEN do NOT start new - # workflow runs, so the failing check would stay stale). Falls back to - # GITHUB_TOKEN — the fix still lands, but CI won't re-run on its own. - token: ${{ secrets.DEPENDABOT_AUTOFIX_TOKEN || secrets.GITHUB_TOKEN }} + # Do not persist any credential: the install/format steps below execute + # code controlled by the dependency bump (install scripts, prettier, + # eslint), which could otherwise read a persisted write token from + # .git/config. The write token is injected only in the push step. + persist-credentials: false - name: Set up pnpm uses: pnpm/action-setup@v6 @@ -51,6 +51,12 @@ jobs: pnpm lint:fix - name: Commit and push if changed + env: + # A PAT / GitHub App token is required so the pushed commit retriggers + # CI (commits pushed with the default GITHUB_TOKEN do NOT start new + # workflow runs, so the failing check would stay stale). Falls back to + # GITHUB_TOKEN — the fix still lands, but CI won't re-run on its own. + PUSH_TOKEN: ${{ secrets.DEPENDABOT_AUTOFIX_TOKEN || secrets.GITHUB_TOKEN }} run: | if [[ -z "$(git status --porcelain)" ]]; then echo "No formatting changes needed." @@ -59,4 +65,4 @@ jobs: git config user.name 'dependabot[bot]' git config user.email '49699333+dependabot[bot]@users.noreply.github.com' git commit -am 'chore(deps): apply formatting after dependency bump' - git push + git push "https://x-access-token:${PUSH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "HEAD:${GITHUB_HEAD_REF}"