From 2ff70eebccce84d92853b5f8343657ea7c422348 Mon Sep 17 00:00:00 2001 From: Kevin Stillhammer Date: Sat, 7 Mar 2026 12:05:51 +0100 Subject: [PATCH] Harden Dependabot build workflow (#788) ## Summary - keep the Dependabot build workflow single-job, but harden it a bit - replace `git-auto-commit-action` with explicit `git` commands and step-scoped push auth - add concurrency, a timeout, stricter Dependabot gating, and a guard for moved PR heads ## Why The workflow currently fails in the commit step because `actions/checkout` uses `persist-credentials: false`, but `git-auto-commit-action` later tries to push via `origin` without any credentials: ``` fatal: could not read Username for 'https://github.com': No such device or address ``` This change fixes that failure while keeping credentials scoped to the push step instead of persisting them for the whole job. ## Details - require `github.event.pull_request.user.login == 'dependabot[bot]'` - also require the PR head repo to match `github.repository` - also require the head ref to start with `dependabot/` - check out the exact PR head SHA - run `npm ci --ignore-scripts` - disable git hooks before commit - skip the dist commit if the PR head moved during the run ## Validation - `actionlint .github/workflows/dependabot-build.yml` --- .github/workflows/dependabot-build.yml | 42 +++++++++++++++++++++----- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/.github/workflows/dependabot-build.yml b/.github/workflows/dependabot-build.yml index 6d6dcc5..3f68f64 100644 --- a/.github/workflows/dependabot-build.yml +++ b/.github/workflows/dependabot-build.yml @@ -4,18 +4,26 @@ on: pull_request: types: [opened, synchronize, reopened] +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + permissions: contents: write jobs: build: runs-on: ubuntu-latest - if: github.event.pull_request.user.login == 'dependabot[bot]' + if: >- + github.event.pull_request.user.login == 'dependabot[bot]' && + github.event.pull_request.head.repo.full_name == github.repository && + startsWith(github.head_ref, 'dependabot/') + timeout-minutes: 15 steps: - name: Checkout PR branch uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - ref: ${{ github.head_ref }} + ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false - name: Setup Node.js @@ -25,15 +33,35 @@ jobs: cache: npm - name: Install dependencies - run: npm ci + run: npm ci --ignore-scripts - name: Build and test run: npm run all - name: Commit built dist - uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5 env: + EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - commit_message: "Build dist for Dependabot update" - file_pattern: dist/ + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --local core.hooksPath /dev/null + + git fetch --no-tags --depth=1 origin "${GITHUB_HEAD_REF}" + if [ "$(git rev-parse FETCH_HEAD)" != "${EXPECTED_HEAD_SHA}" ]; then + echo "::notice::Skipping dist commit because ${GITHUB_HEAD_REF} moved after the workflow started." + exit 0 + fi + + git add --all dist/ + + if git diff --cached --quiet; then + echo "No dist changes to commit." + exit 0 + fi + + git commit -m "Build dist for Dependabot update" + + auth="$(printf 'x-access-token:%s' "$GITHUB_TOKEN" | base64 | tr -d '\n')" + git -c "http.https://github.com/.extraheader=AUTHORIZATION: basic ${auth}" \ + push origin "HEAD:${GITHUB_HEAD_REF}"