[READ-ONLY] Mirror of https://github.com/bombshell-dev/automation. GitHub Actions for the Bombshell organization
ci
0

Configure Feed

Select the types of activity you want to include in your feed.

chore(ci): harden GitHub Actions (#22)

## What does this PR do?

Hardens our reusable workflows in response to GHSA-g7cv-rxg3-hmpx (the
2026-05-11 `@tanstack/*` npm supply-chain compromise).

- Adds `permissions: {}` default-deny at workflow level on all 10
workflow files
- Splits `publish.yml` into separate `build` and `publish` jobs so
`id-token: write` (npm trusted-publisher OIDC) is scoped to a job that
never executes project code; publish job uses `pnpm install
--ignore-scripts`
- Pins `actions/upload-artifact` (`043fb46d...`, v7.0.1) and
`actions/download-artifact` (`3e5f45b2...`, v8.0.1) — new actions
introduced by the publish.yml split
- Re-pins `actions/checkout`, `pnpm/action-setup`, `actions/setup-node`
in the new build job to match the SHA pins already used elsewhere in the
file
- Routes workflow inputs and event context through `env:` instead of
`${{ }}` shell interpolation in `preview.yml`, `detect-agent.yml`, and
`detect-agent-backfill.yml`; quotes `"$VAR"` to prevent word-splitting
and glob expansion on label/glob inputs
- Adds `if: github.repository_owner == 'bombshell-dev'` owner gate to
`detect-agent.yml` and `detect-agent-backfill.yml` (other workflows
already had it)
- Adds `.github/dependabot.yml` for automated weekly SHA bumps on GitHub
Actions, grouped into a single PR

## Type of change

<!-- Check one. -->

- [ ] Bug fix
- [ ] Feature
- [ ] Refactor (no behavior change)
- [ ] Documentation
- [ ] Performance improvement
- [ ] Tests
- [x] Chore (dependencies, CI, tooling)

## AI-generated code disclosure

<!-- If any part of this PR was generated by AI tools (Copilot, Claude,
GPT, Cursor, etc.), check the box. This is fine — we just need to know
so reviewers can pay extra attention to edge cases. -->

- [x] This PR includes AI-generated code

authored by

Nate Moore and committed by
GitHub
(May 13, 2026, 12:05 AM EDT) fefdda5c 9e12379a

+86 -18
+10
.github/dependabot.yml
··· 1 + version: 2 2 + updates: 3 + - package-ecosystem: github-actions 4 + directory: / 5 + schedule: 6 + interval: weekly 7 + groups: 8 + actions: 9 + patterns: 10 + - "*"
+2
.github/workflows/add-issue-to-project.yml
··· 10 10 description: 'The GitHub App Private Key for authenticating with the GitHub API' 11 11 required: true 12 12 13 + permissions: {} 14 + 13 15 jobs: 14 16 issue: 15 17 runs-on: ubuntu-latest
+2
.github/workflows/build.yml
··· 5 5 push: 6 6 branches: [main] 7 7 8 + permissions: {} 9 + 8 10 jobs: 9 11 build: 10 12 runs-on: ubuntu-latest
+4 -2
.github/workflows/detect-agent-backfill.yml
··· 16 16 type: boolean 17 17 required: false 18 18 19 + permissions: {} 20 + 19 21 jobs: 20 22 backfill: 23 + if: github.repository_owner == 'bombshell-dev' 21 24 runs-on: ubuntu-latest 22 25 permissions: 23 26 issues: write ··· 39 42 env: 40 43 GH_TOKEN: ${{ github.token }} 41 44 LABEL: ${{ inputs.LABEL }} 42 - REPO: ${{ github.repository }} 43 - run: gh label create $LABEL --repo $REPO --color "D93F0B" --description "PR author detected as automated" --force 45 + run: gh label create "$LABEL" --repo "$GITHUB_REPOSITORY" --color "D93F0B" --description "PR author detected as automated" --force 44 46 45 47 - name: Scan open PRs 46 48 env:
+11 -10
.github/workflows/detect-agent.yml
··· 26 26 description: "Whether the PR author is classified as automated (true/false)" 27 27 value: ${{ jobs.detect.outputs.is_agent }} 28 28 29 + permissions: {} 30 + 29 31 jobs: 30 32 detect: 33 + if: github.repository_owner == 'bombshell-dev' 31 34 runs-on: ubuntu-latest 32 35 outputs: 33 36 classification: ${{ steps.analyze.outputs.CLASSIFICATION }} ··· 59 62 fi 60 63 # Check org membership 61 64 if [[ "$BYPASS_MEMBERS" == "true" ]]; then 62 - if gh api repos/${{ github.repository }}/collaborators/$PR_AUTHOR --silent 2>/dev/null; then 65 + if gh api "repos/$GITHUB_REPOSITORY/collaborators/$PR_AUTHOR" --silent 2>/dev/null; then 63 66 echo "skip=true" >> "$GITHUB_OUTPUT" 64 67 fi 65 68 fi ··· 69 72 env: 70 73 GH_TOKEN: ${{ github.token }} 71 74 LABEL: ${{ inputs.LABEL }} 72 - REPO: ${{ github.repository }} 73 75 PR_NUMBER: ${{ github.event.pull_request.number }} 74 76 run: | 75 - gh label create $LABEL --repo $REPO --color "D93F0B" --description "PR author detected as automated" --force 76 - gh pr edit $PR_NUMBER --repo $REPO --add-label $LABEL 77 + gh label create "$LABEL" --repo "$GITHUB_REPOSITORY" --color "D93F0B" --description "PR author detected as automated" --force 78 + gh pr edit "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --add-label "$LABEL" 77 79 78 80 - name: Checkout 79 81 if: steps.cache.outputs.cache-hit != 'true' && steps.bypass.outputs.is_bot != 'true' && steps.bypass.outputs.skip != 'true' ··· 106 108 env: 107 109 GH_TOKEN: ${{ github.token }} 108 110 LABEL: ${{ inputs.LABEL }} 109 - REPO: ${{ github.repository }} 110 - run: gh label create $LABEL --repo $REPO --color "D93F0B" --description "PR author detected as automated" --force 111 + run: gh label create "$LABEL" --repo "$GITHUB_REPOSITORY" --color "D93F0B" --description "PR author detected as automated" --force 111 112 112 113 - name: Add label 113 114 if: steps.cache.outputs.cache-hit != 'true' && steps.bypass.outputs.is_bot != 'true' && steps.bypass.outputs.skip != 'true' && steps.analyze.outputs.IS_AGENT == 'true' 114 115 env: 115 116 GH_TOKEN: ${{ github.token }} 116 - PR_NUMBER: ${{ github.event.pull_request.number }} 117 - REPO: ${{ github.repository }} 118 117 LABEL: ${{ inputs.LABEL }} 119 - run: gh pr edit $PR_NUMBER --repo $REPO --add-label $LABEL 118 + PR_NUMBER: ${{ github.event.pull_request.number }} 119 + run: gh pr edit "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --add-label "$LABEL" 120 120 121 121 - name: Comment on PR 122 122 if: steps.cache.outputs.cache-hit != 'true' && steps.bypass.outputs.is_bot != 'true' && steps.bypass.outputs.skip != 'true' && steps.analyze.outputs.IS_AGENT == 'true' 123 123 env: 124 124 GH_TOKEN: ${{ github.token }} 125 125 COMMENT_BODY: ${{ steps.analyze.outputs.COMMENT }} 126 - run: gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "$COMMENT_BODY" 126 + PR_NUMBER: ${{ github.event.pull_request.number }} 127 + run: gh pr comment "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --body "$COMMENT_BODY" 127 128 128 129 - name: Create scan marker 129 130 if: steps.cache.outputs.cache-hit != 'true' && steps.bypass.outputs.is_bot != 'true' && steps.bypass.outputs.skip != 'true'
+2
.github/workflows/format.yml
··· 16 16 description: "The GitHub App Private Key for authenticating with the GitHub API" 17 17 required: true 18 18 19 + permissions: {} 20 + 19 21 jobs: 20 22 format: 21 23 if: github.repository_owner == 'bombshell-dev'
+2
.github/workflows/mergebot.yml
··· 40 40 type: string 41 41 required: false 42 42 43 + permissions: {} 44 + 43 45 jobs: 44 46 post-message: 45 47 runs-on: ubuntu-latest
+2
.github/workflows/move-issue-to-backlog.yml
··· 10 10 description: 'The GitHub App Private Key for authenticating with the GitHub API' 11 11 required: true 12 12 13 + permissions: {} 14 + 13 15 jobs: 14 16 issue: 15 17 runs-on: ubuntu-latest
+3 -1
.github/workflows/preview.yml
··· 13 13 required: false 14 14 type: string 15 15 16 + permissions: {} 17 + 16 18 jobs: 17 19 preview: 18 20 if: github.repository_owner == 'bombshell-dev' ··· 45 47 env: 46 48 TEMPLATE_GLOB: ${{ inputs.template }} 47 49 PUBLISH_GLOB: ${{ inputs.publish }} 48 - run: pnpx pkg-pr-new publish $PUBLISH_GLOB --template $TEMPLATE_GLOB 50 + run: pnpx pkg-pr-new publish "$PUBLISH_GLOB" --template "$TEMPLATE_GLOB"
+46 -5
.github/workflows/publish.yml
··· 10 10 description: "The GitHub App Private Key for authenticating with the GitHub API" 11 11 required: true 12 12 13 + permissions: {} 14 + 13 15 jobs: 16 + build: 17 + if: github.repository_owner == 'bombshell-dev' 18 + runs-on: ubuntu-latest 19 + permissions: 20 + contents: read 21 + steps: 22 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 23 + 24 + - name: Setup PNPM 25 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 26 + 27 + - name: Setup Node 28 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 29 + with: 30 + node-version: 22 31 + cache: "pnpm" 32 + 33 + - name: Update NPM 34 + # WORKAROUND: The latest version of npm breaks itself whilst installing itself 35 + # see https://github.com/npm/cli/issues/9151 36 + run: npm install -g npm@~11.10.0 37 + 38 + - name: Install dependencies 39 + run: pnpm install 40 + 41 + - name: Build 42 + run: pnpm run build 43 + 44 + - name: Upload build artifacts 45 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 46 + with: 47 + name: build-output 48 + path: | 49 + packages/*/dist 50 + if-no-files-found: ignore 51 + retention-days: 1 52 + 14 53 publish: 54 + needs: build 15 55 if: github.repository_owner == 'bombshell-dev' 16 56 runs-on: ubuntu-latest 17 57 permissions: 18 58 contents: write 19 59 pull-requests: write 20 60 id-token: write 21 - 22 61 steps: 23 62 - name: Generate a token 24 63 id: bot-token ··· 52 91 # see https://github.com/npm/cli/issues/9151 53 92 run: npm install -g npm@~11.10.0 54 93 55 - - name: Install dependencies 56 - run: pnpm install 94 + - name: Install dependencies (no scripts) 95 + run: pnpm install --ignore-scripts 57 96 58 - - name: Build 59 - run: pnpm run build 97 + - name: Download build artifacts 98 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 99 + with: 100 + name: build-output 60 101 61 102 - name: Create Release Pull Request or Publish to npm 62 103 id: changesets
+2
.github/workflows/run.yml
··· 9 9 '["lint","test","types"]' 10 10 required: true 11 11 12 + permissions: {} 13 + 12 14 jobs: 13 15 run: 14 16 runs-on: ubuntu-latest