Skip to content

Skip forks for code scanning, and keep the dashboard tiles under Loki's series cap - #277

Merged
cplieger merged 2 commits into
mainfrom
feat/code-scanning-exclude-forks
Aug 21, 2026
Merged

Skip forks for code scanning, and keep the dashboard tiles under Loki's series cap#277
cplieger merged 2 commits into
mainfrom
feat/code-scanning-exclude-forks

Conversation

@cplieger

Copy link
Copy Markdown
Owner

Summary

Two fixes to the same reported symptom: the Grafana dashboard's code-scanning and failed-runs panels returned maximum number of series (500) reached for a single query instead of data.

The tiles no longer count item lines. A metric query costs one Loki series per output row, and Loki caps a query at max_query_series (500 by default), so the three snapshot tiles errored once the open-alert count crossed it. They now read the per-scan scan complete summary line, which already carries open_prs, open_issues and code_alerts. That is a single series at any data volume.

Forks are skipped for code scanning by default. GitHub reports the alerts of the code a fork inherited as the fork's own. One fork of a large upstream project measured 500 open alerts against 6 across every first-party repo, which is both what drowned the signal and what pushed the panel past the ceiling. CODE_SCANNING_EXCLUDE_REPOS could silence a fork by name, but only once someone added it; CODE_SCANNING_EXCLUDE_FORKS (default true) covers a fork the moment it is created.

The flag is scoped to code scanning only, matching the sibling list: a fork's own pull requests and Actions runs are the owner's work. A fork and a named repo produce the identical skip, so neither can mark a scan degraded nor mask a real code-scanning blackout.

What is deliberately unchanged

The two detail tables keep one row per item, which is the right shape for a click-through list, so they stay bounded by the datasource ceiling. Their panel descriptions now say so and record that topk() does not evade the limit, because Loki checks it on the inner aggregation before topk reduces it. The compose example does not carry the new variable, since a knob that defaults correctly belongs in the configuration reference.

Testing

  • go test -count=1 -race ./... clean across all 6 packages; golangci-lint run ./... 0 issues.
  • New tests cover both directions of the flag, its default, envx's tolerant parsing of a malformed value, and independence from the name list.
  • Red-checked against four mutants, each caught by the test meant to catch it: the default flipped to false, the fork bit dropped from the decode, the fork condition dropped from the predicate, and the flag wired always-on (which is what stops the knob silently becoming a hardcoded rule).
  • The three rewritten tile queries were run against a live Loki and each returns exactly one series.

…ki's series cap

The three "At a glance" snapshot tiles counted item lines with
count(count by (repo, number) (...)), which costs one Loki series per
item. Loki caps a metric query at max_query_series (500 by default), so
the Code Scanning tile errored outright once the open-alert count crossed
it rather than reporting a number.

Read the per-scan "scan complete" summary line instead, which already
carries open_prs, open_issues and code_alerts. That is one series
regardless of how many items exist, so the tiles cannot hit the ceiling
at any data volume.

Two details make it one series. The json stage extracts only the fields
it needs, because a bare `| json` promotes every field and each varying
one splits the series. And max_over_time over the snapshot window, not
last_over_time, so a single degraded scan reporting 0 cannot blank a
tile while a signal that stays blind still reads 0.

The two detail tables keep one row per item, which is the right shape for
a click-through list, so they remain bounded by the ceiling. Their panel
descriptions now say so, name the two traps that put them there, and
record that topk() does not evade the limit because it is checked on the
inner aggregation.
GitHub reports the alerts of the code a fork inherited as the fork's own,
so a fork of a large project surfaces hundreds of findings in code the
owner did not write. Measured on one owner: a single fork of a big
upstream project carried 500 open alerts against 6 across every
first-party repo, which drowns the signal the code-scanning panel exists
to raise.

CODE_SCANNING_EXCLUDE_REPOS could already silence a fork by name, but only
once someone remembered to add it, and the flood arrives the moment a scan
is enabled on a new one. CODE_SCANNING_EXCLUDE_FORKS (default true) is the
batch form of that rule, so a fork is covered when it is created.

Scoped to code scanning only, matching the sibling list: a fork's own pull
requests and Actions runs are the owner's work. ghsignal.Repo now carries
the API's fork bit and codeScanningExcluded ORs the two conditions, so a
fork and a named repo produce the identical skip: no API call, a Debug
line, and no entry in the integrity verdict, so neither can mark a scan
degraded nor mask a real code-scanning blackout. The two mechanisms stay
independent, so the flag can be off while individual forks stay named.

Tests cover both directions of the flag, its default, envx's tolerant
parsing, and independence from the name list. Red-checked against four
mutants: the default flipped to false, the fork bit dropped from the
decode, the fork condition dropped from the predicate, and the flag wired
always-on, which is what stops the knob silently becoming a hardcoded
rule.

The README documents the behaviour and how to turn it off. The compose
example deliberately does not carry the variable, since a knob that
defaults correctly belongs in the configuration reference.
@cplieger
cplieger merged commit 124d920 into main Aug 21, 2026
19 checks passed
@cplieger
cplieger deleted the feat/code-scanning-exclude-forks branch August 21, 2026 15:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant