Skip to content

Commit 7f7c5db

Browse files
QualitySecurityPaperclip-Paperclip
andcommitted
chore(ci): add supply-chain security workflow
Adopts the security baseline from quantcli/common (govulncheck + osv-scanner + permissive license allowlist). All actions pinned by full commit SHA; workflow-level permissions default-deny; each job re-grants only contents:read. Refs quantcli/common QUA-7. Co-Authored-By: Paperclip <noreply@paperclip.ing>
1 parent 4d679f0 commit 7f7c5db

1 file changed

Lines changed: 141 additions & 0 deletions

File tree

.github/workflows/security.yml

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
name: security
2+
3+
# Supply-chain and license-policy gate.
4+
# Source of truth lives in quantcli/common; this file is the in-repo copy.
5+
# When updating, propagate the change back to quantcli/common (and the other export-clis).
6+
7+
on:
8+
push:
9+
branches: [main]
10+
pull_request:
11+
branches: [main]
12+
workflow_dispatch:
13+
14+
# Default-deny at workflow level; each job re-grants only what it needs.
15+
permissions: {}
16+
17+
jobs:
18+
govulncheck:
19+
name: govulncheck (Go vuln DB)
20+
runs-on: ubuntu-latest
21+
permissions:
22+
contents: read
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
26+
27+
- name: Detect Go module
28+
id: detect
29+
run: |
30+
if [ -f go.mod ]; then
31+
echo "has_go=true" >> "$GITHUB_OUTPUT"
32+
else
33+
echo "has_go=false" >> "$GITHUB_OUTPUT"
34+
echo "::notice::No go.mod present; skipping govulncheck."
35+
fi
36+
37+
- name: Set up Go
38+
if: steps.detect.outputs.has_go == 'true'
39+
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
40+
with:
41+
go-version-file: go.mod
42+
cache: true
43+
44+
- name: Install govulncheck
45+
if: steps.detect.outputs.has_go == 'true'
46+
run: go install golang.org/x/vuln/cmd/govulncheck@latest
47+
48+
- name: Run govulncheck
49+
if: steps.detect.outputs.has_go == 'true'
50+
run: govulncheck ./...
51+
52+
osv-scanner:
53+
name: osv-scanner (transitive vulns)
54+
runs-on: ubuntu-latest
55+
permissions:
56+
contents: read
57+
steps:
58+
- name: Checkout
59+
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
60+
61+
- name: Set up Go
62+
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
63+
with:
64+
go-version: stable
65+
cache: false
66+
67+
- name: Install osv-scanner
68+
run: go install github.com/google/osv-scanner/v2/cmd/osv-scanner@latest
69+
70+
- name: Run osv-scanner
71+
run: osv-scanner scan source --recursive .
72+
73+
license-policy:
74+
name: license policy (allowlist)
75+
runs-on: ubuntu-latest
76+
permissions:
77+
contents: read
78+
env:
79+
# Policy: every direct + transitive Go dep must resolve to one of these SPDX ids.
80+
# See quantcli/common SECURITY.md "Supply-chain policy" for the rationale.
81+
ALLOWED_LICENSES: "Apache-2.0,MIT,BSD-2-Clause,BSD-3-Clause,MPL-2.0,ISC,Unlicense"
82+
steps:
83+
- name: Checkout
84+
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
85+
86+
- name: Detect Go module
87+
id: detect
88+
run: |
89+
if [ -f go.mod ]; then
90+
echo "has_go=true" >> "$GITHUB_OUTPUT"
91+
else
92+
echo "has_go=false" >> "$GITHUB_OUTPUT"
93+
echo "::notice::No go.mod present; skipping license-policy check."
94+
fi
95+
96+
- name: Set up Go
97+
if: steps.detect.outputs.has_go == 'true'
98+
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
99+
with:
100+
go-version-file: go.mod
101+
cache: true
102+
103+
- name: Install go-licenses
104+
if: steps.detect.outputs.has_go == 'true'
105+
run: go install github.com/google/go-licenses@latest
106+
107+
- name: Check licenses against allowlist
108+
if: steps.detect.outputs.has_go == 'true'
109+
shell: bash
110+
run: |
111+
set -euo pipefail
112+
report=$(mktemp)
113+
# go-licenses csv emits: module,license-url,license-id (one per line).
114+
# Warnings (e.g. license-url not found) go to stderr and are non-fatal here.
115+
go-licenses csv ./... > "$report"
116+
117+
IFS=',' read -ra ALLOWED <<< "$ALLOWED_LICENSES"
118+
is_allowed() {
119+
local needle="$1"
120+
for a in "${ALLOWED[@]}"; do
121+
if [ "$needle" = "$a" ]; then return 0; fi
122+
done
123+
return 1
124+
}
125+
126+
bad=0
127+
while IFS=',' read -r module url license; do
128+
[ -z "$module" ] && continue
129+
if ! is_allowed "$license"; then
130+
echo "::error::Disallowed license: module=$module license=$license"
131+
bad=1
132+
fi
133+
done < "$report"
134+
135+
if [ "$bad" -ne 0 ]; then
136+
echo "::error::License policy violated. Allowlist: ${ALLOWED_LICENSES}"
137+
echo "::error::See quantcli/common SECURITY.md for the policy and how to request an exception."
138+
exit 1
139+
fi
140+
141+
echo "All dependency licenses are within policy."

0 commit comments

Comments
 (0)