changedOutput schema / oneOf
Previous value: -[
- {
- "additionalProperties": {},
- "properties": {
- "coverage": {
- "anyOf": [
- {
- "additionalProperties": {},
- "properties": {
- "batch_size": {
- "description": "The most purls one request carries (the API's cap per request).",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "batches": {
- "description": "Requests the distinct purls make, at batch_size each.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "batches_sent": {
- "description": "Of those, the ones the API answered.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "components_in_document": {
- "anyOf": [
- {
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
- },
- "distinct_purls": {
- "description": "Distinct purls to check: sent plus not_sent.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "duplicates_removed": {
- "description": "Purls that appeared more than once and were sent once.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "input": {
- "anyOf": [
- {
- "enum": [
- "purls",
- "cyclonedx",
- "spdx"
- ],
- "type": "string"
- },
- {
- "type": "string"
- }
- ],
- "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document."
- },
- "not_assessed": {
- "anyOf": [
- {
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "description": "Of those sent, the components with no verdict, as the answer counts them."
- },
- "not_sent": {
- "description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "not_sent_reason": {
- "anyOf": [
- {
- "anyOf": [
- {
- "enum": [
- "time_budget",
- "rate_limited",
- "request_failed",
- "server_busy"
- ],
- "type": "string"
- },
- {
- "type": "string"
- }
- ]
- },
- {
- "type": "null"
- }
- ],
- "description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, before a batch or while one was unanswered, which is then cut off; or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how), server_busy (hosted endpoint: the API's answers took this instance's parse budget more than a quarter past its bound, or this call's request past the 30 MiB one request may reserve, or a batch's answer was larger than the room left, so it was not read; no further batch was sent). null when every purl was sent."
- },
- "partial": {
- "description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
- "type": [
- "boolean",
- "null"
- ]
- },
- "rate_limit_waits": {
- "description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "sent": {
- "description": "Distinct purls sent and answered.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "waited_ms": {
- "description": "Milliseconds spent in those waits.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "with_purl": {
- "description": "Of those, the ones carrying a purl.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "without_purl": {
- "description": "The ones without a purl: not checked, and not clean.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- }
- },
- "required": [
- "input",
- "components_in_document",
- "with_purl",
- "without_purl",
- "duplicates_removed",
- "distinct_purls",
- "batch_size",
- "batches",
- "batches_sent",
- "sent",
- "not_sent",
- "not_sent_reason",
- "rate_limit_waits",
- "waited_ms",
- "not_assessed",
- "partial"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the answer covers; null where the answer says nothing about it."
- },
- "data": {
- "additionalProperties": {},
- "properties": {
- "answered_at": {
- "type": [
- "string",
- "null"
- ]
- },
- "components": {
- "type": [
- "number",
- "null"
- ]
- },
- "match_layer": {
- "type": [
- "string",
- "null"
- ]
- },
- "not_sent_purls": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "The distinct purls not sent (coverage.not_sent_reason says why): not checked, and not clean. Present only when some were not sent."
- },
- "results": {
- "items": {
- "additionalProperties": {},
- "properties": {
- "advisories_considered": {
- "type": [
- "number",
- "null"
- ]
- },
- "assessed": {
- "description": "Whether the matcher produced a verdict for this component. false is never clean.",
- "type": [
- "boolean",
- "null"
- ]
- },
- "candidates_capped": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "capped": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "code": {
- "type": [
- "string",
- "null"
- ]
- },
- "count": {
- "type": [
- "number",
- "null"
- ]
- },
- "cve_ids": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ]
- },
- "ecosystem": {
- "type": [
- "string",
- "null"
- ]
- },
- "error": {
- "type": [
- "string",
- "null"
- ]
- },
- "index": {
- "type": [
- "number",
- "null"
- ]
- },
- "input_kind": {
- "type": [
- "string",
- "null"
- ]
- },
- "matched_package": {
- "description": "The package name the advisories were looked up by (#2836): the purl's own name, or, for a deb or apk purl with an upstream qualifier, the source package it names, which is how Debian and Alpine file advisories.",
- "type": [
- "string",
- "null"
- ]
- },
- "matched_version_from": {
- "description": "Upstream rows: upstream when the qualifier named a version (upstream=name@version) and it was used, purl when the purl's own version was.",
- "type": [
- "string",
- "null"
- ]
- },
- "matched_via": {
- "description": "Which name matched_package is: purl_name (the purl's name), upstream (the purl's upstream qualifier) or coordinates (the component's package).",
- "type": [
- "string",
- "null"
- ]
- },
- "matches": {
- "anyOf": [
- {
- "items": {
- "additionalProperties": {},
- "properties": {
- "cve_id": {
- "type": [
- "string",
- "null"
- ]
- },
- "epss_score": {
- "description": "The CVE's EPSS score (FIRST), as EchelonGraph's record holds it; null when it has none.",
- "type": [
- "number",
- "null"
- ]
- },
- "fixed_in": {
- "description": "The lowest version above this component's that no affected interval of the CVE's record for the package holds, always above it: the fixed bound of the interval that holds the component's version, moved past any overlapping interval that still holds that bound (fixed_in_detail then names it). null when no such version is on record (an interval on the way records no fix: it ends at last_affected, or has no end) or no interval holds the version, with fixed_in_reason saying which. Where fixed_in_dispute is set, the CVE record's CNA and the advisory disagree on the range that holds the component's version, and fixed_in follows the source its higher names (its note says how).",
- "type": [
- "string",
- "null"
- ]
- },
- "fixed_in_detail": {
- "description": "Set when fixed_in is not the fixed bound of the interval that holds the component's version: the overlapping intervals of the same record it moved past, which still hold that bound.",
- "type": [
- "string",
- "null"
- ]
- },
- "fixed_in_dispute": {
- "anyOf": [
- {
- "additionalProperties": {},
- "properties": {
- "advisory_fixed": {
- "type": [
- "string",
- "null"
- ]
- },
- "advisory_id": {
- "type": [
- "string",
- "null"
- ]
- },
- "advisory_introduced": {
- "type": [
- "string",
- "null"
- ]
- },
- "advisory_last_affected": {
- "type": [
- "string",
- "null"
- ]
- },
- "advisory_listed": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "cna": {
- "anyOf": [
- {
- "additionalProperties": {},
- "properties": {
- "name": {
- "type": [
- "string",
- "null"
- ]
- },
- "short_name": {
- "type": [
- "string",
- "null"
- ]
- }
- },
- "type": "object"
- },
- {
- "type": "null"
- }
- ]
- },
- "cna_product": {
- "type": [
- "string",
- "null"
- ]
- },
- "cna_range": {
- "anyOf": [
- {
- "additionalProperties": {},
- "properties": {
- "changes": {
- "anyOf": [
- {
- "items": {
- "additionalProperties": {},
- "properties": {
- "at": {
- "type": [
- "string",
- "null"
- ]
- },
- "status": {
- "type": [
- "string",
- "null"
- ]
- }
- },
- "type": "object"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ]
- },
- "changes_truncated": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "less_than": {
- "type": [
- "string",
- "null"
- ]
- },
- "less_than_or_equal": {
- "type": [
- "string",
- "null"
- ]
- },
- "status": {
- "type": [
- "string",
- "null"
- ]
- },
- "version": {
- "type": [
- "string",
- "null"
- ]
- },
- "version_type": {
- "type": [
- "string",
- "null"
- ]
- }
- },
- "type": "object"
- },
- {
- "type": "null"
- }
- ]
- },
- "cna_range_default": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "higher": {
- "anyOf": [
- {
- "anyOf": [
- {
- "enum": [
- "cna",
- "advisory"
- ],
- "type": "string"
- },
- {
- "type": "string"
- }
- ]
- },
- {
- "type": "null"
- }
- ]
- },
- "kind": {
- "anyOf": [
- {
- "anyOf": [
- {
- "enum": [
- "fixed",
- "introduced"
- ],
- "type": "string"
- },
- {
- "type": "string"
- }
- ]
- },
- {
- "type": "null"
- }
- ]
- },
- "note": {
- "type": [
- "string",
- "null"
- ]
- }
- },
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "Once EchelonGraph's API serves it, set where the API found the CVE record's CNA and the advisory disagreeing on the range that holds this version. kind: fixed (they disagree on where the package is fixed) or introduced (the CNA's range starts below where the advisory's does). The advisory's bound in dispute, exactly one of advisory_fixed, advisory_last_affected and advisory_introduced, as the advisory's own statement gives it (advisory_listed: it lists affected versions rather than a range, and the bound is a version it lists), and advisory_id, the advisory. cna (name, short_name), cna_product (what the CNA's entry names, as the API reads it) and cna_range (version, less_than or less_than_or_equal, status, version_type; changes, each {at, status}, where the range's status changes inside it, with changes_truncated where the record held more): the CNA's range in dispute, as the API reads the record (where higher is cna, the CNA's range that reaches past the advisory's bound: on a cna_affected_range match it holds the version, and on an advisory_interval or exact_version_list match it holds the advisory's bound past the version (its fix, or the versions just above its last affected or listed version), so it may start above the version; where higher is advisory, the CNA's range that ends below it, the CNA saying the version is fixed), from an entry the record writes, or, with cna_range_default true, a span no entry writes that the record's defaultStatus covers. higher: the source the answer follows, the more conservative one (cna or advisory). note: the API's sentence on the dispute and what the answer does with it, relayed verbatim. Fields and values a later API adds are relayed. Its absence is not a finding that the CNA agrees: an API that does not serve it yet, or older than the field, sends none; one that serves it reads a CNA's ranges only where it applies them and only from an entry it matches to the package; and a match the CNA's range alone raises may carry none."
- },
- "fixed_in_reason": {
- "description": "Why fixed_in is null; absent when fixed_in is a version.",
- "type": [
- "string",
- "null"
- ]
- },
- "interval": {
- "anyOf": [
- {
- "additionalProperties": {},
- "properties": {
- "fixed": {
- "type": [
- "string",
- "null"
- ]
- },
- "introduced": {
- "type": [
- "string",
- "null"
- ]
- },
- "last_affected": {
- "type": [
- "string",
- "null"
- ]
- }
- },
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "The affected interval that holds this component's version (fixed is exclusive, last_affected inclusive): the advisory's, or, where version_evidence is cna_affected_range, the CVE record's CNA range. Absent when no interval holds it."
- },
- "kev_listed": {
- "description": "Whether the CVE is in CISA's Known Exploited Vulnerabilities catalog, as EchelonGraph's record holds it.",
- "type": [
- "boolean",
- "null"
- ]
- },
- "match_reason": {
- "description": "Why the match applies, with the affected interval the version falls inside: \"[A, B)\" names that interval's fixed bound B (another interval can still hold B; fixed_in is the version past them all), \"[A, B]\" the last affected version B. The interval is the advisory's, or, where version_evidence is cna_affected_range, the CVE record's CNA range. On an upstream row it ends by naming the source package and the purl name.",
- "type": [
- "string",
- "null"
- ]
- },
- "version_evidence": {
- "anyOf": [
- {
- "anyOf": [
- {
- "enum": [
- "exact_version_list",
- "advisory_interval",
- "fix_boundary_only",
- "no_version_supplied",
- "cna_affected_range"
- ],
- "type": "string"
- },
- {
- "type": "string"
- }
- ]
- },
- {
- "type": "null"
- }
- ],
- "description": "Registry match: how the version was decided: exact_version_list (named in the advisory's list of affected versions), advisory_interval (inside one of its intervals), fix_boundary_only (below its only stored fix, its lower bound assumed), no_version_supplied (no version given, so no claim about it), or, once EchelonGraph's API serves it, cna_affected_range (held by the CVE record's CNA range, where no advisory statement holds it: interval is the CNA's range, and fixed_in_dispute, where the API publishes one, says how the two differ; such a match may carry none). Relayed as the API sends it; a later value is relayed too."
- }
- },
- "type": "object"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ]
- },
- "matches_truncated": {
- "additionalProperties": {},
- "description": "Present only on a row whose matches the structured result's cut (DATA CUT) shortened or left out: total, the row's matches in the answer; returned, the ones data keeps (chosen used in ransomware first, then the other KEV-listed ones, then highest effective_score, and listed in the API's order); and, while they fit, of all its matches, the CVE IDs KEV-listed (kev_listed_cve_ids) or used in ransomware (ransomware_cve_ids), and the distinct fixed_in versions (fixed_in_versions). The same call with full: true returns every match.",
- "properties": {
- "fixed_in_versions": {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "kev_listed_cve_ids": {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "ransomware_cve_ids": {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "returned": {
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "total": {
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- }
- },
- "required": [
- "total",
- "returned"
- ],
- "type": "object"
- },
- "not_affected_count": {
- "type": [
- "number",
- "null"
- ]
- },
- "not_assessed_reason": {
- "description": "Why assessed is false: package_not_in_advisory_corpus, no_decidable_advisory, advisory_lookup_failed, candidate_window_truncated, time_budget, distro_release_unknown, purl_type_unsupported, version_missing or invalid_component.",
- "type": [
- "string",
- "null"
- ]
- },
- "package": {
- "type": [
- "string",
- "null"
- ]
- },
- "purl": {
- "type": [
- "string",
- "null"
- ]
- },
- "purl_name": {
- "description": "Upstream rows: the purl's own (binary) package name, not looked up.",
- "type": [
- "string",
- "null"
- ]
- },
- "undetermined": {
- "anyOf": [
- {
- "items": {
- "additionalProperties": {},
- "properties": {
- "cve_id": {
- "type": [
- "string",
- "null"
- ]
- }
- },
- "type": "object"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ]
- },
- "undetermined_count": {
- "type": [
- "number",
- "null"
- ]
- },
- "verdict": {
- "description": "affected (count > 0); not_affected (assessed, no match, nothing undetermined: the only clean verdict); undetermined (advisories name the package, at least one could not be decided, none matched: not clean); not_assessed (no verdict: not clean).",
- "type": [
- "string",
- "null"
- ]
- },
- "version": {
- "type": [
- "string",
- "null"
- ]
- }
- },
- "type": "object"
- },
- "type": "array"
- },
- "summary": {
- "additionalProperties": {},
- "properties": {
- "affected": {
- "type": [
- "number",
- "null"
- ]
- },
- "components": {
- "type": [
- "number",
- "null"
- ]
- },
- "corpus_cache_max_age_ms": {
- "type": [
- "number",
- "null"
- ]
- },
- "elapsed_ms": {
- "type": [
- "number",
- "null"
- ]
- },
- "lookups": {
- "type": [
- "number",
- "null"
- ]
- },
- "not_affected": {
- "description": "Components with a decided, clean verdict.",
- "type": [
- "number",
- "null"
- ]
- },
- "not_assessed": {
- "description": "Components with no verdict: not clean.",
- "type": [
- "number",
- "null"
- ]
- },
- "not_assessed_by_reason": {
- "anyOf": [
- {
- "additionalProperties": {},
- "properties": {
- "advisory_lookup_failed": {
- "type": "number"
- },
- "candidate_window_truncated": {
- "type": "number"
- },
- "distro_release_unknown": {
- "description": "deb, apk or rpm purls without a distro qualifier naming the release, which EchelonGraph does not guess.",
- "type": "number"
- },
- "invalid_component": {
- "type": "number"
- },
- "no_decidable_advisory": {
- "type": "number"
- },
- "package_not_in_advisory_corpus": {
- "type": "number"
- },
- "purl_type_unsupported": {
- "type": "number"
- },
- "time_budget": {
- "description": "Components the batch's time budget ran out before: not clean; check them again.",
- "type": "number"
- },
- "version_missing": {
- "type": "number"
- }
- },
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "The not_assessed components, counted by not_assessed_reason."
- },
- "partial": {
- "description": "true when the time budget ran out before every component was looked up.",
- "type": [
- "boolean",
- "null"
- ]
- },
- "time_budget_ms": {
- "type": [
- "number",
- "null"
- ]
- },
- "undetermined": {
- "description": "Components whose advisories could not all be decided and none matched: not clean.",
- "type": [
- "number",
- "null"
- ]
- }
- },
- "type": "object"
- }
- },
- "type": "object"
- },
- "data_truncated": {
- "description": "false: data is the answer whole. true: the structured result would pass 30,000 characters of JSON with data whole, so data is cut (DATA CUT): the entries of some of its lists keep only some of their fields, or the lists only some of their entries, truncated gives each, and no string is shortened. The same call with full: true returns data whole.",
- "type": "boolean"
- },
- "freshness": {
- "anyOf": [
- {
- "additionalProperties": {},
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "The producing radar's last completed check (last_run_at), where the API serves one."
- },
- "measured_at": {
- "anyOf": [
- {
- "description": "An RFC 3339 instant.",
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
- },
- "method": {
- "description": "How the numbers were produced.",
- "type": "string"
- },
- "notes": {
- "description": "Caveats, one sentence each.",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "state": {
- "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
- "enum": [
- "measured",
- "not_assessed"
- ],
- "type": "string"
- },
- "truncated": {
- "additionalProperties": {
- "additionalProperties": {},
- "properties": {
- "returned": {
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "thinned": {
- "const": true,
- "type": "boolean"
- },
- "total": {
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- }
- },
- "required": [
- "total",
- "returned"
- ],
- "type": "object"
- },
- "description": "Present when data_truncated is true: each list of data that was cut, by its path in data (a dot between the names of an object and a list inside it), with total, its entries in the answer, returned, the entries data holds, and thinned, true when each of them keeps only some of its fields.",
- "propertyNames": {
- "type": "string"
- },
- "type": "object"
- }
- },
- "required": [
- "state",
- "measured_at",
- "method",
- "coverage",
- "freshness",
- "notes",
- "data_truncated",
- "data"
- ],
- "type": "object"
- },
- {
- "additionalProperties": false,
- "properties": {
- "coverage": {
- "anyOf": [
- {
- "additionalProperties": false,
- "properties": {
- "batch_size": {
- "description": "The most purls one request carries (the API's cap per request).",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "batches": {
- "description": "Requests the distinct purls make, at batch_size each.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "batches_sent": {
- "description": "Of those, the ones the API answered.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "components_in_document": {
- "anyOf": [
- {
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
- },
- "distinct_purls": {
- "description": "Distinct purls to check: sent plus not_sent.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "duplicates_removed": {
- "description": "Purls that appeared more than once and were sent once.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "input": {
- "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
- "enum": [
- "purls",
- "cyclonedx",
- "spdx"
- ],
- "type": "string"
- },
- "not_assessed": {
- "anyOf": [
- {
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "description": "Of those sent, the components with no verdict, as the answer counts them."
- },
- "not_sent": {
- "description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "not_sent_reason": {
- "anyOf": [
- {
- "enum": [
- "time_budget",
- "rate_limited",
- "request_failed"
- ],
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, before a batch or while one was unanswered, which is then cut off; or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how). null when every purl was sent."
- },
- "partial": {
- "description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
- "type": [
- "boolean",
- "null"
- ]
- },
- "rate_limit_waits": {
- "description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "sent": {
- "description": "Distinct purls sent and answered.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "waited_ms": {
- "description": "Milliseconds spent in those waits.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "with_purl": {
- "description": "Of those, the ones carrying a purl.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- "without_purl": {
- "description": "The ones without a purl: not checked, and not clean.",
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- }
- },
- "required": [
- "input",
- "components_in_document",
- "with_purl",
- "without_purl",
- "duplicates_removed",
- "distinct_purls",
- "batch_size",
- "batches",
- "batches_sent",
- "sent",
- "not_sent",
- "not_sent_reason",
- "rate_limit_waits",
- "waited_ms",
- "not_assessed",
- "partial"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ]
- },
- "error": {
- "additionalProperties": false,
- "properties": {
- "kind": {
- "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
- "enum": [
- "network",
- "timeout",
- "http",
- "not_json",
- "not_object",
- "invalid_input",
- "internal",
- "unexpected_shape",
- "radars"
- ],
- "type": "string"
- },
- "message": {
- "description": "The cause: the API's own message, or what went wrong.",
- "type": "string"
- },
- "path": {
- "description": "The API path requested, when a request was made.",
- "type": [
- "string",
- "null"
- ]
- },
- "status": {
- "anyOf": [
- {
- "maximum": 9007199254740991,
- "minimum": -9007199254740991,
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "description": "The HTTP status, when the API answered one; 503 with kind internal and path null where this server was too busy to make the call."
- }
- },
- "required": [
- "kind",
- "path",
- "status",
- "message"
- ],
- "type": "object"
- },
- "freshness": {
- "type": "null"
- },
- "measured_at": {
- "type": "null"
- },
- "method": {
- "type": "null"
- },
- "notes": {
- "description": "Caveats, one sentence each.",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "state": {
- "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
- "enum": [
- "failed",
- "invalid_input"
- ],
- "type": "string"
- }
- },
- "required": [
- "state",
- "measured_at",
- "method",
- "coverage",
- "freshness",
- "notes",
- "error"
- ],
- "type": "object"
- }
-]New value: +[
+ {
+ "additionalProperties": {},
+ "properties": {
+ "coverage": {
+ "anyOf": [
+ {
+ "additionalProperties": {},
+ "properties": {
+ "batch_size": {
+ "description": "The most purls one request carries (the API's cap per request).",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "batches": {
+ "description": "Requests the distinct purls make, at batch_size each.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "batches_sent": {
+ "description": "Of those, the ones the API answered.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "components_in_document": {
+ "anyOf": [
+ {
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
+ },
+ "distinct_purls": {
+ "description": "Distinct purls to check: sent plus not_sent.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "duplicates_removed": {
+ "description": "Purls that appeared more than once and were sent once.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "input": {
+ "anyOf": [
+ {
+ "enum": [
+ "purls",
+ "cyclonedx",
+ "spdx"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "string"
+ }
+ ],
+ "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document."
+ },
+ "not_assessed": {
+ "anyOf": [
+ {
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Of those sent, the components with no verdict, as the answer counts them."
+ },
+ "not_sent": {
+ "description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "not_sent_reason": {
+ "anyOf": [
+ {
+ "anyOf": [
+ {
+ "enum": [
+ "time_budget",
+ "rate_limited",
+ "request_failed",
+ "server_busy"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "string"
+ }
+ ]
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, before a batch or while one was unanswered, which is then cut off; or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how), server_busy (hosted endpoint: the API's answers took this instance's parse budget more than a quarter past its bound, or this call's request past the 30 MiB one request may reserve, or a batch's answer was larger than the room left, so it was not read; no further batch was sent). null when every purl was sent."
+ },
+ "partial": {
+ "description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "rate_limit_waits": {
+ "description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "sent": {
+ "description": "Distinct purls sent and answered.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "waited_ms": {
+ "description": "Milliseconds spent in those waits.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "with_purl": {
+ "description": "Of those, the ones carrying a purl.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "without_purl": {
+ "description": "The ones without a purl: not checked, and not clean.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ }
+ },
+ "required": [
+ "input",
+ "components_in_document",
+ "with_purl",
+ "without_purl",
+ "duplicates_removed",
+ "distinct_purls",
+ "batch_size",
+ "batches",
+ "batches_sent",
+ "sent",
+ "not_sent",
+ "not_sent_reason",
+ "rate_limit_waits",
+ "waited_ms",
+ "not_assessed",
+ "partial"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the answer covers; null where the answer says nothing about it."
+ },
+ "data": {
+ "additionalProperties": {},
+ "properties": {
+ "answered_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "components": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "match_layer": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "not_sent_purls": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The distinct purls not sent (coverage.not_sent_reason says why): not checked, and not clean. Present only when some were not sent."
+ },
+ "results": {
+ "items": {
+ "additionalProperties": {},
+ "properties": {
+ "advisories_considered": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "assessed": {
+ "description": "Whether the matcher produced a verdict for this component. false is never clean.",
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "candidates_capped": {
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "capped": {
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "code": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "count": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "cve_ids": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "ecosystem": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "error": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "index": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "input_kind": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "matched_package": {
+ "description": "The package name the advisories were looked up by (#2836): the purl's own name, or, for a deb or apk purl with an upstream qualifier, the source package it names, which is how Debian and Alpine file advisories.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "matched_version_from": {
+ "description": "Upstream rows: upstream when the qualifier named a version (upstream=name@version) and it was used, purl when the purl's own version was.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "matched_via": {
+ "description": "Which name matched_package is: purl_name (the purl's name), upstream (the purl's upstream qualifier) or coordinates (the component's package).",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "matches": {
+ "anyOf": [
+ {
+ "items": {
+ "additionalProperties": {},
+ "properties": {
+ "cve_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "epss_score": {
+ "description": "The CVE's EPSS score (FIRST), as EchelonGraph's record holds it; null when it has none.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "fixed_in": {
+ "description": "The lowest version above this component's that no affected interval of the CVE's record for the package holds, always above it: the fixed bound of the interval that holds the component's version, moved past any overlapping interval that still holds that bound (fixed_in_detail then names it). null when no such version is on record (an interval on the way records no fix: it ends at last_affected, or has no end) or no interval holds the version, with fixed_in_reason saying which. Where fixed_in_dispute is set, the CVE record's CNA and the advisory disagree on the range that holds the component's version, and fixed_in follows the source its higher names (its note says how).",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "fixed_in_detail": {
+ "description": "Set when fixed_in is not the fixed bound of the interval that holds the component's version: the overlapping intervals of the same record it moved past, which still hold that bound.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "fixed_in_dispute": {
+ "anyOf": [
+ {
+ "additionalProperties": {},
+ "properties": {
+ "advisory_fixed": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "advisory_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "advisory_introduced": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "advisory_last_affected": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "advisory_listed": {
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "cna": {
+ "anyOf": [
+ {
+ "additionalProperties": {},
+ "properties": {
+ "name": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "short_name": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "cna_product": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "cna_range": {
+ "anyOf": [
+ {
+ "additionalProperties": {},
+ "properties": {
+ "changes": {
+ "anyOf": [
+ {
+ "items": {
+ "additionalProperties": {},
+ "properties": {
+ "at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "status": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "changes_truncated": {
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "less_than": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "less_than_or_equal": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "status": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "version": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "version_type": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "cna_range_default": {
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "higher": {
+ "anyOf": [
+ {
+ "anyOf": [
+ {
+ "enum": [
+ "cna",
+ "advisory"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "string"
+ }
+ ]
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "kind": {
+ "anyOf": [
+ {
+ "anyOf": [
+ {
+ "enum": [
+ "fixed",
+ "introduced"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "string"
+ }
+ ]
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Once EchelonGraph's API serves it, set where the API found the CVE record's CNA and the advisory disagreeing on the range that holds this version. kind: fixed (they disagree on where the package is fixed) or introduced (the CNA's range starts below where the advisory's does). The advisory's bound in dispute, exactly one of advisory_fixed, advisory_last_affected and advisory_introduced, as the advisory's own statement gives it (advisory_listed: it lists affected versions rather than a range, and the bound is a version it lists), and advisory_id, the advisory. cna (name, short_name), cna_product (what the CNA's entry names, as the API reads it) and cna_range (version, less_than or less_than_or_equal, status, version_type; changes, each {at, status}, where the range's status changes inside it, with changes_truncated where the record held more): the CNA's range in dispute, as the API reads the record (where higher is cna, the CNA's range that reaches past the advisory's bound: on a cna_affected_range match it holds the version, and on an advisory_interval or exact_version_list match it holds the advisory's bound past the version (its fix, or the versions just above its last affected or listed version), so it may start above the version; where higher is advisory, the CNA's range that ends below it, the CNA saying the version is fixed), from an entry the record writes, or, with cna_range_default true, a span no entry writes that the record's defaultStatus covers. higher: the source the answer follows, the more conservative one (cna or advisory). note: the API's sentence on the dispute and what the answer does with it, relayed verbatim. Fields and values a later API adds are relayed. Its absence is not a finding that the CNA agrees: an API that does not serve it yet, or older than the field, sends none; one that serves it reads a CNA's ranges only where it applies them and only from an entry it matches to the package; and a match the CNA's range alone raises may carry none."
+ },
+ "fixed_in_reason": {
+ "description": "Why fixed_in is null; absent when fixed_in is a version.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "interval": {
+ "anyOf": [
+ {
+ "additionalProperties": {},
+ "properties": {
+ "fixed": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "introduced": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "last_affected": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The affected interval that holds this component's version (fixed is exclusive, last_affected inclusive): the advisory's, or, where version_evidence is cna_affected_range, the CVE record's CNA range. Absent when no interval holds it."
+ },
+ "kev_listed": {
+ "description": "Whether the CVE is in CISA's Known Exploited Vulnerabilities catalog, as EchelonGraph's record holds it.",
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "match_reason": {
+ "description": "Why the match applies, with the affected interval the version falls inside: \"[A, B)\" names that interval's fixed bound B (another interval can still hold B; fixed_in is the version past them all), \"[A, B]\" the last affected version B. The interval is the advisory's, or, where version_evidence is cna_affected_range, the CVE record's CNA range. On an upstream row it ends by naming the source package and the purl name.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "version_evidence": {
+ "anyOf": [
+ {
+ "anyOf": [
+ {
+ "enum": [
+ "exact_version_list",
+ "advisory_interval",
+ "fix_boundary_only",
+ "no_version_supplied",
+ "cna_affected_range"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "string"
+ }
+ ]
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Registry match: how the version was decided: exact_version_list (named in the advisory's list of affected versions), advisory_interval (inside one of its intervals), fix_boundary_only (below its only stored fix, its lower bound assumed), no_version_supplied (no version given, so no claim about it), or, once EchelonGraph's API serves it, cna_affected_range (held by the CVE record's CNA range, where no advisory statement holds it: interval is the CNA's range, and fixed_in_dispute, where the API publishes one, says how the two differ; such a match may carry none; on a match whose match_method is cna package url, no advisory record names the package for the CVE at all, and the CNA's statement is the only source). Relayed as the API sends it; a later value is relayed too."
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "matches_truncated": {
+ "additionalProperties": {},
+ "description": "Present only on a row whose matches the structured result's cut (DATA CUT) shortened or left out: total, the row's matches in the answer; returned, the ones data keeps (chosen used in ransomware first, then the other KEV-listed ones, then highest effective_score, and listed in the API's order); and, while they fit, of all its matches, the CVE IDs KEV-listed (kev_listed_cve_ids) or used in ransomware (ransomware_cve_ids), and the distinct fixed_in versions (fixed_in_versions). The same call with full: true returns every match.",
+ "properties": {
+ "fixed_in_versions": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "kev_listed_cve_ids": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "ransomware_cve_ids": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "returned": {
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "total": {
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ }
+ },
+ "required": [
+ "total",
+ "returned"
+ ],
+ "type": "object"
+ },
+ "not_affected_count": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "not_assessed_reason": {
+ "description": "Why assessed is false: package_not_in_advisory_corpus, no_decidable_advisory, advisory_lookup_failed, candidate_window_truncated, time_budget, distro_release_unknown, purl_type_unsupported, version_missing or invalid_component.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "package": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "purl": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "purl_name": {
+ "description": "Upstream rows: the purl's own (binary) package name, not looked up.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "undetermined": {
+ "anyOf": [
+ {
+ "items": {
+ "additionalProperties": {},
+ "properties": {
+ "cve_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "undetermined_count": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "verdict": {
+ "description": "affected (count > 0); not_affected (assessed, no match, nothing undetermined: the only clean verdict); undetermined (advisories name the package, at least one of its CVEs could not be decided, none matched: not clean); not_assessed (no verdict: not clean).",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "version": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "summary": {
+ "additionalProperties": {},
+ "properties": {
+ "affected": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "components": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "corpus_cache_max_age_ms": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "elapsed_ms": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "lookups": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "not_affected": {
+ "description": "Components with a decided, clean verdict.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "not_assessed": {
+ "description": "Components with no verdict: not clean.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "not_assessed_by_reason": {
+ "anyOf": [
+ {
+ "additionalProperties": {},
+ "properties": {
+ "advisory_lookup_failed": {
+ "type": "number"
+ },
+ "candidate_window_truncated": {
+ "type": "number"
+ },
+ "distro_release_unknown": {
+ "description": "deb, apk or rpm purls without a distro qualifier naming the release, which EchelonGraph does not guess.",
+ "type": "number"
+ },
+ "invalid_component": {
+ "type": "number"
+ },
+ "no_decidable_advisory": {
+ "type": "number"
+ },
+ "package_not_in_advisory_corpus": {
+ "type": "number"
+ },
+ "purl_type_unsupported": {
+ "type": "number"
+ },
+ "time_budget": {
+ "description": "Components the batch's time budget ran out before: not clean; check them again.",
+ "type": "number"
+ },
+ "version_missing": {
+ "type": "number"
+ }
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The not_assessed components, counted by not_assessed_reason."
+ },
+ "partial": {
+ "description": "true when the time budget ran out before every component was looked up.",
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "time_budget_ms": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "undetermined": {
+ "description": "Components whose CVEs could not all be decided, with an advisory naming the package, and none matched: not clean.",
+ "type": [
+ "number",
+ "null"
+ ]
+ }
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
+ "data_truncated": {
+ "description": "false: data is the answer whole. true: the structured result would pass 30,000 characters of JSON with data whole, so data is cut (DATA CUT): the entries of some of its lists keep only some of their fields, or the lists only some of their entries, truncated gives each, and no string is shortened. The same call with full: true returns data whole.",
+ "type": "boolean"
+ },
+ "freshness": {
+ "anyOf": [
+ {
+ "additionalProperties": {},
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The producing radar's last completed check (last_run_at), where the API serves one."
+ },
+ "measured_at": {
+ "anyOf": [
+ {
+ "description": "An RFC 3339 instant.",
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
+ },
+ "method": {
+ "description": "How the numbers were produced.",
+ "type": "string"
+ },
+ "notes": {
+ "description": "Caveats, one sentence each.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "state": {
+ "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
+ "enum": [
+ "measured",
+ "not_assessed"
+ ],
+ "type": "string"
+ },
+ "truncated": {
+ "additionalProperties": {
+ "additionalProperties": {},
+ "properties": {
+ "returned": {
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "thinned": {
+ "const": true,
+ "type": "boolean"
+ },
+ "total": {
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ }
+ },
+ "required": [
+ "total",
+ "returned"
+ ],
+ "type": "object"
+ },
+ "description": "Present when data_truncated is true: each list of data that was cut, by its path in data (a dot between the names of an object and a list inside it), with total, its entries in the answer, returned, the entries data holds, and thinned, true when each of them keeps only some of its fields.",
+ "propertyNames": {
+ "type": "string"
+ },
+ "type": "object"
+ }
+ },
+ "required": [
+ "state",
+ "measured_at",
+ "method",
+ "coverage",
+ "freshness",
+ "notes",
+ "data_truncated",
+ "data"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "properties": {
+ "coverage": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "properties": {
+ "batch_size": {
+ "description": "The most purls one request carries (the API's cap per request).",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "batches": {
+ "description": "Requests the distinct purls make, at batch_size each.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "batches_sent": {
+ "description": "Of those, the ones the API answered.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "components_in_document": {
+ "anyOf": [
+ {
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
+ },
+ "distinct_purls": {
+ "description": "Distinct purls to check: sent plus not_sent.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "duplicates_removed": {
+ "description": "Purls that appeared more than once and were sent once.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "input": {
+ "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
+ "enum": [
+ "purls",
+ "cyclonedx",
+ "spdx"
+ ],
+ "type": "string"
+ },
+ "not_assessed": {
+ "anyOf": [
+ {
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Of those sent, the components with no verdict, as the answer counts them."
+ },
+ "not_sent": {
+ "description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "not_sent_reason": {
+ "anyOf": [
+ {
+ "enum": [
+ "time_budget",
+ "rate_limited",
+ "request_failed"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, before a batch or while one was unanswered, which is then cut off; or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how). null when every purl was sent."
+ },
+ "partial": {
+ "description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "rate_limit_waits": {
+ "description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "sent": {
+ "description": "Distinct purls sent and answered.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "waited_ms": {
+ "description": "Milliseconds spent in those waits.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "with_purl": {
+ "description": "Of those, the ones carrying a purl.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ "without_purl": {
+ "description": "The ones without a purl: not checked, and not clean.",
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ }
+ },
+ "required": [
+ "input",
+ "components_in_document",
+ "with_purl",
+ "without_purl",
+ "duplicates_removed",
+ "distinct_purls",
+ "batch_size",
+ "batches",
+ "batches_sent",
+ "sent",
+ "not_sent",
+ "not_sent_reason",
+ "rate_limit_waits",
+ "waited_ms",
+ "not_assessed",
+ "partial"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "error": {
+ "additionalProperties": false,
+ "properties": {
+ "kind": {
+ "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
+ "enum": [
+ "network",
+ "timeout",
+ "http",
+ "not_json",
+ "not_object",
+ "invalid_input",
+ "internal",
+ "unexpected_shape",
+ "radars"
+ ],
+ "type": "string"
+ },
+ "message": {
+ "description": "The cause: the API's own message, or what went wrong.",
+ "type": "string"
+ },
+ "path": {
+ "description": "The API path requested, when a request was made.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "status": {
+ "anyOf": [
+ {
+ "maximum": 9007199254740991,
+ "minimum": -9007199254740991,
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The HTTP status, when the API answered one; 503 with kind internal and path null where this server was too busy to make the call."
+ }
+ },
+ "required": [
+ "kind",
+ "path",
+ "status",
+ "message"
+ ],
+ "type": "object"
+ },
+ "freshness": {
+ "type": "null"
+ },
+ "measured_at": {
+ "type": "null"
+ },
+ "method": {
+ "type": "null"
+ },
+ "notes": {
+ "description": "Caveats, one sentence each.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "state": {
+ "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
+ "enum": [
+ "failed",
+ "invalid_input"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "state",
+ "measured_at",
+ "method",
+ "coverage",
+ "freshness",
+ "notes",
+ "error"
+ ],
+ "type": "object"
+ }
+]