Skip to content

Commit c322416

Browse files
authored
chore(ci): harden GitHub Actions workflows (#1071)
Move step-security/harden-runner ahead of checkout and other executable steps so outbound network controls are active before third-party actions or checked-out code run. Pair that with persist-credentials=false, narrower permissions, and tighter allowlists to reduce the chance that a compromised dependency or misconfigured workflow can reuse the job token or exfiltrate data. Pin all external GitHub Actions to full SHAs and update them to current stable releases so workflow execution is tied to reviewed commits instead of mutable tags, while Renovate keeps future action updates digest-pinned automatically. This also keeps maintainer-approved fork PR test paths intact, removes endpoints that are not used by the jobs that declared them, removes the gh-pages container that bypassed Harden Runner before the first step, and leaves the remaining high-variance jobs in audit mode until observed egress can be converted into minimal block-mode allowlists.
1 parent 59420ee commit c322416

13 files changed

Lines changed: 162 additions & 78 deletions

.github/workflows/build-push.yml

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,44 @@ jobs:
1515
build-push:
1616
runs-on: ubuntu-latest
1717
steps:
18-
- uses: actions/checkout@v6
18+
- name: Harden Runner
19+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
20+
with:
21+
disable-sudo: true
22+
egress-policy: audit
23+
allowed-endpoints: >
24+
api.github.com:443
25+
github.com:443
26+
auth.docker.io:443
27+
registry-1.docker.io:443
28+
production.cloudflare.docker.com:443
29+
gcr.io:443
30+
golang.org:443
31+
go.dev:443
32+
proxy.golang.org:443
33+
sum.golang.org:443
34+
*.githubusercontent.com:443
35+
storage.googleapis.com:443
36+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
1937
with:
2038
fetch-depth: 0
39+
persist-credentials: false
2140
- name: Set up QEMU
22-
uses: docker/setup-qemu-action@v3
41+
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
2342
- name: Set up Docker Buildx
24-
uses: docker/setup-buildx-action@v3
43+
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
2544
- name: Docker Meta
2645
id: meta
27-
uses: docker/metadata-action@v5
46+
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
2847
with:
2948
images: linode/cluster-api-provider-linode
3049
- name: Login to Docker Hub
31-
uses: docker/login-action@v3
50+
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
3251
with:
3352
username: ${{ secrets.DOCKER_USERNAME }}
3453
password: ${{ secrets.DOCKER_PASSWORD }}
3554
- name: Build and Push to Docker Hub
36-
uses: docker/build-push-action@v6
55+
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
3756
with:
3857
context: .
3958
build-args: VERSION=${{ github.ref_name == 'main' && format('main-{0}', github.sha) || github.ref_name }}

.github/workflows/build_test_ci.yml

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,19 @@ jobs:
2323
# Expose matched filters as job 'src' output variable
2424
paths: ${{ steps.filter.outputs.changes }}
2525
steps:
26-
- uses: actions/checkout@v6
27-
with:
28-
ref: ${{ github.event.pull_request.head.sha }}
2926
- name: Harden Runner
30-
uses: step-security/harden-runner@v2
27+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
3128
with:
3229
disable-sudo: true
3330
egress-policy: block
3431
allowed-endpoints: >
3532
api.github.com:443
3633
github.com:443
37-
- uses: dorny/paths-filter@v3
34+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
35+
with:
36+
persist-credentials: false
37+
ref: ${{ github.event.pull_request.head.sha || github.sha }}
38+
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
3839
id: filter
3940
with:
4041
filters: .github/filters.yml
@@ -46,7 +47,7 @@ jobs:
4647
if: ${{ contains(fromJSON(needs.changes.outputs.paths), 'src') }}
4748
steps:
4849
- name: Harden Runner
49-
uses: step-security/harden-runner@v2
50+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
5051
with:
5152
egress-policy: block
5253
allowed-endpoints: >
@@ -64,18 +65,19 @@ jobs:
6465
dl.k8s.io:443
6566
cdn.dl.k8s.io:443
6667
67-
- uses: actions/checkout@v6
68+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
6869
with:
69-
ref: ${{ github.event.pull_request.head.sha }}
70+
persist-credentials: false
71+
ref: ${{ github.event.pull_request.head.sha || github.sha }}
7072

7173
- name: Set up Go
72-
uses: actions/setup-go@v6
74+
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
7375
with:
7476
go-version-file: 'go.mod'
7577
check-latest: true
7678

7779
- name: Install devbox
78-
uses: jetify-com/devbox-install-action@v0.14.0
80+
uses: jetify-com/devbox-install-action@8c6a66ed6273138b1915457069de78cb52fe3bd7 # v0.15.0
7981
with:
8082
enable-cache: 'true'
8183
refresh-cli: 'false'
@@ -84,7 +86,7 @@ jobs:
8486
run: devbox run make test
8587

8688
- name: Upload coverage reports to Codecov
87-
uses: codecov/codecov-action@v5
89+
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
8890
with:
8991
files: ./coverage.out
9092
fail_ci_if_error: false

.github/workflows/e2e-test.yaml

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,19 @@ jobs:
5757
# Expose matched filters as job 'src' output variable
5858
paths: ${{ steps.filter.outputs.changes }}
5959
steps:
60-
- uses: actions/checkout@v6
61-
with:
62-
ref: ${{ github.event.pull_request.head.sha }}
6360
- name: Harden Runner
64-
uses: step-security/harden-runner@v2
61+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
6562
with:
6663
disable-sudo: true
6764
egress-policy: block
6865
allowed-endpoints: >
6966
api.github.com:443
7067
github.com:443
71-
- uses: dorny/paths-filter@v3
68+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
69+
with:
70+
persist-credentials: false
71+
ref: ${{ github.event.pull_request.head.sha || github.sha }}
72+
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
7273
id: filter
7374
with:
7475
filters: .github/filters.yml
@@ -83,9 +84,9 @@ jobs:
8384
LINODE_TOKEN: ${{ secrets.LINODE_TOKEN }}
8485
steps:
8586
- name: Harden Runner
86-
uses: step-security/harden-runner@v2
87+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
8788
with:
88-
egress-policy: audit
89+
egress-policy: block
8990
allowed-endpoints: >
9091
*:6443
9192
api.linode.com:443
@@ -117,23 +118,24 @@ jobs:
117118
dl.k8s.io:443
118119
cdn.dl.k8s.io:443
119120
120-
- uses: actions/checkout@v6
121+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
121122
with:
122-
ref: ${{ github.event.pull_request.head.sha }}
123+
persist-credentials: false
124+
ref: ${{ github.event.pull_request.head.sha || github.sha }}
123125

124126
- name: Set up Go
125-
uses: actions/setup-go@v6
127+
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
126128
with:
127129
go-version-file: 'go.mod'
128130
check-latest: true
129131

130132
- name: Docker cache
131-
uses: ScribeMD/docker-cache@0.5.0
133+
uses: ScribeMD/docker-cache@fb28c93772363301b8d0a6072ce850224b73f74e # 0.5.0
132134
with:
133135
key: docker-${{ runner.os }}-${{ hashFiles('go.sum') }}
134136

135137
- name: Install devbox
136-
uses: jetify-com/devbox-install-action@v0.14.0
138+
uses: jetify-com/devbox-install-action@8c6a66ed6273138b1915457069de78cb52fe3bd7 # v0.15.0
137139
with:
138140
enable-cache: 'true'
139141
refresh-cli: 'false'
@@ -159,7 +161,7 @@ jobs:
159161
if: ${{ always() }}
160162
run: docker cp tilt-control-plane:/var/log .logs
161163

162-
- uses: actions/upload-artifact@v6
164+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
163165
if: ${{ always() }}
164166
with:
165167
name: ${{ inputs.e2e-selector }}-logs

.github/workflows/e2e-upgrade-test.yaml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,18 @@ jobs:
2222
# Expose matched filters as job 'src' output variable
2323
paths: ${{ steps.filter.outputs.changes }}
2424
steps:
25-
- uses: actions/checkout@v6
2625
- name: Harden Runner
27-
uses: step-security/harden-runner@v2
26+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
2827
with:
2928
disable-sudo: true
3029
egress-policy: block
3130
allowed-endpoints: >
3231
api.github.com:443
3332
github.com:443
34-
- uses: dorny/paths-filter@v3
33+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
34+
with:
35+
persist-credentials: false
36+
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
3537
id: filter
3638
with:
3739
filters: .github/filters.yml
@@ -45,10 +47,10 @@ jobs:
4547
LINODE_TOKEN: ${{ secrets.LINODE_TOKEN }}
4648
steps:
4749
- name: Harden Runner
48-
uses: step-security/harden-runner@v2
50+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
4951
with:
5052
disable-sudo: true
51-
egress-policy: audit
53+
egress-policy: block
5254
allowed-endpoints: >
5355
*:6443
5456
api.linode.com:443
@@ -80,12 +82,13 @@ jobs:
8082
dl.k8s.io:443
8183
cdn.dl.k8s.io:443
8284
83-
- uses: actions/checkout@v6
85+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
8486
with:
8587
fetch-depth: 0
88+
persist-credentials: false
8689

8790
- name: Set up Go
88-
uses: actions/setup-go@v6
91+
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
8992
with:
9093
go-version-file: 'go.mod'
9194
check-latest: true

.github/workflows/gh-pages.yml

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,18 @@ permissions:
1616
jobs:
1717
generate-docs:
1818
runs-on: ubuntu-latest
19-
container: docker.io/node:24-bullseye-slim
2019
timeout-minutes: 2
2120
steps:
22-
- uses: actions/checkout@v6
21+
- name: Harden Runner
22+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
23+
with:
24+
disable-sudo: true
25+
egress-policy: audit
26+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
27+
with:
28+
persist-credentials: false
2329
- name: Setup mdBook
2430
run: |
25-
apt-get update
26-
apt-get install curl -y
2731
mkdir mdbook
2832
curl -sSL https://github.com/rust-lang/mdbook/releases/download/v0.4.37/mdbook-v0.4.37-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook
2933
curl -sSL https://github.com/tommilligan/mdbook-admonish/releases/download/v1.15.0/mdbook-admonish-v1.15.0-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook
@@ -33,9 +37,9 @@ jobs:
3337
cd docs
3438
mdbook build
3539
- name: Setup Pages
36-
uses: actions/configure-pages@v5
40+
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
3741
- name: Upload artifact
38-
uses: actions/upload-pages-artifact@v4
42+
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
3943
with:
4044
path: 'docs/book'
4145

@@ -47,6 +51,11 @@ jobs:
4751
runs-on: ubuntu-latest
4852
timeout-minutes: 2
4953
steps:
54+
- name: Harden Runner
55+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
56+
with:
57+
disable-sudo: true
58+
egress-policy: audit
5059
- name: Deploy to GitHub Pages
5160
id: deployment
52-
uses: actions/deploy-pages@v4
61+
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0

.github/workflows/go-analyze.yml

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,18 @@ jobs:
2020
# Expose matched filters as job 'src' output variable
2121
src: ${{ steps.filter.outputs.src }}
2222
steps:
23-
- uses: actions/checkout@v6
2423
- name: Harden Runner
25-
uses: step-security/harden-runner@v2
24+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
2625
with:
2726
disable-sudo: true
2827
egress-policy: block
2928
allowed-endpoints: >
3029
api.github.com:443
3130
github.com:443
32-
*.githubusercontent.com:443
33-
- uses: dorny/paths-filter@v3
31+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
32+
with:
33+
persist-credentials: false
34+
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
3435
id: filter
3536
with:
3637
predicate-quantifier: 'every'
@@ -41,7 +42,7 @@ jobs:
4142
if: ${{ needs.changes.outputs.src == 'true' }}
4243
steps:
4344
- name: Harden Runner
44-
uses: step-security/harden-runner@v2
45+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
4546
with:
4647
disable-sudo: true
4748
egress-policy: block
@@ -63,16 +64,18 @@ jobs:
6364
registry-1.docker.io:443
6465
auth.docker.io:443
6566
66-
- uses: actions/checkout@v6
67+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
68+
with:
69+
persist-credentials: false
6770

6871
- name: Set up Go
69-
uses: actions/setup-go@v6
72+
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
7073
with:
7174
go-version-file: 'go.mod'
7275
check-latest: true
7376

7477
- name: lint
75-
uses: golangci/golangci-lint-action@v9
78+
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
7679

7780
- name: lint-api
7881
run: make lint-api

.github/workflows/link-checker.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ jobs:
1717
runs-on: ubuntu-latest
1818
steps:
1919
- name: Harden Runner
20-
uses: step-security/harden-runner@v2
20+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
2121
with:
22+
disable-sudo: true
2223
egress-policy: audit
2324

24-
- uses: actions/checkout@v6
25-
- uses: gaurav-nelson/github-action-markdown-link-check@v1
25+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
26+
with:
27+
persist-credentials: false
28+
- uses: gaurav-nelson/github-action-markdown-link-check@3c3b66f1f7d0900e37b71eca45b63ea9eedfce31 # 1.0.17
2629
with:
2730
use-quiet-mode: 'yes'
2831
config-file: .markdownlinkcheck.json

.github/workflows/pr-labeler.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,18 @@ jobs:
1212
label-pr:
1313
name: Update PR labels
1414
permissions:
15-
contents: write
1615
pull-requests: write
1716
runs-on: ubuntu-latest
1817
steps:
19-
- name: Checkout repository
20-
uses: actions/checkout@v6
18+
- name: Harden Runner
19+
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
2120
with:
22-
fetch-depth: 0
21+
disable-sudo: true
22+
egress-policy: block
23+
allowed-endpoints: >
24+
api.github.com:443
2325
- name: Label PR
24-
uses: release-drafter/release-drafter@v6
26+
uses: release-drafter/release-drafter@563bf132657a13ded0b01fcb723c5a58cdd824e2 # v7.2.1
2527
with:
2628
disable-releaser: github.ref != 'refs/heads/main'
2729
env:

0 commit comments

Comments
 (0)