# Event Envelope Schemas Platform services publish strongly typed events; the JSON Schemas in this directory define those envelopes. File names follow `@.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 `@` 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/Mongo 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.*::`). | | `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 (`ui`, `report`, and `policy`) plus an optional `attestation` URL 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/Mongo 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 (`@.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.