CodeQL Collector
Detects GitHub CodeQL security scanning via GitHub Code Scanning check-runs or CLI integration in CI pipelines. Writes to normalized SAST Component JSON paths, enabling tool-agnostic SAST policies.
codeql to your lunar-config.yml:uses: github://earthly/lunar-lib/collectors/codeql@v1.0.5
What This Integration Collects
This integration includes 4 collectors that gather metadata from your systems.
github-app
Detects CodeQL scans on pull requests by querying GitHub check-runs API for the github-advanced-security app. Waits for scan completion and captures check status, conclusion, and URLs.
running-in-prs
Proves CodeQL is running on PRs by querying Lunar Hub for CodeQL data from recent PRs. Used on the default branch to provide compliance proof that PR scanning is happening.
cicd
Detects CodeQL CLI or legacy codeql-runner executions in CI pipelines. Captures command metadata and, when the SARIF output file is available on disk (from codeql database analyze/interpret-results), collects the raw SARIF and normalizes findings into .sast.findings and .sast.issues.
monorepo-fanout
Redistributes a monorepo's repo-wide CodeQL findings to its subdirectory components, so each one gets the findings under its own paths instead of reading as unscanned.
ONLY for monorepos, and target it at the repository ROOT — the component
whose name is the repo itself. Point it at anything else and it does
useless work on every commit: a component with no subcomponents has
nothing to fan out. Scope it with on: ["component:<repo>"], not a broad
domain selector.
Enable alongside cicd on that root: cicd writes the findings, this
distributes them. A finding reaches a subcomponent when its file matches
that subcomponent's paths: (plus the implicit ".sast.native stays on the root;
subcomponents get the severity counts their policies read plus provenance
under .sast.source.fanout. One that already has its own SAST scan is
never overwritten.
Requires Hub v3.3.0+. The root also needs at least one policy — an after-json collector is dispatched by the doneness gate, which is only consulted while bundling a component's policies.
How Collectors Fit into Lunar
Lunar watches your code and CI/CD systems to collect SDLC data from config files, test results, IaC, deployment configurations, security scans, and more.
Collectors are the automatic data-gathering layer. They extract structured metadata from your repositories and pipelines, feeding it into Lunar's centralized database where guardrails evaluate it to enforce your engineering standards.
Learn How Lunar Works →Example Collected Data
This collector writes structured metadata to the Component JSON. Here's an example of the data it produces:
{
"sast": {
"running_in_prs": true,
"source": {
"tool": "codeql",
"version": "2.16.0",
"integration": "ci"
},
"findings": {
"critical": 0,
"high": 1,
"medium": 3,
"low": 0,
"total": 4
},
"issues": [
{
"severity": "high",
"rule": "go/sql-injection",
"file": "db/query.go",
"line": 42,
"message": "Unsanitized input used in SQL query"
}
],
"summary": {
"has_critical": false,
"has_high": true
},
"native": {
"codeql": {
"github_app": {
"id": 12345,
"name": "CodeQL",
"status": "completed",
"conclusion": "success"
},
"cicd": {
"cmds": [
{"cmd": "codeql database interpret-results --format=sarif-latest --output=../results/go.sarif", "version": "2.16.0"}
]
},
"sarif": {}
}
}
}
}
Configuration
Configure this collector in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
monorepo_fanout_include_issues
|
Optional |
false
|
Also write the per-finding array (`.sast.issues`) to each subcomponent, sliced to the findings that component owns. Off by default: `policies/sast` reads `.sast.summary.has_<sev>` and `.sast.findings.<sev>`, and `max-total` reads `.sast.findings.total` — none of them read `.sast.issues`, so shipping it multiplies write size by findings x subcomponents for data no guardrail evaluates. Turn it on if you want the per-finding detail visible on each service in the UI. |
Documentation
View on GitHubCodeQL Collector
Detects GitHub CodeQL security scans and collects scan metadata from GitHub Code Scanning or CLI integrations.
Overview
This collector detects CodeQL static analysis via GitHub's Code Scanning integration or CLI usage in CI pipelines. CodeQL is GitHub's semantic code analysis engine — unlike pattern-matching tools, it compiles source code into a relational database and queries it for vulnerabilities using inter-procedural data flow analysis.
All data is written to the .sast category, enabling tool-agnostic SAST policies that work across CodeQL, Semgrep, Snyk Code, and other SAST tools.
Collected Data
This collector writes to the following Component JSON paths:
| Path | Type | Description |
|---|---|---|
.sast.source |
object | Source metadata (tool, integration, optional version) |
.sast.findings |
object | Severity counts: critical, high, medium, low, total |
.sast.issues[] |
array | Individual findings with severity, rule, file, line, message |
.sast.summary |
object | has_critical, has_high booleans |
.sast.native.codeql.github_app |
object | Raw GitHub Code Scanning check-run data |
.sast.native.codeql.cicd |
object | CodeQL CLI invocations detected in CI |
.sast.native.codeql.sarif |
object | Raw SARIF output from CodeQL analysis (when available) |
.sast.running_in_prs |
boolean | Compliance proof that PRs are being scanned |
.sast.source.fanout |
object | (monorepo-fanout, on each subcomponent) Provenance — root component, root SHA, path patterns used, matched count, fingerprint |
.sast.native.monorepo_fanout |
object | (monorepo-fanout, on the ROOT only) Per-target written/skipped breadcrumb |
Collectors
| Collector | Hook Type | Description |
|---|---|---|
github-app |
code (PRs only) | Detects CodeQL via GitHub Code Scanning check-runs |
running-in-prs |
code (default branch) | Proves CodeQL is running on PRs (compliance proof for default branch) |
cicd |
ci-after-command | Detects codeql and legacy codeql-runner executions in CI, collects SARIF |
monorepo-fanout |
after-json (.sast.issues) |
Redistributes a monorepo's repo-wide findings to its subdirectory components by file path. Enable on the repository ROOT alongside cicd. Writes each subcomponent's severity counts (.sast.findings/.sast.summary) plus provenance; .sast.native stays on the root. Subcomponents are discovered with a prefix-scoped SQL query, and a finding reaches a subcomponent when its file matches that component's paths: plus the implicit <subdir>/*. A subcomponent with zero matches is still written with total: 0, which turns its SAST policy from "no data" into a pass; one that already has its own SAST scan is never overwritten. Requires Hub v3.3.0+, and the root needs at least one policy or the after-json wave is never dispatched |
Installation
Add to your lunar-config.yml:
collectors:
- uses: github://earthly/lunar-lib/collectors/codeql@main
on: ["domain:your-domain"]
secrets:
GH_TOKEN: ${GH_TOKEN}
The github-app collector requires a GH_TOKEN secret for GitHub API access. CodeQL posts check-runs via the github-advanced-security app. The collector queries the check-runs API, filters by this app slug, and waits for completion.
The cicd collector matches both codeql and codeql-runner (legacy) binary executions in CI. When the traced command is codeql database analyze or codeql database interpret-results with a --output= flag, the collector reads the SARIF file from disk and collects it as raw data plus normalized findings counts and issues.
The running-in-prs collector queries the Lunar Hub database to verify PR scanning. It uses lunar sql connection-string to obtain database credentials. If unavailable, the collector skips silently.
Monorepos
CodeQL analyses a whole repository, and the traced scan resolves to the
repository — so in a monorepo the findings land on the repo-root component while
the real components are the subdirectories, which all read as "No SAST scanning
data found" despite having been scanned. monorepo-fanout closes that gap.
Three things have to be true:
- the monorepo's root needs a component of its own — it is where the
repo-wide scan lands and where the fan-out runs. Target the sub-collector at
that root with
on: ["component:<repo>"]; subcomponents are then found automatically. Pointing it at a broad domain selector just makes it do useless work on every non-monorepo component; cicdhas to be enabled on that root, since it is what writes the.sast.issuesthe fan-out reads;- at least one policy must also evaluate the root. An
after-jsoncollector is dispatched by the Hub's doneness gate, and that gate is only consulted while bundling a component's policies — so a component that no policy evaluates never fires its after-json collectors at all. Watch the interaction with domains: a policy declared with noon:resolves todomain:other, so putting the root in a dedicated domain (sensible on its own terms) can silently take it out of every fleet policy's scope.
components:
# The repository root. A scan carrier, not a deployable service — its own
# domain keeps your service guardrails off it.
github.com/acme/repo:
owner: platform@acme.com
domain: engineering.monorepo-roots
branch: "main"
# Subcomponents are unchanged.
github.com/acme/repo/services/api:
domain: engineering.services
paths: ["services/api/*"]
collectors:
- uses: github://earthly/lunar-lib/collectors/codeql@main
on: ["component:github.com/acme/repo"]
include: [cicd, monorepo-fanout]
secrets:
GH_TOKEN: ${GH_TOKEN}
# with:
# # Off by default: no SAST policy reads .sast.issues, so the per-finding
# # array is not shipped to every subcomponent unless you want the detail
# # visible per service.
# monorepo_fanout_include_issues: "false"
policies:
# Point 3 above — without a policy on the root, the fan-out never dispatches.
- uses: github://earthly/lunar-lib/policies/sast@main
on: ["component:github.com/acme/repo"]
include: [executed]
Because the wave is fire-once per (component, sha, pr), re-testing a change
needs a fresh commit — re-running CI on the same commit will not re-fire it.
Open Source
This collector is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore guardrails that use data from CodeQL Collector.
Ready to Automate Your Standards?
See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 200+ built-in guardrails.