From 280e1269b75f94c424edb4424b7e22c55748161e Mon Sep 17 00:00:00 2001 From: finalerock44 <77282157+finalerock44@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:11:14 +0100 Subject: [PATCH 1/3] fix(ci): keep dependabot and fork PRs green Dependabot/fork PRs run without repo secrets, so three jobs failed on them: - lint-and-test: HAS_PRIVATE_ACCESS was true for dependabot (same-repo head), so it tried to clone the private mock-api with an empty DCD_SSH_DEPLOY_KEY. Now excludes dependabot[bot], same as forks (skips mock-api + integration). - claude-code-review: skips dependabot/fork PRs (no CLAUDE_CODE_OAUTH_TOKEN). - cla: skips its action step until PERSONAL_ACCESS_TOKEN is configured so the check is green instead of 'Branch cla-signatures not found'; also fixes two invalid input names (custom-*-prompt -> custom-*-prcomment). --- .github/workflows/cla.yml | 11 +++++++++-- .github/workflows/claude-code-review.yml | 10 ++++------ .github/workflows/cli-ci.yml | 6 +++++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index bcab57c..215c76b 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -30,10 +30,17 @@ permissions: jobs: cla: runs-on: ubuntu-latest + # Empty until the PERSONAL_ACCESS_TOKEN secret is configured (see SETUP above). + # While empty, the action step below is skipped so this check passes (green) + # instead of failing on every PR with "Branch cla-signatures not found". It + # auto-activates once the secret + cla-signatures branch exist. + env: + HAS_CLA_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN != '' }} # Only act on the signature comment or on PR events (not every comment). if: (github.event.issue.pull_request && contains(github.event.comment.body, 'I have read the CLA Document and I hereby sign the CLA')) || github.event_name == 'pull_request_target' steps: - uses: contributor-assistant/github-action@v2.6.1 + if: env.HAS_CLA_TOKEN == 'true' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} @@ -44,6 +51,6 @@ jobs: # PR target branches the CLA applies to. allowlist: dependabot[bot],renovate[bot],*[bot] # Customise the bot's prompts if desired: - custom-notsigned-prompt: "Thanks for your contribution! Please sign our Contributor License Agreement before we can merge. Comment the line below to sign:" + custom-notsigned-prcomment: "Thanks for your contribution! Please sign our Contributor License Agreement before we can merge. Comment the line below to sign:" custom-pr-sign-comment: "I have read the CLA Document and I hereby sign the CLA" - custom-allsigned-prompt: "All contributors have signed the CLA. ✍️ ✅" + custom-allsigned-prcomment: "All contributors have signed the CLA. ✍️ ✅" diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index c396185..5474be8 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -12,12 +12,10 @@ on: jobs: claude-review: - # Optional: Filter by PR author - # if: | - # github.event.pull_request.user.login == 'external-contributor' || - # github.event.pull_request.user.login == 'new-developer' || - # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' - + # The review needs CLAUDE_CODE_OAUTH_TOKEN, which is NOT exposed to PRs that + # run without secrets — Dependabot PRs and PRs from forks. Skip them so the + # check doesn't fail with an empty token; same-repo PRs only. + if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }} runs-on: ubuntu-latest permissions: contents: read diff --git a/.github/workflows/cli-ci.yml b/.github/workflows/cli-ci.yml index d4bb529..9febaea 100644 --- a/.github/workflows/cli-ci.yml +++ b/.github/workflows/cli-ci.yml @@ -40,8 +40,12 @@ jobs: # SSH deploy key. GitHub does NOT expose secrets to pull_request workflows # triggered from forks, so that checkout (and the integration tests that need # it) can only run for same-repo events. Fork PRs still run lint/typecheck/build. + # + # Dependabot PRs branch from this repo (so the fork check passes) but ALSO run + # without secrets — treat them like forks and skip the private checkout, or + # the mock-api clone fails with an empty DCD_SSH_DEPLOY_KEY. env: - HAS_PRIVATE_ACCESS: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + HAS_PRIVATE_ACCESS: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' }} steps: - name: Checkout CLI From 095c235152381827d45107c8f22e4b14b92bc7a0 Mon Sep 17 00:00:00 2001 From: finalerock44 <77282157+finalerock44@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:19:53 +0100 Subject: [PATCH 2/3] ci: group all github-actions bumps into one weekly PR Wildcard pattern so major action bumps join the group too, instead of one PR per action. --- .github/dependabot.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e792454..e93cbd3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -28,7 +28,8 @@ updates: commit-message: prefix: ci groups: + # One PR per week for ALL action bumps (including majors). Actions are + # low-risk and quick to eyeball together; no need for a PR each. actions: - update-types: - - minor - - patch + patterns: + - "*" From dfc7af683d5b7fc7e7ddb62c419c447a134718f5 Mon Sep 17 00:00:00 2001 From: finalerock44 <77282157+finalerock44@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:40:44 +0100 Subject: [PATCH 3/3] ci: power CLA via the shared automation GitHub App Mint the CLA token from the same GitHub App release-please uses, instead of a personal PAT (no expiry, signature commits show as the bot). Rename the App secrets RELEASE_PLEASE_APP_* -> BOT_APP_* since one App now serves both workflows. CLA self-skips until BOT_APP_ID is set, same as before. --- .github/workflows/cla.yml | 39 ++++++++++++++++++---------- .github/workflows/release-please.yml | 21 ++++++++------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 215c76b..b8334e6 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -7,14 +7,20 @@ name: CLA Assistant # service holds the data). Contributors sign by commenting the configured phrase # on their PR; the action records it and flips the check green. # -# SETUP REQUIRED before this can work: -# 1. Create a token with repo write access and add it as the `PERSONAL_ACCESS_TOKEN` -# secret (a fine-grained PAT or the release GitHub App token both work). The -# default GITHUB_TOKEN is also passed, but a PAT is needed to commit the -# signature file back to the repo. -# 2. Create the `cla-signatures` branch (e.g. an empty orphan branch) so the -# action has somewhere to write `signatures/version1/cla.json`. +# AUTH: mints a token from the shared automation GitHub App (the same App +# release-please uses), so signature commits show as the bot and there's no +# personal token to expire. +# +# SETUP REQUIRED before this enforces anything: +# 1. Create/install the automation GitHub App (Contents R/W, Pull requests R/W, +# Issues R/W) and add BOT_APP_ID + BOT_APP_PRIVATE_KEY repo secrets — the +# same secrets release-please uses. +# 2. Create the `cla-signatures` branch (empty orphan) so the action has +# somewhere to write `signatures/version1/cla.json`. # 3. Finalise CLA.md (legal review) — it's the document contributors agree to. +# +# Until the App secrets exist the CLA step self-skips, so the check is green +# (not failing) on every PR and auto-activates once they're set. on: issue_comment: types: [created] @@ -30,20 +36,25 @@ permissions: jobs: cla: runs-on: ubuntu-latest - # Empty until the PERSONAL_ACCESS_TOKEN secret is configured (see SETUP above). - # While empty, the action step below is skipped so this check passes (green) - # instead of failing on every PR with "Branch cla-signatures not found". It - # auto-activates once the secret + cla-signatures branch exist. + # Empty until the automation App secrets are configured (see SETUP above). + # While empty, the steps below self-skip so this check passes (green) instead + # of failing on every PR with "Branch cla-signatures not found". env: - HAS_CLA_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN != '' }} + HAS_APP: ${{ secrets.BOT_APP_ID != '' }} # Only act on the signature comment or on PR events (not every comment). if: (github.event.issue.pull_request && contains(github.event.comment.body, 'I have read the CLA Document and I hereby sign the CLA')) || github.event_name == 'pull_request_target' steps: + - uses: actions/create-github-app-token@v2 + id: app-token + if: env.HAS_APP == 'true' + with: + app-id: ${{ secrets.BOT_APP_ID }} + private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }} - uses: contributor-assistant/github-action@v2.6.1 - if: env.HAS_CLA_TOKEN == 'true' + if: env.HAS_APP == 'true' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + PERSONAL_ACCESS_TOKEN: ${{ steps.app-token.outputs.token }} with: path-to-signatures: "signatures/version1/cla.json" path-to-document: "https://github.com/devicecloud-dev/dcd-cli/blob/dev/CLA.md" diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index f28914a..0745137 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -22,13 +22,14 @@ jobs: release-please-prod: if: github.ref_name == 'production' runs-on: ubuntu-latest - # Empty until the release GitHub App secrets are configured. We use an App - # token (not GITHUB_TOKEN) so the Release PR triggers CI / PR-title / CLA + # Empty until the automation GitHub App secrets are configured (the same App + # powers the CLA workflow). We use an App token (not GITHUB_TOKEN) so the + # Release PR triggers CI / PR-title / CLA # checks — PRs opened by GITHUB_TOKEN do not, which would deadlock branch # protection. Falls back to GITHUB_TOKEN (today's behaviour) until the App # is set up, so this is safe to merge before then. env: - RELEASE_PLEASE_APP_ID: ${{ secrets.RELEASE_PLEASE_APP_ID }} + BOT_APP_ID: ${{ secrets.BOT_APP_ID }} outputs: release_created: ${{ steps.release.outputs.release_created }} tag_name: ${{ steps.release.outputs.tag_name }} @@ -36,10 +37,10 @@ jobs: steps: - uses: actions/create-github-app-token@v2 id: app-token - if: env.RELEASE_PLEASE_APP_ID != '' + if: env.BOT_APP_ID != '' with: - app-id: ${{ secrets.RELEASE_PLEASE_APP_ID }} - private-key: ${{ secrets.RELEASE_PLEASE_APP_PRIVATE_KEY }} + app-id: ${{ secrets.BOT_APP_ID }} + private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }} - uses: googleapis/release-please-action@v4 id: release with: @@ -54,7 +55,7 @@ jobs: # See release-please-prod above for why this uses an App token with a # GITHUB_TOKEN fallback. env: - RELEASE_PLEASE_APP_ID: ${{ secrets.RELEASE_PLEASE_APP_ID }} + BOT_APP_ID: ${{ secrets.BOT_APP_ID }} outputs: release_created: ${{ steps.release.outputs.release_created }} tag_name: ${{ steps.release.outputs.tag_name }} @@ -62,10 +63,10 @@ jobs: steps: - uses: actions/create-github-app-token@v2 id: app-token - if: env.RELEASE_PLEASE_APP_ID != '' + if: env.BOT_APP_ID != '' with: - app-id: ${{ secrets.RELEASE_PLEASE_APP_ID }} - private-key: ${{ secrets.RELEASE_PLEASE_APP_PRIVATE_KEY }} + app-id: ${{ secrets.BOT_APP_ID }} + private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }} - uses: googleapis/release-please-action@v4 id: release with: