Repository navigation
156 lines (149 loc) · 5.46 KB
/
Copy pathsecurity.yml
File metadata and controls
156 lines (149 loc) · 5.46 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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# =============================================================================
# Reusable: the security gate. Same checks on every project.
# =============================================================================
# Split from python-backend.yml on purpose: these checks want their own
# permissions and they should keep running on a schedule even when nobody
# pushes — a dependency becomes vulnerable on a day you were not committing.
#
# Three of the four checks below need GitHub Advanced Security, which a private
# repository on the Free plan does not have: code scanning is off, so CodeQL
# cannot run, SARIF cannot be uploaded, and dependency-review has no API to ask.
# They are therefore opt-in rather than on by default — turn them on for a
# public repository, or once a plan carries them. What is left works on any
# plan and is not a token gesture: secrets over full history, and a filesystem
# scan that fails the build rather than filing a report nobody can read.
#
# uses: CtrlAltDevelop/ci-workflows/.github/workflows/security.yml@v1
#
on:
workflow_call:
inputs:
codeql:
description: "Run CodeQL. Needs code scanning, so public or GHAS only."
type: boolean
default: false
languages:
description: 'CodeQL languages, JSON array, e.g. ["python"]'
type: string
default: '["python"]'
dependency-review:
description: "Review new dependencies on a PR. Public or GHAS only."
type: boolean
default: false
sarif:
description: |
Upload findings to the security tab instead of failing the job on
them. Needs code scanning, so public or GHAS only.
type: boolean
default: false
severity:
description: "Trivy severities that count"
type: string
default: "CRITICAL,HIGH"
permissions: {}
jobs:
# Secrets first. A leaked key is the one finding that cannot be fixed by a
# commit — it has to be rotated, so it should be the loudest.
secrets:
name: Secret scan
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
steps:
- uses: actions/checkout@v7
with:
# gitleaks reads history, not just the tip: a key that was committed
# and then deleted is still in the pack file and still leaked.
fetch-depth: 0
persist-credentials: false
# v3 only moves the runtime to Node 24. Node 20 leaves the hosted
# runners entirely on 16 September 2026, after which v2 stops running
# whatever opt-out flag is set.
- uses: gitleaks/gitleaks-action@v3
env:
GITHUB_TOKEN: ${{ github.token }}
codeql:
name: CodeQL (${{ matrix.language }})
if: inputs.codeql
runs-on: ubuntu-latest
timeout-minutes: 60
permissions:
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ${{ fromJSON(inputs.languages) }}
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: github/codeql-action/init@v3
with:
# `languages`, not `language`. The singular is silently ignored, and
# CodeQL then auto-detects everything in the tree — including the
# Swift under a Flutter app's macos/ directory, which fails on a
# Linux runner for a reason that has nothing to do with your code.
languages: ${{ matrix.language }}
queries: security-extended
- uses: github/codeql-action/autobuild@v3
- uses: github/codeql-action/analyze@v3
# Filesystem scan: dependency manifests and IaC in one pass.
trivy:
name: Trivy
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
# Static on purpose: `permissions` is resolved before inputs exist, so it
# cannot be narrowed by one. Unused when sarif is off.
security-events: write
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
# Without a security tab to file into, the finding has to stop the build
# or it may as well not have been made.
- uses: aquasecurity/trivy-action@v0.36.0
if: ${{ !inputs.sarif }}
with:
scan-type: fs
scanners: vuln,secret,misconfig
format: table
exit-code: "1"
severity: ${{ inputs.severity }}
ignore-unfixed: true
- uses: aquasecurity/trivy-action@v0.36.0
if: inputs.sarif
with:
scan-type: fs
scanners: vuln,secret,misconfig
format: sarif
output: trivy.sarif
severity: ${{ inputs.severity }}
ignore-unfixed: true
- uses: github/codeql-action/upload-sarif@v3
if: inputs.sarif && always()
with:
sarif_file: trivy.sarif
category: trivy-fs
# Only on pull requests: blocks a *new* vulnerable or badly-licensed
# dependency from entering, without failing the build over the backlog of
# ones already there.
dependency-review:
name: Dependency review
if: inputs.dependency-review && github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/dependency-review-action@v4
with:
fail-on-severity: high
comment-summary-in-pr: on-failure