Skip to content

Configuration reference

Complete reference for the ringzero { } extension added by the tech.ringzero.sca plugin. All properties use Gradle’s lazy Property/ Provider types, so they’re compatible with the configuration cache and can be wired to providers.

PropertyTypeDefaultDescription
apiKeyProperty<String>Scoped API key (rz_key_…) with at least sca:upload + scans:read — see Authentication & permissions. Resolution order: this property → RINGZERO_API_KEY env var → ringzero.apiKey Gradle property. See secure provisioning.
apiUrlProperty<String>https://api.ringzero.tech/v1API base URL override. Only change this if RingZero support tells you to (e.g. a regional endpoint). Also settable via RINGZERO_API_URL.
organizationProperty<String>— (required)Your org id (org_9f3k), from Settings → General.
projectProperty<String>root project nameProject id (prj_6h2m) or slug. Pin it explicitly to keep scan history stable across renames. If the slug doesn’t exist server-side, the upload fails with 422 unknown_project — RingZero never auto-creates projects from uploads (a leaked upload key must not be able to create org resources).
suppressionsFileRegularFilePropertyringzero-suppressions.yml in the root projectThe suppressions file (plugin-side upload coming soon — see the note there). The default is used only when the file exists; explicitly setting a path that doesn’t exist is a configuration error.
reportsDirectoryDirectoryPropertybuild/ringzeroWhere the tasks write their machine-readable outputs (snapshot.json, scan.json, summary.json, findings.json).

Controls what goes into the dependency snapshot.

PropertyTypeDefaultDescription
configurationsListProperty<String>["runtimeClasspath"]Gradle configurations to resolve. Accepts exact names or globs ("*RuntimeClasspath"), optionally path-qualified per subproject (":benchmark:runtimeClasspath"; unqualified entries apply to every project). A name matching nothing in a given project is skipped silently (not every subproject has every configuration); an entry matching nothing in any project logs a warning.
excludedConfigurationsListProperty<String>[]Configurations to leave out, same name/glob/path-qualification rules as configurations. The selection is configurations minus excludedConfigurationsexclusion always wins. The motivating pattern is variant-heavy builds: configurations = ["*RuntimeClasspath"] with excludedConfigurations = ["debug*", "*AndroidTest*"].
excludedModulesListProperty<String>[]Glob patterns matched against group:name coordinates ("com.acme.internal:*", "*:fastjson"). Matched modules are removed from the snapshot before upload — they never reach RingZero, produce no findings, and don’t count toward snapshot limits. Transitive dependencies reachable only through an excluded module are pruned with it; ones also reachable via a non-excluded path stay. Use this for genuinely out-of-scope artifacts (in-house modules from an internal repository). To silence a known finding on a package you still want inventoried, use a suppression instead.
includeTransitiveProperty<Boolean>trueInclude transitive dependencies. Disabling this is almost never what you want — most vulnerable packages arrive transitively — but it’s available for diagnostics.
manifestsListProperty<String>auto-detectedManifest paths recorded in the snapshot. Detected per included subproject: build.gradle(.kts), plus gradle.lockfile when dependency locking is enabled. excludeProjects also excludes that project’s manifests. Override only if your build generates manifests in nonstandard locations.
excludeProjectsListProperty<String>[]Subproject paths (e.g. ":samples", ":docs") to leave out of the aggregated snapshot entirely — their configurations, modules, and manifests.

Glob syntax (everywhere globs are accepted): * matches any run of characters within a segment. There is no ** or ?.

Policy evaluated by ringzeroCheck after the scan completes. Without a failOn block, ringzeroCheck still waits for completion and prints the summary — it just never fails the build.

PropertyTypeDefaultDescription
severityProperty<String>unset (never fail)Minimum severity that fails the build: "critical", "high", "medium", or "low". A value of "high" fails on high and critical.
cvssProperty<Double>unsetFail on any finding with a CVSS base score at or above this value (0.0–10.0).
fixableOnlyProperty<Boolean>falseOnly findings with a non-null fixedVersion trip the gate — gate on what the team can action today. Unfixable findings are still reported, they just don’t fail the build.
reachableOnlyProperty<Boolean>falseOnly findings marked reachable trip the gate. Fail-safe rule: findings with no reachability data still gate — unknown ≠ safe.
gracePeriodProperty<Duration>unsetFindings whose advisory was published within the period (e.g. PT168H = 7 days, using the finding’s publishedAt) warn instead of fail — a CVE published overnight shouldn’t redden every pipeline before anyone can triage. Pair with expiring suppressions for the long tail.
unresolvableProperty<Boolean>falseWhat ringzeroCheck does when it can’t get an answer: poll timeout (upload.timeout), network loss mid-poll, or scan status: failed. false = warn and pass (fail open), true = fail the build (fail closed) — typical only in release pipelines. This governs ringzeroCheck only: an upload that exhausts its retries always fails ringzeroScan (there is no scan to check), and a deliberate --offline build runs report-only, never an unresolvable event.

How the thresholds combine: each finding is tested against severity and cvss independently — either trips the gate. A finding with no CVSS score (some advisories ship without a vector) is evaluated against severity only; setting only cvss never consults severity labels. fixableOnly and reachableOnly are filters on top: a finding must pass a threshold and every enabled filter to fail the build.

Network behavior for the snapshot upload and status polling.

PropertyTypeDefaultDescription
timeoutProperty<Duration>PT5MOverall budget for the upload (all attempts and backoff); once ringzeroCheck ships, also its wait-for-completion budget.
connectTimeoutProperty<Duration>PT10STCP/TLS connect timeout per request.
retriesProperty<Int>3Retry count for the upload request (exponential backoff with jitter; retries I/O errors, 5xx, and 429, honoring Retry-After). Other 4xx responses never retry.
pollIntervalProperty<Duration>PT5SInterval between GET /v1/scans/{scanId} polls — reserved for the upcoming ringzeroCheck, unused in v0.1.0.

Uploads are idempotent: the plugin sends the snapshot’s content hash as an Idempotency-Key, so a timeout-then-retry (or two CI jobs racing on the same commit) converges on one scan instead of creating duplicates.

The plugin uses the build JVM’s standard proxy settings — the same ones Gradle itself uses — set in gradle.properties:

gradle.properties
systemProp.https.proxyHost=proxy.internal
systemProp.https.proxyPort=3128
systemProp.http.nonProxyHosts=*.internal

There is deliberately no RingZero-specific proxy DSL: ops teams configure the JVM proxy once and every plugin honors it. (The sidecar, which doesn’t run on a JVM, has its own proxy config.)

Suppress a known, triaged finding without losing sight of it. Suppressions live in a committed YAML file — not the DSL — because they’re governance artifacts: the reason and expiry belong in code review, and the same file format works for direct API integrations.

ringzero-suppressions.yml
suppressions:
- cve: CVE-2025-4410 # required — CVE or GHSA id
package: "com.alibaba:fastjson" # optional glob; omitted = this CVE on any package
reason: "Not exploitable: we never deserialize untrusted input" # required
expires: 2026-10-01 # optional ISO date; omitted = no expiry

Semantics:

  • Suppressions are uploaded with the snapshot and applied server-side: matching findings are marked suppressed, excluded from the scan’s severity counts — and therefore from failOn gating — but remain visible in the app and the API.
  • reason is required. The plugin fails configuration on an entry without one.
  • An expired entry is ignored and produces a build warning naming it — gates come back automatically, which is the point of expires.
  • An entry matching no current finding is an --info-level note, not a warning: fixed CVEs go quiet gracefully.

Contrast with scan.excludedModules: exclusion removes a module from the snapshot entirely (no inventory, no findings, invisible); suppression keeps the dependency and the finding visible but un-gated. Prefer suppression for anything you may need to explain later.

TaskInputsOutputs (under reportsDirectory, default build/ringzero/)
ringzeroScanResolved dependency graphs of the selected configurations; scan { } settings; organization/project/apiUrl; whether an upload will happensnapshot.json (the uploaded snapshot); scan.json{ "id": "scn_7g8h", "url": "…" } after an upload, { "uploaded": false, "reason": "no-api-key" | "offline" } in report-only mode
ringzeroCheck Coming soonscan.json; the failOn { } policyBuild success/failure; console summary; summary.json — always written, pass or fail: { scanId, url, status, findings: {…}, suppressed, policy: { violated, threshold, violations } }; findings.json (raw findings array) when the key has findings:read

summary.json exists so CI can annotate PRs without scraping console output.

ringzeroScan is up-to-date when the resolved dependency graph (after exclusions), project, organization, apiUrl, and whether an upload would happen are all unchanged since the last run — the task then skips the upload and reuses the previous scan id. Consequences worth knowing:

  • Advisory data changes server-side. RingZero re-matches stored snapshots against new advisories continuously — new findings appear in the app — but the gate sees new advisories only on the next real upload (in practice: the next dependency change, or --rerun).
  • Providing an API key after a report-only run counts as a change: the next build re-executes and uploads instead of reporting up-to-date.
  • Force a fresh upload any time with ./gradlew ringzeroScan --rerun.

The tasks are configuration-cache compatible but never build-cacheable: the upload is a side effect, and a cache hit that silently skipped it would be a correctness bug.

Two situations put ringzeroScan in the same report-only mode: Gradle’s --offline flag, and no API key resolving from any source. In both, the task still resolves the graph and writes snapshot.json (handy for inspecting what would upload), skips the upload, logs which mode it is in, and succeeds — a missing key is never an error. scan.json records the outcome as { "uploaded": false, "reason": "no-api-key" | "offline" }.

Deliberate offline is never a failOn.unresolvable failure — that property governs unexpected unreachability only.

For every setting with more than one source, the plugin resolves in this order (first match wins):

PrioritySourceExample
1ringzero { } DSLapiUrl = "https://api.eu.ringzero.tech/v1"
2Environment variableRINGZERO_API_URL=…
3Gradle propertyringzero.apiUrl=… in ~/.gradle/gradle.properties

This applies to scalar top-level properties (apiKey, apiUrl, organization, project), which all have RINGZERO_* env and ringzero.* Gradle-property forms. List-valued and block settings (scan { }, failOn { }, upload { }, suppressionsFile, reportsDirectory) are DSL-only.