diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e66bc1d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + github-actions: + patterns: ['*'] diff --git a/.github/workflows/bumpy-check.yaml b/.github/workflows/bumpy-check.yaml index 118a7af..5b173d8 100644 --- a/.github/workflows/bumpy-check.yaml +++ b/.github/workflows/bumpy-check.yaml @@ -23,17 +23,17 @@ jobs: bumpy-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 # history to diff bump files against the PR base branch - - uses: oven-sh/setup-bun@v2 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 - run: bun install - run: bun run --filter @varlock/bumpy build - run: bun install # link the freshly-built CLI bin - run: bunx @varlock/bumpy ci check --emit-comment ./bumpy-comment env: GH_TOKEN: ${{ github.token }} - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 if: always() # upload even when the check fails — the comment explains why with: name: bumpy-comment diff --git a/.github/workflows/bumpy-comment.yaml b/.github/workflows/bumpy-comment.yaml index cd38477..1fb008f 100644 --- a/.github/workflows/bumpy-comment.yaml +++ b/.github/workflows/bumpy-comment.yaml @@ -15,6 +15,7 @@ on: types: [completed] permissions: + contents: read pull-requests: write jobs: @@ -22,14 +23,14 @@ jobs: runs-on: ubuntu-latest steps: # TRUSTED: default branch (main) only — never the PR. Build our own bumpy. - - uses: actions/checkout@v7 - - uses: oven-sh/setup-bun@v2 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 - run: bun install - run: bun run --filter @varlock/bumpy build - run: bun install # link the freshly-built CLI bin # Download to runner.temp (OUTSIDE the checkout) so the untrusted artifact can't # overwrite our trusted files. - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 continue-on-error: true # the check may not have produced a comment with: name: bumpy-comment diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index da8b7e7..e13b4e3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,12 +1,15 @@ name: CI on: pull_request +permissions: + contents: read + jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: oven-sh/setup-bun@v2 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 - run: bun install - run: cd packages/bumpy && bunx varlock load # need ENV types for tsdown config file - run: bun run check diff --git a/.github/workflows/on-release.yaml b/.github/workflows/on-release.yaml index e50abeb..e5eb5a5 100644 --- a/.github/workflows/on-release.yaml +++ b/.github/workflows/on-release.yaml @@ -7,12 +7,20 @@ on: release: types: [published] +permissions: {} + jobs: verify: runs-on: ubuntu-latest steps: - run: echo "Release event triggered successfully!" - - run: | - echo "Release tag: ${{ github.event.release.tag_name }}" - echo "Release name: ${{ github.event.release.name }}" - echo "Created by: ${{ github.event.release.author.login }}" + # Pass event data via env rather than interpolating `${{ }}` into the script body, + # so a crafted release name/tag can't inject shell. + - env: + TAG_NAME: ${{ github.event.release.tag_name }} + RELEASE_NAME: ${{ github.event.release.name }} + AUTHOR: ${{ github.event.release.author.login }} + run: | + echo "Release tag: $TAG_NAME" + echo "Release name: $RELEASE_NAME" + echo "Created by: $AUTHOR" diff --git a/.github/workflows/pullfrog.yml b/.github/workflows/pullfrog.yml index 34b7c8f..42eab0a 100644 --- a/.github/workflows/pullfrog.yml +++ b/.github/workflows/pullfrog.yml @@ -27,11 +27,11 @@ jobs: contents: read steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: fetch-depth: 1 - name: Run agent - uses: pullfrog/pullfrog@v0 + uses: pullfrog/pullfrog@ad4283a862b8377cb525a0f5bf30f17c023b18ea # v0.1.98 with: prompt: ${{ inputs.prompt }} env: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d831da3..3b85919 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -26,10 +26,10 @@ jobs: mode: ${{ steps.plan.outputs.mode }} packages: ${{ steps.plan.outputs.packages }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: fetch-depth: 0 - - uses: oven-sh/setup-bun@v2 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 - run: bun install # --- You wont need this part --- @@ -55,10 +55,10 @@ jobs: contents: write pull-requests: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: fetch-depth: 0 - - uses: oven-sh/setup-bun@v2 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 - run: bun install # --- You wont need this part --- @@ -83,12 +83,12 @@ jobs: contents: write id-token: write # required for npm trusted publishing (OIDC) steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: fetch-depth: 0 - - uses: oven-sh/setup-bun@v2 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 # Node.js (npm) is needed for npm publish - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: latest - run: npm install -g npm@latest # ensure npm >= 11.15.0 for staged publishing @@ -99,7 +99,9 @@ jobs: - run: bun install # ------------------------------- - - run: echo "📦 Publishing packages:" && echo "${{ needs.plan.outputs.packages }}" + - run: echo "📦 Publishing packages:" && echo "$PACKAGES" + env: + PACKAGES: ${{ needs.plan.outputs.packages }} - run: bunx @varlock/bumpy ci release --expect-mode publish env: diff --git a/docs/github-actions.md b/docs/github-actions.md index b4b2374..5878d70 100644 --- a/docs/github-actions.md +++ b/docs/github-actions.md @@ -26,13 +26,13 @@ These commands facilitate the following: GH_TOKEN: ${{ github.token }} ``` -Give the job `permissions: pull-requests: write`. This runs in the ordinary `pull_request` context — the same trust level as the rest of your CI — so there's nothing special to be careful about: you can `bun install` and run bumpy from your devDeps like any other CLI. (If the job already ran `bun install`, `bunx` picks up your pinned version from `node_modules`; otherwise it fetches the latest.) +Give the job `permissions: { contents: read, pull-requests: write }` (listing any permission zeroes the rest, and checkout needs `contents: read` on private repos). This runs in the ordinary `pull_request` context — the same trust level as the rest of your CI — so there's nothing special to be careful about: you can `bun install` and run bumpy from your devDeps like any other CLI. (If the job already ran `bun install`, `bunx` picks up your pinned version from `node_modules`; otherwise it fetches the latest.) **Fork PRs get the check, but not the comment.** GitHub hands `pull_request` runs from forks a **read-only token and no secrets**, so the comment can't be posted there. `ci check` still runs and fails the job (red ✗) on a missing bump file, with the explanation in the job logs — forks stay gated correctly, you just don't get the rendered comment. For most repos that's the right trade. If you want the comment on fork PRs too, add the two-part setup below. > **Inline step vs. dedicated workflow.** Folding `ci check` into an existing CI job is the least setup and the right default for most repos. Give it its own lightweight `on: pull_request` workflow when either of these applies: > -> - **Slow CI + fork comments.** The fork-comment poster below (`workflow_run`) fires on _whole-workflow_ completion, so if `ci check --emit-comment` rides inside a multi-minute CI workflow, the release-plan comment won't post until everything (lint, typecheck, build, tests) finishes. A dedicated check — no `bun install`, just `bunx bumpy` — completes in seconds, so the comment lands almost immediately. +> - **Slow CI + fork comments.** The fork-comment poster below (`workflow_run`) fires on _whole-workflow_ completion, so if `ci check --emit-comment` rides inside a multi-minute CI workflow, the release-plan comment won't post until everything (lint, typecheck, build, tests) finishes. A dedicated check — no `bun install`, just `bunx @varlock/bumpy` — completes in seconds, so the comment lands almost immediately. > - **A load-bearing gate.** If `ci check` is an early step in your test job, its non-zero exit on a missing bump file fails the job and skips the remaining steps — so a contributor who pushed code before adding the bump file loses all test signal. A separate workflow (or a separate _job_) keeps the gate independent. A separate job doesn't share the test job's `bun install`, so once you're paying for an extra checkout anyway, a dedicated workflow also buys the fast comment above. ## Commenting on fork PRs @@ -72,6 +72,7 @@ on: workflows: ['CI'] # ← the NAME of the workflow that runs your check types: [completed] permissions: + contents: read # checkout of your default branch (for the bumpy version in package.json) pull-requests: write jobs: @@ -192,8 +193,8 @@ jobs: - uses: oven-sh/setup-bun@v2 - uses: actions/setup-node@v6 with: - node-version: latest - - run: npm install -g npm@latest # ensure npm >= 11.15.0 for OIDC/staged publishing + node-version: 24 + - run: npm install -g npm@11 # ensure npm >= 11.15.0 for OIDC/staged publishing # Build steps that need to happen before publish go here. If your build # needs workspace deps, add `bun install` first: # - run: bun install @@ -291,8 +292,8 @@ jobs: - uses: oven-sh/setup-bun@v2 - uses: actions/setup-node@v6 with: - node-version: latest - - run: npm install -g npm@latest + node-version: 24 + - run: npm install -g npm@11 - run: bun install - run: bunx @varlock/bumpy ci release env: @@ -446,6 +447,9 @@ For organizations, a GitHub App avoids tying automation to a personal account: with: app-id: ${{ secrets.BUMPY_APP_ID }} private-key: ${{ secrets.BUMPY_APP_PRIVATE_KEY }} + # Mint only what bumpy needs, not everything the App was installed with + permission-contents: write + permission-pull-requests: write - run: bunx @varlock/bumpy ci release env: GH_TOKEN: ${{ github.token }} diff --git a/docs/snapshots.md b/docs/snapshots.md index e134638..224eb03 100644 --- a/docs/snapshots.md +++ b/docs/snapshots.md @@ -32,9 +32,9 @@ jobs: preview: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: { node-version: 20 } + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: { node-version: 24 } - run: npm ci - run: npm run build # Run this exactly once per workflow — it's how pkg.pr.new avoids spam. @@ -89,19 +89,23 @@ on: pull_request: types: [opened, synchronize, labeled] +permissions: + contents: read + pull-requests: write # for the PR comment + jobs: snapshot: # Opt-in per PR via a label so you don't fill the registry with every PR's builds if: contains(github.event.pull_request.labels.*.name, 'snapshot') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: { fetch-depth: 0 } - uses: ./.github/actions/setup # your registry auth (.npmrc / NPM_TOKEN) - - run: bunx bumpy ci release --snapshot pr-${{ github.event.pull_request.number }} + - run: bunx @varlock/bumpy ci release --snapshot pr-${{ github.event.pull_request.number }} env: NPM_TOKEN: ${{ secrets.PRIVATE_REGISTRY_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # for the PR comment + GH_TOKEN: ${{ github.token }} # for the PR comment ``` Label-gating is the recommended default: pkg.pr.new can fire on every commit because its storage expires, but a real registry keeps every snapshot version until a retention policy prunes it. Trigger on whatever event you like — it's just a CLI command.