mono - chore: defense - harden GitHub Actions (#1701) · jaredwray/cacheable@35a52d6 · GitHub
Skip to content

Commit 35a52d6

Browse files
mono - chore: defense - harden GitHub Actions (#1701)
* mono - chore: defense - harden GitHub Actions Pin every action to a commit SHA, wrap installs with Socket Firewall, lint workflows with zizmor, require frozen lockfiles, and drop credential persistence on read-only checkouts. Co-authored-by: Jared Wray <me@jaredwray.com> * mono - chore: defense - record PR #1701 on Actions items Co-authored-by: Jared Wray <me@jaredwray.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent 7eaa3c9 commit 35a52d6

7 files changed

Lines changed: 127 additions & 56 deletions

File tree

Lines changed: 37 additions & 0 deletions

‎.github/workflows/codecov.yml‎

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,22 @@ jobs:
1919
node-version: ['26']
2020

2121
steps:
22-
- uses: actions/checkout@v7
22+
- name: Checkout
23+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
24+
with:
25+
persist-credentials: false
26+
27+
- name: Install Socket Firewall
28+
uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2
29+
with:
30+
mode: firewall-free
31+
firewall-version: "1.15.0"
32+
2333
- name: Install pnpm
24-
uses: pnpm/action-setup@v6
34+
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
2535

2636
- name: Use Node.js ${{ matrix.node-version }}
27-
uses: actions/setup-node@v6
37+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
2838
with:
2939
node-version: ${{ matrix.node-version }}
3040
cache: pnpm
@@ -36,7 +46,7 @@ jobs:
3646
run: pnpm test:services:start
3747

3848
- name: Install dependencies
39-
run: pnpm install
49+
run: sfw pnpm install --frozen-lockfile
4050

4151
- name: Build
4252
run: pnpm build
@@ -45,6 +55,6 @@ jobs:
4555
run: pnpm test:ci
4656

4757
- name: Codecov
48-
uses: codecov/codecov-action@v7
58+
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
4959
with:
5060
token: ${{ secrets.CODECOV_TOKEN }}

‎.github/workflows/deploy-website.yml‎

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,41 @@ permissions:
1010

1111
jobs:
1212
setup-build-deploy:
13-
name: Deploy Website
1413
runs-on: ubuntu-latest
1514

1615
steps:
17-
- name: Checkout
18-
uses: actions/checkout@v7
19-
20-
- name: Install pnpm
21-
uses: pnpm/action-setup@v6
22-
23-
- name: Use Node.js
24-
uses: actions/setup-node@v6
25-
with:
26-
node-version: 26
27-
cache: pnpm
28-
29-
- name: Enable Corepack
30-
run: corepack enable
31-
32-
- name: Install Modules
33-
run: pnpm install
34-
35-
- name: Build Website
36-
run: pnpm website:build
37-
38-
- name: Publish to Cloudflare Pages
39-
uses: cloudflare/wrangler-action@v4
40-
with:
41-
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
42-
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
43-
command: pages deploy packages/website/site/dist --project-name=cacheableorg --branch=main
16+
- name: Checkout
17+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
18+
with:
19+
persist-credentials: false
20+
21+
- name: Install Socket Firewall
22+
uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2
23+
with:
24+
mode: firewall-free
25+
firewall-version: "1.15.0"
26+
27+
- name: Install pnpm
28+
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
29+
30+
- name: Use Node.js
31+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
32+
with:
33+
node-version: 26
34+
cache: pnpm
35+
36+
- name: Enable Corepack
37+
run: corepack enable
38+
39+
- name: Install Modules
40+
run: sfw pnpm install --frozen-lockfile
41+
42+
- name: Build Website
43+
run: pnpm website:build
44+
45+
- name: Publish to Cloudflare Pages
46+
uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0
47+
with:
48+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
49+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
50+
command: pages deploy packages/website/site/dist --project-name=cacheableorg --branch=main

‎.github/workflows/release.yml‎

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,36 +38,43 @@ concurrency:
3838

3939
permissions:
4040
contents: read
41-
id-token: write # required for OIDC trusted publishing + provenance
4241

4342
jobs:
4443
release:
45-
name: Release
4644
runs-on: ubuntu-latest # provenance/OIDC require a cloud-hosted runner
45+
permissions:
46+
contents: read
47+
id-token: write # required for OIDC trusted publishing + provenance
4748

4849
steps:
4950
- name: Checkout
50-
uses: actions/checkout@v7
51+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
5152
with:
5253
# This job only reads the repo (it never pushes), so don't leave the
5354
# GITHUB_TOKEN in .git/config for later steps / actions to read.
5455
persist-credentials: false
5556

57+
- name: Install Socket Firewall
58+
uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2
59+
with:
60+
mode: firewall-free
61+
firewall-version: "1.15.0"
62+
5663
- name: Install pnpm
57-
uses: pnpm/action-setup@v6
64+
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
5865

5966
- name: Use Node.js
60-
uses: actions/setup-node@v6
67+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
6168
with:
6269
node-version-file: .nvmrc
6370
registry-url: https://registry.npmjs.org # writes the .npmrc the registry expects
64-
cache: pnpm
71+
package-manager-cache: false
6572

6673
- name: Enable Corepack
6774
run: corepack enable
6875

6976
- name: Install dependencies
70-
run: pnpm install --frozen-lockfile
77+
run: sfw pnpm install --frozen-lockfile
7178

7279
- name: Build
7380
run: pnpm build

‎.github/workflows/tests.yml‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,22 @@ jobs:
1919
node-version: ['22', '24', '26']
2020

2121
steps:
22-
- uses: actions/checkout@v7
22+
- name: Checkout
23+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
24+
with:
25+
persist-credentials: false
26+
27+
- name: Install Socket Firewall
28+
uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2
29+
with:
30+
mode: firewall-free
31+
firewall-version: "1.15.0"
32+
2333
- name: Install pnpm
24-
uses: pnpm/action-setup@v6
34+
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
2535

2636
- name: Use Node.js ${{ matrix.node-version }}
27-
uses: actions/setup-node@v6
37+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
2838
with:
2939
node-version: ${{ matrix.node-version }}
3040
cache: pnpm
@@ -36,7 +46,7 @@ jobs:
3646
run: pnpm test:services:start
3747

3848
- name: Install dependencies
39-
run: pnpm install
49+
run: sfw pnpm install --frozen-lockfile
4050

4151
- name: Build
4252
run: pnpm build

‎DEFENSE_IN_DEPTH.md‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,23 @@ Profile: npm library · public
1414

1515
## 3. Dependencies (pnpm)
1616
- [x] `packageManager: pnpm@11.3+` pinned in `package.json` — verified 2026-08-24
17-
- [ ] 7-day cooldown: `minimumReleaseAge: 10080`, `minimumReleaseAgeStrict: true`, `minimumReleaseAgeIgnoreMissingTime: false`; no first-party `minimumReleaseAgeExclude` (PR #1700 pending)
18-
- [ ] `trustPolicy: no-downgrade`; no first-party `trustPolicyExclude` (PR #1700 pending)
19-
- [ ] Lifecycle scripts blocked: `strictDepBuilds: true`, `dangerouslyAllowAllBuilds: false`, `allowBuilds: {}` baseline (PR #1700 pending)
20-
- [ ] `blockExoticSubdeps: true` (PR #1700 pending)
21-
- [ ] Lockfile committed; CI installs with `pnpm install --frozen-lockfile`
17+
- [x] 7-day cooldown: `minimumReleaseAge: 10080`, `minimumReleaseAgeStrict: true`, `minimumReleaseAgeIgnoreMissingTime: false`; no first-party `minimumReleaseAgeExclude` — PR #1700
18+
- [x] `trustPolicy: no-downgrade`; no first-party `trustPolicyExclude` — PR #1700
19+
- [x] Lifecycle scripts blocked: `strictDepBuilds: true`, `dangerouslyAllowAllBuilds: false`, `allowBuilds: {}` baseline — PR #1700
20+
- [x] `blockExoticSubdeps: true` — PR #1700
21+
- [ ] Lockfile committed; CI installs with `pnpm install --frozen-lockfile` (PR #1701 pending)
2222
- [x] No `.github/dependabot.yml`; other dependency-update tools (if any) open PRs only — never auto-merge — verified 2026-08-24
2323

2424
## 4. GitHub Actions
2525
- [x] `permissions: contents: read` (or `{}` + per-job grants) on every workflow — verified 2026-08-24
2626
- [x] No `contents: write` except jobs whose purpose is mutating the repo (GitHub Release, Changesets version PR); generated output is a workflow artifact, never committed back from CI — verified 2026-08-24
27-
- [ ] Every action pinned to a full commit SHA (`npx actions-up`)
28-
- [ ] Every job installs Socket Firewall (`SocketDev/action` SHA-pinned, `firewall-version` pinned); `pnpm install` / `npm install` run as `sfw pnpm install` / `sfw npm install`
29-
- [ ] `.github/workflows/check-workflows.yaml` lints workflows with zizmor on every PR
30-
- [ ] Workflow `name:` and job `name:` contain no spaces (kebab-case) so they can be set as required status checks
31-
- [ ] `persist-credentials: false` on checkouts that don't push
27+
- [ ] Every action pinned to a full commit SHA (`npx actions-up`) (PR #1701 pending)
28+
- [ ] Every job installs Socket Firewall (`SocketDev/action` SHA-pinned, `firewall-version` pinned); `pnpm install` / `npm install` run as `sfw pnpm install` / `sfw npm install` (PR #1701 pending)
29+
- [ ] `.github/workflows/check-workflows.yaml` lints workflows with zizmor on every PR (PR #1701 pending)
30+
- [ ] Workflow `name:` and job `name:` contain no spaces (kebab-case) so they can be set as required status checks (PR #1701 pending)
31+
- [ ] `persist-credentials: false` on checkouts that don't push (PR #1701 pending)
3232
- [x] No `pull_request_target` on workflows that run untrusted PR code — verified 2026-08-24
33-
- [ ] Artifact-publishing workflows disable `actions/setup-node` default caching (`package-manager-cache: false`) to prevent cache poisoning
33+
- [ ] Artifact-publishing workflows disable `actions/setup-node` default caching (`package-manager-cache: false`) to prevent cache poisoning (PR #1701 pending)
3434
- [x] No npm tokens (or other registry credentials) in Actions secrets — verified 2026-08-24
3535

3636
## 5. npm publishing — npm libraries only

‎SECURITY.md‎

Lines changed: 1 addition & 1 deletion

0 commit comments

Comments
 (0)