-
Notifications
You must be signed in to change notification settings - Fork 0
245 lines (225 loc) · 12.3 KB
/
Copy pathcodeql.yml
File metadata and controls
245 lines (225 loc) · 12.3 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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
name: CodeQL
# Static analysis for both languages in this repository.
#
# C# (the Control Panel) runs on every push and pull request. It builds on a
# GitHub-hosted runner in a couple of minutes, so it is cheap enough to gate
# changes on.
#
# C++ (the mail server - every protocol parser, and the whole surface that faces
# the internet) runs weekly and on demand, and deliberately NOT on push or pull
# request. That trade-off costs something, so the reasoning is recorded here
# rather than left to be rediscovered:
#
# * The server cannot be built on a GitHub-hosted runner at all. It needs the
# v145 toolset from Visual Studio 2026 and the prebuilt native dependencies
# (boost_1_91_0, openssl-4.0.1, postgresql-18.3) that $(hMailServerLibs)
# points at. See .github/workflows/server-build.yml, which carries the same
# requirement and the same [self-hosted, windows] label. There is one such
# machine, and it is also the machine that runs the regression suite.
# * CodeQL builds its database by tracing the compiler, so it needs a FULL
# build every time. An incremental build that skips up-to-date files
# produces an empty database and the analysis fails outright with "No source
# code was seen during the build". That means 516 translation units from
# cold, on every run, with the extractor inside every cl.exe invocation.
#
# Putting that on every push would queue pull requests behind a multi-hour job
# on a single machine, and would collide with the regression suite that shares
# it. Weekly plus on-demand is the honest answer.
#
# The cost of that choice, stated plainly: an alert introduced by a pull request
# is not seen until the next weekly run on master, and is then attributed to
# master rather than to the change that introduced it. When a change touches the
# protocol parsers, run this workflow by hand against the branch
# (workflow_dispatch) before merging rather than waiting for the schedule.
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
schedule:
- cron: '32 4 * * 1' # weekly, Monday 04:32 UTC
workflow_dispatch:
inputs:
configuration:
description: 'Build configuration for the C++ server analysis'
type: choice
options: [Release, Debug]
default: Release
permissions:
contents: read
jobs:
csharp:
name: Analyze (csharp)
runs-on: windows-latest
permissions:
security-events: write
actions: read
contents: read
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up .NET 10
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: '10.0.x'
# security-and-quality adds the quality-tagged queries to the security
# suite; their findings surface as code-scanning alerts alongside the
# security ones. (Not, as this comment once claimed, on the Code quality
# page - that page was fed by a separate GitHub-managed buildless scan,
# which ignored this repository's config entirely and was switched off
# deliberately: it re-reported, without type information, the exact
# rules excluded below with measured reasoning.) The six rules that fire
# in bulk here on deliberate design rather than on defects are filtered
# in the config file, each with its measured count and the reasoning.
- name: Initialize CodeQL
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
languages: csharp
build-mode: manual
config-file: ./.github/codeql/codeql-config.yml
queries: security-and-quality
# Both solutions, deliberately: for a traced build, CodeQL analyses only
# what the compiler compiles, so a project left out of this step is a
# project that has never been scanned. That was DBUpdater, DBSetup,
# DBSetupQuick, DataDirectorySynchronizer, ImportTool and Shared until
# the managed quality scan's findings revealed the gap - the only scanner
# covering those tools was the one being switched off for ignoring the
# config. The test projects are not built here and stay unscanned:
# fixtures, not shipped code.
- name: Build Control Panel
run: dotnet build hmailserver/source/Tools/ControlPanel/ControlPanel.csproj -c Release
- name: Build the setup and migration tools
run: dotnet build "hmailserver/source/Tools/hMailServer Tools.sln" -c Release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
category: "/language:csharp"
upload: never
output: sarif-results
# paths-ignore in codeql-config.yml cannot drop these results: for a
# compiled language analysed with build-mode: manual, CodeQL extracts
# whatever the compiler compiles - including the WPF XAML compiler's
# *.g.cs under obj/ and the WinForms designer's *.Designer.cs - and a
# config file's path filters only restrict extraction for interpreted
# languages or for build-mode: none. So both are dropped from the SARIF
# here, between analyse and upload, for the reasons the config records:
# build output is regenerated on every build, and designer files are
# rewritten by Visual Studio on every designer save, so a fix in either
# lasts until the next one. The first scan of the setup tools showed
# nine designer-file results, every one a cast the designer itself wrote.
- name: Drop build-output and designer-generated results from the SARIF
shell: python
run: |
import json
def in_build_output(result):
locations = result.get("locations") or []
if not locations:
return False
uri = locations[0].get("physicalLocation", {}).get("artifactLocation", {}).get("uri", "")
if uri.lower().endswith(".designer.cs"):
return True
return any(part in ("obj", "bin") for part in uri.split("/"))
path = "sarif-results/csharp.sarif"
with open(path, encoding="utf-8") as f:
sarif = json.load(f)
for run in sarif["runs"]:
before = len(run["results"])
run["results"] = [r for r in run["results"] if not in_build_output(r)]
print(f"Dropped {before - len(run['results'])} build-output or designer-generated result(s); {len(run['results'])} remain.")
with open(path, "w", encoding="utf-8") as f:
json.dump(sarif, f)
- name: Upload results
uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
sarif_file: sarif-results/csharp.sarif
category: "/language:csharp"
cpp:
name: Analyze (c-cpp)
# Schedule and manual dispatch only - see the header. A push or pull_request
# run of this job would sit on the one self-hosted machine for hours.
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: [self-hosted, windows]
# A cold traced build of 516 translation units plus query evaluation over
# 6.1 MB of C++. Bounded so a wedged run cannot hold the runner for a day.
timeout-minutes: 360
permissions:
security-events: write
actions: read
contents: read
env:
# inputs.configuration is empty on a scheduled run, and build.ps1 defaults
# to Debug when handed an empty string - which would quietly analyse the
# _DEBUG preprocessor path instead of the one that ships.
BUILD_CONFIGURATION: ${{ inputs.configuration || 'Release' }}
# MSBuild keeps its worker nodes alive between invocations by default. A
# node left over from an earlier job on this runner was started outside
# CodeQL's tracer, so anything it compiles is invisible to the extractor -
# which shows up as a partial database rather than as an error.
MSBUILDDISABLENODEREUSE: '1'
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# Fail here with a legible message rather than 500 lines into MSBuild.
# server-build.yml also warns about each individual dependency folder;
# this checks only the condition that makes the build impossible rather
# than merely likely to fail at link time.
- name: Verify native dependencies
shell: powershell
run: |
if (-not $env:hMailServerLibs) { throw "hMailServerLibs is not set on this runner. See .github/workflows/server-build.yml for what this runner needs." }
if (-not (Test-Path $env:hMailServerLibs)) { throw "hMailServerLibs path '$($env:hMailServerLibs)' does not exist." }
Write-Host "hMailServerLibs = $($env:hMailServerLibs)"
# The service on this runner runs from this checkout's build output, so
# the linker cannot replace hMailServer.exe while it is running. The
# project's own pre-build event does a NET STOP for exactly this reason,
# but build.ps1 suppresses pre- and post-build events, so it happens here
# instead - the same way server-build.yml handles it.
- name: Stop hMailServer service (free the executable)
shell: powershell
run: Stop-Service hMailServer -ErrorAction SilentlyContinue
# security-extended rather than security-and-quality, deliberately, and
# this is the one place the two languages are configured differently:
#
# * CodeQL ships no quality-tagged queries for C++ at all (measured
# in d1c35ec: 108 for C#, zero for C++), so security-and-quality
# would add nothing but the generic maintainability set.
# * What it would buy is roughly a hundred maintainability and
# reliability queries let loose on 6.1 MB of twenty-year-old ATL/COM
# C++, on a codebase that has never been scanned once. d1c35ec was
# written because 733 undifferentiated findings are "not a signal
# anyone can act on"; burying the first ever security scan of the
# protocol parsers under style alerts repeats that mistake.
#
# security-extended is strictly more security coverage with no quality
# queries, which is what this analysis is for. Once the security backlog
# is triaged, moving this to security-and-quality is a one-word change -
# but do it from a measured count, not on principle.
- name: Initialize CodeQL
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
languages: c-cpp
build-mode: manual
config-file: ./.github/codeql/codeql-config.yml
queries: security-extended
# -Clean is not optional. This runner reuses its workspace between runs,
# so without it MSBuild skips every up-to-date translation unit, the
# extractor sees nothing, and the analyze step below fails with "No source
# code was seen during the build" - the classic CodeQL C++ failure on a
# self-hosted runner, and one that reads like a CodeQL bug rather than an
# incremental build.
- name: Build server under CodeQL tracing
shell: powershell
run: ./build/build.ps1 -Configuration $env:BUILD_CONFIGURATION -Clean
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
category: "/language:c-cpp"
- name: Restart hMailServer service
if: ${{ always() }}
shell: powershell
run: |
Start-Service hMailServer -ErrorAction SilentlyContinue
$service = Get-Service hMailServer -ErrorAction SilentlyContinue
if (-not $service -or $service.Status -ne 'Running') {
Write-Warning "hMailServer is not running. A build that failed after the clean step leaves the output directory empty, so the service binary may be missing - rerun server-build.yml to restore it."
}