forked from ChelseaKR/disclosed
-
Notifications
You must be signed in to change notification settings - Fork 0
95 lines (89 loc) · 4.32 KB
/
Copy pathsecurity.yml
File metadata and controls
95 lines (89 loc) · 4.32 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
name: security
# Three gates, none of which may be silenced. A project whose whole argument is that absence of
# disclosure should be visible cannot run its own security checks with `|| true`.
#
# - gitleaks scans history for committed secrets. The only secret this repo legitimately holds
# is DATA_GOV_API_KEY, and it lives in Actions secrets, never in git.
# - semgrep is the SAST pass over the source. It complements the ruff `S` (bandit) rules that
# already run in `make verify`; semgrep sees taint-shaped problems ruff does not. It ran for
# weeks as `--severity=ERROR`, which is the third kind of silencing and the quietest, because
# it looks like rigour. Measured on this repository under the pinned semgrep 1.169.0:
#
# --severity=ERROR 141 rules run, 0 findings, exit 0
# (no filter) 321 rules run, 3 findings, exit 1
#
# All three findings were WARNING, so the threshold sat above every finding the scan has ever
# had here. They are the three `urllib.request.urlopen` calls in the two adapters, which is
# exactly the taint-shaped class the job was added for, and they are now waived at the three
# lines with the reason written beside them rather than dropped by a floor that names nothing.
# The `tests` argument was the other half of the same problem: see `.semgrepignore`.
# - pip-audit checks every locked dependency for known vulnerabilities. The project has zero
# runtime dependencies by design, so the exported set is the dev toolchain, which is the only
# dependency surface that exists.
on:
push:
branches: [main, master]
pull_request:
schedule:
- cron: "17 10 * * 3" # weekly; catches advisories published after the last code change
# Dispatched by the daily snapshot job on its staging ref: master requires these three scans
# on every commit, and the snapshot commit earns them here rather than having them recorded
# by the job that wants to push (ADR 0003).
workflow_dispatch:
permissions:
contents: read
jobs:
secret-scan:
name: Secret scan (gitleaks)
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0 # gitleaks scans history, not just the tip
persist-credentials: false
- uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3.0.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
sast:
name: SAST (semgrep)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- name: Semgrep scan
env:
SEMGREP_SEND_METRICS: "off"
run: |
python -m pip install "semgrep==1.169.0"
# No --severity filter. Every finding this scan has produced on this source is a
# WARNING, so a floor at ERROR made the step incapable of failing; the three known
# ones carry an inline `nosemgrep` and the reason for it. Adding one back would need
# the same argument in writing.
semgrep scan --config p/default --config p/python --config p/security-audit \
--error src tests
dependency-audit:
name: Dependency audit (pip-audit over uv.lock)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- name: pip-audit the locked set
run: |
python -m pip install "pip-audit==2.10.1" "uv==0.12.1"
# --locked, not --frozen. `--frozen` exports the lockfile without checking it against
# pyproject.toml, so a stale lock would be audited clean while the set anyone actually
# installs went unexamined. An audit of the wrong dependency set is worse than no audit,
# because it comes with a green check.
uv export --locked --no-emit-project --output-file /tmp/disclosed-locked.txt
pip-audit --strict --requirement /tmp/disclosed-locked.txt