Add unit tests for PackRunAttestation and SealedInstallEnforcer
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
release-manifest-verify / verify (push) Has been cancelled

- Implement comprehensive tests for PackRunAttestationService, covering attestation generation, verification, and event emission.
- Add tests for SealedInstallEnforcer to validate sealed install requirements and enforcement logic.
- Introduce a MonacoLoaderService stub for testing purposes to prevent Monaco workers/styles from loading during Karma runs.
This commit is contained in:
StellaOps Bot
2025-12-06 22:25:30 +02:00
parent dd0067ea0b
commit 4042fc2184
110 changed files with 20084 additions and 639 deletions

View File

@@ -0,0 +1,526 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/schemas/attestation-pointer.schema.json",
"title": "StellaOps Attestation Pointer Schema",
"description": "Schema for attestation pointers linking findings to verification reports and attestation envelopes. Unblocks LEDGER-ATTEST-73-001 and 73-002.",
"type": "object",
"definitions": {
"AttestationPointer": {
"type": "object",
"description": "Pointer from a finding to its related attestation artifacts",
"required": ["pointer_id", "finding_id", "attestation_type", "created_at"],
"properties": {
"pointer_id": {
"type": "string",
"format": "uuid",
"description": "Unique identifier for this pointer"
},
"finding_id": {
"type": "string",
"format": "uuid",
"description": "Finding this pointer references"
},
"attestation_type": {
"type": "string",
"enum": [
"verification_report",
"dsse_envelope",
"slsa_provenance",
"vex_attestation",
"sbom_attestation",
"scan_attestation",
"policy_attestation",
"approval_attestation"
],
"description": "Type of attestation being pointed to"
},
"attestation_ref": {
"$ref": "#/definitions/AttestationRef"
},
"relationship": {
"type": "string",
"enum": ["verified_by", "attested_by", "signed_by", "approved_by", "derived_from"],
"description": "Semantic relationship to the attestation"
},
"verification_result": {
"$ref": "#/definitions/VerificationResult"
},
"created_at": {
"type": "string",
"format": "date-time"
},
"created_by": {
"type": "string",
"description": "Service or user that created the pointer"
},
"metadata": {
"type": "object",
"additionalProperties": true
}
}
},
"AttestationRef": {
"type": "object",
"description": "Reference to an attestation artifact",
"required": ["digest"],
"properties": {
"attestation_id": {
"type": "string",
"format": "uuid"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "Content-addressable digest of the attestation"
},
"storage_uri": {
"type": "string",
"format": "uri",
"description": "URI to retrieve the attestation"
},
"payload_type": {
"type": "string",
"description": "DSSE payload type (e.g., application/vnd.in-toto+json)"
},
"predicate_type": {
"type": "string",
"description": "in-toto predicate type URI"
},
"subject_digests": {
"type": "array",
"items": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"description": "Digests of subjects this attestation covers"
},
"signer_info": {
"$ref": "#/definitions/SignerInfo"
},
"rekor_entry": {
"$ref": "#/definitions/RekorEntryRef"
}
}
},
"SignerInfo": {
"type": "object",
"description": "Information about the attestation signer",
"properties": {
"key_id": {
"type": "string",
"description": "Key identifier"
},
"issuer": {
"type": "string",
"description": "Certificate issuer (for Fulcio keyless signing)"
},
"subject": {
"type": "string",
"description": "Certificate subject (email, OIDC identity)"
},
"certificate_chain": {
"type": "array",
"items": {
"type": "string"
},
"description": "PEM-encoded certificate chain"
},
"signed_at": {
"type": "string",
"format": "date-time"
}
}
},
"RekorEntryRef": {
"type": "object",
"description": "Reference to Rekor transparency log entry",
"properties": {
"log_index": {
"type": "integer",
"minimum": 0
},
"log_id": {
"type": "string"
},
"uuid": {
"type": "string",
"pattern": "^[a-f0-9]{64}$"
},
"integrated_time": {
"type": "integer",
"description": "Unix timestamp of log entry"
}
}
},
"VerificationResult": {
"type": "object",
"description": "Result of attestation verification",
"required": ["verified", "verified_at"],
"properties": {
"verified": {
"type": "boolean",
"description": "Whether verification passed"
},
"verified_at": {
"type": "string",
"format": "date-time"
},
"verifier": {
"type": "string",
"description": "Service that performed verification"
},
"verifier_version": {
"type": "string"
},
"policy_ref": {
"type": "string",
"description": "Reference to verification policy used"
},
"checks": {
"type": "array",
"items": {
"$ref": "#/definitions/VerificationCheck"
}
},
"warnings": {
"type": "array",
"items": {
"type": "string"
}
},
"errors": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"VerificationCheck": {
"type": "object",
"description": "Individual verification check result",
"required": ["check_type", "passed"],
"properties": {
"check_type": {
"type": "string",
"enum": [
"signature_valid",
"certificate_valid",
"certificate_not_expired",
"certificate_not_revoked",
"rekor_entry_valid",
"timestamp_valid",
"policy_met",
"identity_verified",
"issuer_trusted"
]
},
"passed": {
"type": "boolean"
},
"details": {
"type": "string"
},
"evidence": {
"type": "object",
"additionalProperties": true
}
}
},
"VerificationReport": {
"type": "object",
"description": "Full verification report for a finding",
"required": ["report_id", "finding_id", "created_at", "overall_result"],
"properties": {
"report_id": {
"type": "string",
"format": "uuid"
},
"finding_id": {
"type": "string",
"format": "uuid"
},
"created_at": {
"type": "string",
"format": "date-time"
},
"overall_result": {
"type": "string",
"enum": ["passed", "failed", "partial", "not_applicable"]
},
"attestation_results": {
"type": "array",
"items": {
"$ref": "#/definitions/AttestationVerificationResult"
}
},
"policy_evaluations": {
"type": "array",
"items": {
"$ref": "#/definitions/PolicyEvaluationResult"
}
},
"summary": {
"type": "string"
},
"recommendations": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"AttestationVerificationResult": {
"type": "object",
"description": "Verification result for a specific attestation",
"required": ["attestation_ref", "verification_result"],
"properties": {
"attestation_ref": {
"$ref": "#/definitions/AttestationRef"
},
"verification_result": {
"$ref": "#/definitions/VerificationResult"
},
"relevance": {
"type": "string",
"enum": ["primary", "supporting", "contextual"],
"description": "How relevant this attestation is to the finding"
}
}
},
"PolicyEvaluationResult": {
"type": "object",
"description": "Result of policy evaluation against attestations",
"required": ["policy_id", "result"],
"properties": {
"policy_id": {
"type": "string"
},
"policy_name": {
"type": "string"
},
"policy_version": {
"type": "string"
},
"result": {
"type": "string",
"enum": ["passed", "failed", "skipped", "error"]
},
"reason": {
"type": "string"
},
"attestations_evaluated": {
"type": "array",
"items": {
"type": "string"
},
"description": "Attestation IDs evaluated by this policy"
}
}
},
"DsseEnvelope": {
"type": "object",
"description": "DSSE envelope containing attestation",
"required": ["payloadType", "payload", "signatures"],
"properties": {
"payloadType": {
"type": "string",
"description": "MIME type of payload"
},
"payload": {
"type": "string",
"contentEncoding": "base64",
"description": "Base64-encoded payload"
},
"signatures": {
"type": "array",
"items": {
"$ref": "#/definitions/DsseSignature"
},
"minItems": 1
}
}
},
"DsseSignature": {
"type": "object",
"description": "Signature on DSSE envelope",
"required": ["sig"],
"properties": {
"keyid": {
"type": "string"
},
"sig": {
"type": "string",
"contentEncoding": "base64"
},
"cert": {
"type": "string",
"contentEncoding": "base64",
"description": "Fulcio certificate for keyless signing"
}
}
},
"AttestationSearchQuery": {
"type": "object",
"description": "Query for searching attestations by finding criteria",
"properties": {
"finding_ids": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
}
},
"attestation_types": {
"type": "array",
"items": {
"type": "string"
}
},
"verification_status": {
"type": "string",
"enum": ["verified", "unverified", "failed", "any"]
},
"created_after": {
"type": "string",
"format": "date-time"
},
"created_before": {
"type": "string",
"format": "date-time"
},
"signer_identity": {
"type": "string",
"description": "Filter by signer email or identity"
},
"predicate_type": {
"type": "string",
"description": "Filter by in-toto predicate type"
}
}
},
"AttestationSearchResult": {
"type": "object",
"description": "Result of attestation search",
"required": ["pointers", "total_count"],
"properties": {
"pointers": {
"type": "array",
"items": {
"$ref": "#/definitions/AttestationPointer"
}
},
"total_count": {
"type": "integer",
"minimum": 0
},
"next_page_token": {
"type": "string"
}
}
},
"FindingAttestationSummary": {
"type": "object",
"description": "Summary of attestations for a finding",
"required": ["finding_id", "attestation_count"],
"properties": {
"finding_id": {
"type": "string",
"format": "uuid"
},
"attestation_count": {
"type": "integer",
"minimum": 0
},
"verified_count": {
"type": "integer",
"minimum": 0
},
"latest_attestation": {
"type": "string",
"format": "date-time"
},
"attestation_types": {
"type": "array",
"items": {
"type": "string"
}
},
"overall_verification_status": {
"type": "string",
"enum": ["all_verified", "partially_verified", "none_verified", "no_attestations"]
}
}
}
},
"properties": {
"pointers": {
"type": "array",
"items": {
"$ref": "#/definitions/AttestationPointer"
}
}
},
"examples": [
{
"pointers": [
{
"pointer_id": "550e8400-e29b-41d4-a716-446655440000",
"finding_id": "660e8400-e29b-41d4-a716-446655440001",
"attestation_type": "dsse_envelope",
"attestation_ref": {
"attestation_id": "770e8400-e29b-41d4-a716-446655440002",
"digest": "sha256:abc123def456789012345678901234567890123456789012345678901234abcd",
"storage_uri": "s3://attestations/770e8400.../attestation.json",
"payload_type": "application/vnd.in-toto+json",
"predicate_type": "https://slsa.dev/provenance/v1",
"subject_digests": [
"sha256:def456..."
],
"signer_info": {
"key_id": "fulcio:abc123",
"issuer": "https://accounts.google.com",
"subject": "scanner@stellaops.iam.gserviceaccount.com",
"signed_at": "2025-12-06T10:00:00Z"
},
"rekor_entry": {
"log_index": 12345678,
"log_id": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d",
"uuid": "24296fb24b8ad77a12345678901234567890123456789012345678901234abcd",
"integrated_time": 1733479200
}
},
"relationship": "verified_by",
"verification_result": {
"verified": true,
"verified_at": "2025-12-06T10:05:00Z",
"verifier": "stellaops-attestor",
"verifier_version": "2025.10.0",
"checks": [
{
"check_type": "signature_valid",
"passed": true,
"details": "ECDSA signature verified"
},
{
"check_type": "certificate_valid",
"passed": true,
"details": "Fulcio certificate chain verified"
},
{
"check_type": "rekor_entry_valid",
"passed": true,
"details": "Rekor inclusion proof verified"
}
],
"warnings": [],
"errors": []
},
"created_at": "2025-12-06T10:05:00Z",
"created_by": "attestor-service"
}
]
}
]
}

View File

@@ -0,0 +1,622 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/schemas/console-observability.schema.json",
"title": "StellaOps Console Observability Schema",
"description": "Schema for console observability widgets, asset captures, and deterministic hashes. Unblocks DOCS-CONSOLE-OBS-52-001/002 and CONOBS5201 (2+ tasks).",
"type": "object",
"definitions": {
"WidgetCapture": {
"type": "object",
"description": "Captured widget screenshot/payload",
"required": ["capture_id", "widget_id", "captured_at", "digest"],
"properties": {
"capture_id": {
"type": "string",
"format": "uuid"
},
"widget_id": {
"type": "string",
"description": "Widget identifier"
},
"widget_type": {
"type": "string",
"enum": [
"findings_summary",
"severity_distribution",
"risk_trend",
"remediation_progress",
"compliance_status",
"asset_inventory",
"vulnerability_timeline",
"exception_status",
"scan_activity",
"alert_feed"
]
},
"captured_at": {
"type": "string",
"format": "date-time"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "Content hash for determinism verification"
},
"screenshot": {
"$ref": "#/definitions/ScreenshotRef"
},
"payload": {
"$ref": "#/definitions/WidgetPayload"
},
"viewport": {
"$ref": "#/definitions/ViewportConfig"
},
"theme": {
"type": "string",
"enum": ["light", "dark", "high_contrast"]
},
"locale": {
"type": "string",
"default": "en-US"
}
}
},
"ScreenshotRef": {
"type": "object",
"description": "Reference to captured screenshot",
"properties": {
"filename": {
"type": "string"
},
"format": {
"type": "string",
"enum": ["png", "webp", "svg"]
},
"width": {
"type": "integer"
},
"height": {
"type": "integer"
},
"storage_uri": {
"type": "string",
"format": "uri"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
}
}
},
"WidgetPayload": {
"type": "object",
"description": "Widget data payload",
"properties": {
"data": {
"type": "object",
"additionalProperties": true,
"description": "Canonical JSON data for widget"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "Hash of canonical JSON payload"
},
"schema_version": {
"type": "string"
}
}
},
"ViewportConfig": {
"type": "object",
"description": "Viewport configuration for capture",
"properties": {
"width": {
"type": "integer",
"default": 1920
},
"height": {
"type": "integer",
"default": 1080
},
"device_scale_factor": {
"type": "number",
"default": 1
}
}
},
"DashboardCapture": {
"type": "object",
"description": "Full dashboard capture",
"required": ["capture_id", "dashboard_id", "captured_at"],
"properties": {
"capture_id": {
"type": "string",
"format": "uuid"
},
"dashboard_id": {
"type": "string"
},
"dashboard_name": {
"type": "string"
},
"captured_at": {
"type": "string",
"format": "date-time"
},
"widgets": {
"type": "array",
"items": {
"$ref": "#/definitions/WidgetCapture"
}
},
"layout": {
"$ref": "#/definitions/DashboardLayout"
},
"aggregate_digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "Hash of all widget digests combined"
}
}
},
"DashboardLayout": {
"type": "object",
"description": "Dashboard layout configuration",
"properties": {
"columns": {
"type": "integer",
"default": 12
},
"row_height": {
"type": "integer",
"default": 100
},
"widgets": {
"type": "array",
"items": {
"$ref": "#/definitions/WidgetPosition"
}
}
}
},
"WidgetPosition": {
"type": "object",
"description": "Widget position in grid",
"required": ["widget_id", "x", "y", "width", "height"],
"properties": {
"widget_id": {
"type": "string"
},
"x": {
"type": "integer",
"minimum": 0
},
"y": {
"type": "integer",
"minimum": 0
},
"width": {
"type": "integer",
"minimum": 1
},
"height": {
"type": "integer",
"minimum": 1
}
}
},
"ObservabilityHubConfig": {
"type": "object",
"description": "Observability Hub configuration",
"properties": {
"hub_id": {
"type": "string"
},
"name": {
"type": "string"
},
"dashboards": {
"type": "array",
"items": {
"$ref": "#/definitions/DashboardConfig"
}
},
"metrics_sources": {
"type": "array",
"items": {
"$ref": "#/definitions/MetricsSource"
}
},
"alert_rules": {
"type": "array",
"items": {
"$ref": "#/definitions/AlertRule"
}
},
"retention_days": {
"type": "integer",
"default": 90
}
}
},
"DashboardConfig": {
"type": "object",
"description": "Dashboard configuration",
"required": ["dashboard_id", "name"],
"properties": {
"dashboard_id": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"category": {
"type": "string",
"enum": ["security", "compliance", "operations", "executive"]
},
"refresh_interval_seconds": {
"type": "integer",
"default": 300
},
"time_range": {
"$ref": "#/definitions/TimeRange"
},
"filters": {
"type": "array",
"items": {
"$ref": "#/definitions/FilterConfig"
}
}
}
},
"MetricsSource": {
"type": "object",
"description": "Metrics data source",
"required": ["source_id", "type"],
"properties": {
"source_id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["prometheus", "opentelemetry", "internal", "api"]
},
"endpoint": {
"type": "string",
"format": "uri"
},
"refresh_interval_seconds": {
"type": "integer"
}
}
},
"AlertRule": {
"type": "object",
"description": "Alert rule definition",
"required": ["rule_id", "name", "condition"],
"properties": {
"rule_id": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"condition": {
"$ref": "#/definitions/AlertCondition"
},
"severity": {
"type": "string",
"enum": ["critical", "high", "medium", "low", "info"]
},
"enabled": {
"type": "boolean",
"default": true
},
"notification_channels": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"AlertCondition": {
"type": "object",
"description": "Alert trigger condition",
"properties": {
"metric": {
"type": "string"
},
"operator": {
"type": "string",
"enum": ["gt", "gte", "lt", "lte", "eq", "neq"]
},
"threshold": {
"type": "number"
},
"duration_seconds": {
"type": "integer",
"description": "Duration condition must be true"
}
}
},
"TimeRange": {
"type": "object",
"description": "Time range configuration",
"properties": {
"type": {
"type": "string",
"enum": ["relative", "absolute"]
},
"relative_value": {
"type": "string",
"description": "e.g., 24h, 7d, 30d"
},
"start": {
"type": "string",
"format": "date-time"
},
"end": {
"type": "string",
"format": "date-time"
}
}
},
"FilterConfig": {
"type": "object",
"description": "Dashboard filter configuration",
"properties": {
"filter_id": {
"type": "string"
},
"label": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["select", "multi_select", "date_range", "text"]
},
"field": {
"type": "string"
},
"options": {
"type": "array",
"items": {
"type": "object",
"properties": {
"value": {
"type": "string"
},
"label": {
"type": "string"
}
}
}
}
}
},
"ForensicsCapture": {
"type": "object",
"description": "Forensics data capture",
"required": ["capture_id", "incident_id", "captured_at"],
"properties": {
"capture_id": {
"type": "string",
"format": "uuid"
},
"incident_id": {
"type": "string"
},
"captured_at": {
"type": "string",
"format": "date-time"
},
"capture_type": {
"type": "string",
"enum": ["snapshot", "timeline", "correlation", "evidence_chain"]
},
"data_points": {
"type": "array",
"items": {
"$ref": "#/definitions/ForensicsDataPoint"
}
},
"correlations": {
"type": "array",
"items": {
"$ref": "#/definitions/CorrelationLink"
}
},
"evidence_digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
}
}
},
"ForensicsDataPoint": {
"type": "object",
"description": "Individual forensics data point",
"properties": {
"point_id": {
"type": "string"
},
"timestamp": {
"type": "string",
"format": "date-time"
},
"source": {
"type": "string"
},
"data_type": {
"type": "string",
"enum": ["finding", "event", "metric", "log", "alert"]
},
"data": {
"type": "object",
"additionalProperties": true
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
}
}
},
"CorrelationLink": {
"type": "object",
"description": "Correlation between data points",
"properties": {
"source_id": {
"type": "string"
},
"target_id": {
"type": "string"
},
"relationship": {
"type": "string",
"enum": ["caused_by", "related_to", "precedes", "follows", "indicates"]
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
}
}
},
"AssetManifest": {
"type": "object",
"description": "Manifest of console assets for documentation",
"required": ["manifest_id", "version", "assets"],
"properties": {
"manifest_id": {
"type": "string"
},
"version": {
"type": "string"
},
"generated_at": {
"type": "string",
"format": "date-time"
},
"assets": {
"type": "array",
"items": {
"$ref": "#/definitions/AssetEntry"
}
},
"aggregate_digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
}
}
},
"AssetEntry": {
"type": "object",
"description": "Individual asset entry",
"required": ["asset_id", "filename", "digest"],
"properties": {
"asset_id": {
"type": "string"
},
"filename": {
"type": "string"
},
"category": {
"type": "string",
"enum": ["screenshot", "payload", "config", "schema"]
},
"description": {
"type": "string"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"size_bytes": {
"type": "integer"
},
"mime_type": {
"type": "string"
}
}
}
},
"properties": {
"captures": {
"type": "array",
"items": {
"$ref": "#/definitions/WidgetCapture"
}
},
"manifest": {
"$ref": "#/definitions/AssetManifest"
}
},
"examples": [
{
"manifest": {
"manifest_id": "console-obs-2025.10",
"version": "2025.10.0",
"generated_at": "2025-12-06T10:00:00Z",
"assets": [
{
"asset_id": "findings-summary-widget",
"filename": "findings-summary.png",
"category": "screenshot",
"description": "Findings summary widget showing severity distribution",
"digest": "sha256:abc123def456789012345678901234567890123456789012345678901234abcd",
"size_bytes": 45678,
"mime_type": "image/png"
},
{
"asset_id": "findings-summary-payload",
"filename": "findings-summary.json",
"category": "payload",
"description": "Canonical JSON payload for findings summary",
"digest": "sha256:def456abc789012345678901234567890123456789012345678901234abcdef",
"size_bytes": 2345,
"mime_type": "application/json"
}
],
"aggregate_digest": "sha256:agg123def456789012345678901234567890123456789012345678901234agg"
},
"captures": [
{
"capture_id": "550e8400-e29b-41d4-a716-446655440000",
"widget_id": "findings-summary",
"widget_type": "findings_summary",
"captured_at": "2025-12-06T10:00:00Z",
"digest": "sha256:abc123def456789012345678901234567890123456789012345678901234abcd",
"screenshot": {
"filename": "findings-summary.png",
"format": "png",
"width": 400,
"height": 300,
"digest": "sha256:abc123def456789012345678901234567890123456789012345678901234abcd"
},
"payload": {
"data": {
"critical": 5,
"high": 23,
"medium": 67,
"low": 134,
"total": 229
},
"digest": "sha256:def456abc789012345678901234567890123456789012345678901234abcdef"
},
"viewport": {
"width": 1920,
"height": 1080
},
"theme": "light"
}
]
}
]
}

View File

@@ -0,0 +1,624 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/schemas/deployment-service-list.schema.json",
"title": "StellaOps Deployment Service List Schema",
"description": "Schema for deployment service list, compose configuration, and version pins. Unblocks COMPOSE-44-001 through 45-003 (7 tasks).",
"type": "object",
"definitions": {
"ServiceDefinition": {
"type": "object",
"description": "Service definition for deployment",
"required": ["service_id", "name", "image", "version"],
"properties": {
"service_id": {
"type": "string",
"pattern": "^[a-z][a-z0-9-]*$",
"description": "Unique service identifier (kebab-case)"
},
"name": {
"type": "string",
"description": "Human-readable service name"
},
"description": {
"type": "string"
},
"image": {
"type": "string",
"description": "Container image (without tag)"
},
"version": {
"type": "string",
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(-[a-z0-9.]+)?$",
"description": "Service version (semver)"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "Image digest for pinning"
},
"port": {
"type": "integer",
"minimum": 1,
"maximum": 65535,
"description": "Primary service port"
},
"health_check": {
"$ref": "#/definitions/HealthCheck"
},
"dependencies": {
"type": "array",
"items": {
"type": "string"
},
"description": "Service IDs this service depends on"
},
"environment": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/EnvVarDefinition"
}
},
"volumes": {
"type": "array",
"items": {
"$ref": "#/definitions/VolumeMount"
}
},
"secrets": {
"type": "array",
"items": {
"$ref": "#/definitions/SecretReference"
}
},
"resources": {
"$ref": "#/definitions/ResourceLimits"
},
"replicas": {
"$ref": "#/definitions/ReplicaConfig"
},
"labels": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"annotations": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
},
"HealthCheck": {
"type": "object",
"description": "Health check configuration",
"properties": {
"endpoint": {
"type": "string",
"default": "/health"
},
"port": {
"type": "integer"
},
"interval_seconds": {
"type": "integer",
"default": 30
},
"timeout_seconds": {
"type": "integer",
"default": 10
},
"retries": {
"type": "integer",
"default": 3
},
"start_period_seconds": {
"type": "integer",
"default": 60
}
}
},
"EnvVarDefinition": {
"type": "object",
"description": "Environment variable definition",
"properties": {
"description": {
"type": "string"
},
"required": {
"type": "boolean",
"default": false
},
"default": {
"type": "string"
},
"secret": {
"type": "boolean",
"default": false,
"description": "Whether this is a secret value"
},
"example": {
"type": "string"
}
}
},
"VolumeMount": {
"type": "object",
"description": "Volume mount configuration",
"required": ["name", "mount_path"],
"properties": {
"name": {
"type": "string"
},
"mount_path": {
"type": "string"
},
"read_only": {
"type": "boolean",
"default": false
},
"type": {
"type": "string",
"enum": ["persistent", "ephemeral", "config", "secret"],
"default": "persistent"
},
"size": {
"type": "string",
"pattern": "^[0-9]+(Mi|Gi|Ti)$",
"description": "Volume size (e.g., 10Gi)"
}
}
},
"SecretReference": {
"type": "object",
"description": "Secret reference",
"required": ["name"],
"properties": {
"name": {
"type": "string"
},
"key": {
"type": "string"
},
"env_var": {
"type": "string",
"description": "Environment variable to inject secret"
},
"mount_path": {
"type": "string",
"description": "File path to mount secret"
}
}
},
"ResourceLimits": {
"type": "object",
"description": "Resource limits and requests",
"properties": {
"cpu_request": {
"type": "string",
"pattern": "^[0-9]+(m)?$",
"description": "CPU request (e.g., 100m, 1)"
},
"cpu_limit": {
"type": "string",
"pattern": "^[0-9]+(m)?$"
},
"memory_request": {
"type": "string",
"pattern": "^[0-9]+(Mi|Gi)$",
"description": "Memory request (e.g., 256Mi)"
},
"memory_limit": {
"type": "string",
"pattern": "^[0-9]+(Mi|Gi)$"
}
}
},
"ReplicaConfig": {
"type": "object",
"description": "Replica configuration",
"properties": {
"min": {
"type": "integer",
"minimum": 0,
"default": 1
},
"max": {
"type": "integer",
"minimum": 1,
"default": 1
},
"target_cpu_utilization": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "Target CPU utilization for autoscaling"
}
}
},
"DeploymentProfile": {
"type": "object",
"description": "Deployment profile (dev/staging/prod)",
"required": ["profile_id", "name"],
"properties": {
"profile_id": {
"type": "string",
"enum": ["dev", "staging", "production", "airgap"]
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"service_overrides": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/ServiceOverride"
}
},
"global_environment": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"network_policy": {
"$ref": "#/definitions/NetworkPolicy"
},
"security_context": {
"$ref": "#/definitions/SecurityContext"
}
}
},
"ServiceOverride": {
"type": "object",
"description": "Service-specific overrides for a profile",
"properties": {
"enabled": {
"type": "boolean",
"default": true
},
"replicas": {
"$ref": "#/definitions/ReplicaConfig"
},
"resources": {
"$ref": "#/definitions/ResourceLimits"
},
"environment": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
},
"NetworkPolicy": {
"type": "object",
"description": "Network policy configuration",
"properties": {
"egress_allowed": {
"type": "boolean",
"default": true
},
"allowed_external_hosts": {
"type": "array",
"items": {
"type": "string"
},
"description": "Allowed external hosts for egress"
},
"internal_only_services": {
"type": "array",
"items": {
"type": "string"
},
"description": "Services not exposed externally"
}
}
},
"SecurityContext": {
"type": "object",
"description": "Security context configuration",
"properties": {
"run_as_non_root": {
"type": "boolean",
"default": true
},
"read_only_root_filesystem": {
"type": "boolean",
"default": true
},
"drop_capabilities": {
"type": "array",
"items": {
"type": "string"
},
"default": ["ALL"]
},
"add_capabilities": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"ServiceList": {
"type": "object",
"description": "Complete service list for deployment",
"required": ["list_id", "version", "services"],
"properties": {
"list_id": {
"type": "string"
},
"version": {
"type": "string"
},
"updated_at": {
"type": "string",
"format": "date-time"
},
"services": {
"type": "array",
"items": {
"$ref": "#/definitions/ServiceDefinition"
}
},
"profiles": {
"type": "array",
"items": {
"$ref": "#/definitions/DeploymentProfile"
}
},
"dependencies": {
"$ref": "#/definitions/ExternalDependencies"
},
"observability": {
"$ref": "#/definitions/ObservabilityConfig"
}
}
},
"ExternalDependencies": {
"type": "object",
"description": "External dependencies (databases, queues, etc.)",
"properties": {
"mongodb": {
"$ref": "#/definitions/MongoDbConfig"
},
"postgres": {
"$ref": "#/definitions/PostgresConfig"
},
"redis": {
"$ref": "#/definitions/RedisConfig"
},
"rabbitmq": {
"$ref": "#/definitions/RabbitMqConfig"
},
"s3": {
"$ref": "#/definitions/S3Config"
}
}
},
"MongoDbConfig": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"default": true
},
"version": {
"type": "string",
"default": "7.0"
},
"replica_set": {
"type": "boolean",
"default": false
}
}
},
"PostgresConfig": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"default": true
},
"version": {
"type": "string",
"default": "16"
}
}
},
"RedisConfig": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"default": true
},
"version": {
"type": "string",
"default": "7"
},
"cluster": {
"type": "boolean",
"default": false
}
}
},
"RabbitMqConfig": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"default": true
},
"version": {
"type": "string",
"default": "3.13"
}
}
},
"S3Config": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"default": true
},
"provider": {
"type": "string",
"enum": ["minio", "aws", "gcs", "azure"],
"default": "minio"
}
}
},
"ObservabilityConfig": {
"type": "object",
"description": "Observability stack configuration",
"properties": {
"metrics": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"default": true
},
"endpoint": {
"type": "string",
"default": "/metrics"
},
"port": {
"type": "integer",
"default": 9090
}
}
},
"tracing": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"default": true
},
"otlp_endpoint": {
"type": "string"
},
"sampling_rate": {
"type": "number",
"minimum": 0,
"maximum": 1,
"default": 0.1
}
}
},
"logging": {
"type": "object",
"properties": {
"level": {
"type": "string",
"enum": ["trace", "debug", "info", "warn", "error"],
"default": "info"
},
"format": {
"type": "string",
"enum": ["json", "text"],
"default": "json"
}
}
}
}
}
},
"properties": {
"service_list": {
"$ref": "#/definitions/ServiceList"
}
},
"examples": [
{
"service_list": {
"list_id": "stellaops-2025.10",
"version": "2025.10.0",
"updated_at": "2025-12-06T10:00:00Z",
"services": [
{
"service_id": "concelier",
"name": "Concelier",
"description": "Vulnerability advisory ingestion and merge engine",
"image": "ghcr.io/stellaops/concelier",
"version": "2025.10.0",
"digest": "sha256:abc123def456789012345678901234567890123456789012345678901234abcd",
"port": 8080,
"health_check": {
"endpoint": "/health",
"interval_seconds": 30
},
"dependencies": ["mongodb", "redis"],
"resources": {
"cpu_request": "100m",
"cpu_limit": "1000m",
"memory_request": "256Mi",
"memory_limit": "1Gi"
}
},
{
"service_id": "scanner",
"name": "Scanner",
"description": "Container scanning with SBOM generation",
"image": "ghcr.io/stellaops/scanner",
"version": "2025.10.0",
"port": 8081,
"dependencies": ["concelier", "s3"]
},
{
"service_id": "findings-ledger",
"name": "Findings Ledger",
"description": "Vulnerability findings storage",
"image": "ghcr.io/stellaops/findings-ledger",
"version": "2025.10.0",
"port": 8082,
"dependencies": ["postgres", "redis"]
}
],
"profiles": [
{
"profile_id": "dev",
"name": "Development",
"description": "Local development profile",
"global_environment": {
"ASPNETCORE_ENVIRONMENT": "Development",
"LOG_LEVEL": "Debug"
}
},
{
"profile_id": "production",
"name": "Production",
"description": "Production deployment profile",
"security_context": {
"run_as_non_root": true,
"read_only_root_filesystem": true,
"drop_capabilities": ["ALL"]
}
}
],
"dependencies": {
"mongodb": {
"enabled": true,
"version": "7.0"
},
"postgres": {
"enabled": true,
"version": "16"
},
"redis": {
"enabled": true,
"version": "7"
}
}
}
}
]
}

View File

@@ -0,0 +1,695 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/schemas/devportal-api.schema.json",
"title": "StellaOps DevPortal API Schema",
"description": "Schema for DevPortal API baseline and SDK generator integration. Unblocks APIG0101 chain (62-001 to 63-004).",
"type": "object",
"definitions": {
"ApiEndpoint": {
"type": "object",
"description": "API endpoint definition for DevPortal",
"required": ["path", "method", "operation_id"],
"properties": {
"path": {
"type": "string",
"pattern": "^/api/v[0-9]+/",
"description": "API path (e.g., /api/v1/findings)"
},
"method": {
"type": "string",
"enum": ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]
},
"operation_id": {
"type": "string",
"description": "Unique operation identifier for SDK generation"
},
"summary": {
"type": "string"
},
"description": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"deprecated": {
"type": "boolean",
"default": false
},
"deprecation_info": {
"$ref": "#/definitions/DeprecationInfo"
},
"authentication": {
"$ref": "#/definitions/AuthenticationRequirement"
},
"scopes": {
"type": "array",
"items": {
"type": "string"
},
"description": "Required OAuth2 scopes"
},
"rate_limit": {
"$ref": "#/definitions/RateLimitConfig"
},
"request": {
"$ref": "#/definitions/RequestSpec"
},
"responses": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/ResponseSpec"
}
},
"examples": {
"type": "array",
"items": {
"$ref": "#/definitions/EndpointExample"
}
}
}
},
"DeprecationInfo": {
"type": "object",
"description": "Deprecation details for sunset planning",
"properties": {
"deprecated_at": {
"type": "string",
"format": "date"
},
"sunset_at": {
"type": "string",
"format": "date"
},
"replacement": {
"type": "string",
"description": "Replacement endpoint path"
},
"migration_guide": {
"type": "string",
"format": "uri",
"description": "Link to migration documentation"
},
"reason": {
"type": "string"
}
}
},
"AuthenticationRequirement": {
"type": "object",
"description": "Authentication requirements for endpoint",
"properties": {
"required": {
"type": "boolean",
"default": true
},
"schemes": {
"type": "array",
"items": {
"type": "string",
"enum": ["bearer", "api_key", "oauth2", "mtls", "basic"]
}
},
"oauth2_flows": {
"type": "array",
"items": {
"type": "string",
"enum": ["authorization_code", "client_credentials", "device_code"]
}
}
}
},
"RateLimitConfig": {
"type": "object",
"description": "Rate limiting configuration",
"properties": {
"requests_per_minute": {
"type": "integer",
"minimum": 1
},
"requests_per_hour": {
"type": "integer",
"minimum": 1
},
"burst_limit": {
"type": "integer",
"minimum": 1
},
"tier": {
"type": "string",
"enum": ["free", "standard", "premium", "enterprise"],
"description": "Rate limit tier"
}
}
},
"RequestSpec": {
"type": "object",
"description": "Request specification",
"properties": {
"content_types": {
"type": "array",
"items": {
"type": "string"
},
"default": ["application/json"]
},
"body_schema": {
"type": "string",
"description": "JSON Schema $ref for request body"
},
"parameters": {
"type": "array",
"items": {
"$ref": "#/definitions/ParameterSpec"
}
},
"headers": {
"type": "array",
"items": {
"$ref": "#/definitions/HeaderSpec"
}
}
}
},
"ParameterSpec": {
"type": "object",
"description": "Parameter specification",
"required": ["name", "in"],
"properties": {
"name": {
"type": "string"
},
"in": {
"type": "string",
"enum": ["path", "query", "header", "cookie"]
},
"required": {
"type": "boolean",
"default": false
},
"description": {
"type": "string"
},
"schema": {
"type": "object",
"description": "JSON Schema for parameter"
},
"example": {}
}
},
"HeaderSpec": {
"type": "object",
"description": "Header specification",
"required": ["name"],
"properties": {
"name": {
"type": "string"
},
"required": {
"type": "boolean",
"default": false
},
"description": {
"type": "string"
},
"example": {
"type": "string"
}
}
},
"ResponseSpec": {
"type": "object",
"description": "Response specification",
"properties": {
"description": {
"type": "string"
},
"content_types": {
"type": "array",
"items": {
"type": "string"
}
},
"body_schema": {
"type": "string",
"description": "JSON Schema $ref for response body"
},
"headers": {
"type": "array",
"items": {
"$ref": "#/definitions/HeaderSpec"
}
}
}
},
"EndpointExample": {
"type": "object",
"description": "Example request/response pair",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"request": {
"type": "object",
"additionalProperties": true
},
"response": {
"type": "object",
"additionalProperties": true
}
}
},
"ApiService": {
"type": "object",
"description": "API service definition for DevPortal",
"required": ["service_id", "name", "version", "endpoints"],
"properties": {
"service_id": {
"type": "string",
"description": "Unique service identifier"
},
"name": {
"type": "string",
"description": "Human-readable service name"
},
"description": {
"type": "string"
},
"version": {
"type": "string",
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
},
"base_url": {
"type": "string",
"format": "uri"
},
"openapi_url": {
"type": "string",
"format": "uri",
"description": "URL to OpenAPI spec"
},
"documentation_url": {
"type": "string",
"format": "uri"
},
"status": {
"type": "string",
"enum": ["stable", "beta", "alpha", "deprecated", "sunset"]
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"endpoints": {
"type": "array",
"items": {
"$ref": "#/definitions/ApiEndpoint"
}
},
"webhooks": {
"type": "array",
"items": {
"$ref": "#/definitions/WebhookDefinition"
}
}
}
},
"WebhookDefinition": {
"type": "object",
"description": "Webhook event definition",
"required": ["event_type", "payload_schema"],
"properties": {
"event_type": {
"type": "string",
"description": "Event type (e.g., finding.created)"
},
"description": {
"type": "string"
},
"payload_schema": {
"type": "string",
"description": "JSON Schema $ref for webhook payload"
},
"example_payload": {
"type": "object",
"additionalProperties": true
}
}
},
"SdkConfig": {
"type": "object",
"description": "SDK generator configuration",
"required": ["language", "package_name"],
"properties": {
"language": {
"type": "string",
"enum": ["typescript", "python", "go", "java", "csharp", "ruby", "php"]
},
"package_name": {
"type": "string"
},
"package_version": {
"type": "string"
},
"output_directory": {
"type": "string"
},
"generator_options": {
"type": "object",
"additionalProperties": true,
"description": "Language-specific generator options"
},
"custom_templates": {
"type": "array",
"items": {
"type": "string"
},
"description": "Custom template paths"
}
}
},
"SdkGeneratorRequest": {
"type": "object",
"description": "Request to generate SDK from API spec",
"required": ["service_id", "sdk_configs"],
"properties": {
"service_id": {
"type": "string"
},
"openapi_spec_url": {
"type": "string",
"format": "uri"
},
"sdk_configs": {
"type": "array",
"items": {
"$ref": "#/definitions/SdkConfig"
},
"minItems": 1
},
"include_examples": {
"type": "boolean",
"default": true
},
"include_tests": {
"type": "boolean",
"default": true
}
}
},
"SdkGeneratorResult": {
"type": "object",
"description": "Result of SDK generation",
"required": ["job_id", "status"],
"properties": {
"job_id": {
"type": "string",
"format": "uuid"
},
"status": {
"type": "string",
"enum": ["pending", "running", "completed", "failed"]
},
"started_at": {
"type": "string",
"format": "date-time"
},
"completed_at": {
"type": "string",
"format": "date-time"
},
"artifacts": {
"type": "array",
"items": {
"$ref": "#/definitions/SdkArtifact"
}
},
"errors": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"SdkArtifact": {
"type": "object",
"description": "Generated SDK artifact",
"required": ["language", "artifact_url"],
"properties": {
"language": {
"type": "string"
},
"package_name": {
"type": "string"
},
"version": {
"type": "string"
},
"artifact_url": {
"type": "string",
"format": "uri"
},
"checksum": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"registry_url": {
"type": "string",
"format": "uri",
"description": "Package registry URL (npm, pypi, etc.)"
}
}
},
"DevPortalCatalog": {
"type": "object",
"description": "Full API catalog for DevPortal",
"required": ["catalog_id", "version", "services"],
"properties": {
"catalog_id": {
"type": "string"
},
"version": {
"type": "string"
},
"updated_at": {
"type": "string",
"format": "date-time"
},
"services": {
"type": "array",
"items": {
"$ref": "#/definitions/ApiService"
}
},
"global_tags": {
"type": "array",
"items": {
"$ref": "#/definitions/TagDefinition"
}
},
"authentication_info": {
"$ref": "#/definitions/AuthenticationInfo"
}
}
},
"TagDefinition": {
"type": "object",
"description": "Tag definition for categorization",
"required": ["name"],
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"external_docs": {
"type": "string",
"format": "uri"
}
}
},
"AuthenticationInfo": {
"type": "object",
"description": "Global authentication information",
"properties": {
"oauth2_authorization_url": {
"type": "string",
"format": "uri"
},
"oauth2_token_url": {
"type": "string",
"format": "uri"
},
"api_key_header": {
"type": "string",
"default": "X-API-Key"
},
"documentation_url": {
"type": "string",
"format": "uri"
}
}
},
"ApiCompatibilityReport": {
"type": "object",
"description": "API compatibility check report",
"required": ["report_id", "checked_at", "result"],
"properties": {
"report_id": {
"type": "string",
"format": "uuid"
},
"checked_at": {
"type": "string",
"format": "date-time"
},
"base_version": {
"type": "string"
},
"target_version": {
"type": "string"
},
"result": {
"type": "string",
"enum": ["compatible", "breaking", "minor_changes"]
},
"breaking_changes": {
"type": "array",
"items": {
"$ref": "#/definitions/ApiChange"
}
},
"non_breaking_changes": {
"type": "array",
"items": {
"$ref": "#/definitions/ApiChange"
}
}
}
},
"ApiChange": {
"type": "object",
"description": "Individual API change",
"required": ["change_type", "path"],
"properties": {
"change_type": {
"type": "string",
"enum": [
"endpoint_added",
"endpoint_removed",
"parameter_added",
"parameter_removed",
"parameter_type_changed",
"response_changed",
"schema_changed",
"deprecation_added"
]
},
"path": {
"type": "string"
},
"method": {
"type": "string"
},
"description": {
"type": "string"
},
"severity": {
"type": "string",
"enum": ["breaking", "warning", "info"]
}
}
}
},
"properties": {
"catalog": {
"$ref": "#/definitions/DevPortalCatalog"
}
},
"examples": [
{
"catalog": {
"catalog_id": "stellaops-api-catalog",
"version": "2025.10.0",
"updated_at": "2025-12-06T10:00:00Z",
"services": [
{
"service_id": "findings-ledger",
"name": "Findings Ledger",
"description": "Vulnerability findings storage and query service",
"version": "1.0.0",
"base_url": "https://api.stellaops.io/findings",
"openapi_url": "https://api.stellaops.io/findings/.well-known/openapi.json",
"status": "stable",
"tags": ["findings", "vulnerabilities", "ledger"],
"endpoints": [
{
"path": "/api/v1/findings",
"method": "GET",
"operation_id": "listFindings",
"summary": "List findings with pagination and filtering",
"tags": ["findings"],
"authentication": {
"required": true,
"schemes": ["bearer", "oauth2"]
},
"scopes": ["findings:read"],
"rate_limit": {
"requests_per_minute": 100,
"tier": "standard"
},
"request": {
"parameters": [
{
"name": "page",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"default": 1
}
},
{
"name": "limit",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"default": 50,
"maximum": 200
}
}
]
},
"responses": {
"200": {
"description": "Paginated list of findings",
"content_types": ["application/json"]
},
"401": {
"description": "Unauthorized"
}
}
}
]
}
],
"authentication_info": {
"oauth2_authorization_url": "https://auth.stellaops.io/authorize",
"oauth2_token_url": "https://auth.stellaops.io/token",
"api_key_header": "X-StellaOps-API-Key"
}
}
}
]
}

View File

@@ -0,0 +1,663 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/schemas/evidence-locker-dsse.schema.json",
"title": "StellaOps Evidence Locker DSSE Schema",
"description": "Schema for Evidence Locker DSSE attestations, Merkle locker payloads, and evidence batch operations. Unblocks EXCITITOR-OBS-52/53/54.",
"type": "object",
"definitions": {
"EvidenceLockerBatch": {
"type": "object",
"description": "A batch of evidence artifacts submitted to the Evidence Locker",
"required": ["batch_id", "artifacts", "created_at"],
"properties": {
"batch_id": {
"type": "string",
"format": "uuid",
"description": "Unique identifier for this evidence batch"
},
"artifacts": {
"type": "array",
"items": {
"$ref": "#/definitions/EvidenceArtifact"
},
"minItems": 1,
"description": "List of evidence artifacts in this batch"
},
"created_at": {
"type": "string",
"format": "date-time"
},
"created_by": {
"type": "string",
"description": "Identity of the batch creator"
},
"tenant_id": {
"type": "string",
"format": "uuid"
},
"project_id": {
"type": "string",
"format": "uuid"
},
"pipeline_context": {
"$ref": "#/definitions/PipelineContext"
},
"aggregate_digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "SHA-256 digest of all artifact digests concatenated and sorted"
},
"merkle_root": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "Merkle tree root of the batch"
},
"dsse_envelope": {
"$ref": "#/definitions/DsseEnvelope"
},
"retention_policy": {
"$ref": "#/definitions/RetentionPolicy"
},
"status": {
"type": "string",
"enum": ["pending", "committed", "anchored", "sealed", "expired"],
"description": "Current status of the batch"
}
}
},
"EvidenceArtifact": {
"type": "object",
"description": "A single evidence artifact within a batch",
"required": ["artifact_id", "artifact_type", "digest", "stored_at"],
"properties": {
"artifact_id": {
"type": "string",
"format": "uuid"
},
"artifact_type": {
"type": "string",
"enum": [
"sbom",
"vex",
"scan_result",
"attestation",
"policy_evaluation",
"callgraph",
"runtime_facts",
"timeline_event",
"audit_log",
"configuration",
"signature"
],
"description": "Type of evidence artifact"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "SHA-256 digest of the artifact content"
},
"content_type": {
"type": "string",
"description": "MIME type of the artifact (e.g., application/json)"
},
"size_bytes": {
"type": "integer",
"minimum": 0
},
"storage_uri": {
"type": "string",
"format": "uri",
"description": "URI to retrieve the artifact from object storage"
},
"stored_at": {
"type": "string",
"format": "date-time"
},
"labels": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Key-value labels for filtering and organization"
},
"subject": {
"$ref": "#/definitions/ArtifactSubject"
},
"provenance": {
"$ref": "#/definitions/ArtifactProvenance"
},
"merkle_position": {
"$ref": "#/definitions/MerklePosition"
}
}
},
"ArtifactSubject": {
"type": "object",
"description": "Subject the artifact relates to (e.g., a component or vulnerability)",
"properties": {
"subject_type": {
"type": "string",
"enum": ["component", "vulnerability", "product", "scan", "pipeline", "policy"]
},
"identifier": {
"type": "string",
"description": "Subject identifier (PURL, CVE ID, etc.)"
},
"version": {
"type": "string"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
}
}
},
"ArtifactProvenance": {
"type": "object",
"description": "Provenance information for an artifact",
"properties": {
"producer": {
"type": "string",
"description": "Service or tool that produced this artifact"
},
"producer_version": {
"type": "string"
},
"produced_at": {
"type": "string",
"format": "date-time"
},
"build_invocation_id": {
"type": "string",
"description": "CI/CD build or pipeline invocation ID"
},
"entry_point": {
"type": "string",
"description": "Entry point command or script"
},
"input_digests": {
"type": "array",
"items": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"description": "Digests of inputs used to produce this artifact"
}
}
},
"MerklePosition": {
"type": "object",
"description": "Position in the Merkle tree for tamper detection",
"required": ["index", "tree_size", "proof"],
"properties": {
"index": {
"type": "integer",
"minimum": 0,
"description": "Leaf index in the Merkle tree"
},
"tree_size": {
"type": "integer",
"minimum": 1,
"description": "Total number of leaves in the tree"
},
"proof": {
"type": "array",
"items": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"description": "Audit path hashes for verification"
},
"root_digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "Merkle root at time of inclusion"
}
}
},
"PipelineContext": {
"type": "object",
"description": "Context of the pipeline that created the batch",
"properties": {
"pipeline_id": {
"type": "string"
},
"pipeline_name": {
"type": "string"
},
"run_id": {
"type": "string"
},
"step_id": {
"type": "string"
},
"repository": {
"type": "string"
},
"commit_sha": {
"type": "string",
"pattern": "^[a-f0-9]{40}$"
},
"branch": {
"type": "string"
},
"environment": {
"type": "string",
"enum": ["development", "staging", "production"]
}
}
},
"DsseEnvelope": {
"type": "object",
"description": "DSSE (Dead Simple Signing Envelope) for batch attestation",
"required": ["payloadType", "payload", "signatures"],
"properties": {
"payloadType": {
"type": "string",
"const": "application/vnd.stellaops.evidence-batch.v1+json",
"description": "DSSE payload type"
},
"payload": {
"type": "string",
"contentEncoding": "base64",
"description": "Base64-encoded batch payload"
},
"signatures": {
"type": "array",
"items": {
"$ref": "#/definitions/DsseSignature"
},
"minItems": 1
}
}
},
"DsseSignature": {
"type": "object",
"description": "A signature on the DSSE envelope",
"required": ["sig"],
"properties": {
"keyid": {
"type": "string",
"description": "Key identifier (e.g., Fulcio certificate fingerprint)"
},
"sig": {
"type": "string",
"contentEncoding": "base64",
"description": "Base64-encoded signature"
},
"cert": {
"type": "string",
"contentEncoding": "base64",
"description": "Base64-encoded signing certificate (for keyless signing)"
}
}
},
"RetentionPolicy": {
"type": "object",
"description": "Retention policy for evidence artifacts",
"properties": {
"retention_days": {
"type": "integer",
"minimum": 1,
"description": "Number of days to retain artifacts"
},
"retention_class": {
"type": "string",
"enum": ["standard", "extended", "compliance", "indefinite"],
"description": "Retention class for policy lookup"
},
"expires_at": {
"type": "string",
"format": "date-time"
},
"hold_until": {
"type": "string",
"format": "date-time",
"description": "Legal hold expiration (overrides retention_days)"
},
"archive_after_days": {
"type": "integer",
"minimum": 0,
"description": "Days before archiving to cold storage"
},
"delete_on_expiry": {
"type": "boolean",
"default": true,
"description": "Whether to delete artifacts when retention expires"
}
}
},
"TimelineEvent": {
"type": "object",
"description": "Timeline event linked to evidence artifacts",
"required": ["event_id", "event_type", "occurred_at"],
"properties": {
"event_id": {
"type": "string",
"format": "uuid"
},
"event_type": {
"type": "string",
"enum": [
"evidence_batch_created",
"evidence_batch_committed",
"merkle_anchor_published",
"artifact_accessed",
"artifact_verified",
"retention_extended",
"artifact_archived",
"artifact_deleted",
"batch_sealed",
"verification_failed"
]
},
"occurred_at": {
"type": "string",
"format": "date-time"
},
"actor": {
"type": "string",
"description": "User or service that triggered the event"
},
"batch_id": {
"type": "string",
"format": "uuid"
},
"artifact_ids": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"description": "Affected artifact IDs"
},
"details": {
"type": "object",
"additionalProperties": true
},
"evidence_refs": {
"type": "array",
"items": {
"$ref": "#/definitions/EvidenceRef"
},
"description": "References to related evidence"
}
}
},
"EvidenceRef": {
"type": "object",
"description": "Reference to evidence artifact",
"required": ["artifact_id", "digest"],
"properties": {
"artifact_id": {
"type": "string",
"format": "uuid"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"storage_uri": {
"type": "string",
"format": "uri"
},
"artifact_type": {
"type": "string"
}
}
},
"MerkleAnchor": {
"type": "object",
"description": "Merkle tree anchor published to transparency log",
"required": ["anchor_id", "merkle_root", "tree_size", "published_at"],
"properties": {
"anchor_id": {
"type": "string",
"format": "uuid"
},
"merkle_root": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"tree_size": {
"type": "integer",
"minimum": 1
},
"published_at": {
"type": "string",
"format": "date-time"
},
"batch_ids": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"description": "Batches included in this anchor"
},
"previous_anchor_id": {
"type": "string",
"format": "uuid",
"description": "Previous anchor in the chain"
},
"consistency_proof": {
"type": "array",
"items": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"description": "Consistency proof from previous anchor"
},
"rekor_entry": {
"$ref": "#/definitions/RekorEntry"
}
}
},
"RekorEntry": {
"type": "object",
"description": "Entry in Sigstore Rekor transparency log",
"properties": {
"log_index": {
"type": "integer",
"minimum": 0
},
"log_id": {
"type": "string"
},
"integrated_time": {
"type": "integer",
"description": "Unix timestamp when entry was integrated"
},
"uuid": {
"type": "string",
"pattern": "^[a-f0-9]{64}$"
},
"body": {
"type": "string",
"contentEncoding": "base64"
},
"inclusion_proof": {
"$ref": "#/definitions/InclusionProof"
}
}
},
"InclusionProof": {
"type": "object",
"description": "Inclusion proof for transparency log",
"required": ["log_index", "root_hash", "tree_size", "hashes"],
"properties": {
"log_index": {
"type": "integer",
"minimum": 0
},
"root_hash": {
"type": "string",
"contentEncoding": "base64"
},
"tree_size": {
"type": "integer",
"minimum": 1
},
"hashes": {
"type": "array",
"items": {
"type": "string",
"contentEncoding": "base64"
}
}
}
},
"VerificationRequest": {
"type": "object",
"description": "Request to verify evidence artifact integrity",
"required": ["artifact_id"],
"properties": {
"artifact_id": {
"type": "string",
"format": "uuid"
},
"expected_digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"verify_merkle_proof": {
"type": "boolean",
"default": true
},
"verify_dsse_signature": {
"type": "boolean",
"default": true
},
"verify_rekor_inclusion": {
"type": "boolean",
"default": false
}
}
},
"VerificationResult": {
"type": "object",
"description": "Result of evidence verification",
"required": ["artifact_id", "verified", "timestamp"],
"properties": {
"artifact_id": {
"type": "string",
"format": "uuid"
},
"verified": {
"type": "boolean"
},
"timestamp": {
"type": "string",
"format": "date-time"
},
"checks": {
"type": "array",
"items": {
"$ref": "#/definitions/VerificationCheck"
}
},
"error": {
"type": "string",
"description": "Error message if verification failed"
}
}
},
"VerificationCheck": {
"type": "object",
"description": "Individual verification check result",
"required": ["check_type", "passed"],
"properties": {
"check_type": {
"type": "string",
"enum": [
"digest_match",
"merkle_proof_valid",
"dsse_signature_valid",
"certificate_valid",
"rekor_inclusion_valid",
"timestamp_valid"
]
},
"passed": {
"type": "boolean"
},
"details": {
"type": "string"
}
}
}
},
"properties": {
"batches": {
"type": "array",
"items": {
"$ref": "#/definitions/EvidenceLockerBatch"
}
}
},
"examples": [
{
"batches": [
{
"batch_id": "550e8400-e29b-41d4-a716-446655440000",
"artifacts": [
{
"artifact_id": "660e8400-e29b-41d4-a716-446655440001",
"artifact_type": "sbom",
"digest": "sha256:abc123def456789012345678901234567890123456789012345678901234abcd",
"content_type": "application/vnd.cyclonedx+json",
"size_bytes": 15234,
"storage_uri": "s3://evidence-locker/batches/550e8400.../sbom.json",
"stored_at": "2025-12-06T10:00:00Z",
"labels": {
"project": "frontend-app",
"environment": "production"
},
"subject": {
"subject_type": "component",
"identifier": "pkg:npm/frontend-app@1.0.0",
"digest": "sha256:def456..."
},
"provenance": {
"producer": "stellaops-scanner",
"producer_version": "2025.10.0",
"produced_at": "2025-12-06T09:55:00Z",
"build_invocation_id": "ci-12345"
},
"merkle_position": {
"index": 0,
"tree_size": 3,
"proof": [
"sha256:111...",
"sha256:222..."
],
"root_digest": "sha256:merkleroot..."
}
}
],
"created_at": "2025-12-06T10:00:00Z",
"created_by": "stellaops-pipeline",
"tenant_id": "tenant-001",
"aggregate_digest": "sha256:aggregate123...",
"merkle_root": "sha256:merkleroot...",
"dsse_envelope": {
"payloadType": "application/vnd.stellaops.evidence-batch.v1+json",
"payload": "eyJiYXRjaF9pZCI6IjU1MGU4NDAwLi4uIn0=",
"signatures": [
{
"keyid": "fulcio:abc123",
"sig": "MEUCIQDxxx..."
}
]
},
"retention_policy": {
"retention_days": 365,
"retention_class": "compliance",
"archive_after_days": 90
},
"status": "committed"
}
]
}
]
}

View File

@@ -0,0 +1,745 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/schemas/exception-lifecycle.schema.json",
"title": "StellaOps Exception Lifecycle Schema",
"description": "Schema for exception lifecycle, routing, approvals, and governance. Unblocks DOCS-EXC-25-001 through 25-006 (5 tasks).",
"type": "object",
"definitions": {
"Exception": {
"type": "object",
"description": "Security exception request",
"required": ["exception_id", "finding_id", "status", "justification", "requested_at", "requested_by"],
"properties": {
"exception_id": {
"type": "string",
"format": "uuid"
},
"finding_id": {
"type": "string",
"format": "uuid",
"description": "Finding this exception applies to"
},
"finding_ids": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"description": "Multiple findings for bulk exception"
},
"exception_type": {
"type": "string",
"enum": [
"false_positive",
"risk_accepted",
"compensating_control",
"deferred_remediation",
"not_applicable",
"wont_fix"
]
},
"status": {
"$ref": "#/definitions/ExceptionStatus"
},
"justification": {
"type": "string",
"minLength": 10,
"description": "Business justification for exception"
},
"compensating_controls": {
"type": "array",
"items": {
"$ref": "#/definitions/CompensatingControl"
}
},
"scope": {
"$ref": "#/definitions/ExceptionScope"
},
"effective_at": {
"type": "string",
"format": "date-time"
},
"expires_at": {
"type": "string",
"format": "date-time"
},
"requested_at": {
"type": "string",
"format": "date-time"
},
"requested_by": {
"type": "string",
"description": "User who requested exception"
},
"approvals": {
"type": "array",
"items": {
"$ref": "#/definitions/Approval"
}
},
"routing": {
"$ref": "#/definitions/RoutingInfo"
},
"audit_trail": {
"type": "array",
"items": {
"$ref": "#/definitions/AuditEntry"
}
},
"risk_assessment": {
"$ref": "#/definitions/RiskAssessment"
},
"attachments": {
"type": "array",
"items": {
"$ref": "#/definitions/Attachment"
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"metadata": {
"type": "object",
"additionalProperties": true
}
}
},
"ExceptionStatus": {
"type": "string",
"enum": [
"draft",
"pending_review",
"pending_approval",
"approved",
"rejected",
"expired",
"revoked",
"superseded"
]
},
"CompensatingControl": {
"type": "object",
"description": "Compensating control for accepted risk",
"required": ["control_id", "description"],
"properties": {
"control_id": {
"type": "string"
},
"description": {
"type": "string"
},
"control_type": {
"type": "string",
"enum": ["technical", "administrative", "physical", "procedural"]
},
"effectiveness": {
"type": "string",
"enum": ["high", "medium", "low"]
},
"verification_method": {
"type": "string"
},
"last_verified_at": {
"type": "string",
"format": "date-time"
}
}
},
"ExceptionScope": {
"type": "object",
"description": "Scope of the exception",
"properties": {
"scope_type": {
"type": "string",
"enum": ["finding", "component", "project", "organization"]
},
"tenant_id": {
"type": "string",
"format": "uuid"
},
"project_ids": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
}
},
"component_patterns": {
"type": "array",
"items": {
"type": "string"
},
"description": "PURL patterns to match"
},
"cve_patterns": {
"type": "array",
"items": {
"type": "string"
},
"description": "CVE patterns to match"
}
}
},
"Approval": {
"type": "object",
"description": "Approval record",
"required": ["approver_id", "decision", "decided_at"],
"properties": {
"approval_id": {
"type": "string",
"format": "uuid"
},
"approver_id": {
"type": "string"
},
"approver_name": {
"type": "string"
},
"approver_role": {
"type": "string"
},
"decision": {
"type": "string",
"enum": ["approved", "rejected", "deferred"]
},
"decided_at": {
"type": "string",
"format": "date-time"
},
"comments": {
"type": "string"
},
"conditions": {
"type": "array",
"items": {
"type": "string"
},
"description": "Conditions attached to approval"
},
"signature": {
"type": "string",
"description": "Digital signature of approval"
}
}
},
"RoutingInfo": {
"type": "object",
"description": "Routing configuration for exception workflow",
"properties": {
"workflow_id": {
"type": "string"
},
"current_step": {
"type": "string"
},
"approval_chain": {
"type": "array",
"items": {
"$ref": "#/definitions/ApprovalStep"
}
},
"escalation_policy": {
"$ref": "#/definitions/EscalationPolicy"
},
"notifications": {
"type": "array",
"items": {
"$ref": "#/definitions/NotificationConfig"
}
}
}
},
"ApprovalStep": {
"type": "object",
"description": "Step in approval chain",
"required": ["step_id", "approvers"],
"properties": {
"step_id": {
"type": "string"
},
"step_name": {
"type": "string"
},
"approvers": {
"type": "array",
"items": {
"$ref": "#/definitions/ApproverConfig"
}
},
"approval_type": {
"type": "string",
"enum": ["any", "all", "quorum"],
"default": "any"
},
"quorum_count": {
"type": "integer",
"minimum": 1
},
"timeout_hours": {
"type": "integer"
},
"status": {
"type": "string",
"enum": ["pending", "completed", "skipped"]
}
}
},
"ApproverConfig": {
"type": "object",
"description": "Approver configuration",
"properties": {
"type": {
"type": "string",
"enum": ["user", "role", "group", "dynamic"]
},
"identifier": {
"type": "string"
},
"fallback_approvers": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"EscalationPolicy": {
"type": "object",
"description": "Escalation policy for stalled approvals",
"properties": {
"enabled": {
"type": "boolean",
"default": true
},
"escalation_after_hours": {
"type": "integer",
"default": 48
},
"max_escalation_levels": {
"type": "integer",
"default": 3
},
"escalation_targets": {
"type": "array",
"items": {
"type": "string"
}
},
"auto_approve_on_timeout": {
"type": "boolean",
"default": false
},
"auto_reject_on_timeout": {
"type": "boolean",
"default": false
}
}
},
"NotificationConfig": {
"type": "object",
"description": "Notification configuration",
"properties": {
"event": {
"type": "string",
"enum": [
"exception_created",
"pending_approval",
"approved",
"rejected",
"expiring_soon",
"expired",
"escalated"
]
},
"channels": {
"type": "array",
"items": {
"type": "string",
"enum": ["email", "slack", "teams", "webhook"]
}
},
"recipients": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"AuditEntry": {
"type": "object",
"description": "Audit trail entry",
"required": ["action", "actor", "timestamp"],
"properties": {
"entry_id": {
"type": "string",
"format": "uuid"
},
"action": {
"type": "string",
"enum": [
"created",
"updated",
"submitted",
"approved",
"rejected",
"revoked",
"expired",
"escalated",
"comment_added"
]
},
"actor": {
"type": "string"
},
"timestamp": {
"type": "string",
"format": "date-time"
},
"details": {
"type": "object",
"additionalProperties": true
},
"ip_address": {
"type": "string"
}
}
},
"RiskAssessment": {
"type": "object",
"description": "Risk assessment for exception",
"properties": {
"original_risk_score": {
"type": "number",
"minimum": 0,
"maximum": 10
},
"residual_risk_score": {
"type": "number",
"minimum": 0,
"maximum": 10,
"description": "Risk after compensating controls"
},
"risk_factors": {
"type": "array",
"items": {
"$ref": "#/definitions/RiskFactor"
}
},
"business_impact": {
"type": "string",
"enum": ["critical", "high", "medium", "low", "minimal"]
},
"data_sensitivity": {
"type": "string",
"enum": ["public", "internal", "confidential", "restricted"]
},
"assessed_by": {
"type": "string"
},
"assessed_at": {
"type": "string",
"format": "date-time"
}
}
},
"RiskFactor": {
"type": "object",
"description": "Individual risk factor",
"properties": {
"factor_name": {
"type": "string"
},
"impact": {
"type": "string",
"enum": ["increase", "decrease", "neutral"]
},
"weight": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"rationale": {
"type": "string"
}
}
},
"Attachment": {
"type": "object",
"description": "Supporting attachment",
"required": ["attachment_id", "filename"],
"properties": {
"attachment_id": {
"type": "string",
"format": "uuid"
},
"filename": {
"type": "string"
},
"content_type": {
"type": "string"
},
"size_bytes": {
"type": "integer"
},
"storage_uri": {
"type": "string",
"format": "uri"
},
"checksum": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"uploaded_at": {
"type": "string",
"format": "date-time"
},
"uploaded_by": {
"type": "string"
}
}
},
"ExceptionPolicy": {
"type": "object",
"description": "Exception governance policy",
"required": ["policy_id", "name"],
"properties": {
"policy_id": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"max_exception_duration_days": {
"type": "integer",
"minimum": 1
},
"require_compensating_controls": {
"type": "boolean",
"default": false
},
"require_risk_assessment": {
"type": "boolean",
"default": true
},
"severity_thresholds": {
"$ref": "#/definitions/SeverityThresholds"
},
"auto_renewal": {
"$ref": "#/definitions/AutoRenewalConfig"
},
"compliance_frameworks": {
"type": "array",
"items": {
"type": "string"
},
"description": "Applicable compliance frameworks"
}
}
},
"SeverityThresholds": {
"type": "object",
"description": "Approval thresholds by severity",
"properties": {
"critical": {
"$ref": "#/definitions/ThresholdConfig"
},
"high": {
"$ref": "#/definitions/ThresholdConfig"
},
"medium": {
"$ref": "#/definitions/ThresholdConfig"
},
"low": {
"$ref": "#/definitions/ThresholdConfig"
}
}
},
"ThresholdConfig": {
"type": "object",
"properties": {
"max_duration_days": {
"type": "integer"
},
"required_approver_roles": {
"type": "array",
"items": {
"type": "string"
}
},
"min_approvers": {
"type": "integer",
"minimum": 1
},
"allow_exception": {
"type": "boolean",
"default": true
}
}
},
"AutoRenewalConfig": {
"type": "object",
"description": "Auto-renewal configuration",
"properties": {
"enabled": {
"type": "boolean",
"default": false
},
"max_renewals": {
"type": "integer"
},
"renewal_review_required": {
"type": "boolean",
"default": true
}
}
},
"ExceptionSearchQuery": {
"type": "object",
"description": "Query for searching exceptions",
"properties": {
"exception_ids": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
}
},
"finding_ids": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
}
},
"statuses": {
"type": "array",
"items": {
"$ref": "#/definitions/ExceptionStatus"
}
},
"exception_types": {
"type": "array",
"items": {
"type": "string"
}
},
"requested_by": {
"type": "string"
},
"approved_by": {
"type": "string"
},
"created_after": {
"type": "string",
"format": "date-time"
},
"created_before": {
"type": "string",
"format": "date-time"
},
"expiring_within_days": {
"type": "integer"
},
"page": {
"type": "integer",
"minimum": 1,
"default": 1
},
"page_size": {
"type": "integer",
"minimum": 1,
"maximum": 200,
"default": 50
}
}
},
"ExceptionSearchResult": {
"type": "object",
"description": "Search result",
"required": ["exceptions", "total_count"],
"properties": {
"exceptions": {
"type": "array",
"items": {
"$ref": "#/definitions/Exception"
}
},
"total_count": {
"type": "integer",
"minimum": 0
},
"page": {
"type": "integer"
},
"page_size": {
"type": "integer"
},
"next_page_token": {
"type": "string"
}
}
}
},
"properties": {
"exceptions": {
"type": "array",
"items": {
"$ref": "#/definitions/Exception"
}
}
},
"examples": [
{
"exceptions": [
{
"exception_id": "550e8400-e29b-41d4-a716-446655440000",
"finding_id": "660e8400-e29b-41d4-a716-446655440001",
"exception_type": "risk_accepted",
"status": "approved",
"justification": "This vulnerability exists in a test-only dependency that is not deployed to production. The affected code path is never executed in any deployed environment.",
"compensating_controls": [
{
"control_id": "CC-001",
"description": "Network segmentation prevents access to affected component",
"control_type": "technical",
"effectiveness": "high"
}
],
"scope": {
"scope_type": "component",
"component_patterns": ["pkg:npm/test-lib@*"]
},
"effective_at": "2025-12-06T00:00:00Z",
"expires_at": "2026-06-06T00:00:00Z",
"requested_at": "2025-12-01T10:00:00Z",
"requested_by": "dev-team-lead@example.com",
"approvals": [
{
"approval_id": "770e8400-e29b-41d4-a716-446655440002",
"approver_id": "security-manager@example.com",
"approver_name": "Jane Security",
"approver_role": "Security Manager",
"decision": "approved",
"decided_at": "2025-12-05T14:00:00Z",
"comments": "Approved with 6-month duration due to low residual risk",
"conditions": ["Re-evaluate if component moves to production"]
}
],
"risk_assessment": {
"original_risk_score": 7.5,
"residual_risk_score": 2.0,
"business_impact": "low",
"data_sensitivity": "internal"
}
}
]
}
]
}

View File

@@ -0,0 +1,673 @@
openapi: 3.1.0
info:
title: StellaOps Excititor Chunk API
version: 1.0.0
description: |
API for VEX document chunked ingestion and processing in Excititor service.
Unblocks EXCITITOR-DOCS-0001, EXCITITOR-ENG-0001, EXCITITOR-OPS-0001 (3 tasks).
contact:
name: StellaOps Platform Team
url: https://stella-ops.org
license:
name: AGPL-3.0-or-later
url: https://www.gnu.org/licenses/agpl-3.0.html
servers:
- url: /api/v1/excititor
description: Excititor API base path
tags:
- name: chunks
description: Chunked document upload operations
- name: vex
description: VEX document ingestion
- name: processing
description: Document processing status
- name: health
description: Service health endpoints
paths:
/chunks/initiate:
post:
operationId: initiateChunkedUpload
summary: Initiate a chunked upload session
description: Start a new chunked upload session for large VEX documents
tags:
- chunks
security:
- bearerAuth: []
- oauth2: [excititor:write]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ChunkedUploadInitRequest'
responses:
'201':
description: Upload session created
content:
application/json:
schema:
$ref: '#/components/schemas/ChunkedUploadSession'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/TooManyRequests'
/chunks/{session_id}:
put:
operationId: uploadChunk
summary: Upload a chunk
description: Upload a single chunk for an active upload session
tags:
- chunks
security:
- bearerAuth: []
- oauth2: [excititor:write]
parameters:
- name: session_id
in: path
required: true
schema:
type: string
format: uuid
- name: X-Chunk-Index
in: header
required: true
schema:
type: integer
minimum: 0
- name: X-Chunk-Digest
in: header
required: true
schema:
type: string
pattern: '^sha256:[a-f0-9]{64}$'
- name: Content-Range
in: header
required: false
schema:
type: string
requestBody:
required: true
content:
application/octet-stream:
schema:
type: string
format: binary
responses:
'200':
description: Chunk uploaded successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ChunkUploadResult'
'400':
$ref: '#/components/responses/BadRequest'
'404':
$ref: '#/components/responses/NotFound'
'409':
description: Chunk already uploaded or out of sequence
content:
application/json:
schema:
$ref: '#/components/schemas/ProblemDetails'
get:
operationId: getUploadSessionStatus
summary: Get upload session status
description: Retrieve the current status of a chunked upload session
tags:
- chunks
security:
- bearerAuth: []
- oauth2: [excititor:read]
parameters:
- name: session_id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Upload session status
content:
application/json:
schema:
$ref: '#/components/schemas/ChunkedUploadSession'
'404':
$ref: '#/components/responses/NotFound'
delete:
operationId: cancelUploadSession
summary: Cancel upload session
description: Cancel an active upload session and clean up partial data
tags:
- chunks
security:
- bearerAuth: []
- oauth2: [excititor:write]
parameters:
- name: session_id
in: path
required: true
schema:
type: string
format: uuid
responses:
'204':
description: Session cancelled
'404':
$ref: '#/components/responses/NotFound'
/chunks/{session_id}/complete:
post:
operationId: completeChunkedUpload
summary: Complete chunked upload
description: Finalize a chunked upload and trigger VEX processing
tags:
- chunks
security:
- bearerAuth: []
- oauth2: [excititor:write]
parameters:
- name: session_id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ChunkedUploadCompleteRequest'
responses:
'200':
description: Upload completed, processing started
content:
application/json:
schema:
$ref: '#/components/schemas/VexIngestionJob'
'400':
$ref: '#/components/responses/BadRequest'
'404':
$ref: '#/components/responses/NotFound'
'409':
description: Missing chunks or invalid digest
content:
application/json:
schema:
$ref: '#/components/schemas/ProblemDetails'
/vex/ingest:
post:
operationId: ingestVexDocument
summary: Ingest a VEX document
description: Ingest a small VEX document directly (for documents < 10MB)
tags:
- vex
security:
- bearerAuth: []
- oauth2: [excititor:write]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/VexIngestionRequest'
application/vnd.openvex+json:
schema:
type: object
application/vnd.csaf+json:
schema:
type: object
application/vnd.cyclonedx+json:
schema:
type: object
responses:
'202':
description: VEX document accepted for processing
content:
application/json:
schema:
$ref: '#/components/schemas/VexIngestionJob'
'400':
$ref: '#/components/responses/BadRequest'
'413':
description: Payload too large - use chunked upload
content:
application/json:
schema:
$ref: '#/components/schemas/ProblemDetails'
/vex/jobs/{job_id}:
get:
operationId: getIngestionJobStatus
summary: Get ingestion job status
description: Retrieve the status of a VEX ingestion job
tags:
- processing
security:
- bearerAuth: []
- oauth2: [excititor:read]
parameters:
- name: job_id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Job status
content:
application/json:
schema:
$ref: '#/components/schemas/VexIngestionJob'
'404':
$ref: '#/components/responses/NotFound'
/vex/jobs:
get:
operationId: listIngestionJobs
summary: List ingestion jobs
description: List VEX ingestion jobs with filtering and pagination
tags:
- processing
security:
- bearerAuth: []
- oauth2: [excititor:read]
parameters:
- name: status
in: query
schema:
type: string
enum: [pending, processing, completed, failed]
- name: created_after
in: query
schema:
type: string
format: date-time
- name: created_before
in: query
schema:
type: string
format: date-time
- name: page
in: query
schema:
type: integer
minimum: 1
default: 1
- name: page_size
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
'200':
description: List of jobs
content:
application/json:
schema:
$ref: '#/components/schemas/VexIngestionJobList'
/health:
get:
operationId: healthCheck
summary: Health check
description: Service health check endpoint
tags:
- health
security: []
responses:
'200':
description: Service healthy
content:
application/json:
schema:
$ref: '#/components/schemas/HealthStatus'
'503':
description: Service unhealthy
content:
application/json:
schema:
$ref: '#/components/schemas/HealthStatus'
/health/ready:
get:
operationId: readinessCheck
summary: Readiness check
description: Kubernetes readiness probe endpoint
tags:
- health
security: []
responses:
'200':
description: Service ready
'503':
description: Service not ready
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
oauth2:
type: oauth2
flows:
clientCredentials:
tokenUrl: /oauth/token
scopes:
excititor:read: Read VEX data
excititor:write: Write VEX data
schemas:
ChunkedUploadInitRequest:
type: object
required:
- filename
- total_size
- content_type
properties:
filename:
type: string
description: Original filename
total_size:
type: integer
minimum: 1
description: Total file size in bytes
content_type:
type: string
enum:
- application/json
- application/vnd.openvex+json
- application/vnd.csaf+json
- application/vnd.cyclonedx+json
expected_digest:
type: string
pattern: '^sha256:[a-f0-9]{64}$'
description: Expected SHA-256 digest of complete file
chunk_size:
type: integer
minimum: 1048576
maximum: 104857600
default: 10485760
description: Chunk size in bytes (1MB - 100MB, default 10MB)
metadata:
type: object
additionalProperties: true
description: Optional metadata for the upload
ChunkedUploadSession:
type: object
required:
- session_id
- status
- created_at
properties:
session_id:
type: string
format: uuid
status:
type: string
enum: [active, completed, cancelled, expired]
filename:
type: string
total_size:
type: integer
chunk_size:
type: integer
total_chunks:
type: integer
uploaded_chunks:
type: array
items:
type: integer
chunks_remaining:
type: integer
bytes_uploaded:
type: integer
created_at:
type: string
format: date-time
expires_at:
type: string
format: date-time
upload_url:
type: string
format: uri
description: URL for chunk uploads
ChunkUploadResult:
type: object
required:
- chunk_index
- received
properties:
chunk_index:
type: integer
received:
type: boolean
digest_verified:
type: boolean
bytes_received:
type: integer
chunks_remaining:
type: integer
ChunkedUploadCompleteRequest:
type: object
required:
- final_digest
properties:
final_digest:
type: string
pattern: '^sha256:[a-f0-9]{64}$'
description: SHA-256 digest of reassembled file
process_immediately:
type: boolean
default: true
description: Start processing immediately after assembly
VexIngestionRequest:
type: object
required:
- document
properties:
document:
type: object
description: VEX document (OpenVEX, CSAF, or CycloneDX format)
format:
type: string
enum: [openvex, csaf, cyclonedx, auto]
default: auto
source:
type: string
description: Source identifier for the VEX document
priority:
type: string
enum: [low, normal, high]
default: normal
metadata:
type: object
additionalProperties: true
VexIngestionJob:
type: object
required:
- job_id
- status
- created_at
properties:
job_id:
type: string
format: uuid
status:
type: string
enum: [pending, validating, processing, indexing, completed, failed]
format_detected:
type: string
enum: [openvex, csaf, cyclonedx, unknown]
created_at:
type: string
format: date-time
started_at:
type: string
format: date-time
completed_at:
type: string
format: date-time
document_digest:
type: string
pattern: '^sha256:[a-f0-9]{64}$'
statements_count:
type: integer
description: Number of VEX statements processed
products_count:
type: integer
description: Number of products affected
vulnerabilities_count:
type: integer
description: Number of vulnerabilities referenced
errors:
type: array
items:
$ref: '#/components/schemas/ProcessingError'
warnings:
type: array
items:
type: string
result_ref:
type: string
description: Reference to processing result
VexIngestionJobList:
type: object
required:
- jobs
- total_count
properties:
jobs:
type: array
items:
$ref: '#/components/schemas/VexIngestionJob'
total_count:
type: integer
page:
type: integer
page_size:
type: integer
next_page_token:
type: string
ProcessingError:
type: object
required:
- code
- message
properties:
code:
type: string
message:
type: string
location:
type: string
description: JSON path to error location
details:
type: object
additionalProperties: true
HealthStatus:
type: object
required:
- status
properties:
status:
type: string
enum: [healthy, degraded, unhealthy]
version:
type: string
uptime_seconds:
type: integer
checks:
type: array
items:
type: object
properties:
name:
type: string
status:
type: string
enum: [pass, warn, fail]
message:
type: string
ProblemDetails:
type: object
required:
- type
- title
- status
properties:
type:
type: string
format: uri
title:
type: string
status:
type: integer
detail:
type: string
instance:
type: string
format: uri
errors:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string
responses:
BadRequest:
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ProblemDetails'
Unauthorized:
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ProblemDetails'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/ProblemDetails'
TooManyRequests:
description: Rate limit exceeded
content:
application/json:
schema:
$ref: '#/components/schemas/ProblemDetails'
headers:
Retry-After:
schema:
type: integer
description: Seconds until rate limit resets

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,681 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/schemas/lnm-overlay.schema.json",
"title": "StellaOps Link-Not-Merge Overlay Schema",
"description": "Schema for Link-Not-Merge (LNM) overlay metadata and graph inspector integration. Unblocks EXCITITOR-GRAPH-21-001 through 21-005.",
"type": "object",
"definitions": {
"LnmOverlay": {
"type": "object",
"description": "Link-Not-Merge overlay structure for VEX observation and linkset merge metadata",
"required": ["overlay_id", "source_type", "timestamp"],
"properties": {
"overlay_id": {
"type": "string",
"format": "uuid",
"description": "Unique identifier for this overlay"
},
"source_type": {
"type": "string",
"enum": ["observation", "linkset", "advisory", "vex", "sbom"],
"description": "Type of source contributing to this overlay"
},
"source_ref": {
"$ref": "#/definitions/SourceRef"
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "When this overlay was created"
},
"version": {
"type": "string",
"description": "Version of the overlay schema"
},
"links": {
"type": "array",
"items": {
"$ref": "#/definitions/OverlayLink"
},
"description": "Links to related entities"
},
"conflicts": {
"type": "array",
"items": {
"$ref": "#/definitions/ConflictMarker"
},
"description": "Conflict markers from merge operations"
},
"provenance": {
"$ref": "#/definitions/OverlayProvenance"
},
"indexes": {
"$ref": "#/definitions/OverlayIndexes"
}
}
},
"SourceRef": {
"type": "object",
"description": "Reference to the source document/entity",
"required": ["type", "identifier"],
"properties": {
"type": {
"type": "string",
"enum": ["advisory", "vex", "sbom", "scan_result", "linkset", "observation"]
},
"identifier": {
"type": "string",
"description": "Unique identifier of the source (e.g., advisory ID, SBOM digest)"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "Content-addressable digest of the source"
},
"uri": {
"type": "string",
"format": "uri",
"description": "URI to retrieve the source"
},
"fetched_at": {
"type": "string",
"format": "date-time"
}
}
},
"OverlayLink": {
"type": "object",
"description": "Link between entities in the overlay graph",
"required": ["link_type", "source", "target"],
"properties": {
"link_id": {
"type": "string",
"format": "uuid"
},
"link_type": {
"type": "string",
"enum": [
"affects",
"mitigates",
"remediates",
"supersedes",
"references",
"contains",
"depends_on",
"exploits",
"derived_from"
],
"description": "Semantic relationship type"
},
"source": {
"$ref": "#/definitions/EntityRef"
},
"target": {
"$ref": "#/definitions/EntityRef"
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Confidence score for this link"
},
"evidence": {
"type": "array",
"items": {
"$ref": "#/definitions/LinkEvidence"
}
},
"metadata": {
"type": "object",
"additionalProperties": true
}
}
},
"EntityRef": {
"type": "object",
"description": "Reference to an entity in the graph",
"required": ["entity_type", "identifier"],
"properties": {
"entity_type": {
"type": "string",
"enum": ["vulnerability", "component", "product", "advisory", "vex_statement", "sbom", "finding"]
},
"identifier": {
"type": "string",
"description": "Entity identifier (CVE ID, PURL, product ID, etc.)"
},
"version": {
"type": "string",
"description": "Version specifier if applicable"
}
}
},
"LinkEvidence": {
"type": "object",
"description": "Evidence supporting a link relationship",
"required": ["type"],
"properties": {
"type": {
"type": "string",
"enum": ["explicit", "inferred", "heuristic", "manual"]
},
"source_ref": {
"$ref": "#/definitions/SourceRef"
},
"statement": {
"type": "string",
"description": "Evidence statement or justification"
},
"score": {
"type": "number",
"minimum": 0,
"maximum": 1
}
}
},
"ConflictMarker": {
"type": "object",
"description": "Marker for merge conflicts between overlapping sources",
"required": ["conflict_type", "entities", "resolution_status"],
"properties": {
"conflict_id": {
"type": "string",
"format": "uuid"
},
"conflict_type": {
"type": "string",
"enum": [
"status_mismatch",
"severity_mismatch",
"version_range_overlap",
"product_identity_conflict",
"justification_conflict",
"timestamp_ordering"
],
"description": "Type of conflict detected"
},
"entities": {
"type": "array",
"items": {
"$ref": "#/definitions/ConflictingEntity"
},
"minItems": 2,
"description": "Entities involved in the conflict"
},
"resolution_status": {
"type": "string",
"enum": ["unresolved", "auto_resolved", "manually_resolved", "deferred"],
"description": "Current resolution status"
},
"resolution": {
"$ref": "#/definitions/ConflictResolution"
},
"detected_at": {
"type": "string",
"format": "date-time"
}
}
},
"ConflictingEntity": {
"type": "object",
"description": "Entity involved in a conflict",
"required": ["source_ref", "value"],
"properties": {
"source_ref": {
"$ref": "#/definitions/SourceRef"
},
"value": {
"type": "object",
"additionalProperties": true,
"description": "The conflicting value from this source"
},
"trust_level": {
"type": "string",
"enum": ["authoritative", "trusted", "community", "unknown"],
"description": "Trust level of this source"
},
"precedence": {
"type": "integer",
"minimum": 0,
"description": "Precedence rank for resolution"
}
}
},
"ConflictResolution": {
"type": "object",
"description": "Resolution decision for a conflict",
"required": ["strategy", "resolved_at"],
"properties": {
"strategy": {
"type": "string",
"enum": [
"latest_wins",
"highest_precedence",
"most_specific",
"manual_selection",
"merge_composite"
],
"description": "Resolution strategy used"
},
"selected_source": {
"$ref": "#/definitions/SourceRef"
},
"resolved_value": {
"type": "object",
"additionalProperties": true,
"description": "The resolved value"
},
"justification": {
"type": "string",
"description": "Justification for the resolution"
},
"resolved_at": {
"type": "string",
"format": "date-time"
},
"resolved_by": {
"type": "string",
"description": "User or system that resolved the conflict"
}
}
},
"OverlayProvenance": {
"type": "object",
"description": "Provenance information for the overlay",
"properties": {
"created_at": {
"type": "string",
"format": "date-time"
},
"created_by": {
"type": "string"
},
"pipeline_id": {
"type": "string",
"description": "ID of the ingestion pipeline that created this overlay"
},
"pipeline_version": {
"type": "string"
},
"input_digests": {
"type": "array",
"items": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"description": "Digests of all inputs used to create this overlay"
},
"attestation_ref": {
"type": "string",
"description": "Reference to DSSE attestation for this overlay"
}
}
},
"OverlayIndexes": {
"type": "object",
"description": "Index configuration for graph inspector queries",
"properties": {
"by_vulnerability": {
"$ref": "#/definitions/IndexConfig"
},
"by_component": {
"$ref": "#/definitions/IndexConfig"
},
"by_product": {
"$ref": "#/definitions/IndexConfig"
},
"by_source": {
"$ref": "#/definitions/IndexConfig"
},
"by_conflict_status": {
"$ref": "#/definitions/IndexConfig"
}
}
},
"IndexConfig": {
"type": "object",
"description": "Configuration for a specific index",
"properties": {
"enabled": {
"type": "boolean",
"default": true
},
"fields": {
"type": "array",
"items": {
"type": "string"
},
"description": "Fields to include in the index"
},
"materialized": {
"type": "boolean",
"default": false,
"description": "Whether to use a materialized view"
},
"refresh_interval_seconds": {
"type": "integer",
"minimum": 0,
"description": "Refresh interval for materialized views (0 = immediate)"
}
}
},
"BatchVexFetchRequest": {
"type": "object",
"description": "Request for batched VEX document fetches",
"required": ["product_ids"],
"properties": {
"product_ids": {
"type": "array",
"items": {
"type": "string"
},
"description": "Product identifiers (PURLs, CPEs) to fetch VEX for"
},
"vulnerability_ids": {
"type": "array",
"items": {
"type": "string"
},
"description": "Optional: filter to specific vulnerabilities"
},
"include_overlays": {
"type": "boolean",
"default": true,
"description": "Include overlay metadata in response"
},
"include_conflicts": {
"type": "boolean",
"default": false,
"description": "Include conflict markers in response"
},
"max_results": {
"type": "integer",
"minimum": 1,
"maximum": 1000,
"default": 100
},
"continuation_token": {
"type": "string",
"description": "Token for pagination"
}
}
},
"BatchVexFetchResponse": {
"type": "object",
"description": "Response from batched VEX document fetch",
"required": ["results", "total_count"],
"properties": {
"results": {
"type": "array",
"items": {
"$ref": "#/definitions/VexOverlayResult"
}
},
"total_count": {
"type": "integer",
"minimum": 0
},
"continuation_token": {
"type": "string"
},
"fetch_timestamp": {
"type": "string",
"format": "date-time"
}
}
},
"VexOverlayResult": {
"type": "object",
"description": "VEX result with overlay metadata",
"required": ["product_id"],
"properties": {
"product_id": {
"type": "string"
},
"vex_statements": {
"type": "array",
"items": {
"$ref": "#/definitions/VexStatementSummary"
}
},
"overlay": {
"$ref": "#/definitions/LnmOverlay"
},
"conflicts_count": {
"type": "integer",
"minimum": 0
}
}
},
"VexStatementSummary": {
"type": "object",
"description": "Summary of a VEX statement",
"required": ["vulnerability_id", "status"],
"properties": {
"vulnerability_id": {
"type": "string"
},
"status": {
"type": "string",
"enum": ["not_affected", "affected", "fixed", "under_investigation"]
},
"justification": {
"type": "string"
},
"source_ref": {
"$ref": "#/definitions/SourceRef"
},
"timestamp": {
"type": "string",
"format": "date-time"
}
}
},
"GraphInspectorQuery": {
"type": "object",
"description": "Query for the graph inspector UI",
"required": ["query_type"],
"properties": {
"query_type": {
"type": "string",
"enum": [
"entity_neighbors",
"path_between",
"conflicts_for_entity",
"overlay_history",
"affected_products",
"vulnerability_coverage"
]
},
"entity_ref": {
"$ref": "#/definitions/EntityRef"
},
"filters": {
"$ref": "#/definitions/QueryFilters"
},
"depth": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"default": 2,
"description": "Graph traversal depth"
},
"include_metadata": {
"type": "boolean",
"default": true
}
}
},
"QueryFilters": {
"type": "object",
"description": "Filters for graph queries",
"properties": {
"link_types": {
"type": "array",
"items": {
"type": "string"
},
"description": "Filter by link types"
},
"entity_types": {
"type": "array",
"items": {
"type": "string"
},
"description": "Filter by entity types"
},
"source_types": {
"type": "array",
"items": {
"type": "string"
},
"description": "Filter by source types"
},
"time_range": {
"type": "object",
"properties": {
"from": {
"type": "string",
"format": "date-time"
},
"to": {
"type": "string",
"format": "date-time"
}
}
},
"min_confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"include_conflicts": {
"type": "boolean",
"default": false
},
"conflict_status": {
"type": "array",
"items": {
"type": "string",
"enum": ["unresolved", "auto_resolved", "manually_resolved", "deferred"]
}
}
}
}
},
"properties": {
"overlays": {
"type": "array",
"items": {
"$ref": "#/definitions/LnmOverlay"
}
}
},
"examples": [
{
"overlays": [
{
"overlay_id": "550e8400-e29b-41d4-a716-446655440000",
"source_type": "vex",
"source_ref": {
"type": "vex",
"identifier": "CSAF-2025-0001",
"digest": "sha256:abc123def456789...",
"uri": "https://security.vendor.com/csaf/2025-0001.json"
},
"timestamp": "2025-12-06T10:00:00Z",
"version": "1.0.0",
"links": [
{
"link_id": "660e8400-e29b-41d4-a716-446655440001",
"link_type": "affects",
"source": {
"entity_type": "vulnerability",
"identifier": "CVE-2025-1234"
},
"target": {
"entity_type": "component",
"identifier": "pkg:npm/lodash@4.17.20"
},
"confidence": 0.95,
"evidence": [
{
"type": "explicit",
"statement": "Vendor advisory explicitly lists lodash@4.17.20 as affected"
}
]
}
],
"conflicts": [
{
"conflict_id": "770e8400-e29b-41d4-a716-446655440002",
"conflict_type": "status_mismatch",
"entities": [
{
"source_ref": {
"type": "vex",
"identifier": "CSAF-2025-0001"
},
"value": {
"status": "affected"
},
"trust_level": "authoritative",
"precedence": 1
},
{
"source_ref": {
"type": "vex",
"identifier": "OPENVEX-COMM-2025-0001"
},
"value": {
"status": "not_affected"
},
"trust_level": "community",
"precedence": 3
}
],
"resolution_status": "auto_resolved",
"resolution": {
"strategy": "highest_precedence",
"selected_source": {
"type": "vex",
"identifier": "CSAF-2025-0001"
},
"resolved_value": {
"status": "affected"
},
"justification": "Authoritative vendor source has highest precedence",
"resolved_at": "2025-12-06T10:05:00Z",
"resolved_by": "lnm-pipeline"
},
"detected_at": "2025-12-06T10:00:00Z"
}
],
"provenance": {
"created_at": "2025-12-06T10:00:00Z",
"created_by": "lnm-pipeline",
"pipeline_id": "lnm-ingestion-001",
"pipeline_version": "2025.10.0",
"input_digests": [
"sha256:abc123...",
"sha256:def456..."
]
},
"indexes": {
"by_vulnerability": {
"enabled": true,
"fields": ["vulnerability_id", "status", "timestamp"],
"materialized": true,
"refresh_interval_seconds": 60
},
"by_component": {
"enabled": true,
"fields": ["component_purl", "version_range"],
"materialized": false
}
}
}
]
}
]
}

View File

@@ -0,0 +1,516 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/schemas/orchestrator-envelope.schema.json",
"title": "StellaOps Orchestrator Event Envelope Schema",
"description": "Schema for orchestrator-compatible event envelopes used by Scanner and other services. Unblocks SCANNER-EVENTS-16-301.",
"type": "object",
"definitions": {
"EventEnvelope": {
"type": "object",
"description": "Standard event envelope for orchestrator event bus",
"required": ["envelope_id", "event_type", "timestamp", "source", "payload"],
"properties": {
"envelope_id": {
"type": "string",
"format": "uuid",
"description": "Unique identifier for this event envelope"
},
"event_type": {
"type": "string",
"pattern": "^[a-z]+\\.[a-z_]+\\.[a-z_]+$",
"description": "Dot-notation event type (e.g., scanner.scan.completed)",
"examples": [
"scanner.scan.started",
"scanner.scan.completed",
"scanner.scan.failed",
"scanner.sbom.generated",
"scanner.vulnerability.detected",
"notifier.alert.sent",
"policy.evaluation.completed"
]
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 timestamp when event was created"
},
"source": {
"$ref": "#/definitions/EventSource"
},
"correlation_id": {
"type": "string",
"format": "uuid",
"description": "Correlation ID for tracing related events"
},
"causation_id": {
"type": "string",
"format": "uuid",
"description": "ID of the event that caused this event"
},
"tenant_id": {
"type": "string",
"format": "uuid"
},
"project_id": {
"type": "string",
"format": "uuid"
},
"payload": {
"type": "object",
"description": "Event-specific payload",
"additionalProperties": true
},
"metadata": {
"$ref": "#/definitions/EventMetadata"
},
"version": {
"type": "string",
"default": "1.0",
"description": "Event schema version"
}
}
},
"EventSource": {
"type": "object",
"description": "Source of the event",
"required": ["service", "instance_id"],
"properties": {
"service": {
"type": "string",
"description": "Service name (e.g., scanner, notifier, policy-engine)"
},
"version": {
"type": "string",
"description": "Service version"
},
"instance_id": {
"type": "string",
"description": "Instance identifier (hostname, pod name, etc.)"
},
"region": {
"type": "string",
"description": "Deployment region"
}
}
},
"EventMetadata": {
"type": "object",
"description": "Additional metadata for the event",
"properties": {
"trace_id": {
"type": "string",
"description": "OpenTelemetry trace ID"
},
"span_id": {
"type": "string",
"description": "OpenTelemetry span ID"
},
"priority": {
"type": "string",
"enum": ["low", "normal", "high", "critical"],
"default": "normal"
},
"ttl_seconds": {
"type": "integer",
"minimum": 0,
"description": "Time-to-live for the event"
},
"retry_count": {
"type": "integer",
"minimum": 0,
"default": 0
},
"idempotency_key": {
"type": "string",
"description": "Key for idempotent processing"
},
"content_type": {
"type": "string",
"default": "application/json"
},
"compression": {
"type": "string",
"enum": ["none", "gzip", "lz4"],
"default": "none"
}
}
},
"ScannerEventPayload": {
"type": "object",
"description": "Base payload for scanner events",
"properties": {
"scan_id": {
"type": "string",
"format": "uuid"
},
"job_id": {
"type": "string",
"format": "uuid"
},
"target": {
"$ref": "#/definitions/ScanTarget"
},
"status": {
"type": "string",
"enum": ["started", "in_progress", "completed", "failed", "cancelled"]
},
"started_at": {
"type": "string",
"format": "date-time"
},
"completed_at": {
"type": "string",
"format": "date-time"
},
"duration_ms": {
"type": "integer",
"minimum": 0
},
"results_summary": {
"$ref": "#/definitions/ScanResultsSummary"
},
"error": {
"$ref": "#/definitions/ErrorInfo"
}
}
},
"ScanTarget": {
"type": "object",
"description": "Target being scanned",
"required": ["type", "identifier"],
"properties": {
"type": {
"type": "string",
"enum": ["container_image", "repository", "filesystem", "sbom", "package"]
},
"identifier": {
"type": "string",
"description": "Target identifier (image name, repo URL, path)"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"tag": {
"type": "string"
},
"platform": {
"type": "string",
"description": "Platform (e.g., linux/amd64)"
}
}
},
"ScanResultsSummary": {
"type": "object",
"description": "Summary of scan results",
"properties": {
"total_vulnerabilities": {
"type": "integer",
"minimum": 0
},
"by_severity": {
"type": "object",
"properties": {
"critical": {
"type": "integer",
"minimum": 0
},
"high": {
"type": "integer",
"minimum": 0
},
"medium": {
"type": "integer",
"minimum": 0
},
"low": {
"type": "integer",
"minimum": 0
},
"info": {
"type": "integer",
"minimum": 0
}
}
},
"components_scanned": {
"type": "integer",
"minimum": 0
},
"sbom_generated": {
"type": "boolean"
},
"sbom_ref": {
"type": "string",
"description": "Reference to generated SBOM"
}
}
},
"ErrorInfo": {
"type": "object",
"description": "Error information for failed events",
"required": ["code", "message"],
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"details": {
"type": "object",
"additionalProperties": true
},
"stack_trace": {
"type": "string"
},
"recoverable": {
"type": "boolean",
"default": false
}
}
},
"VulnerabilityDetectedPayload": {
"type": "object",
"description": "Payload for vulnerability detection events",
"required": ["scan_id", "vulnerability"],
"properties": {
"scan_id": {
"type": "string",
"format": "uuid"
},
"vulnerability": {
"$ref": "#/definitions/VulnerabilityInfo"
},
"affected_component": {
"$ref": "#/definitions/ComponentInfo"
},
"reachability": {
"type": "string",
"enum": ["reachable", "unreachable", "potentially_reachable", "unknown"]
}
}
},
"VulnerabilityInfo": {
"type": "object",
"required": ["id", "severity"],
"properties": {
"id": {
"type": "string",
"description": "CVE ID or vulnerability identifier"
},
"severity": {
"type": "string",
"enum": ["critical", "high", "medium", "low", "info"]
},
"cvss_score": {
"type": "number",
"minimum": 0,
"maximum": 10
},
"cvss_vector": {
"type": "string"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"references": {
"type": "array",
"items": {
"type": "string",
"format": "uri"
}
},
"fix_available": {
"type": "boolean"
},
"fixed_version": {
"type": "string"
},
"kev_listed": {
"type": "boolean"
},
"epss_score": {
"type": "number",
"minimum": 0,
"maximum": 1
}
}
},
"ComponentInfo": {
"type": "object",
"required": ["purl"],
"properties": {
"purl": {
"type": "string"
},
"name": {
"type": "string"
},
"version": {
"type": "string"
},
"ecosystem": {
"type": "string"
},
"location": {
"type": "string",
"description": "Location in the target (e.g., layer, file path)"
}
}
},
"NotifierIngestionEvent": {
"type": "object",
"description": "Event structure for Notifier ingestion",
"required": ["envelope_id", "event_type", "severity_threshold_met"],
"properties": {
"envelope_id": {
"type": "string",
"format": "uuid"
},
"event_type": {
"type": "string"
},
"severity_threshold_met": {
"type": "boolean",
"description": "Whether event meets notification severity threshold"
},
"notification_channels": {
"type": "array",
"items": {
"type": "string",
"enum": ["email", "slack", "teams", "webhook", "pagerduty"]
}
},
"digest_eligible": {
"type": "boolean",
"description": "Whether event should be batched into digest"
},
"immediate_dispatch": {
"type": "boolean",
"description": "Whether event requires immediate dispatch"
}
}
},
"EventBatch": {
"type": "object",
"description": "Batch of events for bulk processing",
"required": ["batch_id", "events"],
"properties": {
"batch_id": {
"type": "string",
"format": "uuid"
},
"events": {
"type": "array",
"items": {
"$ref": "#/definitions/EventEnvelope"
},
"minItems": 1
},
"created_at": {
"type": "string",
"format": "date-time"
},
"total_count": {
"type": "integer",
"minimum": 1
}
}
},
"EventSubscription": {
"type": "object",
"description": "Subscription to event types",
"required": ["subscription_id", "event_patterns", "endpoint"],
"properties": {
"subscription_id": {
"type": "string",
"format": "uuid"
},
"event_patterns": {
"type": "array",
"items": {
"type": "string",
"description": "Glob pattern for event types (e.g., scanner.* or scanner.scan.completed)"
}
},
"endpoint": {
"type": "string",
"format": "uri",
"description": "Webhook endpoint for event delivery"
},
"filters": {
"type": "object",
"additionalProperties": true,
"description": "Additional filters on payload fields"
},
"enabled": {
"type": "boolean",
"default": true
}
}
}
},
"properties": {
"events": {
"type": "array",
"items": {
"$ref": "#/definitions/EventEnvelope"
}
}
},
"examples": [
{
"events": [
{
"envelope_id": "550e8400-e29b-41d4-a716-446655440000",
"event_type": "scanner.scan.completed",
"timestamp": "2025-12-06T10:00:00Z",
"source": {
"service": "scanner",
"version": "2025.10.0",
"instance_id": "scanner-pod-abc123"
},
"correlation_id": "660e8400-e29b-41d4-a716-446655440001",
"tenant_id": "770e8400-e29b-41d4-a716-446655440002",
"project_id": "880e8400-e29b-41d4-a716-446655440003",
"payload": {
"scan_id": "990e8400-e29b-41d4-a716-446655440004",
"job_id": "aa0e8400-e29b-41d4-a716-446655440005",
"target": {
"type": "container_image",
"identifier": "myregistry.io/app:v1.0.0",
"digest": "sha256:abc123def456..."
},
"status": "completed",
"started_at": "2025-12-06T09:55:00Z",
"completed_at": "2025-12-06T10:00:00Z",
"duration_ms": 300000,
"results_summary": {
"total_vulnerabilities": 15,
"by_severity": {
"critical": 1,
"high": 3,
"medium": 7,
"low": 4,
"info": 0
},
"components_scanned": 127,
"sbom_generated": true,
"sbom_ref": "s3://sboms/990e8400.../sbom.json"
}
},
"metadata": {
"trace_id": "abc123trace",
"span_id": "def456span",
"priority": "normal"
},
"version": "1.0"
}
]
}
]
}