This commit is contained in:
StellaOps Bot
2025-12-14 23:20:14 +02:00
parent 3411e825cd
commit b058dbe031
356 changed files with 68310 additions and 1108 deletions

View File

@@ -0,0 +1,870 @@
openapi: 3.1.0
info:
title: StellaOps Scanner API
version: 1.0.0
description: |
Scanner service APIs for call graph ingestion, reachability computation,
and vulnerability finding queries. Supports CI/CD integration with
idempotent submissions and async computation.
servers:
- url: /api
description: Scanner service endpoint
tags:
- name: Scans
description: Scan lifecycle management
- name: CallGraphs
description: Call graph ingestion
- name: RuntimeEvidence
description: Runtime evidence collection
- name: Reachability
description: Reachability analysis and queries
- name: Exports
description: Report exports
- name: ProofSpines
description: Verifiable audit trails
paths:
/scans:
post:
tags: [Scans]
operationId: createScan
summary: Create a new scan
description: |
Initiates a new scan context. Returns a scanId for subsequent
call graph and evidence submissions.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateScanRequest'
responses:
'201':
description: Scan created
content:
application/json:
schema:
$ref: '#/components/schemas/CreateScanResponse'
'400':
$ref: '#/components/responses/BadRequest'
/scans/{scanId}:
get:
tags: [Scans]
operationId: getScan
summary: Get scan status
parameters:
- $ref: '#/components/parameters/ScanIdPath'
responses:
'200':
description: Scan details
content:
application/json:
schema:
$ref: '#/components/schemas/ScanDetails'
'404':
$ref: '#/components/responses/NotFound'
/scans/{scanId}/callgraphs:
post:
tags: [CallGraphs]
operationId: submitCallGraph
summary: Submit a call graph
description: |
Submits a language-specific call graph for reachability analysis.
Idempotent: duplicate submissions with same Content-Digest are ignored.
parameters:
- $ref: '#/components/parameters/ScanIdPath'
- name: Content-Digest
in: header
required: true
description: SHA-256 digest for idempotency (RFC 9530)
schema:
type: string
example: sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CallGraphV1'
application/x-ndjson:
schema:
type: string
description: Streaming NDJSON for large graphs
responses:
'202':
description: Call graph accepted
content:
application/json:
schema:
$ref: '#/components/schemas/CallGraphAcceptedResponse'
'409':
description: Duplicate submission (idempotent success)
'400':
$ref: '#/components/responses/BadRequest'
'413':
description: Call graph too large
/scans/{scanId}/runtimeevidence:
post:
tags: [RuntimeEvidence]
operationId: submitRuntimeEvidence
summary: Submit runtime evidence
description: |
Submits runtime execution evidence (stack traces, loaded modules).
Merges with existing evidence for the scan.
parameters:
- $ref: '#/components/parameters/ScanIdPath'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RuntimeEvidenceV1'
responses:
'202':
description: Evidence accepted
content:
application/json:
schema:
$ref: '#/components/schemas/RuntimeEvidenceAcceptedResponse'
'400':
$ref: '#/components/responses/BadRequest'
/scans/{scanId}/sbom:
post:
tags: [Scans]
operationId: submitSbom
summary: Submit SBOM for scan
description: |
Associates an SBOM (CycloneDX or SPDX) with the scan.
Required before reachability computation.
parameters:
- $ref: '#/components/parameters/ScanIdPath'
requestBody:
required: true
content:
application/vnd.cyclonedx+json:
schema:
type: object
application/spdx+json:
schema:
type: object
responses:
'202':
description: SBOM accepted
'400':
$ref: '#/components/responses/BadRequest'
/scans/{scanId}/compute-reachability:
post:
tags: [Reachability]
operationId: computeReachability
summary: Trigger reachability computation
description: |
Triggers reachability analysis for the scan. Idempotent.
Computation is asynchronous; poll scan status for completion.
parameters:
- $ref: '#/components/parameters/ScanIdPath'
requestBody:
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/ComputeReachabilityRequest'
responses:
'202':
description: Computation started
content:
application/json:
schema:
$ref: '#/components/schemas/ComputeReachabilityResponse'
'409':
description: Computation already in progress
'400':
$ref: '#/components/responses/BadRequest'
/scans/{scanId}/reachability/components:
get:
tags: [Reachability]
operationId: getReachabilityByComponent
summary: Get reachability status by component
parameters:
- $ref: '#/components/parameters/ScanIdPath'
- name: purl
in: query
description: Filter by Package URL
schema:
type: string
- name: status
in: query
description: Filter by reachability status
schema:
type: string
enum: [reachable, unreachable, possibly_reachable, unknown]
responses:
'200':
description: Component reachability results
content:
application/json:
schema:
$ref: '#/components/schemas/ComponentReachabilityList'
/scans/{scanId}/reachability/findings:
get:
tags: [Reachability]
operationId: getReachabilityFindings
summary: Get vulnerability findings with reachability
parameters:
- $ref: '#/components/parameters/ScanIdPath'
- name: cve
in: query
description: Filter by CVE ID
schema:
type: string
- name: status
in: query
description: Filter by reachability status
schema:
type: string
enum: [reachable, unreachable, possibly_reachable, unknown]
responses:
'200':
description: Vulnerability findings with reachability
content:
application/json:
schema:
$ref: '#/components/schemas/ReachabilityFindingList'
/scans/{scanId}/reachability/explain:
get:
tags: [Reachability]
operationId: explainReachability
summary: Explain reachability for CVE/component
description: |
Returns detailed explanation of why a CVE affects a component,
including path witness, evidence chain, and contributing factors.
parameters:
- $ref: '#/components/parameters/ScanIdPath'
- name: cve
in: query
required: true
schema:
type: string
- name: purl
in: query
required: true
schema:
type: string
responses:
'200':
description: Reachability explanation
content:
application/json:
schema:
$ref: '#/components/schemas/ReachabilityExplanation'
'404':
description: CVE/component combination not found
/scans/{scanId}/exports/sarif:
get:
tags: [Exports]
operationId: exportSarif
summary: Export findings as SARIF
parameters:
- $ref: '#/components/parameters/ScanIdPath'
responses:
'200':
description: SARIF report
content:
application/sarif+json:
schema:
type: object
/scans/{scanId}/exports/cdxr:
get:
tags: [Exports]
operationId: exportCycloneDxReachability
summary: Export as CycloneDX with reachability extension
parameters:
- $ref: '#/components/parameters/ScanIdPath'
responses:
'200':
description: CycloneDX with reachability
content:
application/vnd.cyclonedx+json:
schema:
type: object
/scans/{scanId}/exports/openvex:
get:
tags: [Exports]
operationId: exportOpenVex
summary: Export as OpenVEX
parameters:
- $ref: '#/components/parameters/ScanIdPath'
responses:
'200':
description: OpenVEX document
content:
application/json:
schema:
type: object
/scans/{scanId}/spines:
get:
tags: [ProofSpines]
operationId: getSpinesByScan
summary: List proof spines for a scan
parameters:
- $ref: '#/components/parameters/ScanIdPath'
responses:
'200':
description: Proof spines for scan
content:
application/json:
schema:
$ref: '#/components/schemas/ProofSpineList'
/spines/{spineId}:
get:
tags: [ProofSpines]
operationId: getSpine
summary: Get a proof spine
description: Returns full spine with all segments and verification status.
parameters:
- name: spineId
in: path
required: true
schema:
type: string
responses:
'200':
description: Proof spine details
content:
application/json:
schema:
$ref: '#/components/schemas/ProofSpine'
'404':
$ref: '#/components/responses/NotFound'
components:
parameters:
ScanIdPath:
name: scanId
in: path
required: true
schema:
type: string
format: uuid
responses:
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
schemas:
CreateScanRequest:
type: object
required: [artifactDigest]
properties:
artifactDigest:
type: string
description: Image or artifact digest (sha256:...)
repoUri:
type: string
commitSha:
type: string
policyProfileId:
type: string
metadata:
type: object
additionalProperties: true
CreateScanResponse:
type: object
properties:
scanId:
type: string
format: uuid
status:
type: string
enum: [created, pending, processing, completed, failed]
createdAt:
type: string
format: date-time
ScanDetails:
type: object
properties:
scanId:
type: string
status:
type: string
artifactDigest:
type: string
callGraphCount:
type: integer
runtimeEvidenceCount:
type: integer
reachabilityStatus:
type: string
enum: [pending, computing, completed, failed]
createdAt:
type: string
format: date-time
completedAt:
type: string
format: date-time
CallGraphV1:
type: object
required: [schema, scanKey, language, nodes, edges]
properties:
schema:
type: string
const: stella.callgraph.v1
scanKey:
type: string
format: uuid
language:
type: string
enum: [dotnet, java, node, python, go, rust, binary, ruby, php]
artifacts:
type: array
items:
$ref: '#/components/schemas/CallGraphArtifact'
nodes:
type: array
items:
$ref: '#/components/schemas/CallGraphNode'
edges:
type: array
items:
$ref: '#/components/schemas/CallGraphEdge'
entrypoints:
type: array
items:
$ref: '#/components/schemas/CallGraphEntrypoint'
CallGraphArtifact:
type: object
properties:
artifactKey:
type: string
kind:
type: string
enum: [assembly, jar, module, binary]
sha256:
type: string
purl:
type: string
CallGraphNode:
type: object
required: [nodeId, symbolKey]
properties:
nodeId:
type: string
artifactKey:
type: string
symbolKey:
type: string
description: Canonical symbol key (Namespace.Type::Method(signature))
visibility:
type: string
enum: [public, internal, private, unknown]
isEntrypointCandidate:
type: boolean
default: false
CallGraphEdge:
type: object
required: [from, to]
properties:
from:
type: string
description: Source node ID
to:
type: string
description: Target node ID
kind:
type: string
enum: [static, heuristic]
default: static
reason:
type: string
enum: [direct_call, virtual_call, reflection_string, di_binding, dynamic_import, unknown]
weight:
type: number
default: 1.0
CallGraphEntrypoint:
type: object
required: [nodeId, kind]
properties:
nodeId:
type: string
kind:
type: string
enum: [http, grpc, cli, job, event, unknown]
route:
type: string
description: HTTP route pattern (e.g., /api/orders/{id})
framework:
type: string
enum: [aspnetcore, minimalapi, spring, express, fastapi, unknown]
CallGraphAcceptedResponse:
type: object
properties:
callgraphId:
type: string
nodeCount:
type: integer
edgeCount:
type: integer
digest:
type: string
RuntimeEvidenceV1:
type: object
required: [schema, scanKey, collectedAt]
properties:
schema:
type: string
const: stella.runtimeevidence.v1
scanKey:
type: string
format: uuid
collectedAt:
type: string
format: date-time
environment:
$ref: '#/components/schemas/RuntimeEnvironment'
samples:
type: array
items:
$ref: '#/components/schemas/RuntimeSample'
loadedArtifacts:
type: array
items:
$ref: '#/components/schemas/LoadedArtifact'
RuntimeEnvironment:
type: object
properties:
os:
type: string
k8s:
type: object
properties:
namespace:
type: string
pod:
type: string
container:
type: string
imageDigest:
type: string
buildId:
type: string
RuntimeSample:
type: object
properties:
timestamp:
type: string
format: date-time
pid:
type: integer
threadId:
type: integer
frames:
type: array
items:
type: string
description: Array of node IDs representing call stack
sampleWeight:
type: number
default: 1.0
LoadedArtifact:
type: object
properties:
artifactKey:
type: string
evidence:
type: string
enum: [loaded_module, mapped_file, jar_loaded]
RuntimeEvidenceAcceptedResponse:
type: object
properties:
evidenceId:
type: string
sampleCount:
type: integer
loadedArtifactCount:
type: integer
ComputeReachabilityRequest:
type: object
properties:
forceRecompute:
type: boolean
default: false
entrypoints:
type: array
items:
type: string
description: Override auto-detected entrypoints
targets:
type: array
items:
type: string
description: Specific symbols to analyze
ComputeReachabilityResponse:
type: object
properties:
jobId:
type: string
status:
type: string
enum: [queued, processing]
estimatedDuration:
type: string
description: ISO-8601 duration estimate
ComponentReachabilityList:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/ComponentReachability'
total:
type: integer
ComponentReachability:
type: object
properties:
purl:
type: string
status:
type: string
enum: [reachable, unreachable, possibly_reachable, unknown]
confidence:
type: number
latticeState:
type: string
why:
type: array
items:
type: string
ReachabilityFindingList:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/ReachabilityFinding'
total:
type: integer
ReachabilityFinding:
type: object
properties:
cveId:
type: string
purl:
type: string
status:
type: string
confidence:
type: number
latticeState:
type: string
severity:
type: string
affectedVersions:
type: string
ReachabilityExplanation:
type: object
properties:
cveId:
type: string
purl:
type: string
status:
type: string
confidence:
type: number
latticeState:
type: string
pathWitness:
type: array
items:
type: string
description: Symbol path from entrypoint to vulnerable code
why:
type: array
items:
$ref: '#/components/schemas/ExplanationReason'
evidence:
$ref: '#/components/schemas/EvidenceChain'
spineId:
type: string
description: Reference to ProofSpine for full audit trail
ExplanationReason:
type: object
properties:
code:
type: string
description:
type: string
impact:
type: number
EvidenceChain:
type: object
properties:
staticAnalysis:
type: object
properties:
callgraphDigest:
type: string
pathLength:
type: integer
edgeTypes:
type: array
items:
type: string
runtimeEvidence:
type: object
properties:
observed:
type: boolean
hitCount:
type: integer
lastObserved:
type: string
format: date-time
policyEvaluation:
type: object
properties:
policyDigest:
type: string
verdict:
type: string
verdictReason:
type: string
ProofSpineList:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/ProofSpineSummary'
total:
type: integer
ProofSpineSummary:
type: object
properties:
spineId:
type: string
artifactId:
type: string
vulnerabilityId:
type: string
verdict:
type: string
segmentCount:
type: integer
createdAt:
type: string
format: date-time
ProofSpine:
type: object
properties:
spineId:
type: string
artifactId:
type: string
vulnerabilityId:
type: string
policyProfileId:
type: string
verdict:
type: string
verdictReason:
type: string
rootHash:
type: string
scanRunId:
type: string
segments:
type: array
items:
$ref: '#/components/schemas/ProofSegment'
createdAt:
type: string
format: date-time
supersededBySpineId:
type: string
ProofSegment:
type: object
properties:
segmentId:
type: string
segmentType:
type: string
enum: [SBOM_SLICE, MATCH, REACHABILITY, GUARD_ANALYSIS, RUNTIME_OBSERVATION, POLICY_EVAL]
index:
type: integer
inputHash:
type: string
resultHash:
type: string
prevSegmentHash:
type: string
toolId:
type: string
toolVersion:
type: string
status:
type: string
enum: [pending, verified, partial, invalid, untrusted]
createdAt:
type: string
format: date-time
ErrorResponse:
type: object
properties:
error:
type: string
message:
type: string
details:
type: object