Add signal contracts for reachability, exploitability, trust, and unknown symbols
- Introduced `ReachabilityState`, `RuntimeHit`, `ExploitabilitySignal`, `ReachabilitySignal`, `SignalEnvelope`, `SignalType`, `TrustSignal`, and `UnknownSymbolSignal` records to define various signal types and their properties. - Implemented JSON serialization attributes for proper data interchange. - Created project files for the new signal contracts library and corresponding test projects. - Added deterministic test fixtures for micro-interaction testing. - Included cryptographic keys for secure operations with cosign.
This commit is contained in:
628
docs/schemas/api-baseline.schema.json
Normal file
628
docs/schemas/api-baseline.schema.json
Normal file
@@ -0,0 +1,628 @@
|
||||
{
|
||||
"$id": "https://stella.ops/schema/api-baseline.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "ApiBaseline",
|
||||
"description": "APIG0101 API governance baseline contract for OpenAPI spec management, compatibility tracking, and changelog generation",
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{ "$ref": "#/$defs/BaselineDocument" },
|
||||
{ "$ref": "#/$defs/CompatibilityReport" },
|
||||
{ "$ref": "#/$defs/ChangelogEntry" },
|
||||
{ "$ref": "#/$defs/DiscoveryManifest" }
|
||||
],
|
||||
"$defs": {
|
||||
"BaselineDocument": {
|
||||
"type": "object",
|
||||
"required": ["documentType", "schemaVersion", "generatedAt", "specVersion", "services"],
|
||||
"properties": {
|
||||
"documentType": {
|
||||
"type": "string",
|
||||
"const": "API_BASELINE"
|
||||
},
|
||||
"schemaVersion": {
|
||||
"type": "integer",
|
||||
"const": 1,
|
||||
"description": "Baseline schema version"
|
||||
},
|
||||
"generatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO-8601 timestamp when baseline was generated"
|
||||
},
|
||||
"specVersion": {
|
||||
"type": "string",
|
||||
"description": "OpenAPI specification version",
|
||||
"examples": ["3.1.0", "3.0.3"]
|
||||
},
|
||||
"aggregateDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "SHA-256 digest of the composed aggregate spec"
|
||||
},
|
||||
"services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/ServiceSpec"
|
||||
},
|
||||
"minItems": 1,
|
||||
"description": "Per-service OpenAPI specifications"
|
||||
},
|
||||
"sharedComponents": {
|
||||
"$ref": "#/$defs/SharedComponentsRef",
|
||||
"description": "Reference to shared component library"
|
||||
},
|
||||
"governanceProfile": {
|
||||
"$ref": "#/$defs/GovernanceProfile",
|
||||
"description": "Governance rules applied to this baseline"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Additional baseline metadata"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ServiceSpec": {
|
||||
"type": "object",
|
||||
"required": ["serviceId", "specPath", "specDigest", "version"],
|
||||
"properties": {
|
||||
"serviceId": {
|
||||
"type": "string",
|
||||
"description": "Unique service identifier",
|
||||
"examples": ["authority", "scanner", "excititor", "concelier"]
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string",
|
||||
"description": "Human-readable service name"
|
||||
},
|
||||
"specPath": {
|
||||
"type": "string",
|
||||
"description": "Relative path to service OpenAPI spec",
|
||||
"examples": ["authority/openapi.yaml", "scanner/openapi.yaml"]
|
||||
},
|
||||
"specDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "SHA-256 digest of the service spec"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Service API version",
|
||||
"examples": ["v1", "v2-beta"]
|
||||
},
|
||||
"operationCount": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Number of operations defined"
|
||||
},
|
||||
"schemaCount": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Number of schemas defined"
|
||||
},
|
||||
"exampleCoverage": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Percentage of responses with examples"
|
||||
},
|
||||
"securitySchemes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Security schemes used by this service",
|
||||
"examples": [["bearerAuth", "mTLS", "OAuth2"]]
|
||||
},
|
||||
"endpoints": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/EndpointSummary"
|
||||
},
|
||||
"description": "Summary of endpoints in this service"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EndpointSummary": {
|
||||
"type": "object",
|
||||
"required": ["path", "method", "operationId"],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "API endpoint path"
|
||||
},
|
||||
"method": {
|
||||
"type": "string",
|
||||
"enum": ["get", "post", "put", "patch", "delete", "head", "options"],
|
||||
"description": "HTTP method"
|
||||
},
|
||||
"operationId": {
|
||||
"type": "string",
|
||||
"description": "Unique operation identifier (lowerCamelCase)"
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"description": "Short operation summary"
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Operation tags for grouping"
|
||||
},
|
||||
"deprecated": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether this endpoint is deprecated"
|
||||
},
|
||||
"hasRequestBody": {
|
||||
"type": "boolean",
|
||||
"description": "Whether operation accepts request body"
|
||||
},
|
||||
"responseStatuses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": "HTTP status codes returned"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SharedComponentsRef": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Path to shared components directory",
|
||||
"examples": ["_shared/"]
|
||||
},
|
||||
"digest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Digest of shared components bundle"
|
||||
},
|
||||
"schemas": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "List of shared schema names"
|
||||
},
|
||||
"securitySchemes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "List of shared security scheme names"
|
||||
},
|
||||
"parameters": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "List of shared parameter names"
|
||||
},
|
||||
"responses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "List of shared response names"
|
||||
}
|
||||
}
|
||||
},
|
||||
"GovernanceProfile": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"spectralRuleset": {
|
||||
"type": "string",
|
||||
"description": "Path to Spectral ruleset file",
|
||||
"examples": [".spectral.yaml"]
|
||||
},
|
||||
"rules": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/GovernanceRule"
|
||||
},
|
||||
"description": "Active governance rules"
|
||||
},
|
||||
"requiredExampleCoverage": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Minimum required example coverage percentage"
|
||||
},
|
||||
"breakingChangePolicy": {
|
||||
"type": "string",
|
||||
"enum": ["BLOCK", "WARN", "ALLOW"],
|
||||
"description": "Policy for breaking changes"
|
||||
}
|
||||
}
|
||||
},
|
||||
"GovernanceRule": {
|
||||
"type": "object",
|
||||
"required": ["ruleId", "severity"],
|
||||
"properties": {
|
||||
"ruleId": {
|
||||
"type": "string",
|
||||
"description": "Spectral rule identifier",
|
||||
"examples": ["stella-2xx-response-examples", "stella-pagination-params"]
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"enum": ["error", "warn", "info", "hint", "off"],
|
||||
"description": "Rule severity level"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Rule description"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CompatibilityReport": {
|
||||
"type": "object",
|
||||
"required": ["documentType", "generatedAt", "baselineDigest", "currentDigest", "compatible"],
|
||||
"properties": {
|
||||
"documentType": {
|
||||
"type": "string",
|
||||
"const": "COMPATIBILITY_REPORT"
|
||||
},
|
||||
"generatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"baselineDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Digest of baseline spec"
|
||||
},
|
||||
"currentDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Digest of current spec"
|
||||
},
|
||||
"compatible": {
|
||||
"type": "boolean",
|
||||
"description": "Whether current spec is backward compatible"
|
||||
},
|
||||
"breakingChanges": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/BreakingChange"
|
||||
},
|
||||
"description": "List of breaking changes detected"
|
||||
},
|
||||
"additiveChanges": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/ApiChange"
|
||||
},
|
||||
"description": "List of additive (non-breaking) changes"
|
||||
},
|
||||
"deprecations": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/Deprecation"
|
||||
},
|
||||
"description": "New deprecations introduced"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BreakingChange": {
|
||||
"type": "object",
|
||||
"required": ["changeType", "path", "description"],
|
||||
"properties": {
|
||||
"changeType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ENDPOINT_REMOVED",
|
||||
"METHOD_REMOVED",
|
||||
"REQUIRED_PARAM_ADDED",
|
||||
"PARAM_REMOVED",
|
||||
"RESPONSE_REMOVED",
|
||||
"SCHEMA_INCOMPATIBLE",
|
||||
"TYPE_CHANGED",
|
||||
"SECURITY_STRENGTHENED"
|
||||
],
|
||||
"description": "Type of breaking change"
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "JSON pointer to changed element"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Human-readable change description"
|
||||
},
|
||||
"service": {
|
||||
"type": "string",
|
||||
"description": "Affected service"
|
||||
},
|
||||
"operationId": {
|
||||
"type": "string",
|
||||
"description": "Affected operation"
|
||||
},
|
||||
"before": {
|
||||
"type": "string",
|
||||
"description": "Previous value (if applicable)"
|
||||
},
|
||||
"after": {
|
||||
"type": "string",
|
||||
"description": "New value (if applicable)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ApiChange": {
|
||||
"type": "object",
|
||||
"required": ["changeType", "path"],
|
||||
"properties": {
|
||||
"changeType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ENDPOINT_ADDED",
|
||||
"METHOD_ADDED",
|
||||
"OPTIONAL_PARAM_ADDED",
|
||||
"RESPONSE_ADDED",
|
||||
"SCHEMA_EXTENDED",
|
||||
"EXAMPLE_ADDED"
|
||||
],
|
||||
"description": "Type of additive change"
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "JSON pointer to changed element"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Human-readable change description"
|
||||
},
|
||||
"service": {
|
||||
"type": "string",
|
||||
"description": "Affected service"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Deprecation": {
|
||||
"type": "object",
|
||||
"required": ["path", "deprecatedAt"],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "JSON pointer to deprecated element"
|
||||
},
|
||||
"deprecatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When deprecation was introduced"
|
||||
},
|
||||
"removalDate": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Planned removal date"
|
||||
},
|
||||
"replacement": {
|
||||
"type": "string",
|
||||
"description": "Replacement endpoint/schema if available"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"description": "Reason for deprecation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ChangelogEntry": {
|
||||
"type": "object",
|
||||
"required": ["documentType", "version", "releaseDate", "changes"],
|
||||
"properties": {
|
||||
"documentType": {
|
||||
"type": "string",
|
||||
"const": "CHANGELOG_ENTRY"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "API version for this changelog entry"
|
||||
},
|
||||
"releaseDate": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Release date"
|
||||
},
|
||||
"specDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Digest of the spec at this version"
|
||||
},
|
||||
"changes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"added": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "New features/endpoints added"
|
||||
},
|
||||
"changed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Changes to existing features"
|
||||
},
|
||||
"deprecated": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Newly deprecated features"
|
||||
},
|
||||
"removed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Removed features"
|
||||
},
|
||||
"fixed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Bug fixes"
|
||||
},
|
||||
"security": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Security-related changes"
|
||||
}
|
||||
}
|
||||
},
|
||||
"contributors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Contributors to this release"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DiscoveryManifest": {
|
||||
"type": "object",
|
||||
"required": ["documentType", "spec", "version", "generatedAt"],
|
||||
"description": "OpenAPI discovery endpoint response (/.well-known/openapi)",
|
||||
"properties": {
|
||||
"documentType": {
|
||||
"type": "string",
|
||||
"const": "DISCOVERY_MANIFEST"
|
||||
},
|
||||
"spec": {
|
||||
"type": "string",
|
||||
"description": "Path to the aggregate OpenAPI spec",
|
||||
"examples": ["/stella.yaml"]
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "API version identifier",
|
||||
"examples": ["v1", "v2"]
|
||||
},
|
||||
"generatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When the spec was generated"
|
||||
},
|
||||
"specDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Digest of the spec file"
|
||||
},
|
||||
"extensions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"x-stellaops-profile": {
|
||||
"type": "string",
|
||||
"enum": ["aggregate", "per-service", "minimal"],
|
||||
"description": "Spec profile type"
|
||||
},
|
||||
"x-stellaops-schemaVersion": {
|
||||
"type": "string",
|
||||
"description": "Schema version for extensions"
|
||||
},
|
||||
"x-stellaops-services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Services included in aggregate"
|
||||
}
|
||||
}
|
||||
},
|
||||
"alternates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/AlternateSpec"
|
||||
},
|
||||
"description": "Alternative spec formats/versions"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AlternateSpec": {
|
||||
"type": "object",
|
||||
"required": ["format", "path"],
|
||||
"properties": {
|
||||
"format": {
|
||||
"type": "string",
|
||||
"enum": ["yaml", "json", "html"],
|
||||
"description": "Spec format"
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Path to alternate spec"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "OpenAPI version if different"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"documentType": "API_BASELINE",
|
||||
"schemaVersion": 1,
|
||||
"generatedAt": "2025-11-21T10:00:00Z",
|
||||
"specVersion": "3.1.0",
|
||||
"aggregateDigest": "sha256:7d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aee",
|
||||
"services": [
|
||||
{
|
||||
"serviceId": "authority",
|
||||
"displayName": "Authority Service",
|
||||
"specPath": "authority/openapi.yaml",
|
||||
"specDigest": "sha256:8d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aef",
|
||||
"version": "v1",
|
||||
"operationCount": 15,
|
||||
"schemaCount": 25,
|
||||
"exampleCoverage": 95.5,
|
||||
"securitySchemes": ["bearerAuth", "OAuth2"]
|
||||
}
|
||||
],
|
||||
"sharedComponents": {
|
||||
"path": "_shared/",
|
||||
"schemas": ["ErrorResponse", "PaginatedResponse", "HealthStatus"],
|
||||
"securitySchemes": ["bearerAuth", "mTLS"]
|
||||
},
|
||||
"governanceProfile": {
|
||||
"spectralRuleset": ".spectral.yaml",
|
||||
"requiredExampleCoverage": 90,
|
||||
"breakingChangePolicy": "BLOCK",
|
||||
"rules": [
|
||||
{
|
||||
"ruleId": "stella-2xx-response-examples",
|
||||
"severity": "error",
|
||||
"description": "Every 2xx response must include at least one example"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"documentType": "DISCOVERY_MANIFEST",
|
||||
"spec": "/stella.yaml",
|
||||
"version": "v1",
|
||||
"generatedAt": "2025-11-21T10:00:00Z",
|
||||
"specDigest": "sha256:7d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aee",
|
||||
"extensions": {
|
||||
"x-stellaops-profile": "aggregate",
|
||||
"x-stellaops-schemaVersion": "1.0.0",
|
||||
"x-stellaops-services": ["authority", "scanner", "excititor", "concelier"]
|
||||
},
|
||||
"alternates": [
|
||||
{ "format": "json", "path": "/stella.json" },
|
||||
{ "format": "html", "path": "/docs/api" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
365
docs/schemas/attestor-transport.schema.json
Normal file
365
docs/schemas/attestor-transport.schema.json
Normal file
@@ -0,0 +1,365 @@
|
||||
{
|
||||
"$id": "https://stella.ops/schema/attestor-transport.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "AttestorTransport",
|
||||
"description": "Attestor SDK transport contract for in-toto/DSSE attestation creation, verification, and storage",
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{ "$ref": "#/$defs/AttestationRequest" },
|
||||
{ "$ref": "#/$defs/AttestationResponse" },
|
||||
{ "$ref": "#/$defs/VerificationRequest" },
|
||||
{ "$ref": "#/$defs/VerificationResponse" }
|
||||
],
|
||||
"$defs": {
|
||||
"AttestationRequest": {
|
||||
"type": "object",
|
||||
"required": ["requestType", "requestId", "predicateType", "subject", "predicate"],
|
||||
"properties": {
|
||||
"requestType": {
|
||||
"type": "string",
|
||||
"const": "CREATE_ATTESTATION"
|
||||
},
|
||||
"requestId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Unique request identifier for idempotency"
|
||||
},
|
||||
"correlationId": {
|
||||
"type": "string",
|
||||
"description": "Correlation ID for tracing"
|
||||
},
|
||||
"predicateType": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "in-toto predicate type URI",
|
||||
"examples": [
|
||||
"https://slsa.dev/provenance/v1",
|
||||
"https://stella.ops/attestation/vex-export/v1",
|
||||
"https://stella.ops/attestation/vuln-scan/v1"
|
||||
]
|
||||
},
|
||||
"subject": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/AttestationSubject"
|
||||
},
|
||||
"minItems": 1,
|
||||
"description": "Subjects being attested"
|
||||
},
|
||||
"predicate": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Predicate payload (schema depends on predicateType)"
|
||||
},
|
||||
"signingOptions": {
|
||||
"$ref": "#/$defs/SigningOptions"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AttestationResponse": {
|
||||
"type": "object",
|
||||
"required": ["responseType", "requestId", "status"],
|
||||
"properties": {
|
||||
"responseType": {
|
||||
"type": "string",
|
||||
"const": "ATTESTATION_CREATED"
|
||||
},
|
||||
"requestId": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["SUCCESS", "FAILED", "PENDING"]
|
||||
},
|
||||
"attestation": {
|
||||
"$ref": "#/$defs/AttestationEnvelope",
|
||||
"description": "Created attestation envelope (if SUCCESS)"
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/$defs/AttestationError",
|
||||
"description": "Error details (if FAILED)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"VerificationRequest": {
|
||||
"type": "object",
|
||||
"required": ["requestType", "requestId", "envelope"],
|
||||
"properties": {
|
||||
"requestType": {
|
||||
"type": "string",
|
||||
"const": "VERIFY_ATTESTATION"
|
||||
},
|
||||
"requestId": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"envelope": {
|
||||
"type": "string",
|
||||
"description": "Base64-encoded DSSE envelope"
|
||||
},
|
||||
"verificationOptions": {
|
||||
"$ref": "#/$defs/VerificationOptions"
|
||||
}
|
||||
}
|
||||
},
|
||||
"VerificationResponse": {
|
||||
"type": "object",
|
||||
"required": ["responseType", "requestId", "verified"],
|
||||
"properties": {
|
||||
"responseType": {
|
||||
"type": "string",
|
||||
"const": "ATTESTATION_VERIFIED"
|
||||
},
|
||||
"requestId": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"verified": {
|
||||
"type": "boolean",
|
||||
"description": "Whether verification succeeded"
|
||||
},
|
||||
"verificationResult": {
|
||||
"$ref": "#/$defs/VerificationResult"
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/$defs/AttestationError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AttestationSubject": {
|
||||
"type": "object",
|
||||
"required": ["name", "digest"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Subject URI or name"
|
||||
},
|
||||
"digest": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Algorithm to digest mapping"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SigningOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"keyId": {
|
||||
"type": "string",
|
||||
"description": "Key identifier to use for signing"
|
||||
},
|
||||
"provider": {
|
||||
"type": "string",
|
||||
"description": "Crypto provider name",
|
||||
"examples": ["default", "pkcs11", "kms", "gost"]
|
||||
},
|
||||
"algorithm": {
|
||||
"type": "string",
|
||||
"description": "Signing algorithm",
|
||||
"examples": ["ES256", "RS256", "EdDSA", "GOST_R34_11_2012_256"]
|
||||
},
|
||||
"transparencyLog": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether to submit to Rekor transparency log"
|
||||
},
|
||||
"timestampAuthority": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "RFC 3161 timestamp authority URL"
|
||||
}
|
||||
}
|
||||
},
|
||||
"VerificationOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"trustedKeyIds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Trusted key identifiers"
|
||||
},
|
||||
"trustedIssuers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Trusted issuer identities"
|
||||
},
|
||||
"requireTransparencyLog": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Require valid transparency log entry"
|
||||
},
|
||||
"requireTimestamp": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Require trusted timestamp"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AttestationEnvelope": {
|
||||
"type": "object",
|
||||
"required": ["payloadType", "payload", "signatures"],
|
||||
"properties": {
|
||||
"payloadType": {
|
||||
"type": "string",
|
||||
"const": "application/vnd.in-toto+json",
|
||||
"description": "DSSE payload type"
|
||||
},
|
||||
"payload": {
|
||||
"type": "string",
|
||||
"description": "Base64-encoded in-toto statement"
|
||||
},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/DsseSignature"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"envelopeDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Digest of the envelope"
|
||||
},
|
||||
"transparencyLogEntry": {
|
||||
"$ref": "#/$defs/TransparencyLogEntry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DsseSignature": {
|
||||
"type": "object",
|
||||
"required": ["keyid", "sig"],
|
||||
"properties": {
|
||||
"keyid": {
|
||||
"type": "string",
|
||||
"description": "Key identifier"
|
||||
},
|
||||
"sig": {
|
||||
"type": "string",
|
||||
"description": "Base64-encoded signature"
|
||||
}
|
||||
}
|
||||
},
|
||||
"TransparencyLogEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"logIndex": {
|
||||
"type": "integer",
|
||||
"description": "Entry index in the log"
|
||||
},
|
||||
"logId": {
|
||||
"type": "string",
|
||||
"description": "Log identifier"
|
||||
},
|
||||
"integratedTime": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When entry was integrated"
|
||||
},
|
||||
"inclusionProof": {
|
||||
"type": "string",
|
||||
"description": "Base64-encoded inclusion proof"
|
||||
},
|
||||
"entryUri": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "URI to the log entry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"VerificationResult": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"signatureValid": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"predicateType": {
|
||||
"type": "string"
|
||||
},
|
||||
"subjects": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/AttestationSubject"
|
||||
}
|
||||
},
|
||||
"signerIdentity": {
|
||||
"type": "string",
|
||||
"description": "Verified signer identity"
|
||||
},
|
||||
"signedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"transparencyLogVerified": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"timestampVerified": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AttestationError": {
|
||||
"type": "object",
|
||||
"required": ["code", "message"],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"description": "Error code",
|
||||
"examples": [
|
||||
"KEY_NOT_FOUND",
|
||||
"SIGNATURE_INVALID",
|
||||
"PREDICATE_VALIDATION_FAILED",
|
||||
"TRANSPARENCY_LOG_UNAVAILABLE"
|
||||
]
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "Human-readable error message"
|
||||
},
|
||||
"details": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Additional error details"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"requestType": "CREATE_ATTESTATION",
|
||||
"requestId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"correlationId": "scan-job-12345",
|
||||
"predicateType": "https://stella.ops/attestation/vuln-scan/v1",
|
||||
"subject": [
|
||||
{
|
||||
"name": "registry.example.com/app:v1.2.3",
|
||||
"digest": {
|
||||
"sha256": "7d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aee"
|
||||
}
|
||||
}
|
||||
],
|
||||
"predicate": {
|
||||
"scanId": "scan-12345",
|
||||
"scanner": "stellaops-scanner/1.0.0",
|
||||
"completedAt": "2025-11-21T10:00:00Z",
|
||||
"vulnerabilities": {
|
||||
"critical": 2,
|
||||
"high": 5,
|
||||
"medium": 12,
|
||||
"low": 8
|
||||
}
|
||||
},
|
||||
"signingOptions": {
|
||||
"keyId": "scanner-signing-key-001",
|
||||
"algorithm": "ES256",
|
||||
"transparencyLog": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
847
docs/schemas/graph-platform.schema.json
Normal file
847
docs/schemas/graph-platform.schema.json
Normal file
@@ -0,0 +1,847 @@
|
||||
{
|
||||
"$id": "https://stella.ops/schema/graph-platform.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "GraphPlatform",
|
||||
"description": "CAGR0101 Graph platform contract for dependency visualization, SBOM graph analysis, and overlay queries",
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{ "$ref": "#/$defs/GraphNode" },
|
||||
{ "$ref": "#/$defs/GraphEdge" },
|
||||
{ "$ref": "#/$defs/GraphQuery" },
|
||||
{ "$ref": "#/$defs/GraphQueryResult" },
|
||||
{ "$ref": "#/$defs/GraphOverlay" },
|
||||
{ "$ref": "#/$defs/GraphSnapshot" },
|
||||
{ "$ref": "#/$defs/GraphMetrics" }
|
||||
],
|
||||
"$defs": {
|
||||
"GraphNode": {
|
||||
"type": "object",
|
||||
"required": ["nodeType", "nodeId", "label"],
|
||||
"description": "Node in the dependency/relationship graph",
|
||||
"properties": {
|
||||
"nodeType": {
|
||||
"type": "string",
|
||||
"const": "GRAPH_NODE"
|
||||
},
|
||||
"nodeId": {
|
||||
"type": "string",
|
||||
"description": "Unique node identifier (usually PURL or digest)"
|
||||
},
|
||||
"nodeKind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"PACKAGE",
|
||||
"IMAGE",
|
||||
"VULNERABILITY",
|
||||
"ADVISORY",
|
||||
"LICENSE",
|
||||
"FILE",
|
||||
"SERVICE",
|
||||
"NAMESPACE",
|
||||
"TENANT"
|
||||
],
|
||||
"description": "Kind of graph node"
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Human-readable node label"
|
||||
},
|
||||
"purl": {
|
||||
"type": "string",
|
||||
"description": "Package URL if applicable"
|
||||
},
|
||||
"digest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Content digest if applicable"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Version string if applicable"
|
||||
},
|
||||
"ecosystem": {
|
||||
"type": "string",
|
||||
"description": "Package ecosystem (npm, maven, pypi, etc.)"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Additional node metadata"
|
||||
},
|
||||
"position": {
|
||||
"$ref": "#/$defs/NodePosition",
|
||||
"description": "Layout position for visualization"
|
||||
},
|
||||
"style": {
|
||||
"$ref": "#/$defs/NodeStyle",
|
||||
"description": "Visual styling hints"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When node was created"
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When node was last updated"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NodePosition": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"x": {
|
||||
"type": "number",
|
||||
"description": "X coordinate"
|
||||
},
|
||||
"y": {
|
||||
"type": "number",
|
||||
"description": "Y coordinate"
|
||||
},
|
||||
"z": {
|
||||
"type": "number",
|
||||
"description": "Z coordinate (for 3D layouts)"
|
||||
},
|
||||
"layer": {
|
||||
"type": "integer",
|
||||
"description": "Layer/depth in hierarchical layout"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NodeStyle": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"color": {
|
||||
"type": "string",
|
||||
"description": "Node color (hex or named)"
|
||||
},
|
||||
"size": {
|
||||
"type": "number",
|
||||
"description": "Node size multiplier"
|
||||
},
|
||||
"shape": {
|
||||
"type": "string",
|
||||
"enum": ["circle", "rectangle", "diamond", "hexagon", "triangle"],
|
||||
"description": "Node shape"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"description": "Icon identifier"
|
||||
},
|
||||
"highlighted": {
|
||||
"type": "boolean",
|
||||
"description": "Whether node should be highlighted"
|
||||
}
|
||||
}
|
||||
},
|
||||
"GraphEdge": {
|
||||
"type": "object",
|
||||
"required": ["edgeType", "edgeId", "sourceId", "targetId", "relationship"],
|
||||
"description": "Edge connecting two nodes in the graph",
|
||||
"properties": {
|
||||
"edgeType": {
|
||||
"type": "string",
|
||||
"const": "GRAPH_EDGE"
|
||||
},
|
||||
"edgeId": {
|
||||
"type": "string",
|
||||
"description": "Unique edge identifier"
|
||||
},
|
||||
"sourceId": {
|
||||
"type": "string",
|
||||
"description": "Source node ID"
|
||||
},
|
||||
"targetId": {
|
||||
"type": "string",
|
||||
"description": "Target node ID"
|
||||
},
|
||||
"relationship": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"DEPENDS_ON",
|
||||
"DEV_DEPENDS_ON",
|
||||
"OPTIONAL_DEPENDS_ON",
|
||||
"CONTAINS",
|
||||
"AFFECTS",
|
||||
"FIXES",
|
||||
"LICENSES",
|
||||
"DESCRIBES",
|
||||
"BUILDS_FROM",
|
||||
"DEPLOYED_TO"
|
||||
],
|
||||
"description": "Type of relationship"
|
||||
},
|
||||
"weight": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"description": "Edge weight for algorithms"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Additional edge metadata"
|
||||
},
|
||||
"style": {
|
||||
"$ref": "#/$defs/EdgeStyle",
|
||||
"description": "Visual styling hints"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EdgeStyle": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"color": {
|
||||
"type": "string",
|
||||
"description": "Edge color"
|
||||
},
|
||||
"width": {
|
||||
"type": "number",
|
||||
"description": "Edge width"
|
||||
},
|
||||
"style": {
|
||||
"type": "string",
|
||||
"enum": ["solid", "dashed", "dotted"],
|
||||
"description": "Line style"
|
||||
},
|
||||
"animated": {
|
||||
"type": "boolean",
|
||||
"description": "Whether edge should animate"
|
||||
}
|
||||
}
|
||||
},
|
||||
"GraphQuery": {
|
||||
"type": "object",
|
||||
"required": ["queryType", "queryId"],
|
||||
"description": "Query against the graph",
|
||||
"properties": {
|
||||
"queryType": {
|
||||
"type": "string",
|
||||
"const": "GRAPH_QUERY"
|
||||
},
|
||||
"queryId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Unique query identifier"
|
||||
},
|
||||
"tenantId": {
|
||||
"type": "string",
|
||||
"description": "Tenant scope"
|
||||
},
|
||||
"operation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"SUBGRAPH",
|
||||
"SHORTEST_PATH",
|
||||
"NEIGHBORS",
|
||||
"IMPACT_ANALYSIS",
|
||||
"DEPENDENCY_TREE",
|
||||
"VULNERABILITY_REACH",
|
||||
"LICENSE_PROPAGATION"
|
||||
],
|
||||
"description": "Query operation type"
|
||||
},
|
||||
"rootNodes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Starting node IDs for traversal"
|
||||
},
|
||||
"filters": {
|
||||
"$ref": "#/$defs/QueryFilters",
|
||||
"description": "Filtering criteria"
|
||||
},
|
||||
"traversal": {
|
||||
"$ref": "#/$defs/TraversalOptions",
|
||||
"description": "Traversal options"
|
||||
},
|
||||
"pagination": {
|
||||
"$ref": "#/$defs/Pagination",
|
||||
"description": "Pagination options"
|
||||
},
|
||||
"timeout": {
|
||||
"type": "integer",
|
||||
"minimum": 100,
|
||||
"maximum": 60000,
|
||||
"description": "Query timeout in milliseconds"
|
||||
}
|
||||
}
|
||||
},
|
||||
"QueryFilters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"nodeKinds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Include only these node kinds"
|
||||
},
|
||||
"relationships": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Include only these relationship types"
|
||||
},
|
||||
"ecosystems": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Filter by ecosystems"
|
||||
},
|
||||
"severityMin": {
|
||||
"type": "string",
|
||||
"enum": ["CRITICAL", "HIGH", "MEDIUM", "LOW", "UNKNOWN"],
|
||||
"description": "Minimum severity for vulnerability nodes"
|
||||
},
|
||||
"dateRange": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"from": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"to": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
"description": "Date range filter"
|
||||
}
|
||||
}
|
||||
},
|
||||
"TraversalOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"direction": {
|
||||
"type": "string",
|
||||
"enum": ["OUTBOUND", "INBOUND", "BOTH"],
|
||||
"default": "OUTBOUND",
|
||||
"description": "Traversal direction"
|
||||
},
|
||||
"maxDepth": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 100,
|
||||
"default": 10,
|
||||
"description": "Maximum traversal depth"
|
||||
},
|
||||
"maxNodes": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 100000,
|
||||
"default": 10000,
|
||||
"description": "Maximum nodes to return"
|
||||
},
|
||||
"algorithm": {
|
||||
"type": "string",
|
||||
"enum": ["BFS", "DFS", "DIJKSTRA"],
|
||||
"default": "BFS",
|
||||
"description": "Traversal algorithm"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Pagination": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"limit": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 10000,
|
||||
"default": 100,
|
||||
"description": "Results per page"
|
||||
},
|
||||
"cursor": {
|
||||
"type": "string",
|
||||
"description": "Pagination cursor"
|
||||
},
|
||||
"sortBy": {
|
||||
"type": "string",
|
||||
"description": "Sort field"
|
||||
},
|
||||
"sortOrder": {
|
||||
"type": "string",
|
||||
"enum": ["asc", "desc"],
|
||||
"default": "asc"
|
||||
}
|
||||
}
|
||||
},
|
||||
"GraphQueryResult": {
|
||||
"type": "object",
|
||||
"required": ["resultType", "queryId", "completedAt"],
|
||||
"description": "Result of a graph query",
|
||||
"properties": {
|
||||
"resultType": {
|
||||
"type": "string",
|
||||
"const": "GRAPH_QUERY_RESULT"
|
||||
},
|
||||
"queryId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Query identifier"
|
||||
},
|
||||
"completedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When query completed"
|
||||
},
|
||||
"durationMs": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Query duration in milliseconds"
|
||||
},
|
||||
"nodes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/GraphNode"
|
||||
},
|
||||
"description": "Nodes in result"
|
||||
},
|
||||
"edges": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/GraphEdge"
|
||||
},
|
||||
"description": "Edges in result"
|
||||
},
|
||||
"statistics": {
|
||||
"$ref": "#/$defs/QueryStatistics",
|
||||
"description": "Query execution statistics"
|
||||
},
|
||||
"pagination": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"nextCursor": {
|
||||
"type": "string"
|
||||
},
|
||||
"hasMore": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"totalCount": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"truncated": {
|
||||
"type": "boolean",
|
||||
"description": "Whether results were truncated"
|
||||
}
|
||||
}
|
||||
},
|
||||
"QueryStatistics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"nodesScanned": {
|
||||
"type": "integer",
|
||||
"description": "Total nodes scanned"
|
||||
},
|
||||
"nodesReturned": {
|
||||
"type": "integer",
|
||||
"description": "Nodes returned in result"
|
||||
},
|
||||
"edgesScanned": {
|
||||
"type": "integer",
|
||||
"description": "Total edges scanned"
|
||||
},
|
||||
"edgesReturned": {
|
||||
"type": "integer",
|
||||
"description": "Edges returned in result"
|
||||
},
|
||||
"maxDepthReached": {
|
||||
"type": "integer",
|
||||
"description": "Maximum depth reached in traversal"
|
||||
},
|
||||
"cacheHit": {
|
||||
"type": "boolean",
|
||||
"description": "Whether result was served from cache"
|
||||
}
|
||||
}
|
||||
},
|
||||
"GraphOverlay": {
|
||||
"type": "object",
|
||||
"required": ["overlayType", "overlayId", "name"],
|
||||
"description": "Overlay layer for graph visualization",
|
||||
"properties": {
|
||||
"overlayType": {
|
||||
"type": "string",
|
||||
"const": "GRAPH_OVERLAY"
|
||||
},
|
||||
"overlayId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Unique overlay identifier"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Overlay name"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Overlay description"
|
||||
},
|
||||
"overlayKind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"VULNERABILITY_HEATMAP",
|
||||
"LICENSE_COMPLIANCE",
|
||||
"DEPENDENCY_AGE",
|
||||
"REACHABILITY",
|
||||
"SEVERITY_GRADIENT",
|
||||
"CUSTOM"
|
||||
],
|
||||
"description": "Type of overlay"
|
||||
},
|
||||
"nodeStyles": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/$defs/NodeStyle"
|
||||
},
|
||||
"description": "Node ID to style mapping"
|
||||
},
|
||||
"edgeStyles": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/$defs/EdgeStyle"
|
||||
},
|
||||
"description": "Edge ID to style mapping"
|
||||
},
|
||||
"legend": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/LegendItem"
|
||||
},
|
||||
"description": "Legend items for overlay"
|
||||
},
|
||||
"cachedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When overlay was cached"
|
||||
},
|
||||
"expiresAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When cache expires"
|
||||
}
|
||||
}
|
||||
},
|
||||
"LegendItem": {
|
||||
"type": "object",
|
||||
"required": ["label"],
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Legend label"
|
||||
},
|
||||
"color": {
|
||||
"type": "string",
|
||||
"description": "Color for this legend item"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Description of what this represents"
|
||||
}
|
||||
}
|
||||
},
|
||||
"GraphSnapshot": {
|
||||
"type": "object",
|
||||
"required": ["snapshotType", "snapshotId", "createdAt"],
|
||||
"description": "Point-in-time snapshot of graph state",
|
||||
"properties": {
|
||||
"snapshotType": {
|
||||
"type": "string",
|
||||
"const": "GRAPH_SNAPSHOT"
|
||||
},
|
||||
"snapshotId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Unique snapshot identifier"
|
||||
},
|
||||
"tenantId": {
|
||||
"type": "string",
|
||||
"description": "Tenant scope"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Snapshot name"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Snapshot description"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When snapshot was created"
|
||||
},
|
||||
"createdBy": {
|
||||
"type": "string",
|
||||
"description": "User/service that created snapshot"
|
||||
},
|
||||
"nodeCount": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Number of nodes in snapshot"
|
||||
},
|
||||
"edgeCount": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Number of edges in snapshot"
|
||||
},
|
||||
"digest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Content digest of snapshot"
|
||||
},
|
||||
"storageLocation": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Where snapshot data is stored"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Additional snapshot metadata"
|
||||
}
|
||||
}
|
||||
},
|
||||
"GraphMetrics": {
|
||||
"type": "object",
|
||||
"required": ["metricsType", "collectedAt"],
|
||||
"description": "Graph platform metrics for monitoring",
|
||||
"properties": {
|
||||
"metricsType": {
|
||||
"type": "string",
|
||||
"const": "GRAPH_METRICS"
|
||||
},
|
||||
"collectedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When metrics were collected"
|
||||
},
|
||||
"ingestLagSeconds": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Lag between event and graph update (graph_ingest_lag_seconds)"
|
||||
},
|
||||
"tileLatencySeconds": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Tile rendering latency (graph_tile_latency_seconds)"
|
||||
},
|
||||
"queryBudgetDeniedTotal": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Queries denied due to budget (graph_query_budget_denied_total)"
|
||||
},
|
||||
"overlayCacheHitRatio": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"description": "Overlay cache hit ratio (graph_overlay_cache_hit_ratio)"
|
||||
},
|
||||
"nodeCount": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Total nodes in graph"
|
||||
},
|
||||
"edgeCount": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Total edges in graph"
|
||||
},
|
||||
"queryRate": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Queries per second"
|
||||
},
|
||||
"avgQueryDurationMs": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Average query duration"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BenchmarkConfig": {
|
||||
"type": "object",
|
||||
"required": ["benchmarkType", "targetNodeCount"],
|
||||
"description": "Configuration for graph benchmarking (BENCH-GRAPH-21-001/002)",
|
||||
"properties": {
|
||||
"benchmarkType": {
|
||||
"type": "string",
|
||||
"const": "BENCHMARK_CONFIG"
|
||||
},
|
||||
"targetNodeCount": {
|
||||
"type": "integer",
|
||||
"minimum": 1000,
|
||||
"maximum": 1000000,
|
||||
"description": "Target node count for benchmark",
|
||||
"examples": [50000, 100000]
|
||||
},
|
||||
"targetEdgeRatio": {
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"maximum": 100,
|
||||
"default": 3,
|
||||
"description": "Target edges per node ratio"
|
||||
},
|
||||
"queryPatterns": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": ["SUBGRAPH", "SHORTEST_PATH", "IMPACT_ANALYSIS", "DEPENDENCY_TREE"]
|
||||
},
|
||||
"description": "Query patterns to benchmark"
|
||||
},
|
||||
"iterations": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"default": 100,
|
||||
"description": "Number of iterations per pattern"
|
||||
},
|
||||
"warmupIterations": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 10,
|
||||
"description": "Warmup iterations"
|
||||
},
|
||||
"memoryThresholdMb": {
|
||||
"type": "integer",
|
||||
"minimum": 100,
|
||||
"description": "Memory threshold in MB"
|
||||
},
|
||||
"latencyThresholdMs": {
|
||||
"type": "integer",
|
||||
"minimum": 10,
|
||||
"description": "P99 latency threshold in ms"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BenchmarkResult": {
|
||||
"type": "object",
|
||||
"required": ["resultType", "benchmarkId", "completedAt", "passed"],
|
||||
"description": "Result of graph benchmark run",
|
||||
"properties": {
|
||||
"resultType": {
|
||||
"type": "string",
|
||||
"const": "BENCHMARK_RESULT"
|
||||
},
|
||||
"benchmarkId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Benchmark run identifier"
|
||||
},
|
||||
"completedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When benchmark completed"
|
||||
},
|
||||
"passed": {
|
||||
"type": "boolean",
|
||||
"description": "Whether benchmark passed thresholds"
|
||||
},
|
||||
"nodeCount": {
|
||||
"type": "integer",
|
||||
"description": "Actual node count"
|
||||
},
|
||||
"edgeCount": {
|
||||
"type": "integer",
|
||||
"description": "Actual edge count"
|
||||
},
|
||||
"patternResults": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/PatternResult"
|
||||
},
|
||||
"description": "Results per query pattern"
|
||||
},
|
||||
"memoryPeakMb": {
|
||||
"type": "number",
|
||||
"description": "Peak memory usage in MB"
|
||||
},
|
||||
"totalDurationSeconds": {
|
||||
"type": "number",
|
||||
"description": "Total benchmark duration"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PatternResult": {
|
||||
"type": "object",
|
||||
"required": ["pattern", "iterations"],
|
||||
"properties": {
|
||||
"pattern": {
|
||||
"type": "string",
|
||||
"description": "Query pattern"
|
||||
},
|
||||
"iterations": {
|
||||
"type": "integer",
|
||||
"description": "Completed iterations"
|
||||
},
|
||||
"p50LatencyMs": {
|
||||
"type": "number",
|
||||
"description": "P50 latency"
|
||||
},
|
||||
"p95LatencyMs": {
|
||||
"type": "number",
|
||||
"description": "P95 latency"
|
||||
},
|
||||
"p99LatencyMs": {
|
||||
"type": "number",
|
||||
"description": "P99 latency"
|
||||
},
|
||||
"throughputQps": {
|
||||
"type": "number",
|
||||
"description": "Queries per second"
|
||||
},
|
||||
"passed": {
|
||||
"type": "boolean",
|
||||
"description": "Whether pattern passed threshold"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"queryType": "GRAPH_QUERY",
|
||||
"queryId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"tenantId": "acme-corp",
|
||||
"operation": "VULNERABILITY_REACH",
|
||||
"rootNodes": ["pkg:npm/lodash@4.17.21"],
|
||||
"filters": {
|
||||
"nodeKinds": ["PACKAGE", "VULNERABILITY"],
|
||||
"severityMin": "HIGH"
|
||||
},
|
||||
"traversal": {
|
||||
"direction": "INBOUND",
|
||||
"maxDepth": 5,
|
||||
"maxNodes": 1000
|
||||
},
|
||||
"timeout": 10000
|
||||
},
|
||||
{
|
||||
"metricsType": "GRAPH_METRICS",
|
||||
"collectedAt": "2025-11-21T10:00:00Z",
|
||||
"ingestLagSeconds": 0.5,
|
||||
"tileLatencySeconds": 0.12,
|
||||
"queryBudgetDeniedTotal": 42,
|
||||
"overlayCacheHitRatio": 0.85,
|
||||
"nodeCount": 150000,
|
||||
"edgeCount": 450000,
|
||||
"queryRate": 125.5,
|
||||
"avgQueryDurationMs": 45.2
|
||||
},
|
||||
{
|
||||
"benchmarkType": "BENCHMARK_CONFIG",
|
||||
"targetNodeCount": 100000,
|
||||
"targetEdgeRatio": 3,
|
||||
"queryPatterns": ["SUBGRAPH", "IMPACT_ANALYSIS", "DEPENDENCY_TREE"],
|
||||
"iterations": 100,
|
||||
"warmupIterations": 10,
|
||||
"memoryThresholdMb": 2048,
|
||||
"latencyThresholdMs": 500
|
||||
}
|
||||
]
|
||||
}
|
||||
608
docs/schemas/ledger-airgap-staleness.schema.json
Normal file
608
docs/schemas/ledger-airgap-staleness.schema.json
Normal file
@@ -0,0 +1,608 @@
|
||||
{
|
||||
"$id": "https://stella.ops/schema/ledger-airgap-staleness.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "LedgerAirgapStaleness",
|
||||
"description": "LEDGER-AIRGAP-56-002 staleness specification for air-gap provenance tracking and freshness enforcement",
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{ "$ref": "#/$defs/StalenessConfig" },
|
||||
{ "$ref": "#/$defs/BundleProvenance" },
|
||||
{ "$ref": "#/$defs/StalenessMetrics" },
|
||||
{ "$ref": "#/$defs/StalenessValidationResult" }
|
||||
],
|
||||
"$defs": {
|
||||
"StalenessConfig": {
|
||||
"type": "object",
|
||||
"required": ["configType", "freshnessThresholdSeconds"],
|
||||
"description": "Configuration for air-gap staleness enforcement policies",
|
||||
"properties": {
|
||||
"configType": {
|
||||
"type": "string",
|
||||
"const": "STALENESS_CONFIG"
|
||||
},
|
||||
"freshnessThresholdSeconds": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 604800,
|
||||
"description": "Maximum age in seconds before data is considered stale (default: 7 days = 604800)"
|
||||
},
|
||||
"enforcementMode": {
|
||||
"type": "string",
|
||||
"enum": ["STRICT", "WARN", "DISABLED"],
|
||||
"default": "STRICT",
|
||||
"description": "How staleness violations are handled"
|
||||
},
|
||||
"gracePeriodSeconds": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 86400,
|
||||
"description": "Grace period after threshold before hard enforcement (default: 1 day)"
|
||||
},
|
||||
"allowedDomains": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Domains exempt from staleness enforcement",
|
||||
"examples": [["vex-advisories", "vulnerability-feeds"]]
|
||||
},
|
||||
"notificationThresholds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/NotificationThreshold"
|
||||
},
|
||||
"description": "Alert thresholds for approaching staleness"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NotificationThreshold": {
|
||||
"type": "object",
|
||||
"required": ["percentOfThreshold", "severity"],
|
||||
"properties": {
|
||||
"percentOfThreshold": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 100,
|
||||
"description": "Percentage of freshness threshold to trigger notification"
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"enum": ["info", "warning", "critical"],
|
||||
"description": "Notification severity level"
|
||||
},
|
||||
"channels": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": ["email", "slack", "teams", "webhook", "metric"]
|
||||
},
|
||||
"description": "Notification delivery channels"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BundleProvenance": {
|
||||
"type": "object",
|
||||
"required": ["provenanceType", "bundleId", "importedAt", "sourceTimestamp"],
|
||||
"description": "Provenance record for an imported air-gap bundle",
|
||||
"properties": {
|
||||
"provenanceType": {
|
||||
"type": "string",
|
||||
"const": "BUNDLE_PROVENANCE"
|
||||
},
|
||||
"bundleId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Unique bundle identifier"
|
||||
},
|
||||
"domainId": {
|
||||
"type": "string",
|
||||
"description": "Bundle domain (vex-advisories, vulnerability-feeds, etc.)"
|
||||
},
|
||||
"importedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When bundle was imported into this environment"
|
||||
},
|
||||
"sourceTimestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Original generation timestamp from source environment"
|
||||
},
|
||||
"sourceEnvironment": {
|
||||
"type": "string",
|
||||
"description": "Source environment identifier",
|
||||
"examples": ["prod-us-east", "staging", "upstream-mirror"]
|
||||
},
|
||||
"bundleDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "SHA-256 digest of the bundle contents"
|
||||
},
|
||||
"manifestDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "SHA-256 digest of the bundle manifest"
|
||||
},
|
||||
"stalenessSeconds": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Calculated staleness at import time (importedAt - sourceTimestamp)"
|
||||
},
|
||||
"timeAnchor": {
|
||||
"$ref": "#/$defs/TimeAnchor",
|
||||
"description": "Time anchor used for staleness calculation"
|
||||
},
|
||||
"attestation": {
|
||||
"$ref": "#/$defs/BundleAttestation",
|
||||
"description": "Attestation covering this bundle"
|
||||
},
|
||||
"exports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/ExportRecord"
|
||||
},
|
||||
"description": "Exports included in this bundle"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Additional bundle metadata"
|
||||
}
|
||||
}
|
||||
},
|
||||
"TimeAnchor": {
|
||||
"type": "object",
|
||||
"required": ["anchorType", "timestamp"],
|
||||
"description": "Trusted time reference for staleness calculations",
|
||||
"properties": {
|
||||
"anchorType": {
|
||||
"type": "string",
|
||||
"enum": ["NTP", "ROUGHTIME", "HARDWARE_CLOCK", "ATTESTATION_TSA", "MANUAL"],
|
||||
"description": "Type of time anchor"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Anchor timestamp (UTC)"
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"description": "Time source identifier",
|
||||
"examples": ["pool.ntp.org", "roughtime.cloudflare.com", "tsa.stellaops.local"]
|
||||
},
|
||||
"uncertainty": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Time uncertainty in milliseconds"
|
||||
},
|
||||
"signatureDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Digest of time attestation signature if applicable"
|
||||
},
|
||||
"verified": {
|
||||
"type": "boolean",
|
||||
"description": "Whether time anchor was cryptographically verified"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BundleAttestation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"predicateType": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "in-toto predicate type",
|
||||
"examples": ["https://stella.ops/attestation/airgap-bundle/v1"]
|
||||
},
|
||||
"envelopeDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "DSSE envelope digest"
|
||||
},
|
||||
"signedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When attestation was signed"
|
||||
},
|
||||
"keyId": {
|
||||
"type": "string",
|
||||
"description": "Signing key identifier"
|
||||
},
|
||||
"transparencyLog": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Rekor transparency log entry if available"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ExportRecord": {
|
||||
"type": "object",
|
||||
"required": ["exportId", "key", "format", "createdAt", "artifactDigest"],
|
||||
"properties": {
|
||||
"exportId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Export identifier"
|
||||
},
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "Export key",
|
||||
"examples": ["vex-openvex-all", "vuln-critical-cve"]
|
||||
},
|
||||
"format": {
|
||||
"type": "string",
|
||||
"enum": ["openvex", "csaf", "cyclonedx", "spdx", "ndjson", "json"],
|
||||
"description": "Export data format"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When export was created"
|
||||
},
|
||||
"artifactDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Export artifact digest"
|
||||
},
|
||||
"recordCount": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Number of records in export"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StalenessMetrics": {
|
||||
"type": "object",
|
||||
"required": ["metricsType", "collectedAt"],
|
||||
"description": "Staleness metrics for monitoring and dashboards",
|
||||
"properties": {
|
||||
"metricsType": {
|
||||
"type": "string",
|
||||
"const": "STALENESS_METRICS"
|
||||
},
|
||||
"collectedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When metrics were collected"
|
||||
},
|
||||
"tenantId": {
|
||||
"type": "string",
|
||||
"description": "Tenant scope"
|
||||
},
|
||||
"domainMetrics": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/DomainStalenessMetric"
|
||||
},
|
||||
"description": "Per-domain staleness metrics"
|
||||
},
|
||||
"aggregates": {
|
||||
"$ref": "#/$defs/AggregateMetrics",
|
||||
"description": "Aggregate staleness statistics"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DomainStalenessMetric": {
|
||||
"type": "object",
|
||||
"required": ["domainId", "stalenessSeconds", "lastImportAt"],
|
||||
"properties": {
|
||||
"domainId": {
|
||||
"type": "string",
|
||||
"description": "Domain identifier"
|
||||
},
|
||||
"stalenessSeconds": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Current staleness in seconds"
|
||||
},
|
||||
"lastImportAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Last bundle import timestamp"
|
||||
},
|
||||
"lastSourceTimestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Source timestamp of last import"
|
||||
},
|
||||
"bundleCount": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Total bundles imported for this domain"
|
||||
},
|
||||
"isStale": {
|
||||
"type": "boolean",
|
||||
"description": "Whether domain data exceeds staleness threshold"
|
||||
},
|
||||
"percentOfThreshold": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Staleness as percentage of threshold"
|
||||
},
|
||||
"projectedStaleAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When data will become stale if no updates"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AggregateMetrics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"totalDomains": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Total domains tracked"
|
||||
},
|
||||
"staleDomains": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Domains exceeding staleness threshold"
|
||||
},
|
||||
"warningDomains": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Domains approaching staleness threshold"
|
||||
},
|
||||
"healthyDomains": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Domains within healthy staleness range"
|
||||
},
|
||||
"maxStalenessSeconds": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Maximum staleness across all domains"
|
||||
},
|
||||
"avgStalenessSeconds": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Average staleness across all domains"
|
||||
},
|
||||
"oldestBundle": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Timestamp of oldest bundle source data"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StalenessValidationResult": {
|
||||
"type": "object",
|
||||
"required": ["validationType", "validatedAt", "passed"],
|
||||
"description": "Result of staleness validation check",
|
||||
"properties": {
|
||||
"validationType": {
|
||||
"type": "string",
|
||||
"const": "STALENESS_VALIDATION"
|
||||
},
|
||||
"validatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When validation was performed"
|
||||
},
|
||||
"passed": {
|
||||
"type": "boolean",
|
||||
"description": "Whether validation passed"
|
||||
},
|
||||
"context": {
|
||||
"type": "string",
|
||||
"enum": ["EXPORT", "QUERY", "POLICY_EVAL", "ATTESTATION"],
|
||||
"description": "Context where validation was triggered"
|
||||
},
|
||||
"domainId": {
|
||||
"type": "string",
|
||||
"description": "Domain being validated"
|
||||
},
|
||||
"stalenessSeconds": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Current staleness at validation time"
|
||||
},
|
||||
"thresholdSeconds": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Threshold used for validation"
|
||||
},
|
||||
"enforcementMode": {
|
||||
"type": "string",
|
||||
"enum": ["STRICT", "WARN", "DISABLED"],
|
||||
"description": "Enforcement mode at validation time"
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/$defs/StalenessError",
|
||||
"description": "Error details if validation failed"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/StalenessWarning"
|
||||
},
|
||||
"description": "Warnings generated during validation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StalenessError": {
|
||||
"type": "object",
|
||||
"required": ["code", "message"],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ERR_AIRGAP_STALE",
|
||||
"ERR_AIRGAP_NO_BUNDLE",
|
||||
"ERR_AIRGAP_TIME_ANCHOR_MISSING",
|
||||
"ERR_AIRGAP_TIME_DRIFT",
|
||||
"ERR_AIRGAP_ATTESTATION_INVALID"
|
||||
],
|
||||
"description": "Error code"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "Human-readable error message"
|
||||
},
|
||||
"domainId": {
|
||||
"type": "string",
|
||||
"description": "Affected domain"
|
||||
},
|
||||
"stalenessSeconds": {
|
||||
"type": "integer",
|
||||
"description": "Actual staleness when error occurred"
|
||||
},
|
||||
"thresholdSeconds": {
|
||||
"type": "integer",
|
||||
"description": "Threshold that was exceeded"
|
||||
},
|
||||
"recommendation": {
|
||||
"type": "string",
|
||||
"description": "Recommended action to resolve"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StalenessWarning": {
|
||||
"type": "object",
|
||||
"required": ["code", "message"],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"WARN_AIRGAP_APPROACHING_STALE",
|
||||
"WARN_AIRGAP_TIME_UNCERTAINTY_HIGH",
|
||||
"WARN_AIRGAP_BUNDLE_OLD",
|
||||
"WARN_AIRGAP_NO_RECENT_IMPORT"
|
||||
],
|
||||
"description": "Warning code"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "Human-readable warning message"
|
||||
},
|
||||
"percentOfThreshold": {
|
||||
"type": "number",
|
||||
"description": "Current staleness as percentage of threshold"
|
||||
},
|
||||
"projectedStaleAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When data will become stale"
|
||||
}
|
||||
}
|
||||
},
|
||||
"LedgerProjectionUpdate": {
|
||||
"type": "object",
|
||||
"required": ["projectionId", "airgap"],
|
||||
"description": "Update to ledger_projection collection for staleness tracking",
|
||||
"properties": {
|
||||
"projectionId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Projection document ID"
|
||||
},
|
||||
"airgap": {
|
||||
"type": "object",
|
||||
"required": ["stalenessSeconds", "lastBundleId", "lastImportAt"],
|
||||
"properties": {
|
||||
"stalenessSeconds": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Current staleness in seconds"
|
||||
},
|
||||
"lastBundleId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Last imported bundle ID"
|
||||
},
|
||||
"lastImportAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When last bundle was imported"
|
||||
},
|
||||
"lastSourceTimestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Source timestamp of last bundle"
|
||||
},
|
||||
"timeAnchorAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Time anchor used for calculation"
|
||||
},
|
||||
"isStale": {
|
||||
"type": "boolean",
|
||||
"description": "Whether projection data is stale"
|
||||
}
|
||||
},
|
||||
"description": "Air-gap staleness fields for projection"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"configType": "STALENESS_CONFIG",
|
||||
"freshnessThresholdSeconds": 604800,
|
||||
"enforcementMode": "STRICT",
|
||||
"gracePeriodSeconds": 86400,
|
||||
"allowedDomains": ["local-overrides"],
|
||||
"notificationThresholds": [
|
||||
{
|
||||
"percentOfThreshold": 75,
|
||||
"severity": "warning",
|
||||
"channels": ["slack", "metric"]
|
||||
},
|
||||
{
|
||||
"percentOfThreshold": 90,
|
||||
"severity": "critical",
|
||||
"channels": ["email", "slack", "metric"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provenanceType": "BUNDLE_PROVENANCE",
|
||||
"bundleId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"domainId": "vex-advisories",
|
||||
"importedAt": "2025-11-21T10:00:00Z",
|
||||
"sourceTimestamp": "2025-11-20T08:00:00Z",
|
||||
"sourceEnvironment": "prod-us-east",
|
||||
"bundleDigest": "sha256:7d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aee",
|
||||
"stalenessSeconds": 93600,
|
||||
"timeAnchor": {
|
||||
"anchorType": "NTP",
|
||||
"timestamp": "2025-11-21T10:00:00Z",
|
||||
"source": "pool.ntp.org",
|
||||
"uncertainty": 50,
|
||||
"verified": true
|
||||
},
|
||||
"exports": [
|
||||
{
|
||||
"exportId": "660e8400-e29b-41d4-a716-446655440001",
|
||||
"key": "vex-openvex-all",
|
||||
"format": "openvex",
|
||||
"createdAt": "2025-11-20T08:00:00Z",
|
||||
"artifactDigest": "sha256:8d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aef",
|
||||
"recordCount": 15420
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"validationType": "STALENESS_VALIDATION",
|
||||
"validatedAt": "2025-11-28T14:30:00Z",
|
||||
"passed": false,
|
||||
"context": "EXPORT",
|
||||
"domainId": "vex-advisories",
|
||||
"stalenessSeconds": 691200,
|
||||
"thresholdSeconds": 604800,
|
||||
"enforcementMode": "STRICT",
|
||||
"error": {
|
||||
"code": "ERR_AIRGAP_STALE",
|
||||
"message": "VEX advisories data is stale (8 days old, threshold 7 days)",
|
||||
"domainId": "vex-advisories",
|
||||
"stalenessSeconds": 691200,
|
||||
"thresholdSeconds": 604800,
|
||||
"recommendation": "Import a fresh VEX bundle from upstream using 'stella airgap import'"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
281
docs/schemas/mirror-bundle.schema.json
Normal file
281
docs/schemas/mirror-bundle.schema.json
Normal file
@@ -0,0 +1,281 @@
|
||||
{
|
||||
"$id": "https://stella.ops/schema/mirror-bundle.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "MirrorBundle",
|
||||
"description": "Air-gap mirror bundle format for offline operation with DSSE signature support",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schemaVersion",
|
||||
"generatedAt",
|
||||
"domainId",
|
||||
"exports"
|
||||
],
|
||||
"properties": {
|
||||
"schemaVersion": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"description": "Bundle schema version for compatibility"
|
||||
},
|
||||
"generatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO-8601 timestamp when bundle was generated"
|
||||
},
|
||||
"targetRepository": {
|
||||
"type": "string",
|
||||
"description": "Target OCI repository for this bundle (optional)"
|
||||
},
|
||||
"domainId": {
|
||||
"type": "string",
|
||||
"description": "Domain identifier for bundle categorization",
|
||||
"examples": ["vex-advisories", "vulnerability-feeds", "policy-packs"]
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string",
|
||||
"description": "Human-readable domain display name"
|
||||
},
|
||||
"exports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/BundleExport"
|
||||
},
|
||||
"minItems": 1,
|
||||
"description": "Exported data sets in this bundle"
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"BundleExport": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"key",
|
||||
"format",
|
||||
"exportId",
|
||||
"createdAt",
|
||||
"artifactDigest"
|
||||
],
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "Export identifier key",
|
||||
"examples": ["vex-openvex-all", "vuln-critical-cve"]
|
||||
},
|
||||
"format": {
|
||||
"type": "string",
|
||||
"enum": ["openvex", "csaf", "cyclonedx", "spdx", "ndjson", "json"],
|
||||
"description": "Export data format"
|
||||
},
|
||||
"exportId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Unique export execution identifier"
|
||||
},
|
||||
"querySignature": {
|
||||
"type": "string",
|
||||
"description": "Hash of query parameters used for this export"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When this export was created"
|
||||
},
|
||||
"artifactSizeBytes": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Size of the exported artifact in bytes"
|
||||
},
|
||||
"artifactDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "SHA-256 digest of the artifact"
|
||||
},
|
||||
"consensusRevision": {
|
||||
"type": "string",
|
||||
"description": "Consensus revision for VEX exports"
|
||||
},
|
||||
"policyRevisionId": {
|
||||
"type": "string",
|
||||
"description": "Policy revision ID if policy was applied"
|
||||
},
|
||||
"policyDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Policy content digest"
|
||||
},
|
||||
"consensusDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Consensus document digest"
|
||||
},
|
||||
"scoreDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Score document digest"
|
||||
},
|
||||
"sourceProviders": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "VEX providers included in this export"
|
||||
},
|
||||
"attestation": {
|
||||
"$ref": "#/$defs/AttestationDescriptor",
|
||||
"description": "Attestation for this export if signed"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AttestationDescriptor": {
|
||||
"type": "object",
|
||||
"required": ["predicateType"],
|
||||
"properties": {
|
||||
"predicateType": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "in-toto predicate type URI"
|
||||
},
|
||||
"rekorLocation": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Sigstore Rekor transparency log entry"
|
||||
},
|
||||
"envelopeDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "DSSE envelope digest"
|
||||
},
|
||||
"signedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When the attestation was signed"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BundleSignature": {
|
||||
"type": "object",
|
||||
"required": ["algorithm", "keyId", "signedAt"],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Relative path to signature file"
|
||||
},
|
||||
"algorithm": {
|
||||
"type": "string",
|
||||
"description": "Signing algorithm used",
|
||||
"examples": ["ES256", "RS256", "EdDSA"]
|
||||
},
|
||||
"keyId": {
|
||||
"type": "string",
|
||||
"description": "Key identifier used for signing"
|
||||
},
|
||||
"provider": {
|
||||
"type": "string",
|
||||
"description": "Crypto provider name"
|
||||
},
|
||||
"signedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When the bundle was signed"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BundleManifest": {
|
||||
"type": "object",
|
||||
"required": ["schemaVersion", "generatedAt", "domainId", "bundle"],
|
||||
"description": "Domain manifest pointing to bundle and exports",
|
||||
"properties": {
|
||||
"schemaVersion": {
|
||||
"type": "integer"
|
||||
},
|
||||
"generatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"domainId": {
|
||||
"type": "string"
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string"
|
||||
},
|
||||
"targetRepository": {
|
||||
"type": "string"
|
||||
},
|
||||
"bundle": {
|
||||
"$ref": "#/$defs/FileDescriptor"
|
||||
},
|
||||
"exports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/ManifestExportEntry"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"FileDescriptor": {
|
||||
"type": "object",
|
||||
"required": ["path", "sizeBytes", "digest"],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Relative file path"
|
||||
},
|
||||
"sizeBytes": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"digest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$"
|
||||
},
|
||||
"signature": {
|
||||
"$ref": "#/$defs/BundleSignature"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ManifestExportEntry": {
|
||||
"type": "object",
|
||||
"required": ["key", "format", "exportId", "createdAt", "artifactDigest"],
|
||||
"properties": {
|
||||
"key": { "type": "string" },
|
||||
"format": { "type": "string" },
|
||||
"exportId": { "type": "string" },
|
||||
"querySignature": { "type": "string" },
|
||||
"createdAt": { "type": "string", "format": "date-time" },
|
||||
"artifactDigest": { "type": "string" },
|
||||
"artifactSizeBytes": { "type": "integer" },
|
||||
"consensusRevision": { "type": "string" },
|
||||
"policyRevisionId": { "type": "string" },
|
||||
"policyDigest": { "type": "string" },
|
||||
"consensusDigest": { "type": "string" },
|
||||
"scoreDigest": { "type": "string" },
|
||||
"sourceProviders": { "type": "array", "items": { "type": "string" } },
|
||||
"attestation": { "$ref": "#/$defs/AttestationDescriptor" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generatedAt": "2025-11-21T10:00:00Z",
|
||||
"targetRepository": "oci://registry.internal/stella/mirrors",
|
||||
"domainId": "vex-advisories",
|
||||
"displayName": "VEX Advisories",
|
||||
"exports": [
|
||||
{
|
||||
"key": "vex-openvex-all",
|
||||
"format": "openvex",
|
||||
"exportId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"querySignature": "abc123def456",
|
||||
"createdAt": "2025-11-21T10:00:00Z",
|
||||
"artifactSizeBytes": 1048576,
|
||||
"artifactDigest": "sha256:7d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aee",
|
||||
"sourceProviders": ["anchore", "github", "redhat"],
|
||||
"attestation": {
|
||||
"predicateType": "https://stella.ops/attestation/vex-export/v1",
|
||||
"signedAt": "2025-11-21T10:00:01Z",
|
||||
"envelopeDigest": "sha256:8d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aef"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
965
docs/schemas/php-analyzer-bootstrap.schema.json
Normal file
965
docs/schemas/php-analyzer-bootstrap.schema.json
Normal file
@@ -0,0 +1,965 @@
|
||||
{
|
||||
"$id": "https://stella.ops/schema/php-analyzer-bootstrap.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "PhpAnalyzerBootstrap",
|
||||
"description": "PHP Language Analyzer bootstrap specification for composer-based projects with autoload graph analysis",
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{ "$ref": "#/$defs/PluginManifest" },
|
||||
{ "$ref": "#/$defs/AnalyzerConfig" },
|
||||
{ "$ref": "#/$defs/AnalysisOutput" },
|
||||
{ "$ref": "#/$defs/CapabilityReport" }
|
||||
],
|
||||
"$defs": {
|
||||
"PluginManifest": {
|
||||
"type": "object",
|
||||
"required": ["schemaVersion", "id", "displayName", "version", "entryPoint", "capabilities"],
|
||||
"description": "Plugin manifest for language analyzer discovery and loading",
|
||||
"properties": {
|
||||
"schemaVersion": {
|
||||
"type": "string",
|
||||
"const": "1.0",
|
||||
"description": "Manifest schema version"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^stellaops\\.analyzer\\.lang\\.[a-z]+$",
|
||||
"description": "Unique plugin identifier",
|
||||
"examples": ["stellaops.analyzer.lang.php"]
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string",
|
||||
"description": "Human-readable plugin name",
|
||||
"examples": ["StellaOps PHP Analyzer"]
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9]+)?$",
|
||||
"description": "Semantic version"
|
||||
},
|
||||
"requiresRestart": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether scanner restart is required after plugin load"
|
||||
},
|
||||
"entryPoint": {
|
||||
"$ref": "#/$defs/EntryPoint",
|
||||
"description": "Plugin entry point configuration"
|
||||
},
|
||||
"capabilities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"language-analyzer",
|
||||
"php",
|
||||
"composer",
|
||||
"packagist",
|
||||
"autoload",
|
||||
"phar",
|
||||
"framework-detection",
|
||||
"extension-scan"
|
||||
]
|
||||
},
|
||||
"minItems": 1,
|
||||
"description": "Plugin capabilities"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"org.stellaops.analyzer.language": {
|
||||
"type": "string",
|
||||
"const": "php"
|
||||
},
|
||||
"org.stellaops.analyzer.kind": {
|
||||
"type": "string",
|
||||
"const": "language"
|
||||
},
|
||||
"org.stellaops.restart.required": {
|
||||
"type": "string",
|
||||
"enum": ["true", "false"]
|
||||
}
|
||||
},
|
||||
"description": "OCI-style metadata labels"
|
||||
},
|
||||
"dependencies": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/PluginDependency"
|
||||
},
|
||||
"description": "Required plugin dependencies"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EntryPoint": {
|
||||
"type": "object",
|
||||
"required": ["type", "assembly", "typeName"],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["dotnet", "native"],
|
||||
"description": "Entry point type"
|
||||
},
|
||||
"assembly": {
|
||||
"type": "string",
|
||||
"description": "Assembly filename",
|
||||
"examples": ["StellaOps.Scanner.Analyzers.Lang.Php.dll"]
|
||||
},
|
||||
"typeName": {
|
||||
"type": "string",
|
||||
"description": "Fully qualified type name",
|
||||
"examples": ["StellaOps.Scanner.Analyzers.Lang.Php.PhpAnalyzerPlugin"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"PluginDependency": {
|
||||
"type": "object",
|
||||
"required": ["pluginId", "versionRange"],
|
||||
"properties": {
|
||||
"pluginId": {
|
||||
"type": "string",
|
||||
"description": "Dependent plugin identifier"
|
||||
},
|
||||
"versionRange": {
|
||||
"type": "string",
|
||||
"description": "SemVer version range",
|
||||
"examples": [">=1.0.0", "^1.0.0", "1.x"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"AnalyzerConfig": {
|
||||
"type": "object",
|
||||
"required": ["configType", "analyzerId"],
|
||||
"description": "Runtime configuration for PHP analyzer",
|
||||
"properties": {
|
||||
"configType": {
|
||||
"type": "string",
|
||||
"const": "ANALYZER_CONFIG"
|
||||
},
|
||||
"analyzerId": {
|
||||
"type": "string",
|
||||
"const": "php"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether analyzer is enabled"
|
||||
},
|
||||
"composerDetection": {
|
||||
"$ref": "#/$defs/ComposerDetectionConfig",
|
||||
"description": "Composer manifest detection settings"
|
||||
},
|
||||
"autoloadAnalysis": {
|
||||
"$ref": "#/$defs/AutoloadAnalysisConfig",
|
||||
"description": "Autoload graph analysis settings"
|
||||
},
|
||||
"capabilityScanning": {
|
||||
"$ref": "#/$defs/CapabilityScanConfig",
|
||||
"description": "Runtime capability scanning settings"
|
||||
},
|
||||
"frameworkDetection": {
|
||||
"$ref": "#/$defs/FrameworkDetectionConfig",
|
||||
"description": "Framework detection settings"
|
||||
},
|
||||
"pharScanning": {
|
||||
"$ref": "#/$defs/PharScanConfig",
|
||||
"description": "PHAR archive scanning settings"
|
||||
},
|
||||
"extensionScanning": {
|
||||
"$ref": "#/$defs/ExtensionScanConfig",
|
||||
"description": "PHP extension detection settings"
|
||||
},
|
||||
"timeouts": {
|
||||
"$ref": "#/$defs/AnalyzerTimeouts",
|
||||
"description": "Per-phase timeout settings"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ComposerDetectionConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"searchPaths": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"default": ["composer.json"],
|
||||
"description": "Paths to search for composer manifests"
|
||||
},
|
||||
"includeLockfile": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Parse composer.lock for exact versions"
|
||||
},
|
||||
"includeInstalledJson": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Parse vendor/composer/installed.json"
|
||||
},
|
||||
"ignoreDevDependencies": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Skip require-dev packages"
|
||||
},
|
||||
"trustLockfileVersions": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Use lockfile versions as authoritative"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AutoloadAnalysisConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable autoload graph analysis"
|
||||
},
|
||||
"includePsr0": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Analyze PSR-0 autoload mappings"
|
||||
},
|
||||
"includePsr4": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Analyze PSR-4 autoload mappings"
|
||||
},
|
||||
"includeClassmap": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Analyze classmap autoloading"
|
||||
},
|
||||
"includeFiles": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Analyze files autoloading"
|
||||
},
|
||||
"maxDepth": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 100,
|
||||
"default": 50,
|
||||
"description": "Maximum autoload resolution depth"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CapabilityScanConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable capability scanning"
|
||||
},
|
||||
"detectFileOperations": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Detect file I/O capabilities"
|
||||
},
|
||||
"detectNetworkOperations": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Detect network capabilities"
|
||||
},
|
||||
"detectProcessOperations": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Detect process execution capabilities"
|
||||
},
|
||||
"detectCryptoOperations": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Detect cryptographic operations"
|
||||
},
|
||||
"maxFilesToScan": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"default": 10000,
|
||||
"description": "Maximum PHP files to scan"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FrameworkDetectionConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable framework detection"
|
||||
},
|
||||
"frameworks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"laravel",
|
||||
"symfony",
|
||||
"wordpress",
|
||||
"drupal",
|
||||
"magento",
|
||||
"yii",
|
||||
"codeigniter",
|
||||
"cakephp",
|
||||
"slim",
|
||||
"lumen",
|
||||
"zend",
|
||||
"laminas"
|
||||
]
|
||||
},
|
||||
"default": ["laravel", "symfony", "wordpress", "drupal"],
|
||||
"description": "Frameworks to detect"
|
||||
},
|
||||
"detectPlugins": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Detect framework plugins/bundles"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PharScanConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable PHAR archive scanning"
|
||||
},
|
||||
"extractContents": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Extract and analyze PHAR contents"
|
||||
},
|
||||
"verifySignatures": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Verify PHAR signatures"
|
||||
},
|
||||
"maxPharSize": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"default": 104857600,
|
||||
"description": "Maximum PHAR size to process (bytes)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ExtensionScanConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable extension scanning"
|
||||
},
|
||||
"checkPhpIni": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Parse php.ini for extensions"
|
||||
},
|
||||
"checkDockerConfig": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Parse Dockerfile for php-ext-install"
|
||||
},
|
||||
"requiredExtensions": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Extensions to verify presence"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AnalyzerTimeouts": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"composerParseMs": {
|
||||
"type": "integer",
|
||||
"minimum": 100,
|
||||
"default": 5000,
|
||||
"description": "Composer manifest parse timeout"
|
||||
},
|
||||
"autoloadAnalysisMs": {
|
||||
"type": "integer",
|
||||
"minimum": 100,
|
||||
"default": 30000,
|
||||
"description": "Autoload graph analysis timeout"
|
||||
},
|
||||
"capabilityScanMs": {
|
||||
"type": "integer",
|
||||
"minimum": 100,
|
||||
"default": 60000,
|
||||
"description": "Capability scan timeout"
|
||||
},
|
||||
"totalAnalysisMs": {
|
||||
"type": "integer",
|
||||
"minimum": 1000,
|
||||
"default": 300000,
|
||||
"description": "Total analysis timeout"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AnalysisOutput": {
|
||||
"type": "object",
|
||||
"required": ["outputType", "analyzerId", "completedAt", "packages"],
|
||||
"description": "PHP analyzer output with discovered packages",
|
||||
"properties": {
|
||||
"outputType": {
|
||||
"type": "string",
|
||||
"const": "ANALYSIS_OUTPUT"
|
||||
},
|
||||
"analyzerId": {
|
||||
"type": "string",
|
||||
"const": "php"
|
||||
},
|
||||
"completedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Analysis completion timestamp"
|
||||
},
|
||||
"durationMs": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Analysis duration in milliseconds"
|
||||
},
|
||||
"projectMetadata": {
|
||||
"$ref": "#/$defs/PhpProjectMetadata",
|
||||
"description": "Detected project metadata"
|
||||
},
|
||||
"packages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/PhpPackage"
|
||||
},
|
||||
"description": "Discovered packages"
|
||||
},
|
||||
"autoloadGraph": {
|
||||
"$ref": "#/$defs/AutoloadGraph",
|
||||
"description": "Autoload dependency graph"
|
||||
},
|
||||
"capabilities": {
|
||||
"$ref": "#/$defs/CapabilityReport",
|
||||
"description": "Detected runtime capabilities"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/AnalysisWarning"
|
||||
},
|
||||
"description": "Non-fatal warnings during analysis"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PhpProjectMetadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Project name from composer.json"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Project description"
|
||||
},
|
||||
"phpVersion": {
|
||||
"type": "string",
|
||||
"description": "Required PHP version constraint"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["project", "library", "metapackage", "composer-plugin"],
|
||||
"description": "Composer package type"
|
||||
},
|
||||
"license": {
|
||||
"type": "string",
|
||||
"description": "License identifier"
|
||||
},
|
||||
"framework": {
|
||||
"type": "string",
|
||||
"description": "Detected framework"
|
||||
},
|
||||
"frameworkVersion": {
|
||||
"type": "string",
|
||||
"description": "Detected framework version"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PhpPackage": {
|
||||
"type": "object",
|
||||
"required": ["name", "version", "purl"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Package name (vendor/package format)"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Installed version"
|
||||
},
|
||||
"purl": {
|
||||
"type": "string",
|
||||
"pattern": "^pkg:composer/",
|
||||
"description": "Package URL",
|
||||
"examples": ["pkg:composer/symfony/http-foundation@6.4.0"]
|
||||
},
|
||||
"componentKey": {
|
||||
"type": "string",
|
||||
"description": "Stable component identifier for ordering"
|
||||
},
|
||||
"isDev": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether package is a dev dependency"
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": ["lockfile", "installed.json", "manifest", "inferred"],
|
||||
"description": "How package was discovered"
|
||||
},
|
||||
"installPath": {
|
||||
"type": "string",
|
||||
"description": "Relative installation path"
|
||||
},
|
||||
"autoloadType": {
|
||||
"type": "string",
|
||||
"enum": ["psr-0", "psr-4", "classmap", "files"],
|
||||
"description": "Primary autoload type"
|
||||
},
|
||||
"license": {
|
||||
"type": "string",
|
||||
"description": "Package license"
|
||||
},
|
||||
"homepage": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Package homepage"
|
||||
},
|
||||
"sourceRef": {
|
||||
"$ref": "#/$defs/SourceReference",
|
||||
"description": "VCS source reference"
|
||||
},
|
||||
"distRef": {
|
||||
"$ref": "#/$defs/DistReference",
|
||||
"description": "Distribution reference"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SourceReference": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["git", "svn", "hg"],
|
||||
"description": "VCS type"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Repository URL"
|
||||
},
|
||||
"reference": {
|
||||
"type": "string",
|
||||
"description": "Commit/tag reference"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DistReference": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["zip", "tar", "gzip"],
|
||||
"description": "Distribution type"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Distribution URL"
|
||||
},
|
||||
"shasum": {
|
||||
"type": "string",
|
||||
"description": "Distribution checksum"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AutoloadGraph": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"nodes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/AutoloadNode"
|
||||
},
|
||||
"description": "Autoload graph nodes"
|
||||
},
|
||||
"edges": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/AutoloadEdge"
|
||||
},
|
||||
"description": "Autoload graph edges"
|
||||
},
|
||||
"entryPoints": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Application entry points"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AutoloadNode": {
|
||||
"type": "object",
|
||||
"required": ["id", "type"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Node identifier (namespace or file path)"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["namespace", "class", "file", "package"],
|
||||
"description": "Node type"
|
||||
},
|
||||
"package": {
|
||||
"type": "string",
|
||||
"description": "Owning package"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AutoloadEdge": {
|
||||
"type": "object",
|
||||
"required": ["from", "to", "edgeType"],
|
||||
"properties": {
|
||||
"from": {
|
||||
"type": "string",
|
||||
"description": "Source node ID"
|
||||
},
|
||||
"to": {
|
||||
"type": "string",
|
||||
"description": "Target node ID"
|
||||
},
|
||||
"edgeType": {
|
||||
"type": "string",
|
||||
"enum": ["autoloads", "includes", "requires", "uses"],
|
||||
"description": "Edge relationship type"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CapabilityReport": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reportType": {
|
||||
"type": "string",
|
||||
"const": "CAPABILITY_REPORT"
|
||||
},
|
||||
"fileOperations": {
|
||||
"$ref": "#/$defs/FileCapabilities"
|
||||
},
|
||||
"networkOperations": {
|
||||
"$ref": "#/$defs/NetworkCapabilities"
|
||||
},
|
||||
"processOperations": {
|
||||
"$ref": "#/$defs/ProcessCapabilities"
|
||||
},
|
||||
"cryptoOperations": {
|
||||
"$ref": "#/$defs/CryptoCapabilities"
|
||||
},
|
||||
"extensions": {
|
||||
"$ref": "#/$defs/ExtensionCapabilities"
|
||||
},
|
||||
"pharArchives": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/PharInfo"
|
||||
},
|
||||
"description": "Detected PHAR archives"
|
||||
},
|
||||
"evidences": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/CapabilityEvidence"
|
||||
},
|
||||
"description": "Evidence supporting capability detection"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FileCapabilities": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detected": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"reads": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"writes": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"deletes": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"executes": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tempFiles": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"uploads": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NetworkCapabilities": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detected": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"httpClient": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"sockets": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"curl": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"dnsLookup": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"smtp": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ProcessCapabilities": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detected": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"exec": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"shell_exec": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"system": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"passthru": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"proc_open": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"backticks": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CryptoCapabilities": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detected": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"openssl": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"sodium": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"mcrypt": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hash": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"password_hash": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ExtensionCapabilities": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"required": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Required PHP extensions"
|
||||
},
|
||||
"suggested": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Suggested PHP extensions"
|
||||
},
|
||||
"detected": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Extensions detected in code"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PharInfo": {
|
||||
"type": "object",
|
||||
"required": ["path"],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "PHAR file path"
|
||||
},
|
||||
"alias": {
|
||||
"type": "string",
|
||||
"description": "PHAR alias"
|
||||
},
|
||||
"signatureType": {
|
||||
"type": "string",
|
||||
"enum": ["md5", "sha1", "sha256", "sha512", "openssl", "none"],
|
||||
"description": "Signature algorithm"
|
||||
},
|
||||
"signatureValid": {
|
||||
"type": "boolean",
|
||||
"description": "Signature verification result"
|
||||
},
|
||||
"fileCount": {
|
||||
"type": "integer",
|
||||
"description": "Number of files in archive"
|
||||
},
|
||||
"uncompressedSize": {
|
||||
"type": "integer",
|
||||
"description": "Uncompressed size in bytes"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CapabilityEvidence": {
|
||||
"type": "object",
|
||||
"required": ["capability", "file", "line"],
|
||||
"properties": {
|
||||
"capability": {
|
||||
"type": "string",
|
||||
"description": "Capability type"
|
||||
},
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Source file path"
|
||||
},
|
||||
"line": {
|
||||
"type": "integer",
|
||||
"description": "Line number"
|
||||
},
|
||||
"function": {
|
||||
"type": "string",
|
||||
"description": "Function/method name"
|
||||
},
|
||||
"snippet": {
|
||||
"type": "string",
|
||||
"description": "Code snippet (redacted if sensitive)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AnalysisWarning": {
|
||||
"type": "object",
|
||||
"required": ["code", "message"],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"COMPOSER_LOCK_MISSING",
|
||||
"INSTALLED_JSON_MISSING",
|
||||
"AUTOLOAD_RESOLUTION_FAILED",
|
||||
"PHAR_SIGNATURE_INVALID",
|
||||
"TIMEOUT_EXCEEDED"
|
||||
]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"recoverable": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"schemaVersion": "1.0",
|
||||
"id": "stellaops.analyzer.lang.php",
|
||||
"displayName": "StellaOps PHP Analyzer",
|
||||
"version": "0.1.0",
|
||||
"requiresRestart": true,
|
||||
"entryPoint": {
|
||||
"type": "dotnet",
|
||||
"assembly": "StellaOps.Scanner.Analyzers.Lang.Php.dll",
|
||||
"typeName": "StellaOps.Scanner.Analyzers.Lang.Php.PhpAnalyzerPlugin"
|
||||
},
|
||||
"capabilities": [
|
||||
"language-analyzer",
|
||||
"php",
|
||||
"composer",
|
||||
"packagist",
|
||||
"autoload",
|
||||
"framework-detection"
|
||||
],
|
||||
"metadata": {
|
||||
"org.stellaops.analyzer.language": "php",
|
||||
"org.stellaops.analyzer.kind": "language",
|
||||
"org.stellaops.restart.required": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"outputType": "ANALYSIS_OUTPUT",
|
||||
"analyzerId": "php",
|
||||
"completedAt": "2025-11-21T10:15:00Z",
|
||||
"durationMs": 2500,
|
||||
"projectMetadata": {
|
||||
"name": "acme/webapp",
|
||||
"phpVersion": "^8.2",
|
||||
"type": "project",
|
||||
"framework": "laravel",
|
||||
"frameworkVersion": "10.0"
|
||||
},
|
||||
"packages": [
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "10.48.0",
|
||||
"purl": "pkg:composer/laravel/framework@10.48.0",
|
||||
"componentKey": "laravel/framework@10.48.0",
|
||||
"isDev": false,
|
||||
"source": "lockfile",
|
||||
"autoloadType": "psr-4",
|
||||
"license": "MIT"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "6.4.0",
|
||||
"purl": "pkg:composer/symfony/http-foundation@6.4.0",
|
||||
"componentKey": "symfony/http-foundation@6.4.0",
|
||||
"isDev": false,
|
||||
"source": "lockfile",
|
||||
"autoloadType": "psr-4",
|
||||
"license": "MIT"
|
||||
}
|
||||
],
|
||||
"capabilities": {
|
||||
"fileOperations": {
|
||||
"detected": true,
|
||||
"reads": true,
|
||||
"writes": true,
|
||||
"uploads": true
|
||||
},
|
||||
"networkOperations": {
|
||||
"detected": true,
|
||||
"httpClient": true,
|
||||
"curl": true
|
||||
},
|
||||
"extensions": {
|
||||
"required": ["openssl", "pdo", "mbstring", "tokenizer"],
|
||||
"detected": ["redis", "imagick"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
241
docs/schemas/provenance-feed.schema.json
Normal file
241
docs/schemas/provenance-feed.schema.json
Normal file
@@ -0,0 +1,241 @@
|
||||
{
|
||||
"$id": "https://stella.ops/schema/provenance-feed.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "ProvenanceFeed",
|
||||
"description": "SGSI0101 provenance feed contract for runtime facts and signal ingestion with attestation support",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schemaVersion",
|
||||
"feedId",
|
||||
"feedType",
|
||||
"generatedAt",
|
||||
"records"
|
||||
],
|
||||
"properties": {
|
||||
"schemaVersion": {
|
||||
"type": "integer",
|
||||
"const": 1,
|
||||
"description": "Schema version for compatibility"
|
||||
},
|
||||
"feedId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Unique feed generation identifier"
|
||||
},
|
||||
"feedType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"RUNTIME_FACTS",
|
||||
"SIGNAL_ENRICHMENT",
|
||||
"CAS_PROMOTION",
|
||||
"SCORING_OUTPUT",
|
||||
"AUTHORITY_SCOPES"
|
||||
],
|
||||
"description": "Type of provenance feed"
|
||||
},
|
||||
"generatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO-8601 timestamp of feed generation"
|
||||
},
|
||||
"sourceService": {
|
||||
"type": "string",
|
||||
"description": "Service that generated this feed",
|
||||
"examples": ["scanner-worker", "signal-aggregator", "cas-promoter"]
|
||||
},
|
||||
"tenantId": {
|
||||
"type": "string",
|
||||
"description": "Tenant scope for multi-tenant isolation"
|
||||
},
|
||||
"correlationId": {
|
||||
"type": "string",
|
||||
"description": "Correlation ID for tracing across services"
|
||||
},
|
||||
"records": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/ProvenanceRecord"
|
||||
},
|
||||
"description": "Provenance records in this feed"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Additional feed metadata"
|
||||
},
|
||||
"attestation": {
|
||||
"$ref": "#/$defs/FeedAttestation",
|
||||
"description": "Attestation covering this feed"
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"ProvenanceRecord": {
|
||||
"type": "object",
|
||||
"required": ["recordId", "recordType", "subject", "occurredAt"],
|
||||
"properties": {
|
||||
"recordId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Unique record identifier"
|
||||
},
|
||||
"recordType": {
|
||||
"type": "string",
|
||||
"description": "Type of provenance record",
|
||||
"examples": [
|
||||
"runtime.process.observed",
|
||||
"runtime.network.connection",
|
||||
"runtime.file.access",
|
||||
"signal.cache.available",
|
||||
"signal.enrichment.applied",
|
||||
"cas.promotion.completed",
|
||||
"scoring.output.generated"
|
||||
]
|
||||
},
|
||||
"subject": {
|
||||
"$ref": "#/$defs/ProvenanceSubject",
|
||||
"description": "Subject of this provenance record"
|
||||
},
|
||||
"occurredAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When this event occurred"
|
||||
},
|
||||
"observedBy": {
|
||||
"type": "string",
|
||||
"description": "Agent/sensor that observed this record"
|
||||
},
|
||||
"confidence": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"description": "Confidence score (0.0 - 1.0)"
|
||||
},
|
||||
"facts": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Type-specific facts for this record"
|
||||
},
|
||||
"evidence": {
|
||||
"$ref": "#/$defs/RecordEvidence",
|
||||
"description": "Evidence supporting this record"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ProvenanceSubject": {
|
||||
"type": "object",
|
||||
"required": ["type", "identifier"],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["CONTAINER", "PROCESS", "PACKAGE", "FILE", "NETWORK", "IMAGE"],
|
||||
"description": "Type of subject"
|
||||
},
|
||||
"identifier": {
|
||||
"type": "string",
|
||||
"description": "Subject identifier (image ref, package PURL, etc.)"
|
||||
},
|
||||
"digest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Subject content digest if applicable"
|
||||
},
|
||||
"namespace": {
|
||||
"type": "string",
|
||||
"description": "Namespace context (k8s namespace, etc.)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RecordEvidence": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sourceDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Digest of evidence source"
|
||||
},
|
||||
"captureMethod": {
|
||||
"type": "string",
|
||||
"enum": ["eBPF", "PROC_SCAN", "API_CALL", "LOG_ANALYSIS", "STATIC_ANALYSIS"],
|
||||
"description": "How evidence was captured"
|
||||
},
|
||||
"rawDataRef": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Reference to raw evidence data"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FeedAttestation": {
|
||||
"type": "object",
|
||||
"required": ["predicateType", "signedAt"],
|
||||
"properties": {
|
||||
"predicateType": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "in-toto predicate type",
|
||||
"examples": ["https://stella.ops/attestation/provenance-feed/v1"]
|
||||
},
|
||||
"signedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When the attestation was signed"
|
||||
},
|
||||
"keyId": {
|
||||
"type": "string",
|
||||
"description": "Signing key identifier"
|
||||
},
|
||||
"envelopeDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "DSSE envelope digest"
|
||||
},
|
||||
"transparencyLog": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Transparency log entry (Rekor)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"feedId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"feedType": "RUNTIME_FACTS",
|
||||
"generatedAt": "2025-11-21T10:00:00Z",
|
||||
"sourceService": "scanner-worker",
|
||||
"tenantId": "acme-corp",
|
||||
"correlationId": "scan-job-12345",
|
||||
"records": [
|
||||
{
|
||||
"recordId": "660e8400-e29b-41d4-a716-446655440001",
|
||||
"recordType": "runtime.process.observed",
|
||||
"subject": {
|
||||
"type": "CONTAINER",
|
||||
"identifier": "registry.example.com/app:v1.2.3",
|
||||
"digest": "sha256:7d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aee"
|
||||
},
|
||||
"occurredAt": "2025-11-21T09:55:00Z",
|
||||
"observedBy": "ebpf-agent",
|
||||
"confidence": 0.95,
|
||||
"facts": {
|
||||
"processName": "python3",
|
||||
"execPath": "/usr/bin/python3",
|
||||
"loadedLibraries": ["libssl.so.1.1", "libcrypto.so.1.1"]
|
||||
},
|
||||
"evidence": {
|
||||
"captureMethod": "eBPF",
|
||||
"rawDataRef": "s3://evidence-bucket/runtime/12345.json"
|
||||
}
|
||||
}
|
||||
],
|
||||
"attestation": {
|
||||
"predicateType": "https://stella.ops/attestation/provenance-feed/v1",
|
||||
"signedAt": "2025-11-21T10:00:01Z",
|
||||
"keyId": "scanner-signing-key-001"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
1001
docs/schemas/reachability-evidence-chain.schema.json
Normal file
1001
docs/schemas/reachability-evidence-chain.schema.json
Normal file
File diff suppressed because it is too large
Load Diff
417
docs/schemas/scanner-surface.schema.json
Normal file
417
docs/schemas/scanner-surface.schema.json
Normal file
@@ -0,0 +1,417 @@
|
||||
{
|
||||
"$id": "https://stella.ops/schema/scanner-surface.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "ScannerSurface",
|
||||
"description": "SCANNER-SURFACE-01 task contract defining scanner job execution, surface analysis, and result reporting",
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{ "$ref": "#/$defs/ScanTaskRequest" },
|
||||
{ "$ref": "#/$defs/ScanTaskResult" },
|
||||
{ "$ref": "#/$defs/ScanTaskProgress" }
|
||||
],
|
||||
"$defs": {
|
||||
"ScanTaskRequest": {
|
||||
"type": "object",
|
||||
"required": ["taskType", "taskId", "subject", "surfaces"],
|
||||
"properties": {
|
||||
"taskType": {
|
||||
"type": "string",
|
||||
"const": "SCAN_REQUEST"
|
||||
},
|
||||
"taskId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Unique task identifier"
|
||||
},
|
||||
"correlationId": {
|
||||
"type": "string",
|
||||
"description": "Correlation ID for tracing"
|
||||
},
|
||||
"tenantId": {
|
||||
"type": "string",
|
||||
"description": "Tenant scope"
|
||||
},
|
||||
"subject": {
|
||||
"$ref": "#/$defs/ScanSubject",
|
||||
"description": "Subject to scan"
|
||||
},
|
||||
"surfaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"VULNERABILITY",
|
||||
"SBOM",
|
||||
"SECRETS",
|
||||
"MALWARE",
|
||||
"COMPLIANCE",
|
||||
"LICENSE",
|
||||
"REACHABILITY"
|
||||
]
|
||||
},
|
||||
"minItems": 1,
|
||||
"description": "Analysis surfaces to execute"
|
||||
},
|
||||
"options": {
|
||||
"$ref": "#/$defs/ScanOptions"
|
||||
},
|
||||
"priority": {
|
||||
"type": "string",
|
||||
"enum": ["LOW", "NORMAL", "HIGH", "CRITICAL"],
|
||||
"default": "NORMAL"
|
||||
},
|
||||
"deadline": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Optional deadline for task completion"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ScanTaskResult": {
|
||||
"type": "object",
|
||||
"required": ["taskType", "taskId", "status", "completedAt"],
|
||||
"properties": {
|
||||
"taskType": {
|
||||
"type": "string",
|
||||
"const": "SCAN_RESULT"
|
||||
},
|
||||
"taskId": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["COMPLETED", "FAILED", "PARTIAL", "CANCELLED"]
|
||||
},
|
||||
"completedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"durationMs": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Task duration in milliseconds"
|
||||
},
|
||||
"subject": {
|
||||
"$ref": "#/$defs/ScanSubject"
|
||||
},
|
||||
"surfaceResults": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/SurfaceResult"
|
||||
}
|
||||
},
|
||||
"summary": {
|
||||
"$ref": "#/$defs/ScanSummary"
|
||||
},
|
||||
"artifacts": {
|
||||
"$ref": "#/$defs/ScanArtifacts"
|
||||
},
|
||||
"attestation": {
|
||||
"$ref": "#/$defs/AttestationRef"
|
||||
},
|
||||
"errors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/ScanError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ScanTaskProgress": {
|
||||
"type": "object",
|
||||
"required": ["taskType", "taskId", "phase", "progressPercent"],
|
||||
"properties": {
|
||||
"taskType": {
|
||||
"type": "string",
|
||||
"const": "SCAN_PROGRESS"
|
||||
},
|
||||
"taskId": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"phase": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"QUEUED",
|
||||
"STARTING",
|
||||
"PULLING_IMAGE",
|
||||
"EXTRACTING",
|
||||
"ANALYZING",
|
||||
"CORRELATING",
|
||||
"FINALIZING"
|
||||
]
|
||||
},
|
||||
"progressPercent": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
"currentSurface": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ScanSubject": {
|
||||
"type": "object",
|
||||
"required": ["type", "reference"],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["IMAGE", "DIRECTORY", "ARCHIVE", "SBOM", "REPOSITORY"],
|
||||
"description": "Type of scan subject"
|
||||
},
|
||||
"reference": {
|
||||
"type": "string",
|
||||
"description": "Subject reference (image ref, path, etc.)"
|
||||
},
|
||||
"digest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Content digest if known"
|
||||
},
|
||||
"platform": {
|
||||
"type": "string",
|
||||
"description": "Target platform (linux/amd64, etc.)"
|
||||
},
|
||||
"credentials": {
|
||||
"$ref": "#/$defs/CredentialRef",
|
||||
"description": "Credentials for accessing subject"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CredentialRef": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"secretName": {
|
||||
"type": "string",
|
||||
"description": "Secret name for credential lookup"
|
||||
},
|
||||
"provider": {
|
||||
"type": "string",
|
||||
"enum": ["VAULT", "K8S_SECRET", "ENV", "FILE"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ScanOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"severityThreshold": {
|
||||
"type": "string",
|
||||
"enum": ["CRITICAL", "HIGH", "MEDIUM", "LOW", "UNKNOWN"],
|
||||
"description": "Minimum severity to report"
|
||||
},
|
||||
"includeUnfixed": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Include vulnerabilities without fixes"
|
||||
},
|
||||
"sbomFormat": {
|
||||
"type": "string",
|
||||
"enum": ["SPDX_JSON", "CYCLONEDX_JSON", "SYFT_JSON"],
|
||||
"description": "SBOM output format"
|
||||
},
|
||||
"analyzers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Specific analyzers to run"
|
||||
},
|
||||
"skipAnalyzers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Analyzers to skip"
|
||||
},
|
||||
"layerAnalysis": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Perform per-layer analysis"
|
||||
},
|
||||
"generateAttestation": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Generate signed attestation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SurfaceResult": {
|
||||
"type": "object",
|
||||
"required": ["surface", "status"],
|
||||
"properties": {
|
||||
"surface": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["SUCCESS", "FAILED", "SKIPPED", "PARTIAL"]
|
||||
},
|
||||
"durationMs": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"artifactDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$"
|
||||
},
|
||||
"findings": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Surface-specific findings summary"
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/$defs/ScanError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ScanSummary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vulnerabilities": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"critical": { "type": "integer", "minimum": 0 },
|
||||
"high": { "type": "integer", "minimum": 0 },
|
||||
"medium": { "type": "integer", "minimum": 0 },
|
||||
"low": { "type": "integer", "minimum": 0 },
|
||||
"unknown": { "type": "integer", "minimum": 0 }
|
||||
}
|
||||
},
|
||||
"packages": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Total packages discovered"
|
||||
},
|
||||
"secretsDetected": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"complianceViolations": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"licenseIssues": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"ScanArtifacts": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sbom": {
|
||||
"$ref": "#/$defs/ArtifactRef"
|
||||
},
|
||||
"vulnerabilityReport": {
|
||||
"$ref": "#/$defs/ArtifactRef"
|
||||
},
|
||||
"secretsReport": {
|
||||
"$ref": "#/$defs/ArtifactRef"
|
||||
},
|
||||
"complianceReport": {
|
||||
"$ref": "#/$defs/ArtifactRef"
|
||||
},
|
||||
"reachabilityReport": {
|
||||
"$ref": "#/$defs/ArtifactRef"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ArtifactRef": {
|
||||
"type": "object",
|
||||
"required": ["digest", "mediaType"],
|
||||
"properties": {
|
||||
"digest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$"
|
||||
},
|
||||
"mediaType": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"location": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Storage location"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AttestationRef": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"envelopeDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$"
|
||||
},
|
||||
"predicateType": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"location": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"transparencyLog": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ScanError": {
|
||||
"type": "object",
|
||||
"required": ["code", "message"],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"IMAGE_PULL_FAILED",
|
||||
"ANALYZER_TIMEOUT",
|
||||
"INSUFFICIENT_RESOURCES",
|
||||
"INVALID_FORMAT"
|
||||
]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"surface": {
|
||||
"type": "string"
|
||||
},
|
||||
"retryable": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"taskType": "SCAN_REQUEST",
|
||||
"taskId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"correlationId": "pipeline-run-abc123",
|
||||
"tenantId": "acme-corp",
|
||||
"subject": {
|
||||
"type": "IMAGE",
|
||||
"reference": "registry.example.com/app:v1.2.3",
|
||||
"platform": "linux/amd64"
|
||||
},
|
||||
"surfaces": ["VULNERABILITY", "SBOM", "SECRETS"],
|
||||
"options": {
|
||||
"severityThreshold": "LOW",
|
||||
"sbomFormat": "SPDX_JSON",
|
||||
"generateAttestation": true
|
||||
},
|
||||
"priority": "NORMAL"
|
||||
}
|
||||
]
|
||||
}
|
||||
170
docs/schemas/timeline-event.schema.json
Normal file
170
docs/schemas/timeline-event.schema.json
Normal file
@@ -0,0 +1,170 @@
|
||||
{
|
||||
"$id": "https://stella.ops/schema/timeline-event.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "TimelineEvent",
|
||||
"description": "Unified timeline event schema for audit trail, observability, and evidence chain tracking",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"eventId",
|
||||
"tenantId",
|
||||
"eventType",
|
||||
"source",
|
||||
"occurredAt"
|
||||
],
|
||||
"properties": {
|
||||
"eventSeq": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Monotonically increasing sequence number for ordering"
|
||||
},
|
||||
"eventId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Globally unique event identifier"
|
||||
},
|
||||
"tenantId": {
|
||||
"type": "string",
|
||||
"description": "Tenant scope for multi-tenant isolation"
|
||||
},
|
||||
"eventType": {
|
||||
"type": "string",
|
||||
"description": "Event type identifier following namespace convention",
|
||||
"examples": [
|
||||
"scan.started",
|
||||
"scan.completed",
|
||||
"vex.imported",
|
||||
"policy.evaluated",
|
||||
"attestation.created",
|
||||
"mirror.bundle.registered"
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"description": "Service or component that emitted this event",
|
||||
"examples": ["scanner-worker", "policy-engine", "excititor", "orchestrator"]
|
||||
},
|
||||
"occurredAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO-8601 timestamp when the event actually occurred"
|
||||
},
|
||||
"receivedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO-8601 timestamp when the event was received by timeline indexer"
|
||||
},
|
||||
"correlationId": {
|
||||
"type": "string",
|
||||
"description": "Correlation ID linking related events across services"
|
||||
},
|
||||
"traceId": {
|
||||
"type": "string",
|
||||
"description": "OpenTelemetry trace ID for distributed tracing"
|
||||
},
|
||||
"spanId": {
|
||||
"type": "string",
|
||||
"description": "OpenTelemetry span ID within the trace"
|
||||
},
|
||||
"actor": {
|
||||
"type": "string",
|
||||
"description": "User, service account, or system that triggered the event"
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"enum": ["debug", "info", "warning", "error", "critical"],
|
||||
"default": "info",
|
||||
"description": "Event severity level"
|
||||
},
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Key-value attributes for filtering and querying"
|
||||
},
|
||||
"payloadHash": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "SHA-256 hash of the raw payload for integrity"
|
||||
},
|
||||
"rawPayloadJson": {
|
||||
"type": "string",
|
||||
"description": "Original event payload as JSON string"
|
||||
},
|
||||
"normalizedPayloadJson": {
|
||||
"type": "string",
|
||||
"description": "Canonicalized JSON for deterministic hashing"
|
||||
},
|
||||
"evidencePointer": {
|
||||
"$ref": "#/$defs/EvidencePointer",
|
||||
"description": "Reference to associated evidence bundle or attestation"
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"EvidencePointer": {
|
||||
"type": "object",
|
||||
"required": ["type"],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["BUNDLE", "ATTESTATION", "MANIFEST", "ARTIFACT"],
|
||||
"description": "Type of evidence being referenced"
|
||||
},
|
||||
"bundleId": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Evidence bundle identifier"
|
||||
},
|
||||
"bundleDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Content digest of the evidence bundle"
|
||||
},
|
||||
"attestationSubject": {
|
||||
"type": "string",
|
||||
"description": "Subject URI for the attestation"
|
||||
},
|
||||
"attestationDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Digest of the attestation envelope"
|
||||
},
|
||||
"manifestUri": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "URI to the evidence manifest"
|
||||
},
|
||||
"lockerPath": {
|
||||
"type": "string",
|
||||
"description": "Path within evidence locker storage"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"eventSeq": 12345,
|
||||
"eventId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"tenantId": "acme-corp",
|
||||
"eventType": "scan.completed",
|
||||
"source": "scanner-worker",
|
||||
"occurredAt": "2025-11-21T10:15:00Z",
|
||||
"receivedAt": "2025-11-21T10:15:01Z",
|
||||
"correlationId": "job-abc123",
|
||||
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
|
||||
"actor": "service:scanner-worker",
|
||||
"severity": "info",
|
||||
"attributes": {
|
||||
"image": "registry.example.com/app:v1.2.3",
|
||||
"vulnerabilityCount": "42",
|
||||
"criticalCount": "3"
|
||||
},
|
||||
"payloadHash": "sha256:7d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aee",
|
||||
"evidencePointer": {
|
||||
"type": "BUNDLE",
|
||||
"bundleId": "660e8400-e29b-41d4-a716-446655440001",
|
||||
"bundleDigest": "sha256:8d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aef"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
303
docs/schemas/vex-normalization.schema.json
Normal file
303
docs/schemas/vex-normalization.schema.json
Normal file
@@ -0,0 +1,303 @@
|
||||
{
|
||||
"$id": "https://stella.ops/schema/vex-normalization.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "VexNormalization",
|
||||
"description": "Normalized VEX representation supporting OpenVEX, CSAF VEX, and CycloneDX VEX formats with unified semantics",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schemaVersion",
|
||||
"documentId",
|
||||
"sourceFormat",
|
||||
"statements"
|
||||
],
|
||||
"properties": {
|
||||
"schemaVersion": {
|
||||
"type": "integer",
|
||||
"const": 1,
|
||||
"description": "Schema version for forward compatibility"
|
||||
},
|
||||
"documentId": {
|
||||
"type": "string",
|
||||
"description": "Unique document identifier derived from source VEX",
|
||||
"examples": ["openvex:ghsa-2022-0001", "csaf:rhsa-2023-1234"]
|
||||
},
|
||||
"sourceFormat": {
|
||||
"type": "string",
|
||||
"enum": ["OPENVEX", "CSAF_VEX", "CYCLONEDX_VEX", "SPDX_VEX", "STELLAOPS"],
|
||||
"description": "Original VEX document format before normalization"
|
||||
},
|
||||
"sourceDigest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "SHA-256 digest of original source document"
|
||||
},
|
||||
"sourceUri": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "URI where source document was obtained"
|
||||
},
|
||||
"issuer": {
|
||||
"$ref": "#/$defs/VexIssuer",
|
||||
"description": "Issuing authority for this VEX document"
|
||||
},
|
||||
"issuedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO-8601 timestamp when VEX was originally issued"
|
||||
},
|
||||
"lastUpdatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO-8601 timestamp when VEX was last modified"
|
||||
},
|
||||
"statements": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/NormalizedStatement"
|
||||
},
|
||||
"minItems": 1,
|
||||
"description": "Normalized VEX statements extracted from source"
|
||||
},
|
||||
"provenance": {
|
||||
"$ref": "#/$defs/NormalizationProvenance",
|
||||
"description": "Metadata about the normalization process"
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"VexIssuer": {
|
||||
"type": "object",
|
||||
"required": ["id", "name"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique issuer identifier (e.g., PURL, domain)",
|
||||
"examples": ["pkg:github/anchore", "redhat.com", "github.com/github"]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable issuer name"
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"enum": ["VENDOR", "DISTRIBUTOR", "COMMUNITY", "INTERNAL", "AGGREGATOR"],
|
||||
"description": "Issuer category for trust weighting"
|
||||
},
|
||||
"trustTier": {
|
||||
"type": "string",
|
||||
"enum": ["AUTHORITATIVE", "TRUSTED", "UNTRUSTED", "UNKNOWN"],
|
||||
"description": "Trust tier for policy evaluation"
|
||||
},
|
||||
"keyFingerprints": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Known signing key fingerprints for this issuer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NormalizedStatement": {
|
||||
"type": "object",
|
||||
"required": ["statementId", "vulnerabilityId", "product", "status"],
|
||||
"properties": {
|
||||
"statementId": {
|
||||
"type": "string",
|
||||
"description": "Unique statement identifier within this document"
|
||||
},
|
||||
"vulnerabilityId": {
|
||||
"type": "string",
|
||||
"description": "CVE, GHSA, or other vulnerability identifier",
|
||||
"examples": ["CVE-2023-12345", "GHSA-xxxx-yyyy-zzzz"]
|
||||
},
|
||||
"vulnerabilityAliases": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Known aliases for this vulnerability"
|
||||
},
|
||||
"product": {
|
||||
"$ref": "#/$defs/NormalizedProduct"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["not_affected", "affected", "fixed", "under_investigation"],
|
||||
"description": "Normalized VEX status using OpenVEX terminology"
|
||||
},
|
||||
"statusNotes": {
|
||||
"type": "string",
|
||||
"description": "Additional notes about the status determination"
|
||||
},
|
||||
"justification": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"component_not_present",
|
||||
"vulnerable_code_not_present",
|
||||
"vulnerable_code_not_in_execute_path",
|
||||
"vulnerable_code_cannot_be_controlled_by_adversary",
|
||||
"inline_mitigations_already_exist"
|
||||
],
|
||||
"description": "Normalized justification when status is not_affected"
|
||||
},
|
||||
"impactStatement": {
|
||||
"type": "string",
|
||||
"description": "Impact description when status is affected"
|
||||
},
|
||||
"actionStatement": {
|
||||
"type": "string",
|
||||
"description": "Recommended action to remediate"
|
||||
},
|
||||
"actionStatementTimestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"versions": {
|
||||
"$ref": "#/$defs/VersionRange",
|
||||
"description": "Version constraints for this statement"
|
||||
},
|
||||
"subcomponents": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/NormalizedProduct"
|
||||
},
|
||||
"description": "Specific subcomponents affected within the product"
|
||||
},
|
||||
"firstSeen": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When this statement was first observed"
|
||||
},
|
||||
"lastSeen": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When this statement was last confirmed"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NormalizedProduct": {
|
||||
"type": "object",
|
||||
"required": ["key"],
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "Canonical product key (preferably PURL)"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable product name"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Specific version if applicable"
|
||||
},
|
||||
"purl": {
|
||||
"type": "string",
|
||||
"pattern": "^pkg:",
|
||||
"description": "Package URL if available"
|
||||
},
|
||||
"cpe": {
|
||||
"type": "string",
|
||||
"pattern": "^cpe:",
|
||||
"description": "CPE identifier if available"
|
||||
},
|
||||
"hashes": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Content hashes (algorithm -> value)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"VersionRange": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"affected": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Version expressions for affected versions"
|
||||
},
|
||||
"fixed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Version expressions for fixed versions"
|
||||
},
|
||||
"unaffected": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Version expressions for unaffected versions"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NormalizationProvenance": {
|
||||
"type": "object",
|
||||
"required": ["normalizedAt", "normalizer"],
|
||||
"properties": {
|
||||
"normalizedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When normalization was performed"
|
||||
},
|
||||
"normalizer": {
|
||||
"type": "string",
|
||||
"description": "Service/version that performed normalization",
|
||||
"examples": ["stellaops-excititor/1.0.0"]
|
||||
},
|
||||
"sourceRevision": {
|
||||
"type": "string",
|
||||
"description": "Source document revision if tracked"
|
||||
},
|
||||
"transformationRules": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Transformation rules applied during normalization"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"documentId": "openvex:ghsa-2023-0001",
|
||||
"sourceFormat": "OPENVEX",
|
||||
"sourceDigest": "sha256:7d9cd5f1a2a0dd9a41a2c43a5b7d8a0bcd9e34cf39b3f43a70595c834f0a4aee",
|
||||
"sourceUri": "https://github.com/anchore/vex-data/example.json",
|
||||
"issuer": {
|
||||
"id": "pkg:github/anchore",
|
||||
"name": "Anchore",
|
||||
"category": "VENDOR",
|
||||
"trustTier": "TRUSTED"
|
||||
},
|
||||
"issuedAt": "2025-11-21T10:00:00Z",
|
||||
"statements": [
|
||||
{
|
||||
"statementId": "stmt-001",
|
||||
"vulnerabilityId": "CVE-2023-12345",
|
||||
"product": {
|
||||
"key": "pkg:npm/example@1.0.0",
|
||||
"name": "example",
|
||||
"version": "1.0.0",
|
||||
"purl": "pkg:npm/example@1.0.0"
|
||||
},
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"statusNotes": "The vulnerable function is not used in the package's runtime code path.",
|
||||
"firstSeen": "2025-11-21T10:00:00Z",
|
||||
"lastSeen": "2025-11-21T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"provenance": {
|
||||
"normalizedAt": "2025-11-21T10:15:00Z",
|
||||
"normalizer": "stellaops-excititor/1.0.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user