From 9654c80cf38617641a5a4053289d3f324f4bd628 Mon Sep 17 00:00:00 2001 From: Altay Date: Thu, 20 Aug 2026 05:31:37 +0300 Subject: [PATCH 1/2] ci: add scheduled lockfile maintenance for transitive security updates pnpm 11.x ignores targeted updates of transitive-only dependencies (pnpm/pnpm#12744), so Dependabot's security-update command is a silent no-op. A monthly and on-demand untargeted lockfile refresh lands the same fixes with workspace overrides untouched. Refs putdotio/putio-frontend#29 Co-Authored-By: Claude Fable 5 --- .github/workflows/lockfile-maintenance.yml | 85 ++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 .github/workflows/lockfile-maintenance.yml diff --git a/.github/workflows/lockfile-maintenance.yml b/.github/workflows/lockfile-maintenance.yml new file mode 100644 index 0000000..a226482 --- /dev/null +++ b/.github/workflows/lockfile-maintenance.yml @@ -0,0 +1,85 @@ +# Compensates for pnpm 11.x ignoring targeted updates of transitive-only +# dependencies (https://github.com/pnpm/pnpm/issues/12744), which makes +# Dependabot's transitive security updates a silent no-op. Refreshes every +# in-range transitive resolution with workspace overrides untouched. Run it +# from the Actions tab when a security alert fires; the cron covers drift. +# Retire path: bump packageManager once a stable pnpm ships the upstream fix. +name: Lockfile maintenance + +on: + schedule: + - cron: "0 6 1 * *" + workflow_dispatch: + +permissions: {} + +jobs: + refresh: + name: Refresh lockfile + runs-on: ubuntu-latest + timeout-minutes: 15 + concurrency: + group: lockfile-maintenance-${{ github.repository }} + cancel-in-progress: false + steps: + - name: Create release bot token + id: release-bot + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + client-id: ${{ vars.PUTIO_RELEASE_BOT_CLIENT_ID }} + private-key: ${{ secrets.PUTIO_RELEASE_BOT_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + + - name: Resolve release bot identity + id: release-bot-identity + env: + GH_TOKEN: ${{ steps.release-bot.outputs.token }} + APP_SLUG: ${{ steps.release-bot.outputs.app-slug }} + run: | + set -euo pipefail + user_id="$(gh api "/users/${APP_SLUG}[bot]" --jq .id)" + if [[ ! "$user_id" =~ ^[0-9]+$ ]]; then + echo "failed to resolve numeric bot user id for ${APP_SLUG}[bot]" >&2 + exit 1 + fi + echo "user-id=${user_id}" >> "$GITHUB_OUTPUT" + + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Set up Node + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version-file: .node-version + + - name: Refresh transitive lockfile resolutions + run: corepack pnpm update --lockfile-only -r + + - name: Open or update pull request + env: + GH_TOKEN: ${{ steps.release-bot.outputs.token }} + APP_SLUG: ${{ steps.release-bot.outputs.app-slug }} + BOT_USER_ID: ${{ steps.release-bot-identity.outputs.user-id }} + run: | + set -euo pipefail + if git diff --quiet -- pnpm-lock.yaml; then + echo "lockfile already current" + exit 0 + fi + branch="chore/lockfile-maintenance" + git config user.name "${APP_SLUG}[bot]" + git config user.email "${BOT_USER_ID}+${APP_SLUG}[bot]@users.noreply.github.com" + git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + git checkout -B "$branch" + git add pnpm-lock.yaml + git commit -m "chore(deps): refresh transitive lockfile resolutions" + git push --force origin "HEAD:refs/heads/${branch}" + if [ -z "$(gh pr list --head "$branch" --state open --json number --jq '.[].number')" ]; then + gh pr create \ + --head "$branch" \ + --title "chore(deps): refresh transitive lockfile resolutions" \ + --body "Scheduled lockfile maintenance. Re-resolves transitive dependencies within existing ranges because pnpm 11.x ignores targeted transitive updates (pnpm/pnpm#12744), so Dependabot security updates cannot land them. Workspace overrides are untouched." + fi From dd0ca790b92831da320980290b738c0b53012c12 Mon Sep 17 00:00:00 2001 From: Altay Date: Thu, 20 Aug 2026 06:43:50 +0300 Subject: [PATCH 2/2] ci: gate lockfile maintenance on main, release environment, read scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - run only on refs/heads/main: a workflow_dispatch from another ref would force-push the maintenance branch from a stale base - environment: release — PUTIO_RELEASE_BOT_CLIENT_ID and the App private key are environment-scoped; the first dispatch failed to mint a token without it (taizn actions run 32328993072) - job-level contents: read for checkout, matching the house baseline - align the bot identity lookup with the fleet-majority form (%5Bbot%5D path, user_id output) Refs putdotio/putio-frontend#29 Co-Authored-By: Claude Fable 5 --- .github/workflows/lockfile-maintenance.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lockfile-maintenance.yml b/.github/workflows/lockfile-maintenance.yml index a226482..05b4c4d 100644 --- a/.github/workflows/lockfile-maintenance.yml +++ b/.github/workflows/lockfile-maintenance.yml @@ -16,11 +16,18 @@ permissions: {} jobs: refresh: name: Refresh lockfile + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest timeout-minutes: 15 concurrency: group: lockfile-maintenance-${{ github.repository }} cancel-in-progress: false + environment: + name: release + deployment: false + permissions: + contents: read + steps: - name: Create release bot token id: release-bot @@ -38,12 +45,12 @@ jobs: APP_SLUG: ${{ steps.release-bot.outputs.app-slug }} run: | set -euo pipefail - user_id="$(gh api "/users/${APP_SLUG}[bot]" --jq .id)" + user_id="$(gh api "/users/${APP_SLUG}%5Bbot%5D" --jq .id)" if [[ ! "$user_id" =~ ^[0-9]+$ ]]; then echo "failed to resolve numeric bot user id for ${APP_SLUG}[bot]" >&2 exit 1 fi - echo "user-id=${user_id}" >> "$GITHUB_OUTPUT" + echo "user_id=${user_id}" >> "$GITHUB_OUTPUT" - name: Check out repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -62,7 +69,7 @@ jobs: env: GH_TOKEN: ${{ steps.release-bot.outputs.token }} APP_SLUG: ${{ steps.release-bot.outputs.app-slug }} - BOT_USER_ID: ${{ steps.release-bot-identity.outputs.user-id }} + BOT_USER_ID: ${{ steps.release-bot-identity.outputs.user_id }} run: | set -euo pipefail if git diff --quiet -- pnpm-lock.yaml; then