docs consolidation and others
This commit is contained in:
91
docs/modules/signals/events/README.md
Normal file
91
docs/modules/signals/events/README.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Event Envelope Schemas
|
||||
|
||||
Platform services publish strongly typed events; the JSON Schemas in this directory define those envelopes. File names follow `<event-name>@<version>.json` so producers and consumers can negotiate contracts explicitly.
|
||||
|
||||
## Catalog
|
||||
**Orchestrator envelopes (ORCH-SVC-38-101)**
|
||||
- `scanner.event.report.ready@1.json` — orchestrator event emitted when a signed report is persisted. Supersedes the legacy `scanner.report.ready@1` schema and adds versioning, idempotency keys, and trace context. Consumers: Orchestrator bus, Notifications Studio, UI timeline.
|
||||
- `scanner.event.scan.completed@1.json` — orchestrator event emitted when a scan run finishes. Supersedes the legacy `scanner.scan.completed@1` schema. Consumers: Orchestrator bus, Notifications Studio, Scheduler replay tooling.
|
||||
|
||||
**Legacy envelopes (Redis-backed)**
|
||||
- `scanner.report.ready@1.json` — legacy Redis stream event emitted once a signed report is persisted (kept for transitional compatibility).
|
||||
- `scanner.scan.completed@1.json` — legacy Redis stream event emitted alongside the signed report for automation.
|
||||
- `scheduler.rescan.delta@1.json` — emitted by Scheduler when BOM-Index diffs require fresh scans. Consumers: Notify, Policy Engine.
|
||||
- `scheduler.graph.job.completed@1.json` — emitted when a Cartographer graph build/overlay job finishes (`status = completed|failed|cancelled`). Consumers: Scheduler WebService (lag metrics/API), Cartographer cache warmers, UI overlay freshness indicators.
|
||||
- `attestor.logged@1.json` — emitted by Attestor after storing the Rekor inclusion proof. Consumers: UI attestation panel, Governance exports.
|
||||
|
||||
Additive payload changes (new optional fields) can stay within the same version. Any breaking change (removing a field, tightening validation, altering semantics) must increment the `@<version>` suffix and update downstream consumers. For full orchestrator guidance see [`orchestrator-scanner-events.md`](orchestrator-scanner-events.md).
|
||||
|
||||
## Envelope structure
|
||||
|
||||
### Orchestrator envelope (version 1)
|
||||
| Field | Type | Notes |
|
||||
|-------|------|-------|
|
||||
| `eventId` | `uuid` | Globally unique per occurrence. |
|
||||
| `kind` | `string` | e.g., `scanner.event.report.ready`. |
|
||||
| `version` | `integer` | Schema version (`1` for the initial release). |
|
||||
| `tenant` | `string` | Multi‑tenant isolation key; mirror the value recorded in queue/PostgreSQL metadata. |
|
||||
| `occurredAt` | `date-time` | RFC 3339 UTC timestamp describing when the state transition happened. |
|
||||
| `recordedAt` | `date-time` | RFC 3339 UTC timestamp for durable persistence (optional but recommended). |
|
||||
| `source` | `string` | Producer identifier (`scanner.webservice`). |
|
||||
| `idempotencyKey` | `string` | Deterministic dedupe key (`scanner.event.*:<tenant>:<report|scan>`). |
|
||||
| `correlationId` | `string` | Ties the event to the originating scan/API request. |
|
||||
| `traceId` / `spanId` | `string` | W3C trace context propagated into downstream telemetry. |
|
||||
| `scope` | `object` | Optional block with at least `repo` and `digest`. |
|
||||
| `payload` | `object` | Event-specific body; schemas embed the canonical report and DSSE envelope. |
|
||||
| `attributes` | `object` | Optional metadata bag (`string` keys/values) for downstream correlation. |
|
||||
|
||||
For Scanner orchestrator events, `links` include console and API deep links (`report.ui`, `report.api`, etc.) plus optional attestation references when a DSSE envelope is present. See [`orchestrator-scanner-events.md`](orchestrator-scanner-events.md) for details.
|
||||
|
||||
### Legacy Redis envelope
|
||||
| Field | Type | Notes |
|
||||
|-------|------|-------|
|
||||
| `eventId` | `uuid` | Must be globally unique per occurrence; producers log duplicates as fatal. |
|
||||
| `kind` | `string` | Fixed per schema (e.g., `scanner.report.ready`). Downstream services reject unknown kinds or versions. |
|
||||
| `tenant` | `string` | Multi‑tenant isolation key; mirror the value recorded in queue/PostgreSQL metadata. |
|
||||
| `ts` | `date-time` | RFC 3339 UTC timestamp. Use monotonic clocks or atomic offsets so ordering survives retries. |
|
||||
| `scope` | `object` | Optional block used when the event concerns a specific image or repository. See schema for required fields (e.g., `repo`, `digest`). |
|
||||
| `payload` | `object` | Event-specific body. Schemas allow additional properties so producers can add optional hints (e.g., `reportId`, `quietedFindingCount`) without breaking consumers. See `docs/runtime/SCANNER_RUNTIME_READINESS.md` for the runtime consumer checklist covering these hints. |
|
||||
| `attributes` | `object` | Optional metadata bag (`string` keys/values) for downstream correlation (e.g., pipeline identifiers). Omit when unused to keep payloads concise. |
|
||||
|
||||
When adding new optional fields, document the behaviour in the schema’s `description` block and update the consumer checklist in the next sprint sync.
|
||||
|
||||
## Canonical samples & validation
|
||||
Reference payloads live under `docs/events/samples/`, mirroring the schema version (`<event-name>@<version>.sample.json`). They illustrate common field combinations, including the optional attributes that downstream teams rely on for UI affordances and audit trails. Scanner samples reuse the exact DSSE envelope checked into `samples/api/reports/report-sample.dsse.json`, and unit tests (`ReportSamplesTests`, `PlatformEventSchemaValidationTests`) guard that payloads stay canonical and continue to satisfy the published schemas.
|
||||
|
||||
Run the following loop offline to validate both schemas and samples:
|
||||
|
||||
```bash
|
||||
# Validate schemas (same check as CI)
|
||||
for schema in docs/events/*.json; do
|
||||
npx ajv compile -c ajv-formats -s "$schema"
|
||||
done
|
||||
|
||||
# Validate canonical samples against their schemas
|
||||
for sample in docs/events/samples/*.sample.json; do
|
||||
schema="docs/events/$(basename "${sample%.sample.json}").json"
|
||||
npx ajv validate -c ajv-formats -s "$schema" -d "$sample"
|
||||
done
|
||||
```
|
||||
|
||||
Consumers can copy the samples into integration tests to guarantee backwards compatibility. When emitting new event versions, include a matching sample and update this README so air-gapped operators stay in sync.
|
||||
|
||||
## CI validation
|
||||
The Docs CI workflow (`.gitea/workflows/docs.yml`) installs `ajv-cli` and compiles every schema on pull requests. Run the same check locally before opening a PR:
|
||||
|
||||
```bash
|
||||
for schema in docs/events/*.json; do
|
||||
npx ajv compile -c ajv-formats -s "$schema"
|
||||
done
|
||||
```
|
||||
|
||||
Tip: run `npm install --no-save ajv ajv-cli ajv-formats` once per clone so `npx` can resolve the tooling offline.
|
||||
|
||||
If a schema references additional files, include `-r` flags so CI and local runs stay consistent.
|
||||
|
||||
## Working with schemas
|
||||
- Producers should validate outbound payloads using the matching schema during unit tests.
|
||||
- Consumers should pin to a specific version and log when encountering unknown versions to catch missing migrations early.
|
||||
- Store real payload samples under `docs/events/samples/` (mirrors the schema version) and mirror them into `samples/events/` when you need fixtures in integration repositories.
|
||||
|
||||
Contact the Platform Events group in Docs Guild if you need help shaping a new event or version strategy.
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"$id": "https://stella-ops.org/schemas/events/advisoryai.evidence.bundle@0.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "AdvisoryAI evidence bundle (draft v0)",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["bundleId", "advisoryId", "tenant", "generatedAt", "observations"],
|
||||
"properties": {
|
||||
"bundleId": {"type": "string", "description": "Deterministic bundle identifier (UUID or ULID)."},
|
||||
"advisoryId": {"type": "string", "description": "Upstream advisory identifier (vendor or CVE-style)."},
|
||||
"tenant": {"type": "string", "description": "Owning tenant."},
|
||||
"generatedAt": {"type": "string", "format": "date-time", "description": "UTC timestamp when bundle was assembled."},
|
||||
"schemaVersion": {"type": "integer", "default": 0},
|
||||
"observations": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["observationId", "source"],
|
||||
"properties": {
|
||||
"observationId": {"type": "string"},
|
||||
"source": {"type": "string", "description": "Publisher or feed name."},
|
||||
"purl": {"type": "string", "description": "Optional package URL."},
|
||||
"cve": {"type": "string"},
|
||||
"severity": {"type": "string", "description": "Publisher-reported severity label."},
|
||||
"cvss": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"vector": {"type": "string"},
|
||||
"score": {"type": "number"}
|
||||
}
|
||||
},
|
||||
"summary": {"type": "string"},
|
||||
"evidence": {
|
||||
"type": "object",
|
||||
"description": "Raw upstream statement or excerpt.",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["signature", "keyId"],
|
||||
"properties": {
|
||||
"signature": {"type": "string", "description": "Base64 signature over canonical JSON."},
|
||||
"keyId": {"type": "string"},
|
||||
"algorithm": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://stellaops.org/schemas/events/advisoryai.evidence.bundle@1.schema.json",
|
||||
"title": "AdvisoryAI Evidence Bundle Schema v1",
|
||||
"description": "Schema for AdvisoryAI evidence bundles containing advisory observations with CVSS vectors and optional signatures. Used by ExportCenter and Timeline services for evidence aggregation.",
|
||||
"type": "object",
|
||||
"required": ["bundleId", "advisoryId", "tenant", "generatedAt", "schemaVersion"],
|
||||
"$defs": {
|
||||
"cvssVector": {
|
||||
"type": "object",
|
||||
"title": "CVSS Vector",
|
||||
"description": "Common Vulnerability Scoring System vector and score",
|
||||
"properties": {
|
||||
"vector": {
|
||||
"type": ["string", "null"],
|
||||
"description": "CVSS vector string (v2, v3.0, v3.1, or v4.0)",
|
||||
"examples": [
|
||||
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
|
||||
]
|
||||
},
|
||||
"score": {
|
||||
"type": ["number", "null"],
|
||||
"minimum": 0,
|
||||
"maximum": 10,
|
||||
"description": "CVSS base score (0.0 to 10.0)"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"signatureInfo": {
|
||||
"type": "object",
|
||||
"title": "Signature Information",
|
||||
"description": "Cryptographic signature for bundle authentication",
|
||||
"required": ["signature", "keyId"],
|
||||
"properties": {
|
||||
"signature": {
|
||||
"type": "string",
|
||||
"description": "Base64-encoded cryptographic signature"
|
||||
},
|
||||
"keyId": {
|
||||
"type": "string",
|
||||
"description": "Identifier of the signing key",
|
||||
"examples": ["sha256:abc123...", "stellaops-prod-2025"]
|
||||
},
|
||||
"algorithm": {
|
||||
"type": ["string", "null"],
|
||||
"description": "Signature algorithm used",
|
||||
"examples": ["ECDSA-P256-SHA256", "RSA-PSS-SHA256", "Ed25519"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"advisoryObservation": {
|
||||
"type": "object",
|
||||
"title": "Advisory Observation",
|
||||
"description": "An individual advisory observation within the bundle",
|
||||
"required": ["observationId", "source"],
|
||||
"properties": {
|
||||
"observationId": {
|
||||
"type": "string",
|
||||
"description": "Unique identifier for this observation",
|
||||
"minLength": 1
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"description": "Source of the observation (e.g., scanner, user, vex-lens)",
|
||||
"examples": ["scanner", "manual", "vex-lens", "advisoryai", "concelier"]
|
||||
},
|
||||
"purl": {
|
||||
"type": ["string", "null"],
|
||||
"description": "Package URL identifying the affected component",
|
||||
"pattern": "^pkg:[a-z]+/",
|
||||
"examples": ["pkg:npm/lodash@4.17.21", "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1"]
|
||||
},
|
||||
"cve": {
|
||||
"type": ["string", "null"],
|
||||
"description": "CVE identifier",
|
||||
"pattern": "^CVE-[0-9]{4}-[0-9]+$",
|
||||
"examples": ["CVE-2021-44228", "CVE-2024-12345"]
|
||||
},
|
||||
"severity": {
|
||||
"type": ["string", "null"],
|
||||
"description": "Severity level",
|
||||
"enum": ["critical", "high", "medium", "low", "info", "unknown", null]
|
||||
},
|
||||
"cvss": {
|
||||
"oneOf": [
|
||||
{ "$ref": "#/$defs/cvssVector" },
|
||||
{ "type": "null" }
|
||||
],
|
||||
"description": "CVSS vector and score"
|
||||
},
|
||||
"summary": {
|
||||
"type": ["string", "null"],
|
||||
"description": "Brief summary of the observation"
|
||||
},
|
||||
"evidence": {
|
||||
"type": ["object", "null"],
|
||||
"additionalProperties": true,
|
||||
"description": "Arbitrary evidence data attached to the observation",
|
||||
"examples": [
|
||||
{
|
||||
"reachability": "reachable",
|
||||
"callPaths": ["main() -> vulnerable_func()"],
|
||||
"exploitMaturity": "poc"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"bundleId": {
|
||||
"type": "string",
|
||||
"description": "Unique identifier for this evidence bundle",
|
||||
"minLength": 1,
|
||||
"examples": ["bundle-550e8400-e29b-41d4-a716-446655440000"]
|
||||
},
|
||||
"advisoryId": {
|
||||
"type": "string",
|
||||
"description": "Identifier of the related advisory or assessment",
|
||||
"minLength": 1,
|
||||
"examples": ["advisory-2025-001", "assessment-abc123"]
|
||||
},
|
||||
"tenant": {
|
||||
"type": "string",
|
||||
"description": "Tenant identifier (may be UUID or name)",
|
||||
"minLength": 1,
|
||||
"examples": ["00000000-0000-0000-0000-000000000001", "acme-corp"]
|
||||
},
|
||||
"generatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO 8601 timestamp when the bundle was generated"
|
||||
},
|
||||
"schemaVersion": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Schema version number for this bundle format",
|
||||
"default": 1
|
||||
},
|
||||
"observations": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/advisoryObservation"
|
||||
},
|
||||
"default": [],
|
||||
"description": "List of advisory observations in this bundle"
|
||||
},
|
||||
"signatures": {
|
||||
"type": ["array", "null"],
|
||||
"items": {
|
||||
"$ref": "#/$defs/signatureInfo"
|
||||
},
|
||||
"description": "Optional cryptographic signatures for bundle verification"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"examples": [
|
||||
{
|
||||
"bundleId": "bundle-550e8400-e29b-41d4-a716-446655440000",
|
||||
"advisoryId": "assessment-log4shell-2024",
|
||||
"tenant": "00000000-0000-0000-0000-000000000001",
|
||||
"generatedAt": "2025-12-07T10:30:00Z",
|
||||
"schemaVersion": 1,
|
||||
"observations": [
|
||||
{
|
||||
"observationId": "obs-001",
|
||||
"source": "scanner",
|
||||
"purl": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1",
|
||||
"cve": "CVE-2021-44228",
|
||||
"severity": "critical",
|
||||
"cvss": {
|
||||
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
|
||||
"score": 10.0
|
||||
},
|
||||
"summary": "Log4Shell RCE vulnerability detected in log4j-core",
|
||||
"evidence": {
|
||||
"reachability": "reachable",
|
||||
"callPaths": [
|
||||
"com.example.App.main() -> org.apache.logging.log4j.Logger.error()"
|
||||
],
|
||||
"exploitMaturity": "weaponized",
|
||||
"kevListed": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"observationId": "obs-002",
|
||||
"source": "vex-lens",
|
||||
"purl": "pkg:maven/org.apache.logging.log4j/log4j-api@2.14.1",
|
||||
"cve": "CVE-2021-45105",
|
||||
"severity": "high",
|
||||
"cvss": {
|
||||
"vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H",
|
||||
"score": 5.9
|
||||
},
|
||||
"summary": "Log4j2 infinite recursion DoS vulnerability"
|
||||
}
|
||||
],
|
||||
"signatures": [
|
||||
{
|
||||
"signature": "MEUCIQDx...",
|
||||
"keyId": "sha256:abc123def456...",
|
||||
"algorithm": "ECDSA-P256-SHA256"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
43
docs/modules/signals/events/attestor.logged@1.json
Normal file
43
docs/modules/signals/events/attestor.logged@1.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"$id": "https://stella-ops.org/schemas/events/attestor.logged@1.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"required": ["eventId", "kind", "tenant", "ts", "payload"],
|
||||
"properties": {
|
||||
"eventId": {"type": "string", "format": "uuid"},
|
||||
"kind": {"const": "attestor.logged"},
|
||||
"tenant": {"type": "string"},
|
||||
"ts": {"type": "string", "format": "date-time"},
|
||||
"payload": {
|
||||
"type": "object",
|
||||
"required": ["artifactSha256", "rekor", "subject"],
|
||||
"properties": {
|
||||
"artifactSha256": {"type": "string"},
|
||||
"rekor": {
|
||||
"type": "object",
|
||||
"required": ["uuid", "url"],
|
||||
"properties": {
|
||||
"uuid": {"type": "string"},
|
||||
"url": {"type": "string", "format": "uri"},
|
||||
"index": {"type": "integer", "minimum": 0}
|
||||
}
|
||||
},
|
||||
"subject": {
|
||||
"type": "object",
|
||||
"required": ["type", "name"],
|
||||
"properties": {
|
||||
"type": {"enum": ["sbom", "report", "vex-export"]},
|
||||
"name": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"description": "Optional event attributes for downstream correlation.",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
124
docs/modules/signals/events/orchestrator-scanner-events.md
Normal file
124
docs/modules/signals/events/orchestrator-scanner-events.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Scanner Orchestrator Events (ORCH-SVC-38-101)
|
||||
|
||||
Last updated: 2025-10-26
|
||||
|
||||
The Notifications Studio initiative (NOTIFY-SVC-38-001) and orchestrator backlog (ORCH-SVC-38-101) standardise how platform services emit lifecycle events. This document describes the Scanner WebService contract for the new **orchestrator envelopes** (`scanner.event.*`) and how they supersede the legacy Redis-backed `scanner.report.ready` / `scanner.scan.completed` events.
|
||||
|
||||
## 1. Envelope overview
|
||||
|
||||
Orchestrator events share a deterministic JSON envelope:
|
||||
|
||||
| Field | Type | Notes |
|
||||
|-------|------|-------|
|
||||
| `eventId` | `uuid` | Globally unique identifier generated per occurrence. |
|
||||
| `kind` | `string` | Event identifier; Scanner emits `scanner.event.report.ready` and `scanner.event.scan.completed`. |
|
||||
| `version` | `integer` | Schema version. Initial release uses `1`. |
|
||||
| `tenant` | `string` | Tenant that owns the scan/report. Mirrors Authority claims. |
|
||||
| `occurredAt` | `date-time` | UTC instant when the underlying state transition happened (e.g., report persisted). |
|
||||
| `recordedAt` | `date-time` | UTC instant when the event was durably written. Optional but recommended. |
|
||||
| `source` | `string` | Producer identifier (`scanner.webservice`). |
|
||||
| `idempotencyKey` | `string` | Deterministic key for duplicate suppression (see §4). |
|
||||
| `correlationId` | `string` | Maps back to the API request or scan identifier. |
|
||||
| `traceId` / `spanId` | `string` | W3C trace context propagated into downstream telemetry. |
|
||||
| `scope` | `object` | Describes the affected artefact. Requires `repo` and `digest`; optional `namespace`, `component`, `image`. |
|
||||
| `attributes` | `object` | Flat string map for frequently queried metadata (e.g., policy revision). |
|
||||
| `payload` | `object` | Event-specific body (see §2). |
|
||||
|
||||
Canonical schemas live under `docs/events/scanner.event.*@1.json`. Samples that round-trip through `NotifyCanonicalJsonSerializer` are stored in `docs/events/samples/`.
|
||||
|
||||
## 2. Event kinds and payloads
|
||||
|
||||
### 2.1 `scanner.event.report.ready`
|
||||
|
||||
Emitted once a signed report is persisted and attested. Payload highlights:
|
||||
|
||||
- `reportId` / `scanId` — identifiers for the persisted report and originating scan. Until Scan IDs are surfaced by the API, `scanId` mirrors `reportId` so downstream correlators can stabilise on a single key.
|
||||
- **Attributes:** `reportId`, `policyRevisionId`, `policyDigest`, `verdict` — pre-sorted for deterministic routing.
|
||||
- **Links:**
|
||||
- `report.ui` → `/ui/reports/{reportId}` on the current host.
|
||||
- `report.api` → `{apiBasePath}/{reportsSegment}/{reportId}` (defaults to `/api/v1/reports/{reportId}`).
|
||||
- `policy.ui` → `/ui/policy/revisions/{revisionId}` when a revision is present.
|
||||
- `policy.api` → `{apiBasePath}/{policySegment}/revisions/{revisionId}` when a revision is present.
|
||||
- `attestation.ui` → `/ui/attestations/{reportId}` when a DSSE envelope is included.
|
||||
- `attestation.api` → `{apiBasePath}/{reportsSegment}/{reportId}/attestation` when a DSSE envelope is included.
|
||||
- UI routes honour the configurable `scanner:console` options (`basePath`, `reportsSegment`, `policySegment`, `attestationsSegment`) so operators can move links under `/console` without code changes.
|
||||
- `imageDigest` — OCI image digest associated with the analysis.
|
||||
- `generatedAt` — report generation timestamp (ISO-8601 UTC).
|
||||
- `verdict` — `pass`, `warn`, or `fail` after policy evaluation.
|
||||
- `summary` — blocked/warned/ignored/quieted counters (all non-negative integers).
|
||||
- `delta` — newly critical/high counts and optional `kev` array.
|
||||
- `quietedFindingCount` — mirrors `summary.quieted`.
|
||||
- `policy` — revision metadata (`digest`, `revisionId`) surfaced for routing.
|
||||
- `links` — UI/report/policy URLs suitable for operators.
|
||||
- `dsse` — embedded DSSE envelope (payload, type, signature list).
|
||||
- `report` — canonical report document; identical to the DSSE payload.
|
||||
|
||||
Schema: `docs/events/scanner.event.report.ready@1.json`
|
||||
Sample: `docs/events/samples/scanner.event.report.ready@1.sample.json`
|
||||
|
||||
### 2.2 `scanner.event.scan.completed`
|
||||
|
||||
Emitted after scan execution finishes (success or policy failure). Payload highlights:
|
||||
|
||||
- `reportId` / `scanId` / `imageDigest` — identifiers mirroring the report-ready event. As with the report-ready payload, `scanId` currently mirrors `reportId` as a temporary shim.
|
||||
- **Attributes:** `reportId`, `policyRevisionId`, `policyDigest`, `verdict`.
|
||||
- **Links:** same as above (`report.*`, `policy.*`) with `attestation.*` populated when DSSE metadata exists.
|
||||
- `verdict`, `summary`, `delta`, `policy` — same semantics as above.
|
||||
- `findings` — array of surfaced findings with `id`, `severity`, optional `cve`, `purl`, and `reachability`.
|
||||
- `links`, `dsse`, `report` — same structure as §2.1 (allows Notifier to reuse signatures).
|
||||
|
||||
Schema: `docs/events/scanner.event.scan.completed@1.json`
|
||||
Sample: `docs/events/samples/scanner.event.scan.completed@1.sample.json`
|
||||
|
||||
### 2.3 Relationship to legacy events
|
||||
|
||||
| Legacy Redis event | Replacement orchestrator event | Notes |
|
||||
|--------------------|-------------------------------|-------|
|
||||
| `scanner.report.ready` | `scanner.event.report.ready` | Adds versioning, idempotency, trace context. Payload is a superset of the legacy fields. |
|
||||
| `scanner.scan.completed` | `scanner.event.scan.completed` | Same data plus explicit scan identifiers and orchestrator metadata. |
|
||||
|
||||
Legacy schemas remain for backwards-compatibility during migration, but new integrations **must** target the orchestrator variants.
|
||||
|
||||
## 3. Deterministic serialization
|
||||
|
||||
- Producers must serialise events using `NotifyCanonicalJsonSerializer` to guarantee consistent key ordering and whitespace.
|
||||
- Timestamps (`occurredAt`, `recordedAt`, `payload.generatedAt`) use `DateTimeOffset.UtcDateTime.ToString("O")`.
|
||||
- Payload arrays (`delta.kev`, `findings`) should be pre-sorted (e.g., alphabetical CVE order) so hash-based consumers remain stable.
|
||||
- Optional fields are omitted rather than emitted as `null`.
|
||||
|
||||
## 4. Idempotency and correlation
|
||||
|
||||
Idempotency keys dedupe repeated publishes and align with the orchestrator’s outbox pattern:
|
||||
|
||||
| Event kind | Idempotency key template |
|
||||
|------------|-------------------------|
|
||||
| `scanner.event.report.ready` | `scanner.event.report.ready:<tenant>:<reportId>` |
|
||||
| `scanner.event.scan.completed` | `scanner.event.scan.completed:<tenant>:<scanId>` |
|
||||
|
||||
Keys are ASCII lowercase; components should be trimmed and validated before concatenation. Retries must reuse the same key.
|
||||
|
||||
`correlationId` should match the scan identifier that appears in REST responses (`scanId`). Re-using the same value across the pair of events allows Notifier and orchestrator analytics to stitch lifecycle data together.
|
||||
|
||||
## 5. Versioning and evolution
|
||||
|
||||
- Increment the `version` field and the `@<version>` suffix for **breaking** changes (field removals, type changes, semantic shifts).
|
||||
- Additive optional fields may remain within version 1; update the JSON schema and samples accordingly.
|
||||
- When introducing `@2`, keep the `@1` schema/docs in place until orchestrator subscribers confirm migration.
|
||||
|
||||
## 6. Consumer checklist
|
||||
|
||||
1. Validate incoming payloads against the schema for the targeted version.
|
||||
2. Use `idempotencyKey` for dedupe, not `eventId`.
|
||||
3. Map `traceId`/`spanId` into telemetry spans to preserve causality.
|
||||
4. Prefer `payload.report` → `policy.revisionId` when populating templates; the top-level `attributes` are convenience duplicates for quick routing.
|
||||
5. Reserve the legacy Redis events for transitional compatibility only; downstream systems should subscribe to the orchestrator bus exposed by ORCH-SVC-38-101.
|
||||
|
||||
## 7. Implementation status and next actions
|
||||
|
||||
- **Scanner WebService** — `SCANNER-EVENTS-16-301` (blocked) and `SCANNER-EVENTS-16-302` (done) track the production of these envelopes. Dispatcher link customisation landed and samples updated; full `dotnet test` suite now succeeds after Surface cache ctor drift was patched and DSSE fixtures re-synced (2025-11-06).
|
||||
- **Gateway/Notifier consumers** — subscribe to the orchestrator stream documented in ORCH-SVC-38-101. When the Scanner tasks unblock, regenerate notifier contract tests against the sample events included here.
|
||||
- **Docs cadence** — update this file and the matching JSON schemas whenever payload fields change. Use the rehearsal checklist in `docs/modules/devops/runbooks/launch-cutover.md` to confirm downstream validation before the production cutover. Record gaps or newly required fields in `docs/modules/devops/runbooks/launch-readiness.md` so they land in the launch checklist.
|
||||
|
||||
---
|
||||
|
||||
**Imposed rule reminder:** work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"bundleId": "19bd7cf7-c7a6-4c1c-9b9c-6f2f794e9b1a",
|
||||
"advisoryId": "CVE-2025-12345",
|
||||
"tenant": "demo-tenant",
|
||||
"generatedAt": "2025-11-18T12:00:00Z",
|
||||
"schemaVersion": 0,
|
||||
"observations": [
|
||||
{
|
||||
"observationId": "obs-001",
|
||||
"source": "vendor.psirt",
|
||||
"purl": "pkg:maven/org.example/app@1.2.3",
|
||||
"cve": "CVE-2025-12345",
|
||||
"severity": "critical",
|
||||
"cvss": {
|
||||
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"score": 9.8
|
||||
},
|
||||
"summary": "Remote code execution via deserialization of untrusted data.",
|
||||
"evidence": {
|
||||
"statement": "Vendor confirms unauthenticated RCE in versions <1.2.4",
|
||||
"references": ["https://example.com/advisory"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"signatures": [
|
||||
{
|
||||
"signature": "MEQCID...==",
|
||||
"keyId": "authority-root-1",
|
||||
"algorithm": "ecdsa-p256-sha256"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"eventId": "1fdcaa1a-7a27-4154-8bac-cf813d8f4f6f",
|
||||
"kind": "attestor.logged",
|
||||
"tenant": "tenant-acme-solar",
|
||||
"ts": "2025-10-18T15:45:27+00:00",
|
||||
"payload": {
|
||||
"artifactSha256": "sha256:8927d9151ad3f44e61a9c647511f9a31af2b4d245e7e031fe5cb4a0e8211c5d9",
|
||||
"dsseEnvelopeDigest": "sha256:51c1dd189d5f16cfe87e82841d67b4fbc27d6fa9f5a09af0cd7e18945fb4c2a9",
|
||||
"rekor": {
|
||||
"index": 563421,
|
||||
"url": "https://rekor.example/api/v1/log/entries/d6d0f897e7244edc9cb0bb2c68b05c96",
|
||||
"uuid": "d6d0f897e7244edc9cb0bb2c68b05c96"
|
||||
},
|
||||
"signer": "cosign-stellaops",
|
||||
"subject": {
|
||||
"name": "scanner/report/sha256-0f0a8de5c1f93d6716b7249f6f4ea3a8",
|
||||
"type": "report"
|
||||
}
|
||||
},
|
||||
"attributes": {}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
{
|
||||
"eventId": "6d2d1b77-f3c3-4f70-8a9d-6f2d0c8801ab",
|
||||
"kind": "scanner.event.report.ready",
|
||||
"version": 1,
|
||||
"tenant": "tenant-alpha",
|
||||
"occurredAt": "2025-10-19T12:34:56+00:00",
|
||||
"recordedAt": "2025-10-19T12:34:57+00:00",
|
||||
"source": "scanner.webservice",
|
||||
"idempotencyKey": "scanner.event.report.ready:tenant-alpha:report-abc",
|
||||
"correlationId": "report-abc",
|
||||
"traceId": "0af7651916cd43dd8448eb211c80319c",
|
||||
"spanId": "b7ad6b7169203331",
|
||||
"scope": {
|
||||
"namespace": "acme/edge",
|
||||
"repo": "api",
|
||||
"digest": "sha256:feedface"
|
||||
},
|
||||
"payload": {
|
||||
"reportId": "report-abc",
|
||||
"scanId": "report-abc",
|
||||
"imageDigest": "sha256:feedface",
|
||||
"generatedAt": "2025-10-19T12:34:56+00:00",
|
||||
"verdict": "fail",
|
||||
"summary": {
|
||||
"total": 1,
|
||||
"blocked": 1,
|
||||
"warned": 0,
|
||||
"ignored": 0,
|
||||
"quieted": 0
|
||||
},
|
||||
"delta": {
|
||||
"newCritical": 1,
|
||||
"kev": [
|
||||
"CVE-2024-9999"
|
||||
]
|
||||
},
|
||||
"quietedFindingCount": 0,
|
||||
"policy": {
|
||||
"revisionId": "rev-42",
|
||||
"digest": "digest-123"
|
||||
},
|
||||
"links": {
|
||||
"report": {
|
||||
"ui": "https://scanner.example/ui/reports/report-abc",
|
||||
"api": "https://scanner.example/api/v1/reports/report-abc"
|
||||
},
|
||||
"policy": {
|
||||
"ui": "https://scanner.example/ui/policy/revisions/rev-42",
|
||||
"api": "https://scanner.example/api/v1/policy/revisions/rev-42"
|
||||
},
|
||||
"attestation": {
|
||||
"ui": "https://scanner.example/ui/attestations/report-abc",
|
||||
"api": "https://scanner.example/api/v1/reports/report-abc/attestation"
|
||||
}
|
||||
},
|
||||
"dsse": {
|
||||
"payloadType": "application/vnd.stellaops.report+json",
|
||||
"payload": "eyJyZXBvcnRJZCI6InJlcG9ydC1hYmMiLCJpbWFnZURpZ2VzdCI6InNoYTI1NjpmZWVkZmFjZSIsImdlbmVyYXRlZEF0IjoiMjAyNS0xMC0xOVQxMjozNDo1NiswMDowMCIsInZlcmRpY3QiOiJibG9ja2VkIiwicG9saWN5Ijp7InJldmlzaW9uSWQiOiJyZXYtNDIiLCJkaWdlc3QiOiJkaWdlc3QtMTIzIn0sInN1bW1hcnkiOnsidG90YWwiOjEsImJsb2NrZWQiOjEsIndhcm5lZCI6MCwiaWdub3JlZCI6MCwicXVpZXRlZCI6MH0sInZlcmRpY3RzIjpbeyJmaW5kaW5nSWQiOiJmaW5kaW5nLTEiLCJyZWFjaGFiaWxpdHkiOiJydW50aW1lIiwic2NvcmUiOjQ3LjUsInNvdXJjZVRydXN0IjoiTlZEIiwic3RhdHVzIjoiQmxvY2tlZCJ9XSwiaXNzdWVzIjpbXSwic3VyZmFjZSI6eyJ0ZW5hbnQiOiJ0ZW5hbnQtYWxwaGEiLCJnZW5lcmF0ZWRBdCI6IjIwMjUtMTAtMTlUMTI6MzQ6NTYrMDA6MDAiLCJtYW5pZmVzdERpZ2VzdCI6InNoYTI1Njo0ZmVlODdkMTg2MjkxZGRmYmJjYzJjNTZjOGVkMGU4Mjg1MjBiOGY1MmUxY2RlMGUxM2JiYTA4MmYxMDkxOGQ3IiwibWFuaWZlc3RVcmkiOiJjYXM6Ly9zY2FubmVyLWFydGlmYWN0cy9zY2FubmVyL3N1cmZhY2UvbWFuaWZlc3RzL3RlbmFudC1hbHBoYS9zaGEyNTYvNGYvZWUvNGZlZTg3ZDE4NjI5MWRkZmJiY2MyYzU2YzhlZDBlODI4NTIwYjhmNTJlMWNkZTBlMTNiYmEwODJmMTA5MThkNy5qc29uIiwibWFuaWZlc3QiOnsic2NoZW1hIjoic3RlbGxhb3BzLnN1cmZhY2UubWFuaWZlc3RAMSIsInRlbmFudCI6InRlbmFudC1hbHBoYSIsImltYWdlRGlnZXN0Ijoic2hhMjU2OmZlZWRmYWNlIiwiZ2VuZXJhdGVkQXQiOiIyMDI1LTEwLTE5VDEyOjM0OjU2KzAwOjAwIiwiYXJ0aWZhY3RzIjpbeyJraW5kIjoiZW50cnktdHJhY2UiLCJ1cmkiOiJjYXM6Ly9zY2FubmVyLWFydGlmYWN0cy9zY2FubmVyL2VudHJ5LXRyYWNlL2YwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwL2VudHJ5LXRyYWNlLmpzb24iLCJkaWdlc3QiOiJzaGEyNTY6ZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMCIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL2pzb24iLCJmb3JtYXQiOiJqc29uIiwic2l6ZUJ5dGVzIjo0MDk2fSx7ImtpbmQiOiJzYm9tLWludmVudG9yeSIsInVyaSI6ImNhczovL3NjYW5uZXItYXJ0aWZhY3RzL3NjYW5uZXIvaW1hZ2VzL2ZlZWRmYWNlL3Nib20uY2R4Lmpzb24iLCJkaWdlc3QiOiJzaGEyNTY6MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMSIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5jeWNsb25lZHgranNvbjt2ZXJzaW9uPTEuNjt2aWV3PWludmVudG9yeSIsImZvcm1hdCI6ImNkeC1qc29uIiwic2l6ZUJ5dGVzIjoyNDU3NiwidmlldyI6ImludmVudG9yeSJ9LHsia2luZCI6InNib20tdXNhZ2UiLCJ1cmkiOiJjYXM6Ly9zY2FubmVyLWFydGlmYWN0cy9zY2FubmVyL2ltYWdlcy9mZWVkZmFjZS9zYm9tLXVzYWdlLmNkeC5qc29uIiwiZGlnZXN0Ijoic2hhMjU2OjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIiLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuY3ljbG9uZWR4K2pzb247dmVyc2lvbj0xLjY7dmlldz11c2FnZSIsImZvcm1hdCI6ImNkeC1qc29uIiwic2l6ZUJ5dGVzIjoxNjM4NCwidmlldyI6InVzYWdlIn1dfX19",
|
||||
"signatures": [
|
||||
{
|
||||
"keyId": "test-key",
|
||||
"algorithm": "hs256",
|
||||
"signature": "signature-value"
|
||||
}
|
||||
]
|
||||
},
|
||||
"report": {
|
||||
"reportId": "report-abc",
|
||||
"imageDigest": "sha256:feedface",
|
||||
"generatedAt": "2025-10-19T12:34:56+00:00",
|
||||
"verdict": "blocked",
|
||||
"policy": {
|
||||
"revisionId": "rev-42",
|
||||
"digest": "digest-123"
|
||||
},
|
||||
"summary": {
|
||||
"total": 1,
|
||||
"blocked": 1,
|
||||
"warned": 0,
|
||||
"ignored": 0,
|
||||
"quieted": 0
|
||||
},
|
||||
"verdicts": [
|
||||
{
|
||||
"findingId": "finding-1",
|
||||
"reachability": "runtime",
|
||||
"score": 47.5,
|
||||
"sourceTrust": "NVD",
|
||||
"status": "Blocked"
|
||||
}
|
||||
],
|
||||
"issues": [],
|
||||
"surface": {
|
||||
"tenant": "tenant-alpha",
|
||||
"generatedAt": "2025-10-19T12:34:56+00:00",
|
||||
"manifestDigest": "sha256:4fee87d186291ddfbbcc2c56c8ed0e828520b8f52e1cde0e13bba082f10918d7",
|
||||
"manifestUri": "cas://scanner-artifacts/scanner/surface/manifests/tenant-alpha/sha256/4f/ee/4fee87d186291ddfbbcc2c56c8ed0e828520b8f52e1cde0e13bba082f10918d7.json",
|
||||
"manifest": {
|
||||
"schema": "stellaops.surface.manifest@1",
|
||||
"tenant": "tenant-alpha",
|
||||
"imageDigest": "sha256:feedface",
|
||||
"generatedAt": "2025-10-19T12:34:56+00:00",
|
||||
"artifacts": [
|
||||
{
|
||||
"kind": "entry-trace",
|
||||
"uri": "cas://scanner-artifacts/scanner/entry-trace/f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0/entry-trace.json",
|
||||
"digest": "sha256:f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0",
|
||||
"mediaType": "application/json",
|
||||
"format": "json",
|
||||
"sizeBytes": 4096
|
||||
},
|
||||
{
|
||||
"kind": "sbom-inventory",
|
||||
"uri": "cas://scanner-artifacts/scanner/images/feedface/sbom.cdx.json",
|
||||
"digest": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"mediaType": "application/vnd.cyclonedx+json;version=1.6;view=inventory",
|
||||
"format": "cdx-json",
|
||||
"sizeBytes": 24576,
|
||||
"view": "inventory"
|
||||
},
|
||||
{
|
||||
"kind": "sbom-usage",
|
||||
"uri": "cas://scanner-artifacts/scanner/images/feedface/sbom-usage.cdx.json",
|
||||
"digest": "sha256:2222222222222222222222222222222222222222222222222222222222222222",
|
||||
"mediaType": "application/vnd.cyclonedx+json;version=1.6;view=usage",
|
||||
"format": "cdx-json",
|
||||
"sizeBytes": 16384,
|
||||
"view": "usage"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"attributes": {
|
||||
"policyDigest": "digest-123",
|
||||
"policyRevisionId": "rev-42",
|
||||
"reportId": "report-abc",
|
||||
"verdict": "blocked"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
{
|
||||
"eventId": "08a6de24-4a94-4d14-8432-9d14f36f6da3",
|
||||
"kind": "scanner.event.scan.completed",
|
||||
"version": 1,
|
||||
"tenant": "tenant-alpha",
|
||||
"occurredAt": "2025-10-19T12:34:56+00:00",
|
||||
"recordedAt": "2025-10-19T12:34:57+00:00",
|
||||
"source": "scanner.webservice",
|
||||
"idempotencyKey": "scanner.event.scan.completed:tenant-alpha:report-abc",
|
||||
"correlationId": "report-abc",
|
||||
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
|
||||
"scope": {
|
||||
"namespace": "acme/edge",
|
||||
"repo": "api",
|
||||
"digest": "sha256:feedface"
|
||||
},
|
||||
"payload": {
|
||||
"reportId": "report-abc",
|
||||
"scanId": "report-abc",
|
||||
"imageDigest": "sha256:feedface",
|
||||
"verdict": "fail",
|
||||
"summary": {
|
||||
"total": 1,
|
||||
"blocked": 1,
|
||||
"warned": 0,
|
||||
"ignored": 0,
|
||||
"quieted": 0
|
||||
},
|
||||
"delta": {
|
||||
"newCritical": 1,
|
||||
"kev": [
|
||||
"CVE-2024-9999"
|
||||
]
|
||||
},
|
||||
"policy": {
|
||||
"revisionId": "rev-42",
|
||||
"digest": "digest-123"
|
||||
},
|
||||
"findings": [
|
||||
{
|
||||
"id": "finding-1",
|
||||
"severity": "Critical",
|
||||
"cve": "CVE-2024-9999",
|
||||
"purl": "pkg:docker/acme/edge-api@sha256-feedface",
|
||||
"reachability": "runtime"
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"report": {
|
||||
"ui": "https://scanner.example/ui/reports/report-abc",
|
||||
"api": "https://scanner.example/api/v1/reports/report-abc"
|
||||
},
|
||||
"policy": {
|
||||
"ui": "https://scanner.example/ui/policy/revisions/rev-42",
|
||||
"api": "https://scanner.example/api/v1/policy/revisions/rev-42"
|
||||
},
|
||||
"attestation": {
|
||||
"ui": "https://scanner.example/ui/attestations/report-abc",
|
||||
"api": "https://scanner.example/api/v1/reports/report-abc/attestation"
|
||||
}
|
||||
},
|
||||
"dsse": {
|
||||
"payloadType": "application/vnd.stellaops.report+json",
|
||||
"payload": "eyJyZXBvcnRJZCI6InJlcG9ydC1hYmMiLCJpbWFnZURpZ2VzdCI6InNoYTI1NjpmZWVkZmFjZSIsImdlbmVyYXRlZEF0IjoiMjAyNS0xMC0xOVQxMjozNDo1NiswMDowMCIsInZlcmRpY3QiOiJibG9ja2VkIiwicG9saWN5Ijp7InJldmlzaW9uSWQiOiJyZXYtNDIiLCJkaWdlc3QiOiJkaWdlc3QtMTIzIn0sInN1bW1hcnkiOnsidG90YWwiOjEsImJsb2NrZWQiOjEsIndhcm5lZCI6MCwiaWdub3JlZCI6MCwicXVpZXRlZCI6MH0sInZlcmRpY3RzIjpbeyJmaW5kaW5nSWQiOiJmaW5kaW5nLTEiLCJyZWFjaGFiaWxpdHkiOiJydW50aW1lIiwic2NvcmUiOjQ3LjUsInNvdXJjZVRydXN0IjoiTlZEIiwic3RhdHVzIjoiQmxvY2tlZCJ9XSwiaXNzdWVzIjpbXSwic3VyZmFjZSI6eyJ0ZW5hbnQiOiJ0ZW5hbnQtYWxwaGEiLCJnZW5lcmF0ZWRBdCI6IjIwMjUtMTAtMTlUMTI6MzQ6NTYrMDA6MDAiLCJtYW5pZmVzdERpZ2VzdCI6InNoYTI1Njo0ZmVlODdkMTg2MjkxZGRmYmJjYzJjNTZjOGVkMGU4Mjg1MjBiOGY1MmUxY2RlMGUxM2JiYTA4MmYxMDkxOGQ3IiwibWFuaWZlc3RVcmkiOiJjYXM6Ly9zY2FubmVyLWFydGlmYWN0cy9zY2FubmVyL3N1cmZhY2UvbWFuaWZlc3RzL3RlbmFudC1hbHBoYS9zaGEyNTYvNGYvZWUvNGZlZTg3ZDE4NjI5MWRkZmJiY2MyYzU2YzhlZDBlODI4NTIwYjhmNTJlMWNkZTBlMTNiYmEwODJmMTA5MThkNy5qc29uIiwibWFuaWZlc3QiOnsic2NoZW1hIjoic3RlbGxhb3BzLnN1cmZhY2UubWFuaWZlc3RAMSIsInRlbmFudCI6InRlbmFudC1hbHBoYSIsImltYWdlRGlnZXN0Ijoic2hhMjU2OmZlZWRmYWNlIiwiZ2VuZXJhdGVkQXQiOiIyMDI1LTEwLTE5VDEyOjM0OjU2KzAwOjAwIiwiYXJ0aWZhY3RzIjpbeyJraW5kIjoiZW50cnktdHJhY2UiLCJ1cmkiOiJjYXM6Ly9zY2FubmVyLWFydGlmYWN0cy9zY2FubmVyL2VudHJ5LXRyYWNlL2YwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwL2VudHJ5LXRyYWNlLmpzb24iLCJkaWdlc3QiOiJzaGEyNTY6ZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMCIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL2pzb24iLCJmb3JtYXQiOiJqc29uIiwic2l6ZUJ5dGVzIjo0MDk2fSx7ImtpbmQiOiJzYm9tLWludmVudG9yeSIsInVyaSI6ImNhczovL3NjYW5uZXItYXJ0aWZhY3RzL3NjYW5uZXIvaW1hZ2VzL2ZlZWRmYWNlL3Nib20uY2R4Lmpzb24iLCJkaWdlc3QiOiJzaGEyNTY6MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMSIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5jeWNsb25lZHgranNvbjt2ZXJzaW9uPTEuNjt2aWV3PWludmVudG9yeSIsImZvcm1hdCI6ImNkeC1qc29uIiwic2l6ZUJ5dGVzIjoyNDU3NiwidmlldyI6ImludmVudG9yeSJ9LHsia2luZCI6InNib20tdXNhZ2UiLCJ1cmkiOiJjYXM6Ly9zY2FubmVyLWFydGlmYWN0cy9zY2FubmVyL2ltYWdlcy9mZWVkZmFjZS9zYm9tLXVzYWdlLmNkeC5qc29uIiwiZGlnZXN0Ijoic2hhMjU2OjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIiLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuY3ljbG9uZWR4K2pzb247dmVyc2lvbj0xLjY7dmlldz11c2FnZSIsImZvcm1hdCI6ImNkeC1qc29uIiwic2l6ZUJ5dGVzIjoxNjM4NCwidmlldyI6InVzYWdlIn1dfX19",
|
||||
"signatures": [
|
||||
{
|
||||
"keyId": "test-key",
|
||||
"algorithm": "hs256",
|
||||
"signature": "signature-value"
|
||||
}
|
||||
]
|
||||
},
|
||||
"report": {
|
||||
"reportId": "report-abc",
|
||||
"imageDigest": "sha256:feedface",
|
||||
"generatedAt": "2025-10-19T12:34:56+00:00",
|
||||
"verdict": "blocked",
|
||||
"policy": {
|
||||
"revisionId": "rev-42",
|
||||
"digest": "digest-123"
|
||||
},
|
||||
"summary": {
|
||||
"total": 1,
|
||||
"blocked": 1,
|
||||
"warned": 0,
|
||||
"ignored": 0,
|
||||
"quieted": 0
|
||||
},
|
||||
"verdicts": [
|
||||
{
|
||||
"findingId": "finding-1",
|
||||
"reachability": "runtime",
|
||||
"score": 47.5,
|
||||
"sourceTrust": "NVD",
|
||||
"status": "Blocked"
|
||||
}
|
||||
],
|
||||
"issues": [],
|
||||
"surface": {
|
||||
"tenant": "tenant-alpha",
|
||||
"generatedAt": "2025-10-19T12:34:56+00:00",
|
||||
"manifestDigest": "sha256:4fee87d186291ddfbbcc2c56c8ed0e828520b8f52e1cde0e13bba082f10918d7",
|
||||
"manifestUri": "cas://scanner-artifacts/scanner/surface/manifests/tenant-alpha/sha256/4f/ee/4fee87d186291ddfbbcc2c56c8ed0e828520b8f52e1cde0e13bba082f10918d7.json",
|
||||
"manifest": {
|
||||
"schema": "stellaops.surface.manifest@1",
|
||||
"tenant": "tenant-alpha",
|
||||
"imageDigest": "sha256:feedface",
|
||||
"generatedAt": "2025-10-19T12:34:56+00:00",
|
||||
"artifacts": [
|
||||
{
|
||||
"kind": "entry-trace",
|
||||
"uri": "cas://scanner-artifacts/scanner/entry-trace/f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0/entry-trace.json",
|
||||
"digest": "sha256:f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0",
|
||||
"mediaType": "application/json",
|
||||
"format": "json",
|
||||
"sizeBytes": 4096
|
||||
},
|
||||
{
|
||||
"kind": "sbom-inventory",
|
||||
"uri": "cas://scanner-artifacts/scanner/images/feedface/sbom.cdx.json",
|
||||
"digest": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"mediaType": "application/vnd.cyclonedx+json;version=1.6;view=inventory",
|
||||
"format": "cdx-json",
|
||||
"sizeBytes": 24576,
|
||||
"view": "inventory"
|
||||
},
|
||||
{
|
||||
"kind": "sbom-usage",
|
||||
"uri": "cas://scanner-artifacts/scanner/images/feedface/sbom-usage.cdx.json",
|
||||
"digest": "sha256:2222222222222222222222222222222222222222222222222222222222222222",
|
||||
"mediaType": "application/vnd.cyclonedx+json;version=1.6;view=usage",
|
||||
"format": "cdx-json",
|
||||
"sizeBytes": 16384,
|
||||
"view": "usage"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"attributes": {
|
||||
"policyDigest": "digest-123",
|
||||
"policyRevisionId": "rev-42",
|
||||
"reportId": "report-abc",
|
||||
"verdict": "blocked"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"eventId": "6d2d1b77-f3c3-4f70-8a9d-6f2d0c8801ab",
|
||||
"kind": "scanner.report.ready",
|
||||
"tenant": "tenant-alpha",
|
||||
"ts": "2025-10-19T12:34:56+00:00",
|
||||
"scope": {
|
||||
"namespace": "acme/edge",
|
||||
"repo": "api",
|
||||
"digest": "sha256:feedface",
|
||||
"labels": {},
|
||||
"attributes": {}
|
||||
},
|
||||
"payload": {
|
||||
"delta": {
|
||||
"kev": ["CVE-2024-9999"],
|
||||
"newCritical": 1
|
||||
},
|
||||
"dsse": {
|
||||
"payload": "eyJyZXBvcnRJZCI6InJlcG9ydC1hYmMiLCJpbWFnZURpZ2VzdCI6InNoYTI1NjpmZWVkZmFjZSIsImdlbmVyYXRlZEF0IjoiMjAyNS0xMC0xOVQxMjozNDo1NiswMDowMCIsInZlcmRpY3QiOiJibG9ja2VkIiwicG9saWN5Ijp7InJldmlzaW9uSWQiOiJyZXYtNDIiLCJkaWdlc3QiOiJkaWdlc3QtMTIzIn0sInN1bW1hcnkiOnsidG90YWwiOjEsImJsb2NrZWQiOjEsIndhcm5lZCI6MCwiaWdub3JlZCI6MCwicXVpZXRlZCI6MH0sInZlcmRpY3RzIjpbeyJmaW5kaW5nSWQiOiJmaW5kaW5nLTEiLCJzdGF0dXMiOiJCbG9ja2VkIiwic2NvcmUiOjQ3LjUsInNvdXJjZVRydXN0IjoiTlZEIiwicmVhY2hhYmlsaXR5IjoicnVudGltZSJ9XSwiaXNzdWVzIjpbXX0=",
|
||||
"payloadType": "application/vnd.stellaops.report\u002Bjson",
|
||||
"signatures": [{
|
||||
"algorithm": "hs256",
|
||||
"keyId": "test-key",
|
||||
"signature": "signature-value"
|
||||
}]
|
||||
},
|
||||
"generatedAt": "2025-10-19T12:34:56+00:00",
|
||||
"links": {
|
||||
"ui": "https://scanner.example/ui/reports/report-abc"
|
||||
},
|
||||
"quietedFindingCount": 0,
|
||||
"report": {
|
||||
"generatedAt": "2025-10-19T12:34:56+00:00",
|
||||
"imageDigest": "sha256:feedface",
|
||||
"issues": [],
|
||||
"policy": {
|
||||
"digest": "digest-123",
|
||||
"revisionId": "rev-42"
|
||||
},
|
||||
"reportId": "report-abc",
|
||||
"summary": {
|
||||
"blocked": 1,
|
||||
"ignored": 0,
|
||||
"quieted": 0,
|
||||
"total": 1,
|
||||
"warned": 0
|
||||
},
|
||||
"verdict": "blocked",
|
||||
"verdicts": [
|
||||
{
|
||||
"findingId": "finding-1",
|
||||
"status": "Blocked",
|
||||
"score": 47.5,
|
||||
"sourceTrust": "NVD",
|
||||
"reachability": "runtime"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reportId": "report-abc",
|
||||
"summary": {
|
||||
"blocked": 1,
|
||||
"ignored": 0,
|
||||
"quieted": 0,
|
||||
"total": 1,
|
||||
"warned": 0
|
||||
},
|
||||
"verdict": "fail"
|
||||
},
|
||||
"attributes": {}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"eventId": "08a6de24-4a94-4d14-8432-9d14f36f6da3",
|
||||
"kind": "scanner.scan.completed",
|
||||
"tenant": "tenant-alpha",
|
||||
"ts": "2025-10-19T12:34:56+00:00",
|
||||
"scope": {
|
||||
"namespace": "acme/edge",
|
||||
"repo": "api",
|
||||
"digest": "sha256:feedface",
|
||||
"labels": {},
|
||||
"attributes": {}
|
||||
},
|
||||
"payload": {
|
||||
"delta": {
|
||||
"kev": ["CVE-2024-9999"],
|
||||
"newCritical": 1
|
||||
},
|
||||
"digest": "sha256:feedface",
|
||||
"dsse": {
|
||||
"payload": "eyJyZXBvcnRJZCI6InJlcG9ydC1hYmMiLCJpbWFnZURpZ2VzdCI6InNoYTI1NjpmZWVkZmFjZSIsImdlbmVyYXRlZEF0IjoiMjAyNS0xMC0xOVQxMjozNDo1NiswMDowMCIsInZlcmRpY3QiOiJibG9ja2VkIiwicG9saWN5Ijp7InJldmlzaW9uSWQiOiJyZXYtNDIiLCJkaWdlc3QiOiJkaWdlc3QtMTIzIn0sInN1bW1hcnkiOnsidG90YWwiOjEsImJsb2NrZWQiOjEsIndhcm5lZCI6MCwiaWdub3JlZCI6MCwicXVpZXRlZCI6MH0sInZlcmRpY3RzIjpbeyJmaW5kaW5nSWQiOiJmaW5kaW5nLTEiLCJzdGF0dXMiOiJCbG9ja2VkIiwic2NvcmUiOjQ3LjUsInNvdXJjZVRydXN0IjoiTlZEIiwicmVhY2hhYmlsaXR5IjoicnVudGltZSJ9XSwiaXNzdWVzIjpbXX0=",
|
||||
"payloadType": "application/vnd.stellaops.report\u002Bjson",
|
||||
"signatures": [{
|
||||
"algorithm": "hs256",
|
||||
"keyId": "test-key",
|
||||
"signature": "signature-value"
|
||||
}]
|
||||
},
|
||||
"findings": [
|
||||
{
|
||||
"cve": "CVE-2024-9999",
|
||||
"id": "finding-1",
|
||||
"reachability": "runtime",
|
||||
"severity": "Critical"
|
||||
}
|
||||
],
|
||||
"policy": {
|
||||
"digest": "digest-123",
|
||||
"revisionId": "rev-42"
|
||||
},
|
||||
"report": {
|
||||
"generatedAt": "2025-10-19T12:34:56+00:00",
|
||||
"imageDigest": "sha256:feedface",
|
||||
"issues": [],
|
||||
"policy": {
|
||||
"digest": "digest-123",
|
||||
"revisionId": "rev-42"
|
||||
},
|
||||
"reportId": "report-abc",
|
||||
"summary": {
|
||||
"blocked": 1,
|
||||
"ignored": 0,
|
||||
"quieted": 0,
|
||||
"total": 1,
|
||||
"warned": 0
|
||||
},
|
||||
"verdict": "blocked",
|
||||
"verdicts": [
|
||||
{
|
||||
"findingId": "finding-1",
|
||||
"status": "Blocked",
|
||||
"score": 47.5,
|
||||
"sourceTrust": "NVD",
|
||||
"reachability": "runtime"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reportId": "report-abc",
|
||||
"summary": {
|
||||
"blocked": 1,
|
||||
"ignored": 0,
|
||||
"quieted": 0,
|
||||
"total": 1,
|
||||
"warned": 0
|
||||
},
|
||||
"verdict": "fail"
|
||||
},
|
||||
"attributes": {}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"eventId": "4d33c19c-1c8a-44d1-9954-1d5e98b2af71",
|
||||
"kind": "scheduler.graph.job.completed",
|
||||
"tenant": "tenant-alpha",
|
||||
"ts": "2025-10-26T12:00:45Z",
|
||||
"payload": {
|
||||
"jobType": "build",
|
||||
"status": "completed",
|
||||
"occurredAt": "2025-10-26T12:00:45Z",
|
||||
"job": {
|
||||
"schemaVersion": "scheduler.graph-build-job@1",
|
||||
"id": "gbj_20251026a",
|
||||
"tenantId": "tenant-alpha",
|
||||
"sbomId": "sbom_20251026",
|
||||
"sbomVersionId": "sbom_ver_20251026",
|
||||
"sbomDigest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||
"graphSnapshotId": "graph_snap_20251026",
|
||||
"status": "completed",
|
||||
"trigger": "sbom-version",
|
||||
"attempts": 1,
|
||||
"cartographerJobId": "carto_job_42",
|
||||
"correlationId": "evt_svc_987",
|
||||
"createdAt": "2025-10-26T12:00:00+00:00",
|
||||
"startedAt": "2025-10-26T12:00:05+00:00",
|
||||
"completedAt": "2025-10-26T12:00:45+00:00",
|
||||
"metadata": {
|
||||
"sbomEventId": "sbom_evt_20251026"
|
||||
}
|
||||
},
|
||||
"resultUri": "oras://cartographer/offline/tenant-alpha/graph_snap_20251026"
|
||||
},
|
||||
"attributes": {
|
||||
"cartographerCluster": "offline-kit",
|
||||
"plannerShard": "graph-builders-01"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"eventId": "51d0ef8d-3a17-4af3-b2d7-4ad3db3d9d2c",
|
||||
"kind": "scheduler.rescan.delta",
|
||||
"tenant": "tenant-acme-solar",
|
||||
"ts": "2025-10-18T15:40:11+00:00",
|
||||
"payload": {
|
||||
"impactedDigests": [
|
||||
"sha256:0f0a8de5c1f93d6716b7249f6f4ea3a8db451dc3f3c3ff823f53c9cbde5d5e8a",
|
||||
"sha256:ab921f9679dd8d0832f3710a4df75dbadbd58c2d95f26a4d4efb2fa8c3d9b4ce"
|
||||
],
|
||||
"reason": "policy-change:scoring/v2",
|
||||
"scheduleId": "rescan-weekly-critical",
|
||||
"summary": {
|
||||
"newCritical": 0,
|
||||
"newHigh": 1,
|
||||
"total": 4
|
||||
}
|
||||
},
|
||||
"attributes": {}
|
||||
}
|
||||
173
docs/modules/signals/events/scanner.event.report.ready@1.json
Normal file
173
docs/modules/signals/events/scanner.event.report.ready@1.json
Normal file
@@ -0,0 +1,173 @@
|
||||
{
|
||||
"$id": "https://stella-ops.org/schemas/events/scanner.event.report.ready@1.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Scanner orchestrator event – report ready (v1)",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"eventId",
|
||||
"kind",
|
||||
"version",
|
||||
"tenant",
|
||||
"occurredAt",
|
||||
"source",
|
||||
"idempotencyKey",
|
||||
"payload"
|
||||
],
|
||||
"properties": {
|
||||
"eventId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Globally unique identifier for this occurrence."
|
||||
},
|
||||
"kind": {
|
||||
"const": "scanner.event.report.ready",
|
||||
"description": "Event kind identifier consumed by orchestrator subscribers."
|
||||
},
|
||||
"version": {
|
||||
"const": 1,
|
||||
"description": "Schema version for orchestrator envelopes."
|
||||
},
|
||||
"tenant": {
|
||||
"type": "string",
|
||||
"description": "Tenant that owns the scan/report."
|
||||
},
|
||||
"occurredAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Timestamp (UTC) when the report transitioned to ready."
|
||||
},
|
||||
"recordedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Timestamp (UTC) when the event was persisted. Optional."
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"description": "Producer identifier, e.g. `scanner.webservice`."
|
||||
},
|
||||
"idempotencyKey": {
|
||||
"type": "string",
|
||||
"minLength": 8,
|
||||
"description": "Deterministic key used to deduplicate events downstream."
|
||||
},
|
||||
"correlationId": {
|
||||
"type": "string",
|
||||
"description": "Correlation identifier that ties this event to a request or workflow."
|
||||
},
|
||||
"traceId": {
|
||||
"type": "string",
|
||||
"description": "W3C trace ID (32 hex chars) for distributed tracing."
|
||||
},
|
||||
"spanId": {
|
||||
"type": "string",
|
||||
"description": "Optional span identifier associated with traceId."
|
||||
},
|
||||
"scope": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["repo", "digest"],
|
||||
"properties": {
|
||||
"namespace": {"type": "string"},
|
||||
"repo": {"type": "string"},
|
||||
"digest": {"type": "string"},
|
||||
"component": {"type": "string"},
|
||||
"image": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"description": "String attributes for downstream correlation (policy revision, scan id, etc.).",
|
||||
"additionalProperties": {"type": "string"}
|
||||
},
|
||||
"payload": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"required": ["reportId", "verdict", "summary", "links", "report"],
|
||||
"properties": {
|
||||
"reportId": {"type": "string"},
|
||||
"scanId": {"type": "string"},
|
||||
"imageDigest": {"type": "string"},
|
||||
"generatedAt": {"type": "string", "format": "date-time"},
|
||||
"verdict": {"enum": ["pass", "warn", "fail"]},
|
||||
"summary": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["total", "blocked", "warned", "ignored", "quieted"],
|
||||
"properties": {
|
||||
"total": {"type": "integer", "minimum": 0},
|
||||
"blocked": {"type": "integer", "minimum": 0},
|
||||
"warned": {"type": "integer", "minimum": 0},
|
||||
"ignored": {"type": "integer", "minimum": 0},
|
||||
"quieted": {"type": "integer", "minimum": 0}
|
||||
}
|
||||
},
|
||||
"delta": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"newCritical": {"type": "integer", "minimum": 0},
|
||||
"newHigh": {"type": "integer", "minimum": 0},
|
||||
"kev": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"quietedFindingCount": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"policy": {
|
||||
"type": "object",
|
||||
"description": "Policy revision metadata surfaced alongside the report."
|
||||
},
|
||||
"links": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"report": {"$ref": "#/definitions/linkTarget"},
|
||||
"policy": {"$ref": "#/definitions/linkTarget"},
|
||||
"attestation": {"$ref": "#/definitions/linkTarget"}
|
||||
}
|
||||
},
|
||||
"dsse": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["payloadType", "payload", "signatures"],
|
||||
"properties": {
|
||||
"payloadType": {"type": "string"},
|
||||
"payload": {"type": "string"},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["keyId", "algorithm", "signature"],
|
||||
"properties": {
|
||||
"keyId": {"type": "string"},
|
||||
"algorithm": {"type": "string"},
|
||||
"signature": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"report": {
|
||||
"type": "object",
|
||||
"description": "Canonical scanner report document that aligns with the DSSE payload."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"definitions": {
|
||||
"linkTarget": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"ui": {"type": "string", "format": "uri"},
|
||||
"api": {"type": "string", "format": "uri"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
183
docs/modules/signals/events/scanner.event.scan.completed@1.json
Normal file
183
docs/modules/signals/events/scanner.event.scan.completed@1.json
Normal file
@@ -0,0 +1,183 @@
|
||||
{
|
||||
"$id": "https://stella-ops.org/schemas/events/scanner.event.scan.completed@1.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Scanner orchestrator event – scan completed (v1)",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"eventId",
|
||||
"kind",
|
||||
"version",
|
||||
"tenant",
|
||||
"occurredAt",
|
||||
"source",
|
||||
"idempotencyKey",
|
||||
"payload"
|
||||
],
|
||||
"properties": {
|
||||
"eventId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Globally unique identifier for this occurrence."
|
||||
},
|
||||
"kind": {
|
||||
"const": "scanner.event.scan.completed",
|
||||
"description": "Event kind identifier consumed by orchestrator subscribers."
|
||||
},
|
||||
"version": {
|
||||
"const": 1,
|
||||
"description": "Schema version for orchestrator envelopes."
|
||||
},
|
||||
"tenant": {
|
||||
"type": "string",
|
||||
"description": "Tenant that owns the scan."
|
||||
},
|
||||
"occurredAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Timestamp (UTC) when the scan completed."
|
||||
},
|
||||
"recordedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Timestamp (UTC) when the event was persisted. Optional."
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"description": "Producer identifier, e.g. `scanner.webservice`."
|
||||
},
|
||||
"idempotencyKey": {
|
||||
"type": "string",
|
||||
"minLength": 8,
|
||||
"description": "Deterministic key used to deduplicate events downstream."
|
||||
},
|
||||
"correlationId": {
|
||||
"type": "string",
|
||||
"description": "Correlation identifier tying this event to a request or workflow."
|
||||
},
|
||||
"traceId": {
|
||||
"type": "string",
|
||||
"description": "W3C trace ID (32 hex chars) for distributed tracing."
|
||||
},
|
||||
"spanId": {
|
||||
"type": "string",
|
||||
"description": "Optional span identifier associated with traceId."
|
||||
},
|
||||
"scope": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["repo", "digest"],
|
||||
"properties": {
|
||||
"namespace": {"type": "string"},
|
||||
"repo": {"type": "string"},
|
||||
"digest": {"type": "string"},
|
||||
"component": {"type": "string"},
|
||||
"image": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"description": "String attributes for downstream correlation (policy revision, scan id, etc.).",
|
||||
"additionalProperties": {"type": "string"}
|
||||
},
|
||||
"payload": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"required": ["reportId", "scanId", "imageDigest", "verdict", "summary", "report"],
|
||||
"properties": {
|
||||
"reportId": {"type": "string"},
|
||||
"scanId": {"type": "string"},
|
||||
"imageDigest": {"type": "string"},
|
||||
"verdict": {"enum": ["pass", "warn", "fail"]},
|
||||
"summary": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["total", "blocked", "warned", "ignored", "quieted"],
|
||||
"properties": {
|
||||
"total": {"type": "integer", "minimum": 0},
|
||||
"blocked": {"type": "integer", "minimum": 0},
|
||||
"warned": {"type": "integer", "minimum": 0},
|
||||
"ignored": {"type": "integer", "minimum": 0},
|
||||
"quieted": {"type": "integer", "minimum": 0}
|
||||
}
|
||||
},
|
||||
"delta": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"newCritical": {"type": "integer", "minimum": 0},
|
||||
"newHigh": {"type": "integer", "minimum": 0},
|
||||
"kev": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"policy": {
|
||||
"type": "object",
|
||||
"description": "Policy revision metadata surfaced alongside the report."
|
||||
},
|
||||
"findings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["id"],
|
||||
"properties": {
|
||||
"id": {"type": "string"},
|
||||
"severity": {"type": "string"},
|
||||
"cve": {"type": "string"},
|
||||
"purl": {"type": "string"},
|
||||
"reachability": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"report": {"$ref": "#/definitions/linkTarget"},
|
||||
"policy": {"$ref": "#/definitions/linkTarget"},
|
||||
"attestation": {"$ref": "#/definitions/linkTarget"}
|
||||
}
|
||||
},
|
||||
"dsse": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["payloadType", "payload", "signatures"],
|
||||
"properties": {
|
||||
"payloadType": {"type": "string"},
|
||||
"payload": {"type": "string"},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["keyId", "algorithm", "signature"],
|
||||
"properties": {
|
||||
"keyId": {"type": "string"},
|
||||
"algorithm": {"type": "string"},
|
||||
"signature": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"report": {
|
||||
"type": "object",
|
||||
"description": "Canonical scanner report document that aligns with the DSSE payload."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"definitions": {
|
||||
"linkTarget": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"ui": {"type": "string", "format": "uri"},
|
||||
"api": {"type": "string", "format": "uri"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
89
docs/modules/signals/events/scanner.report.ready@1.json
Normal file
89
docs/modules/signals/events/scanner.report.ready@1.json
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"$id": "https://stella-ops.org/schemas/events/scanner.report.ready@1.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"required": ["eventId", "kind", "tenant", "ts", "scope", "payload"],
|
||||
"properties": {
|
||||
"eventId": {"type": "string", "format": "uuid"},
|
||||
"kind": {"const": "scanner.report.ready"},
|
||||
"tenant": {"type": "string"},
|
||||
"ts": {"type": "string", "format": "date-time"},
|
||||
"scope": {
|
||||
"type": "object",
|
||||
"required": ["repo", "digest"],
|
||||
"properties": {
|
||||
"namespace": {"type": "string"},
|
||||
"repo": {"type": "string"},
|
||||
"digest": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"payload": {
|
||||
"type": "object",
|
||||
"required": ["verdict", "delta", "links"],
|
||||
"properties": {
|
||||
"reportId": {"type": "string"},
|
||||
"generatedAt": {"type": "string", "format": "date-time"},
|
||||
"verdict": {"enum": ["pass", "warn", "fail"]},
|
||||
"summary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {"type": "integer", "minimum": 0},
|
||||
"blocked": {"type": "integer", "minimum": 0},
|
||||
"warned": {"type": "integer", "minimum": 0},
|
||||
"ignored": {"type": "integer", "minimum": 0},
|
||||
"quieted": {"type": "integer", "minimum": 0}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"delta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"newCritical": {"type": "integer", "minimum": 0},
|
||||
"newHigh": {"type": "integer", "minimum": 0},
|
||||
"kev": {"type": "array", "items": {"type": "string"}}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"links": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ui": {"type": "string", "format": "uri"},
|
||||
"rekor": {"type": "string", "format": "uri"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"quietedFindingCount": {"type": "integer", "minimum": 0},
|
||||
"report": {"type": "object"},
|
||||
"dsse": {
|
||||
"type": "object",
|
||||
"required": ["payloadType", "payload", "signatures"],
|
||||
"properties": {
|
||||
"payloadType": {"type": "string"},
|
||||
"payload": {"type": "string"},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["keyId", "algorithm", "signature"],
|
||||
"properties": {
|
||||
"keyId": {"type": "string"},
|
||||
"algorithm": {"type": "string"},
|
||||
"signature": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"description": "Optional event attributes for downstream correlation.",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
102
docs/modules/signals/events/scanner.scan.completed@1.json
Normal file
102
docs/modules/signals/events/scanner.scan.completed@1.json
Normal file
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"$id": "https://stella-ops.org/schemas/events/scanner.scan.completed@1.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"required": ["eventId", "kind", "tenant", "ts", "scope", "payload"],
|
||||
"properties": {
|
||||
"eventId": {"type": "string", "format": "uuid"},
|
||||
"kind": {"const": "scanner.scan.completed"},
|
||||
"tenant": {"type": "string"},
|
||||
"ts": {"type": "string", "format": "date-time"},
|
||||
"scope": {
|
||||
"type": "object",
|
||||
"required": ["repo", "digest"],
|
||||
"properties": {
|
||||
"namespace": {"type": "string"},
|
||||
"repo": {"type": "string"},
|
||||
"digest": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"payload": {
|
||||
"type": "object",
|
||||
"required": ["reportId", "digest", "verdict", "summary"],
|
||||
"properties": {
|
||||
"reportId": {"type": "string"},
|
||||
"digest": {"type": "string"},
|
||||
"verdict": {"enum": ["pass", "warn", "fail"]},
|
||||
"summary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {"type": "integer", "minimum": 0},
|
||||
"blocked": {"type": "integer", "minimum": 0},
|
||||
"warned": {"type": "integer", "minimum": 0},
|
||||
"ignored": {"type": "integer", "minimum": 0},
|
||||
"quieted": {"type": "integer", "minimum": 0}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"delta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"newCritical": {"type": "integer", "minimum": 0},
|
||||
"newHigh": {"type": "integer", "minimum": 0},
|
||||
"kev": {"type": "array", "items": {"type": "string"}}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"policy": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"revisionId": {"type": "string"},
|
||||
"digest": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"findings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"type": "string"},
|
||||
"severity": {"type": "string"},
|
||||
"cve": {"type": "string"},
|
||||
"purl": {"type": "string"},
|
||||
"reachability": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"report": {"type": "object"},
|
||||
"dsse": {
|
||||
"type": "object",
|
||||
"required": ["payloadType", "payload", "signatures"],
|
||||
"properties": {
|
||||
"payloadType": {"type": "string"},
|
||||
"payload": {"type": "string"},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["keyId", "algorithm", "signature"],
|
||||
"properties": {
|
||||
"keyId": {"type": "string"},
|
||||
"algorithm": {"type": "string"},
|
||||
"signature": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"description": "Optional event attributes for downstream correlation.",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
196
docs/modules/signals/events/scheduler.graph.job.completed@1.json
Normal file
196
docs/modules/signals/events/scheduler.graph.job.completed@1.json
Normal file
@@ -0,0 +1,196 @@
|
||||
{
|
||||
"$id": "https://stella-ops.org/schemas/events/scheduler.graph.job.completed@1.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Scheduler Graph Job Completed Event",
|
||||
"description": "Legacy scheduler event emitted when a graph build or overlay job reaches a terminal state. Consumers validate downstream caches and surface overlay freshness.",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["eventId", "kind", "tenant", "ts", "payload"],
|
||||
"properties": {
|
||||
"eventId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Globally unique identifier per event."
|
||||
},
|
||||
"kind": {
|
||||
"const": "scheduler.graph.job.completed"
|
||||
},
|
||||
"tenant": {
|
||||
"type": "string",
|
||||
"description": "Tenant identifier scoped to the originating job."
|
||||
},
|
||||
"ts": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "UTC timestamp when the job reached a terminal state."
|
||||
},
|
||||
"payload": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["jobType", "job", "status", "occurredAt"],
|
||||
"properties": {
|
||||
"jobType": {
|
||||
"type": "string",
|
||||
"enum": ["build", "overlay"],
|
||||
"description": "Job flavour, matches the CLR type of the serialized job payload."
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["completed", "failed", "cancelled"],
|
||||
"description": "Terminal status recorded for the job."
|
||||
},
|
||||
"occurredAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "UTC timestamp of the terminal transition, mirrors job.CompletedAt."
|
||||
},
|
||||
"job": {
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/graphBuildJob"},
|
||||
{"$ref": "#/definitions/graphOverlayJob"}
|
||||
],
|
||||
"description": "Canonical serialized representation of the finished job."
|
||||
},
|
||||
"resultUri": {
|
||||
"type": "string",
|
||||
"description": "Optional URI pointing to Cartographer snapshot or overlay bundle (if available)."
|
||||
}
|
||||
}
|
||||
},
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"description": "Optional correlation bag for downstream consumers.",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"graphBuildJob": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"schemaVersion",
|
||||
"id",
|
||||
"tenantId",
|
||||
"sbomId",
|
||||
"sbomVersionId",
|
||||
"sbomDigest",
|
||||
"status",
|
||||
"trigger",
|
||||
"attempts",
|
||||
"createdAt"
|
||||
],
|
||||
"properties": {
|
||||
"schemaVersion": {
|
||||
"const": "scheduler.graph-build-job@1"
|
||||
},
|
||||
"id": {"type": "string"},
|
||||
"tenantId": {"type": "string"},
|
||||
"sbomId": {"type": "string"},
|
||||
"sbomVersionId": {"type": "string"},
|
||||
"sbomDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$"
|
||||
},
|
||||
"graphSnapshotId": {"type": "string"},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["pending", "queued", "running", "completed", "failed", "cancelled"]
|
||||
},
|
||||
"trigger": {
|
||||
"type": "string",
|
||||
"enum": ["sbom-version", "backfill", "manual"]
|
||||
},
|
||||
"attempts": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"cartographerJobId": {"type": "string"},
|
||||
"correlationId": {"type": "string"},
|
||||
"createdAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"startedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"completedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"error": {"type": "string"},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"graphOverlayJob": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"schemaVersion",
|
||||
"id",
|
||||
"tenantId",
|
||||
"graphSnapshotId",
|
||||
"overlayKind",
|
||||
"overlayKey",
|
||||
"status",
|
||||
"trigger",
|
||||
"attempts",
|
||||
"createdAt"
|
||||
],
|
||||
"properties": {
|
||||
"schemaVersion": {
|
||||
"const": "scheduler.graph-overlay-job@1"
|
||||
},
|
||||
"id": {"type": "string"},
|
||||
"tenantId": {"type": "string"},
|
||||
"graphSnapshotId": {"type": "string"},
|
||||
"buildJobId": {"type": "string"},
|
||||
"overlayKind": {
|
||||
"type": "string",
|
||||
"enum": ["policy", "advisory", "vex"]
|
||||
},
|
||||
"overlayKey": {"type": "string"},
|
||||
"subjects": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["pending", "queued", "running", "completed", "failed", "cancelled"]
|
||||
},
|
||||
"trigger": {
|
||||
"type": "string",
|
||||
"enum": ["policy", "advisory", "vex", "sbom-version", "manual"]
|
||||
},
|
||||
"attempts": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"correlationId": {"type": "string"},
|
||||
"createdAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"startedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"completedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"error": {"type": "string"},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
docs/modules/signals/events/scheduler.rescan.delta@1.json
Normal file
38
docs/modules/signals/events/scheduler.rescan.delta@1.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$id": "https://stella-ops.org/schemas/events/scheduler.rescan.delta@1.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"required": ["eventId", "kind", "tenant", "ts", "payload"],
|
||||
"properties": {
|
||||
"eventId": {"type": "string", "format": "uuid"},
|
||||
"kind": {"const": "scheduler.rescan.delta"},
|
||||
"tenant": {"type": "string"},
|
||||
"ts": {"type": "string", "format": "date-time"},
|
||||
"payload": {
|
||||
"type": "object",
|
||||
"required": ["scheduleId", "impactedDigests", "summary"],
|
||||
"properties": {
|
||||
"scheduleId": {"type": "string"},
|
||||
"impactedDigests": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
},
|
||||
"summary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"newCritical": {"type": "integer", "minimum": 0},
|
||||
"newHigh": {"type": "integer", "minimum": 0},
|
||||
"total": {"type": "integer", "minimum": 0}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"description": "Optional event attributes for downstream correlation.",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
Reference in New Issue
Block a user