-
Notifications
You must be signed in to change notification settings - Fork 0
137 lines (120 loc) · 5.7 KB
/
security.yml
File metadata and controls
137 lines (120 loc) · 5.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
name: Security & Compliance
# Runs on every push to main and on every PR.
# Generates license manifests for both Rust and Node ecosystems and uploads
# them as CI artifacts for review / inclusion in releases.
#
# This workflow is intentionally separate from ci.yml so license failures are
# surfaced without blocking the primary test matrix.
on:
push:
branches: [main]
pull_request:
env:
CARGO_TERM_COLOR: always
jobs:
# ─────────────────────────────────────────────────────────────────────────
# License compliance — generate manifests for Rust + Node dependencies
# ─────────────────────────────────────────────────────────────────────────
license-compliance:
name: License compliance
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
# ── Rust license manifest ─────────────────────────────────────────────
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-license-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-license-
- name: Cache cargo-license binary
id: cache-cargo-license
uses: actions/cache@v5
with:
path: ~/.cargo/bin/cargo-license
key: cargo-license-bin-${{ runner.os }}-v1
- name: Install cargo-license
if: steps.cache-cargo-license.outputs.cache-hit != 'true'
run: cargo install cargo-license --locked
- name: Generate Rust license manifest
env:
TUITBOT_SKIP_DASHBOARD_BUILD: '1'
run: |
mkdir -p licenses
# Human-readable text manifest (tab-separated: name, version, authors, license)
cargo license \
--all-features \
--avoid-build-deps \
--avoid-dev-deps \
> licenses/rust-licenses.txt
echo "=== Rust license summary (top licenses by crate count) ==="
# Second column in the TSV is the license identifier
awk -F'\t' 'NR>1 {print $3}' licenses/rust-licenses.txt \
| sort | uniq -c | sort -rn || true
# ── Node license manifest ─────────────────────────────────────────────
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: dashboard/package-lock.json
- name: Install dashboard dependencies
run: cd dashboard && npm ci
- name: Generate frontend license manifest
run: |
mkdir -p licenses
cd dashboard
# license-checker outputs CSV and JSON for the manifest
npx license-checker \
--production \
--csv \
--out ../licenses/frontend-licenses.csv
npx license-checker \
--production \
--json \
--out ../licenses/frontend-licenses.json
echo "=== Frontend license summary ==="
npx license-checker --production --summary || true
# ── Fail on copy-left in production deps ─────────────────────────────
- name: Check for disallowed licenses
run: |
# Disallow GPL/AGPL/SSPL in production dependencies.
# LGPL is allowed with review (dynamic linking, not modified/distributed).
# MPL-2.0 is allowed (file-level copyleft, compatible with MIT binaries).
#
# Explicit GPL exceptions (must document rationale + replacement plan):
# rquest-util (GPL-3.0): browser-emulation fingerprinting for local/scraper
# mode only (not the default OAuth path). Accepted short-term; tracked as
# tech debt — replace with MIT-licensed alternative when available.
# See: https://crates.io/crates/rquest-util
disallowed_pattern='(^|[[:space:]])(GPL-[0-9]|AGPL-[0-9]|SSPL)'
rust_violations=$(grep -E "$disallowed_pattern" licenses/rust-licenses.txt \
| grep -v 'rquest-util' \
|| true)
node_violations=$(grep -E "$disallowed_pattern" licenses/frontend-licenses.csv || true)
if [ -n "$rust_violations" ] || [ -n "$node_violations" ]; then
echo "::error::Disallowed license (GPL/AGPL/SSPL) found in production dependencies."
echo ""
echo "Rust violations:"
echo "${rust_violations:- (none)}"
echo ""
echo "Node violations:"
echo "${node_violations:- (none)}"
echo ""
echo "Resolution: add an explicit exception in .cargo/audit.toml and document"
echo "the rationale, or replace the dependency."
exit 1
fi
echo "✅ No disallowed licenses in production dependencies."
# ── Upload license manifests ──────────────────────────────────────────
- name: Upload license manifests
uses: actions/upload-artifact@v7
if: always()
with:
name: license-manifests
path: licenses/
retention-days: 90