Stdlib-only scanner per docs/17: Kubernetes API inventory, Trivy runner, persisted state, schema-validated report.json, strict acceptances parser, server-rendered page, aggregate metrics, internal API, and a scan loop that stays live while scanning. L1 tests under conformance/tests/l1-rendering/vuln-scanner-* run the actual modules against recorded fixtures with a fake Trivy runner. Co-Authored-By: Claude Opus 5.5 <[email protected]>
111 lines
4.6 KiB
JSON
111 lines
4.6 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "report.schema.json",
|
|
"title": "vuln-scanner report (docs/17, schemaVersion 1)",
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["schemaVersion", "generatedAt", "database", "run", "targets", "findings", "remediation"],
|
|
"properties": {
|
|
"schemaVersion": {"const": 1},
|
|
"generatedAt": {"type": "string", "format": "date-time"},
|
|
"database": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["updatedAt", "version"],
|
|
"properties": {
|
|
"updatedAt": {"type": "string", "format": "date-time"},
|
|
"version": {"type": "string", "minLength": 1, "maxLength": 128}
|
|
}
|
|
},
|
|
"run": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["startedAt", "finishedAt", "status"],
|
|
"properties": {
|
|
"startedAt": {"type": "string", "format": "date-time"},
|
|
"finishedAt": {"type": "string", "format": "date-time"},
|
|
"status": {"enum": ["complete", "degraded"]}
|
|
}
|
|
},
|
|
"targets": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["id", "type", "image", "digest", "state", "reason", "lastScannedAt", "workloads"],
|
|
"properties": {
|
|
"id": {"type": "string", "minLength": 1, "maxLength": 2048},
|
|
"type": {"enum": ["image", "vm", "node"]},
|
|
"image": {"type": "string", "maxLength": 2048},
|
|
"digest": {"type": ["string", "null"], "pattern": "^sha256:[0-9a-f]{64}$"},
|
|
"state": {"enum": ["scanned", "pending", "stale", "failed", "credential-required", "by-tag", "not-covered"]},
|
|
"reason": {"type": ["string", "null"], "maxLength": 1024},
|
|
"lastScannedAt": {"type": ["string", "null"], "format": "date-time"},
|
|
"workloads": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["namespace", "kind", "name", "containers"],
|
|
"properties": {
|
|
"namespace": {"type": "string", "maxLength": 253},
|
|
"kind": {"type": "string", "minLength": 1, "maxLength": 253},
|
|
"name": {"type": "string", "minLength": 1, "maxLength": 253},
|
|
"containers": {"type": "array", "items": {"type": "string", "maxLength": 253}}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"findings": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["id", "targetId", "severity", "cvss", "package", "installedVersion", "fixedVersion",
|
|
"title", "url", "firstSeenAt", "status"],
|
|
"properties": {
|
|
"id": {"type": "string", "minLength": 1, "maxLength": 256},
|
|
"targetId": {"type": "string", "minLength": 1, "maxLength": 2048},
|
|
"severity": {"enum": ["CRITICAL", "HIGH", "MEDIUM", "LOW", "UNKNOWN"]},
|
|
"cvss": {"type": ["number", "null"], "minimum": 0, "maximum": 10},
|
|
"package": {"type": "string", "maxLength": 256},
|
|
"installedVersion": {"type": "string", "maxLength": 256},
|
|
"fixedVersion": {"type": ["string", "null"], "maxLength": 512},
|
|
"title": {"type": "string", "maxLength": 512},
|
|
"url": {"type": "string", "maxLength": 2048, "pattern": "^(https?://.+)?$"},
|
|
"firstSeenAt": {"type": "string", "format": "date-time"},
|
|
"status": {"enum": ["open", "fix-available", "accepted"]},
|
|
"acceptance": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["reason", "expires"],
|
|
"properties": {
|
|
"reason": {"type": "string", "minLength": 1, "maxLength": 2048},
|
|
"expires": {"type": "string", "format": "date"}
|
|
}
|
|
}
|
|
},
|
|
"if": {"properties": {"status": {"const": "accepted"}}},
|
|
"then": {"required": ["acceptance"]},
|
|
"else": {"not": {"required": ["acceptance"]}}
|
|
}
|
|
},
|
|
"remediation": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["image", "state", "url", "updatedAt"],
|
|
"properties": {
|
|
"image": {"type": "string", "minLength": 1, "maxLength": 512},
|
|
"state": {"enum": ["pr-open", "approval-requested", "no-update-identified", "not-tracked"]},
|
|
"url": {"type": ["string", "null"], "maxLength": 2048, "pattern": "^https?://.+$"},
|
|
"updatedAt": {"type": "string", "format": "date-time"}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|