ci(codeql): move to advanced setup with concurrency control and non-alerting query exclusions - #397
MichaelTaylor3d wants to merge 4 commits into
Conversation
Confirmed live on PR #397: varying build-mode (always 'none' for every language here) produced the check name 'Analyze (rust, none)' instead of the 'Analyze (rust)' branch protection requires. Single-axis matrix on language alone keeps the registered name identical, so no branch-protection change is needed. Co-Authored-By: Claude <noreply@anthropic.com>
…ound 1 found Round 1 excluded the two queries measured to dominate the ~100-minute query evaluation phase (type-inference-consistency-counts, nodes-at-type-path- length-limit). That exclusion works -- PR #397's own run proves both are gone from the 36-query default suite -- but wall time did not move: the same job was still running past its 30-minute timeout, evaluating DataFlowConsistencyCounts.ql, an `@kind diagnostic` query with the identical "full-database consistency check" shape as the query round 1 already found ruinous. Generalize round 1's own reasoning instead of chasing queries one at a time: exclude every `@kind diagnostic` / `@kind metric` Rust query (18 more, confirmed individually against their github/codeql main headers), since code-scanning SARIF only ever alerts on `@kind problem` / `@kind path-problem`. This leaves exactly the 16 security/CWE-* queries running -- zero security coverage lost. Also raises the job timeout to 90 minutes (from 30) TEMPORARILY so this PR's next run measures a real completion time instead of being truncated by the same ceiling that cut round 1's post-fix run short at exactly 30m11s. Comes back down once a green run gives a real number. Refs DIG-Network/dig_ecosystem#3205
Default setup (`dynamic/github-code-scanning/codeql`, no workflow file) took no concurrency group, so every push started a fresh full analysis and superseded runs were never cancelled -- measured 2026-09-06, six CodeQL runs in progress at once across PR #394 and #395. Stacking was not the whole story: a single, uncontested run (job 101430031199, PR #395) still took ~101 minutes. Its own job log shows why -- extraction (rust-analyzer, build-mode: none) finished in ~6.5 minutes, then `rust/diagnostics/type-inference-consistency-counts` alone ran 44m34s and `rust/summary/nodes-at-type-path-length-limit` a further ~49m. Both are internal CodeQL diagnostic/telemetry queries (zero security alerts, ever) that force a full-database type-inference relation nothing else needs at that granularity -- every real security query (TaintedPath, XSS, SqlInjection, ...) then completed within seconds of each other once that relation was warm. - Add `.github/workflows/codeql.yml`: advanced setup, `concurrency: cancel-in-progress` keyed on ref+workflow+event, `timeout-minutes: 30` as a regression backstop, same four languages and same SARIF `category` default setup used (so existing alerts keep their identity). - Add `.github/codeql/codeql-config.yml`: `query-filters` excluding exactly the two internal queries above, by their upstream `@id`. No security query is touched. - Bump the workspace version 15.2.0 -> 15.3.1 (above both #394's 15.3.0 and #395's 15.2.1, the two other PRs open against this version line). Branch protection's required context `Analyze (rust)` is updated separately, once this workflow's real check name is confirmed from a live run (advanced setup can register under a different name than default setup did). Refs DIG-Network/dig_ecosystem#3205 Co-Authored-By: Claude <noreply@anthropic.com>
Confirmed live on PR #397: varying build-mode (always 'none' for every language here) produced the check name 'Analyze (rust, none)' instead of the 'Analyze (rust)' branch protection requires. Single-axis matrix on language alone keeps the registered name identical, so no branch-protection change is needed. Co-Authored-By: Claude <noreply@anthropic.com>
…ound 1 found Round 1 excluded the two queries measured to dominate the ~100-minute query evaluation phase (type-inference-consistency-counts, nodes-at-type-path- length-limit). That exclusion works -- PR #397's own run proves both are gone from the 36-query default suite -- but wall time did not move: the same job was still running past its 30-minute timeout, evaluating DataFlowConsistencyCounts.ql, an `@kind diagnostic` query with the identical "full-database consistency check" shape as the query round 1 already found ruinous. Generalize round 1's own reasoning instead of chasing queries one at a time: exclude every `@kind diagnostic` / `@kind metric` Rust query (18 more, confirmed individually against their github/codeql main headers), since code-scanning SARIF only ever alerts on `@kind problem` / `@kind path-problem`. This leaves exactly the 16 security/CWE-* queries running -- zero security coverage lost. Also raises the job timeout to 90 minutes (from 30) TEMPORARILY so this PR's next run measures a real completion time instead of being truncated by the same ceiling that cut round 1's post-fix run short at exactly 30m11s. Comes back down once a green run gives a real number. Refs DIG-Network/dig_ecosystem#3205
f5cb62b to
b7d8529
Compare
…timeout Round 2 (run 34034753310, 16 security queries only, 90-minute ceiling) did not finish: extraction 6m15s, TRAP import 1m39s, then all 16 security queries started by 13:08:42Z and not one completed in the following 81m27s. Cross-read with the unfiltered default-setup run 34027560462 (SUCCESS, 122m24s), where TypeInferenceConsistencyCounts finished at eval 54m32s, NodesWithTypeAtLengthLimit at 113m21s, and then every security query finished inside the next 45 seconds each stamped "eval 113mXXs", the picture is unambiguous: the ~113 minutes is a single shared type-inference relation every Rust taint/data-flow query depends on. Round 1 booked it against the two queries that happened to consume it first. Excluding reporters cannot remove a shared predicate. So: keep the 20 exclusions (correct, zero coverage loss, ~6 minutes of cheap work saved) but rewrite both files' comments to state what was actually measured instead of the misattribution, and put timeout-minutes back to 30 as an explicitly non-shippable fail-fast placeholder -- a value that passes would have to clear today's 101-199 minute spread, which is the wait this ticket exists to remove. The remaining lever is a gate-shape decision (run the Rust analysis on push:main + schedule instead of every pull_request), left for the orchestrator on dig_ecosystem#3205. Also records the verified default-setup handoff: no dynamic run fired on this push, so the earlier double-runs were a propagation lag -- but with default setup off and this workflow not yet on main, every other open PR now has NO Analyze (rust) check-run at all, and that required context reads as ABSENT (dig-app#395 head 991ddf1, measured 14:35Z). Refs DIG-Network/dig_ecosystem#3205
|
Closing: the user has decided to disable CodeQL for now — "codeql is taking to long, its infeasible to keep using it, i would like to disable it for now" (2026-09-06). This PR was moving CodeQL from GitHub's default setup to an advanced workflow so its stacking could be controlled. That work is now moot, and it had also caused a repo-wide merge outage: disabling default setup left
The measurement is worth keeping, because it is why the decision is right rather than a retreat:
Excluding 18 diagnostic queries cut the total from 122.4 min, but the cost is query evaluation of the 16 Re-enabling is tracked on dig-app#398, which is now scoped to that decision rather than to restoring a required check. |
Round 2 measurement: the Rust floor is ~2 hours and it is not in any excludable queryTL;DR: the round-1 diagnosis ("two internal telemetry queries dominate") was a misattribution of a shared predicate. Excluding them worked (verified) and changed nothing (verified). Every Rust security query depends on one ~113-minute type-inference relation; whichever query consumes it first gets the bill. No config-file change can remove it. The three runs, all CodeQL 2.26.4 /
|
| run | what ran | outcome | extraction | TRAP import | query evaluation |
|---|---|---|---|---|---|
34027560462 (GitHub default setup, dynamic/github-code-scanning/codeql, unfiltered, 36 queries) |
on b61011eb |
SUCCESS, 122m24s (10:29:32Z -> 12:31:56Z) | 5m44s | 1m28s | 12 cheap diagnostic/summary queries done by eval-min 6; TypeInferenceConsistencyCounts done at 54m32s; NodesWithTypeAtLengthLimit done at 113m21s; then all 16 security queries finish within the next 45 s, each stamped eval 113mXXs |
| 34027562265 (this workflow, round-1 filters, 34 queries) | on b61011eb |
CANCELLED at 30m11s (job timeout) | 5m52s | 1m25s | the 2 exclusions provably applied (Loaded N/34); the same 12 cheap queries done by eval-min 6; nothing else finished in the next 16 min |
| 34034753310 (this workflow, round-2 filters, 16 security queries only) | on b7d8529a |
CANCELLED at 90m11s (job timeout raised to 90 for this measurement) | 6m15s | 1m39s | all 16 started by 13:08:42Z; not one finished in the following 81m27s |
Read together: in the unfiltered run the security queries were never "fast" -- they were waiting 113 minutes on the shared type-inference relation and then finished in seconds. Remove the two reporter queries and the identical cost moves into the security queries themselves. The 4-core / 14.5 GB runner shows no memory pressure in any log; this is CPU-bound relational evaluation.
Levers, each measured or checked
| lever | result |
|---|---|
build-mode: none |
already in force (log: --build-mode=none, rust-analyzer-style extraction). Extraction is 6 min, not the problem. |
| exclude the 2 round-1 queries | applied (34 not 36 loaded). Worth 0 minutes of wall time. |
exclude every @kind diagnostic / @kind metric query (18 more, each verified against its github/codeql header) |
applied (16 loaded). Worth ~6 minutes (the cheap queries). Zero coverage change: only @kind problem/path-problem become alerts and all 16 of those still run. Kept. |
| query suite in force | default (not security-extended), confirmed from the default-setup API and the loaded list. |
| newer CodeQL with faster Rust type inference | none exists: codeql-bundle-v2.26.4 is the latest release and is what github/codeql-action@v4 already pins. |
| larger runner | not available: the org has 0 GitHub-hosted larger runners and its default runner group excludes public repos. Would be a paid org-level setup, and even a 3x speedup lands ~40 min. |
| path scoping | would trim our own 329 inputs only; the type-inference cost is over the dependency graph (ExtractLibrary phase), so expected payoff is small and it was not spent a 2-hour run on. |
dependency-caching: true |
already on; "no caching configuration for rust" in the log -- the Rust extractor has nothing to cache in build-mode none. |
What is on the branch now (89817bc7, rebased onto main @ 4852247e, version kept at 15.3.1 > main's 15.3.0)
- the advanced workflow +
concurrencycancellation (the stacking half, still real and still working:e1c3b0c4's run was cancelled 91 s afterb61011ebsuperseded it); - the 20 exclusions, with both files' comments rewritten to say what was measured instead of the misattribution;
timeout-minutes: 30restored as an explicitly non-shippable fail-fast placeholder. A passing value would have to clear today's observed default-setup spread of 101-199 minutes (i.e. ~210), which codifies the very wait this ticket exists to remove.- check name
Analyze (rust)unchanged (single-axis matrix); branch protection untouched.
Two things the orchestrator has to decide -- I have not taken either
- Gate shape. The only lever left that reaches "under 30 minutes per PR" is to stop running the Rust analysis on every
pull_request: run it onpush: main+ the weekly schedule, and let theAnalyze (rust)matrix entry skip on PRs via a job-levelif:. A job skipped byif:still registers a check-run (conclusionskipped), which branch protection treats as satisfied, so the required-context name is preserved and no protection edit is needed. Cost, stated plainly: Rust findings would surface as alerts onmainafter merge, not as a blocking check before it. Same queries, same coverage, different timing. Alternatively: raise the timeout to ~210 and accept ~2-hour PRs (no latency fix), or re-enable default setup (same 2 hours, plus the stacking comes back). - A live hazard, independent of the above. Default setup is off and this workflow is not on
main, so every OTHER open dig-app PR now gets noAnalyze (rust)check-run at all -- and a required context that never appears reads as ABSENT and blocks the merge. Measured: dig-app#395 head991ddf15has zero such check-runs. That stays true until either this file lands onmainor default setup is re-enabled.
Nothing is analysed less than before on any path above: the 16 alert-producing Rust queries run in every variant.
Status: DRAFT -- the stacking half is fixed, the duration half is MEASURED, not fixed
Refs
DIG-Network/dig_ecosystem#3205-- CodeQL'sAnalyze (rust)required check was taking~130 minutes per PR. This PR fixes the run-stacking and measures the duration to its floor;
it does not reach the sub-30-minute target, and it says so rather than claiming to.
The remaining lever is a gate-shape decision recorded on the parent ticket, not a config
change (see the "Round 2 measurement" comment below for the full evidence table).
Diagnosis, measured on three real runs (CodeQL 2.26.4 / rust-queries 0.1.41, 2026-09-06)
dynamic/github-code-scanning/codeql) accepts noconcurrency:block. Measured 10:07Z: six CodeQL runs in progress at once across two PRs,none of the superseded ones ever cancelled. With this workflow's
concurrencygroup,e1c3b0c4's run was cancelled 91 s afterb61011ebsuperseded it.34027560462(SUCCESS, 122m24s) profiles as: extraction 5m44s, TRAP import 1m28s, 12 cheap
diagnostic/summary queries by eval-minute 6,
TypeInferenceConsistencyCountsdone at54m32s,
NodesWithTypeAtLengthLimitdone at 113m21s, then all 16 security queriesfinish inside the next 45 seconds, each stamped
eval 113mXXs. Excluding those twoqueries (round 1, run
34027562265) provably applied and changed nothing. Excluding everynon-alerting query so only the 16 security queries remain (round 2, run
34034753310,90-minute ceiling) still did not finish: all 16 started by 13:08:42Z, none completed in
the following 81m27s. The ~113 minutes is one shared type-inference relation every Rust
taint/data-flow query depends on; whichever query consumes it first gets the bill. No
exclusion can remove a shared predicate. Runner shows no memory pressure; CPU-bound.
build-mode: nonewas already in force (extraction is 6 min); thesuite in force is
default;codeql-bundle-v2.26.4is the latest release and alreadypinned by
github/codeql-action@v4; the org has zero GitHub-hosted larger runners and itsdefault group excludes public repos; path scoping cannot reach the dependency-graph
type inference.
What changed
.github/workflows/codeql.yml(new) -- advanced setup replacing default setup.concurrency: { group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}, cancel-in-progress: true }(this repo'sci.ymlconvention). Same four languages, samebuild-mode: none, samedependency-caching: true, same SARIFcategoryper language soexisting alerts keep their identity. Single-axis matrix so the check is still literally
Analyze (rust).timeout-minutes: 30is an explicitly non-shippable fail-fastplaceholder (a passing value would be ~210, clearing today's 101-199 minute spread);
the header comment records the measured floor and the pending decision.
.github/codeql/codeql-config.yml(new) --query-filtersexcluding 20 query IDs,every one
@kind diagnosticor@kind metric(verified per file against github/codeqlmain). Code scanning only turns
@kind problem/path-probleminto alerts, so nosecurity query is touched; all 16
security/CWE-*queries still run. Worth ~6 minutesand quieter telemetry, nothing more -- the comment says exactly that.
Cargo.toml/Cargo.lock-- workspace version15.3.0 -> 15.3.1(rebased ontomain@4852247e; strictly greater than main, kept per the parent ticket).The two traps this PR is careful about
Analyze (rust); a required contextthat never appears is ABSENT, not red, and blocks every future PR silently. The check
name is preserved (single-axis matrix) and branch protection is untouched.
(
state: not-configured, and no dynamic run fired on this PR's 13:00Z push), and thisworkflow is not yet on
main, so other PRs get noAnalyze (rust)check-run at all.Measured: dig-app#395 head
991ddf15has zero such check-runs. This stays true untilthis workflow lands on
mainin some shape, or default setup is re-enabled.Decision pending on the parent ticket (not taken here)
push: main+ weekly schedule onlyand skip the
Analyze (rust)matrix entry onpull_requestvia job-levelif:. A skippedjob still registers its check-run and branch protection treats
skippedas satisfied, sothe required-context name survives with no protection edit. Cost, stated plainly: Rust
findings become post-merge alerts on
main, not a pre-merge blocking check. Same queries.timeout-minutes: ~210, accept ~2-hour PRs. No latency fix.Blast radius checked
Two workflow/config files + the version manifest. No overlap with #395's changed files.
Nothing is analysed less than before on any path above.