Repository navigation
133 lines (121 loc) · 5.88 KB
/
Copy pathcodeql.yml
File metadata and controls
133 lines (121 loc) · 5.88 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
name: CodeQL
# Static analysis, deliberately kept off the release path.
#
# This is a separate workflow, not a job in test.yml and not called by release.yml, and it
# must stay that way. test.yml is the gate that decides whether a merge to main ships a
# binary; a finding from a scanner that updates its query pack on its own schedule is not a
# reason to refuse to release. The same argument the clippy and fmt steps already make in
# test.yml, for the same reason - so do not add these jobs to the repository's required
# status checks.
#
# All three languages analyse without a build. Rust analysis went generally available in
# October 2025 as a buildless extractor, which is what makes this affordable here: it reads
# src-tauri without compiling any of its 799 crates.
on:
pull_request:
branches: [main, develop]
# The default branch needs analysing on its own for the Security tab to have a baseline to
# compare pull requests against, and nothing pushes to main except a release. A schedule
# runs against the default branch, which covers it without putting a second workflow in
# front of every merge.
schedule:
- cron: '41 4 * * 1'
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.head.sha || github.sha }}
cancel-in-progress: true
jobs:
# The rust leg is the whole length of this workflow: six to eight minutes against about one
# for each of the other two, and caching the cargo registry was measured to save nothing.
# Almost none of that time is this repository's code. The extractor spends it resolving the
# 799 crates in Cargo.lock and reading their signatures, and the queries spend it on one
# shared pass over the database that builds - which is why all 37 finish together, and why
# dropping queries would not help. So a pull request that touches no Rust skips it.
#
# Only pull requests. The weekly schedule and a manual dispatch always analyse everything,
# which is what keeps the Security tab's baseline for main complete. A skipped PR shows a
# warning in the Code scanning check that the rust configuration was not found; that is the
# expected cost of skipping, not a failure.
rust-changes:
name: Rust changed?
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
pull-requests: read
outputs:
analyze: ${{ steps.check.outputs.analyze }}
steps:
- name: Look for changes the rust analysis would see
id: check
env:
GH_TOKEN: ${{ github.token }}
EVENT: ${{ github.event_name }}
PR: ${{ github.event.pull_request.number }}
run: |
analyze=true
# Every doubt resolves to analysing. A failed lookup reads as "no files", which
# would otherwise mean "no Rust" and skip the one thing this workflow is slow for.
if [ "$EVENT" = pull_request ] \
&& files=$(gh api "repos/$GITHUB_REPOSITORY/pulls/$PR/files" --paginate --jq '.[].filename'); then
count=$(printf '%s\n' "$files" | grep -c . || true)
# The files endpoint stops at 3000. Past that the list is incomplete.
if [ "$count" -gt 0 ] && [ "$count" -lt 3000 ] \
&& ! printf '%s\n' "$files" | grep -qE '^(src-tauri/|\.github/workflows/codeql\.yml$)'; then
analyze=false
fi
echo "$count files changed; rust analysis: $analyze"
fi
echo "analyze=$analyze" >> "$GITHUB_OUTPUT"
analyze:
name: Analyze (${{ matrix.language }})
needs: rust-changes
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
# The only one that is not read-only: this is what lets the run upload its results to
# the Security tab. Everything else is narrowed to read.
security-events: write
actions: read
contents: read
strategy:
# One language failing should still leave the other two reporting.
fail-fast: false
matrix:
include:
# The workflows themselves, and the most interesting of the three in this
# repository: release.yml interpolates ${{ }} expressions directly into `run:`
# shell blocks in several places, which is exactly the shape this pack looks at.
- language: actions
build-mode: none
# Covers src/lib/**/*.ts, which is where the logic lives. Note what it does *not*
# cover: CodeQL's extractor does not parse .svelte files, so the script blocks
# inside components are invisible to it. Worth remembering before reading a clean
# result as "the frontend is clean".
- language: javascript-typescript
build-mode: none
- language: rust
build-mode: none
# Decided per step rather than per job, because a job-level `if` is evaluated before the
# matrix expands and cannot see `matrix.language`. The skipped rust leg still reports, as a
# green job with a note in its summary, rather than vanishing from the PR.
env:
SKIP: ${{ matrix.language == 'rust' && needs.rust-changes.outputs.analyze != 'true' }}
steps:
- name: Note the skip
if: env.SKIP == 'true'
run: echo "No Rust changed in this pull request, so the rust analysis was skipped. The weekly scheduled run still covers it." >> "$GITHUB_STEP_SUMMARY"
- name: Checkout code
if: env.SKIP != 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Initialize CodeQL
if: env.SKIP != 'true'
uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
- name: Analyze
if: env.SKIP != 'true'
uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4
with:
category: "/language:${{ matrix.language }}"