
- Added detailed task completion records for KMS interface implementation and CLI support for file-based keys. - Documented security enhancements including Argon2id password hashing, audit event contracts, and rate limiting configurations. - Included scoped service support and integration updates for the Plugin platform, ensuring proper DI handling and testing coverage.
8.4 KiB
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
mirrorsreportId
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.
imageDigest
— OCI image digest associated with the analysis.generatedAt
— report generation timestamp (ISO-8601 UTC).verdict
—pass
,warn
, orfail
after policy evaluation.summary
— blocked/warned/ignored/quieted counters (all non-negative integers).delta
— newly critical/high counts and optionalkev
array.quietedFindingCount
— mirrorssummary.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 mirrorsreportId
as a temporary shim.- Attributes:
reportId
,policyRevisionId
,policyDigest
,verdict
. - Links: same as above (
report.*
,policy.*
) withattestation.*
populated when DSSE metadata exists. verdict
,summary
,delta
,policy
— same semantics as above.findings
— array of surfaced findings withid
,severity
, optionalcve
,purl
, andreachability
.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
) useDateTimeOffset.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
- Validate incoming payloads against the schema for the targeted version.
- Use
idempotencyKey
for dedupe, noteventId
. - Map
traceId
/spanId
into telemetry spans to preserve causality. - Prefer
payload.report
→policy.revisionId
when populating templates; the top-levelattributes
are convenience duplicates for quick routing. - 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) andSCANNER-EVENTS-16-302
(doing) track the production of these envelopes. The remaining blocker is the .NET 10 preview OpenAPI/Auth dependency drift that currently breaksdotnet test
. Once Gateway and Notifier owners land the replacement packages, rerun the full test suite and capture fresh fixtures underdocs/events/samples/
. - 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 indocs/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.