Min Coverage + SonarQube Collector
Enforce Min Coverage using data collected by SonarQube Collector. Automatically check testing and quality standards on every PR.
How SonarQube Collector Powers This Guardrail
The SonarQube Collector gathers metadata from your code analysis systems. This data flows into Lunar's Component JSON, where the Min Coverage guardrail evaluates it against your standards.
When enabled, this check runs automatically on every PR and in AI coding workflows, providing real-time enforcement with actionable feedback.
Quick Start Configuration
Add both the collector and policy to your lunar-config.yml to enable this guardrail.
# Step 1: Enable the SonarQube Collector
collectors:
- uses: github://earthly/lunar-lib/collectors/sonarqube@v1.0.5
# with: ...
# Step 2: Enable the Code Quality Guardrails
policies:
- uses: github://earthly/lunar-lib/policies/code-quality@v1.0.5
include: [min-coverage]
# with: ...
What SonarQube Collector Collects
This collector gathers the following data that the Min Coverage guardrail evaluates.
api
Queries the SonarQube/SonarCloud Web API for code-quality metrics, scoped
per-commit. On default-branch commits the query uses branch=<default>;
on PR commits it uses pullRequest=$LUNAR_COMPONENT_PR — the only
difference between the two paths is the query param, so they share one
sub-collector. Because SonarQube's Compute Engine queues analyses
asynchronously — typically publishing 10–60s after sonar-scanner exits,
longer for large projects — this sub-collector polls
api/project_analyses/search for up to api_poll_timeout_seconds
(default 180s) waiting for an analysis whose revision matches the
current head_sha. If the matching analysis never appears, writes
.code_quality.source.analysis_status = "pending" and no metrics, so
policies can distinguish "SonarQube hasn't finished yet" from "SonarQube
isn't configured". Discovers the project key from the
sonarqube/project-key meta annotation (typically set by a
company-specific cataloger via lunar catalog component --meta sonarqube/project-key <key>), or falls back to the explicit
project_key input. Writes a tool-agnostic passing signal, coverage
and duplication percentages, and severity-bucketed issue counts at the
.code_quality.* top level. SonarQube-specific structure (quality gate
detail, the reliability/security/maintainability rating split, SQALE
debt, native metric names) lands under .code_quality.native.sonarqube
for SonarQube-specific policies that need it. Runs on both default-branch
and PR commits by default — users who want only one can narrow
runs_on on their import in lunar-config.yml.
auto
Runs sonar-scanner on the checked-out source against the configured
SonarQube/SonarCloud server, then polls the Web API for results — an
all-in-one alternative to api for users who don't trigger SonarQube
from their own CI. On default-branch commits the scanner is invoked with
-Dsonar.branch.name=<default>; on PR commits with
-Dsonar.pullrequest.key=$LUNAR_COMPONENT_PR,
-Dsonar.pullrequest.branch=$LUNAR_COMPONENT_HEAD_BRANCH, and
-Dsonar.pullrequest.base=$LUNAR_COMPONENT_BASE_BRANCH. Scanner
invocation metadata (version, exit code, duration) is captured under
.code_quality.native.sonarqube.auto. Once the scanner exits, the same
polling path used by api reads the published analysis and writes the
tool-agnostic .code_quality.* fields with "integration": "auto". If
the scanner fails, writes
.code_quality.native.sonarqube.auto.status = "scanner-failed" with the
exit code and no downstream metrics. Requires SONARQUBE_TOKEN with
Execute Analysis permission (read-only Browse is not sufficient).
Mutually exclusive with api and with a user-run sonar-scanner in CI
on the same commit — enabling both means the scanner runs twice. A
future collector-dependency feature will let auto fire only when the
cicd sub-collector did not capture a scan for the same head_sha.
Runs on both default-branch and PR commits by default — narrow runs_on
on the import to restrict the scope.
config
Detects SonarQube/SonarCloud configuration in the repository — the
sonar-project.properties file, the sonar-maven-plugin in pom.xml,
the org.sonarqube plugin in build.gradle/build.gradle.kts, or
<SonarQubeEnabled> in a .csproj. Writes discovered config file
paths under .code_quality.native.sonarqube.config. Presence of this
data signals that SonarQube is wired up for the component even when
the api sub-collector cannot reach the project or no analysis has
been published yet.
cicd
Detects sonar-scanner invocations in CI pipelines via a
ci-after-command hook. Captures the command string, exit code, and
scanner version. Writes to .code_quality.native.sonarqube.cicd.cmds[],
mirroring the snyk/cli pattern. Maven (mvn sonar:sonar) and Gradle
(gradle sonarqube) launchers are not covered in V1 — those need
separate binary-match rules and will be added in follow-up PRs.
Example Data Flow
Here's an example of the data that SonarQube Collector writes to the Component JSON, which Min Coverage then evaluates.
{
"code_quality": {
"source": {
"tool": "sonarqube",
"integration": "api",
"project_key": "my-org_my-service",
"api_url": "https://sonarcloud.io",
"analysis_status": "complete"
},
"passing": true,
"coverage_percentage": 78.3,
"duplication_percentage": 3.1,
"issues": {
"total": 46,
"critical": 0,
"high": 1,
"medium": 3,
"low": 42
},
"native": {
"sonarqube": {
"quality_gate": {
"status": "OK",
"conditions_failed": 0
},
"ratings": {
"reliability": "A",
"security": "B",
"maintainability": "A",
"security_review": "A"
},
"metrics": {
"bugs": 3,
"vulnerabilities": 1,
"code_smells": 42,
"lines_of_code": 12500
},
"auto": {
"status": "complete",
"version": "7.0.0.4796",
"exit_code": 0,
"duration_seconds": 47
},
"config": {
"files": ["sonar-project.properties"]
},
"cicd": {
"cmds": [
{"cmd": "sonar-scanner -Dsonar.projectKey=my-org_my-service", "version": "5.0.1", "exit_code": 0}
]
},
"github_app": {
"status": "complete",
"state": "success",
"context": "SonarCloud Code Analysis",
"target_url": "https://sonarcloud.io/dashboard?id=my-org_my-service&pullRequest=42"
}
}
}
}
}
Configuration Options
SonarQube Collector Inputs
| Input | Required | Default | Description |
|---|---|---|---|
project_key |
Required | — | SonarQube/SonarCloud project key (e.g. `my-org_my-service`). Used by the `api` and `auto` sub-collectors. Optional if the component has a `sonarqube/project-key` meta annotation set by a cataloger. |
sonarqube_base_url |
Optional |
https://sonarcloud.io
|
SonarQube/SonarCloud API base URL. Defaults to SonarCloud. Set to your SonarQube server URL (e.g. `https://sonar.example.com`) for self-hosted. |
api_poll_timeout_seconds |
Optional |
180
|
Total seconds the `api` and `auto` sub-collectors will wait for a SonarQube analysis matching the current `head_sha` to appear before giving up and emitting `analysis_status: "pending"`. SonarQube's Compute Engine queues analyses asynchronously; results typically publish 10–60s after `sonar-scanner` exits, longer for large projects. |
api_poll_interval_seconds |
Optional |
10
|
Seconds between polls while the `api` and `auto` sub-collectors wait for SonarQube analysis to complete. |
auto_scanner_version |
Optional |
7.0.0.4796
|
Version of the `sonar-scanner` CLI downloaded and executed by the `auto` sub-collector. Pinned for reproducibility. If the collector image already ships with `sonar-scanner` on PATH, this input is ignored. |
auto_sources |
Optional |
.
|
Source root passed to `sonar-scanner` as `-Dsonar.sources=<value>` by the `auto` sub-collector. Defaults to the repo root. Override for monorepos where only a sub-tree should be analysed. |
auto_extra_args |
Required | — | Extra command-line arguments appended to every `sonar-scanner` invocation (e.g. `-Dsonar.exclusions=**/*.min.js`). Applied by the `auto` sub-collector on both default-branch and PR paths. |
github_app_poll_timeout_seconds |
Optional |
180
|
Total seconds the `github-app` sub-collector will wait for the SonarCloud GitHub check run to appear on the PR head SHA. |
github_app_poll_interval_seconds |
Optional |
10
|
Seconds between polls while the `github-app` sub-collector waits for the SonarCloud check run. |
Code Quality Guardrails Inputs
| Input | Required | Default | Description |
|---|---|---|---|
min_severity |
Optional |
high
|
Minimum severity to fail on (critical, high, medium, low) |
max_total_threshold |
Required | — | Maximum total issues allowed (must be configured) |
min_coverage_percentage |
Optional |
80
|
Minimum line-coverage percentage (0-100) |
max_duplication_percentage |
Optional |
5
|
Maximum duplicated-lines percentage (0-100) |
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.