Skip to content

Commit 3acf8b1

Browse files
ci(security): pin actions to SHAs, least-privilege permissions, verify gitleaks (P2, lane 21)
- Pin every third-party action to an immutable commit SHA (with a # vN comment) in ci.yml, secret-scan.yml, license-check.yml, docker-publish.yml. Mutable major tags (actions/checkout@v6 etc.) can be silently re-pointed by a compromised upstream. Dependabot keeps SHAs current. - Add `permissions: contents: read` to ci.yml, secret-scan.yml, license-check.yml so jobs don't inherit a write-capable GITHUB_TOKEN from the repo default. (docker-publish.yml already scopes contents:read + packages:write per job.) - secret-scan.yml: verify the downloaded gitleaks tarball against the published SHA256 checksum before extracting/executing it. - Add .github/CODEOWNERS requiring owner review on .github/ changes. Addresses lane 21 MEDIUMs (permissions, SHA-pinning, unverified gitleaks download) + LOW (CODEOWNERS). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: KingArthur000 <sathyaprakashelango@gmail.com>
1 parent df315a5 commit 3acf8b1

5 files changed

Lines changed: 34 additions & 13 deletions

File tree

.github/CODEOWNERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Code owners — GitHub requests review from these owners on matching changes.
2+
#
3+
# CI/CD and automation config is security-sensitive (workflow permissions,
4+
# pinned action SHAs, secret scanning). Require the repo owner's review on any
5+
# change under .github/ so a privilege-escalating workflow edit can't merge
6+
# unreviewed. Enforce via a branch-protection rule requiring CODEOWNERS review.
7+
/.github/ @KingArthur000

.github/workflows/ci.yml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,18 @@ on:
66
pull_request:
77
branches: [main]
88

9+
# Least privilege: CI only needs to read the repo. Override the repo-wide
10+
# default (which may be "read and write") so a compromised action can't push.
11+
permissions:
12+
contents: read
13+
914
jobs:
1015
backend:
1116
name: Backend (install + syntax check)
1217
runs-on: ubuntu-latest
1318
steps:
14-
- uses: actions/checkout@v6
15-
- uses: actions/setup-node@v6
19+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
20+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
1621
with:
1722
node-version: '20'
1823
cache: 'npm'
@@ -36,8 +41,8 @@ jobs:
3641
name: Frontend (build)
3742
runs-on: ubuntu-latest
3843
steps:
39-
- uses: actions/checkout@v6
40-
- uses: actions/setup-node@v6
44+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
45+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
4146
with:
4247
node-version: '20'
4348
cache: 'npm'
@@ -67,7 +72,7 @@ jobs:
6772
--health-cmd "pg_isready -U postgres"
6873
--health-interval 5s --health-timeout 5s --health-retries 10
6974
steps:
70-
- uses: actions/checkout@v6
75+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
7176
- name: Apply every migration in order against a fresh DB
7277
env:
7378
PGPASSWORD: ci
@@ -85,7 +90,7 @@ jobs:
8590
name: Secret scan (reject obvious tokens)
8691
runs-on: ubuntu-latest
8792
steps:
88-
- uses: actions/checkout@v6
93+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
8994
with: { fetch-depth: 0 }
9095
- name: Grep for high-confidence secret patterns
9196
run: |

.github/workflows/docker-publish.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,20 @@ jobs:
3030
- name: frontend
3131
context: ./frontend
3232
steps:
33-
- uses: actions/checkout@v6
34-
- uses: docker/login-action@v4
33+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
34+
- uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
3535
with:
3636
registry: ghcr.io
3737
username: ${{ github.actor }}
3838
password: ${{ secrets.GITHUB_TOKEN }}
39-
- uses: docker/metadata-action@v6
39+
- uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6
4040
id: meta
4141
with:
4242
images: ghcr.io/${{ github.repository }}-${{ matrix.name }}
4343
tags: |
4444
type=semver,pattern={{version}}
4545
type=semver,pattern={{major}}.{{minor}}
46-
- uses: docker/build-push-action@v7
46+
- uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
4747
with:
4848
context: ${{ matrix.context }}
4949
push: true

.github/workflows/license-check.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ name: License Check
1212

1313
on: [pull_request]
1414

15+
permissions:
16+
contents: read
17+
1518
jobs:
1619
licenses:
1720
name: Licenses (${{ matrix.dir }})
@@ -21,8 +24,8 @@ jobs:
2124
matrix:
2225
dir: [backend, frontend]
2326
steps:
24-
- uses: actions/checkout@v6
25-
- uses: actions/setup-node@v6
27+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
28+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
2629
with:
2730
node-version: '20'
2831
- name: Install ${{ matrix.dir }} production dependencies

.github/workflows/secret-scan.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,23 @@ on:
1414
push:
1515
pull_request:
1616

17+
permissions:
18+
contents: read
19+
1720
jobs:
1821
gitleaks:
1922
runs-on: ubuntu-latest
2023
steps:
21-
- uses: actions/checkout@v6
24+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
2225
with:
2326
fetch-depth: 0 # full history
2427
- name: Run gitleaks
2528
env:
2629
GITLEAKS_VERSION: "8.18.4"
2730
run: |
2831
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -o gitleaks.tar.gz
32+
# Verify the download against the published checksum before executing it.
33+
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_checksums.txt" -o checksums.txt
34+
grep "gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" checksums.txt | sha256sum -c -
2935
tar -xzf gitleaks.tar.gz gitleaks
3036
./gitleaks detect --source . --redact --verbose --exit-code 1

0 commit comments

Comments
 (0)