Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ updates:
update-types:
- minor
- patch

- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
cooldown:
# gives a hijacked action release time to be caught before it is proposed
default-days: 7
14 changes: 7 additions & 7 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: pnpm/action-setup@v6
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- run: pnpm i

Expand All @@ -28,9 +28,9 @@ jobs:
node-version: [26, 24, 22, 20]
fail-fast: false
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: pnpm/action-setup@v6
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- run: pnpm runtime set node ${{ matrix.node-version }}

Expand All @@ -40,7 +40,7 @@ jobs:

- run: pnpm run test:coverage

- uses: codecov/codecov-action@v7
- uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
# TODO: use v26, there're tests skipped on v26
if: matrix.node-version == 24
with:
Expand All @@ -49,9 +49,9 @@ jobs:
publish_preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: pnpm/action-setup@v6
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- run: pnpm i

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/codspeed.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ jobs:
benchmarks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: pnpm/action-setup@v6
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- run: pnpm i

- uses: CodSpeedHQ/action@v4
- uses: CodSpeedHQ/action@f22792bfac16f3e14eb9fbea76f4a48e9cc22b93 # v4.19.1
with:
mode: simulation
run: pnpm run bench
4 changes: 2 additions & 2 deletions .github/workflows/pullfrog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,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:
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ concurrency:

jobs:
release:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: npm-release
permissions:
contents: write
id-token: write
Expand Down Expand Up @@ -62,11 +64,11 @@ jobs:
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"

- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0

- uses: pnpm/action-setup@v6
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- run: pnpm i

Expand Down
20 changes: 11 additions & 9 deletions .github/workflows/sponsors-sync.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,20 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: pnpm/action-setup@v6
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- run: pnpm i

- run: pnpm run sponsors:sync

- uses: EndBug/add-and-commit@v10
with:
author_name: GitHub Actions
author_email: 41898282+github-actions[bot]@users.noreply.github.com
message: 'chore: sync sponsors'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Commit and push changes
run: |
git add .
if git diff --cached --quiet; then
echo "No changes to commit"
exit 0
fi
git -c user.name="GitHub Actions" -c user.email="41898282+github-actions[bot]@users.noreply.github.com" commit -m "chore: sync sponsors"
git push origin HEAD
60 changes: 60 additions & 0 deletions tests/github-workflows.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { readdirSync, readFileSync } from 'node:fs'
import { join } from 'node:path'
import { fileURLToPath } from 'node:url'

const githubDir = fileURLToPath(new URL('../.github/', import.meta.url))
const workflowsDir = join(githubDir, 'workflows')

const workflows = readdirSync(workflowsDir)
.filter((name) => /\.ya?ml$/.test(name))
.map((name) => ({ name, content: readFileSync(join(workflowsDir, name), 'utf8') }))

/**
* Collects every `uses:` reference across all workflows, with its version comment if any.
*/
function collectUses(): { location: string; ref: string; comment: string | undefined }[] {
return workflows.flatMap(({ name, content }) =>
content.split('\n').flatMap((line, index) => {
const match = /^\s*(?:-\s+)?uses:\s*(['"]?)([^\s'"]+)\1(?:\s+#\s*(.*?))?\s*$/.exec(line)
return match ? [{ location: `${name}:${index + 1}`, ref: match[2]!, comment: match[3] }] : []
}),
)
}

describe('github workflows', () => {
it('pins every third-party action to a full commit SHA with a version comment', () => {
const uses = collectUses().filter(({ ref }) => !ref.startsWith('./'))
expect(uses.length).toBeGreaterThan(0)

const unpinned = uses
.filter(
({ ref, comment }) =>
!/@[0-9a-f]{40}$/.test(ref) || !/^v\d+\.\d+\.\d+$/.test(comment ?? ''),
)
.map(
({ location, ref, comment }) =>
`${location}: ${ref}${comment === undefined ? '' : ` # ${comment}`}`,
)
expect(unpinned).toEqual([])
})

it('keeps action pins updated through dependabot', () => {
expect(readFileSync(join(githubDir, 'dependabot.yml'), 'utf8')).toMatch(
/^\s*-\s+package-ecosystem:\s*github-actions\s*$/m,
)
})

it('gates the release job behind an environment and the main branch', () => {
const release = readFileSync(join(workflowsDir, 'release.yaml'), 'utf8')
expect(release).toMatch(/^\s+environment:\s*npm-release\s*$/m)
expect(release).toMatch(/^\s+if:\s*github\.ref\s*==\s*'refs\/heads\/main'\s*$/m)
})

it('does not hand a write token to EndBug/add-and-commit', () => {
expect(
workflows
.filter(({ content }) => content.includes('EndBug/add-and-commit'))
.map(({ name }) => name),
).toEqual([])
})
})
Loading