Triage Evidence Export API Reference
Version: 1.0 · Status: Stable
The Triage Evidence Export API lets you download the complete, verifiable evidence package behind any Stella Ops finding — the SBOM excerpt, reachability proof, VEX claims, attestations, deltas, policy decision, and a copy-ready replay command — as a single archive or as structured JSON. It is written for auditors, CI integrations, and tooling that need portable, offline-verifiable evidence for a release decision.
For the broader triage contract (findings table, case narrative, decisions, snapshots) see the Triage API Contract v1; for the underlying evidence model see the Unified Evidence Model.
Overview
The Triage Evidence Export API provides endpoints for downloading complete evidence packages as archives. These endpoints support both individual finding exports and batch exports for entire scan runs.
Base URL
/api/v1/triage
Endpoints
Export Finding Evidence Bundle
Downloads a complete evidence bundle for a single finding as a ZIP or TAR.GZ archive.
GET /findings/{findingId}/evidence/export
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
findingId | UUID | Yes | Bare Scanner Triage UUID returned unchanged by /inbox?artifactDigest=... in paths[].findingIds[] |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
format | string | zip | Archive format: zip, tar.gz, targz, tgz |
Response Headers
| Header | Description |
|---|---|
Content-Type | application/zip or application/gzip |
Content-Disposition | attachment; filename="evidence-{findingId}.zip" |
X-Archive-Digest | SHA-256 digest of the archive: sha256:{digest} |
Response Codes
| Code | Description |
|---|---|
| 200 | Success - archive stream returned |
| 400 | Invalid format specified |
| 404 | Finding not found |
Example Request
curl -X GET \
"https://api.stellaops.example/api/v1/triage/findings/10000000-0000-0000-0000-000000000001/evidence/export?format=zip" \
-H "Authorization: ${STELLAOPS_AUTH_HEADER}" \
-o evidence-f-abc123.zip
Example Response
Binary stream of the archive file.
Get Unified Evidence
Retrieves the unified evidence package as JSON (not downloadable archive).
GET /findings/{findingId}/evidence
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
findingId | UUID | Yes | Bare Scanner Triage UUID returned unchanged by /inbox?artifactDigest=... in paths[].findingIds[] |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
includeSbom | boolean | true | Include SBOM evidence |
includeReachability | boolean | true | Include reachability evidence |
includeVex | boolean | true | Include VEX claims |
includeAttestations | boolean | true | Include attestations |
includeDeltas | boolean | true | Include delta evidence |
includePolicy | boolean | true | Include policy evidence |
includeReplayCommand | boolean | true | Include replay command |
Response Headers
| Header | Description |
|---|---|
ETag | Content-addressed cache key: "{cacheKey}" |
Cache-Control | private, max-age=300 |
Response Codes
| Code | Description |
|---|---|
| 200 | Finding exists; complete or partial evidence returned with explicit availability |
| 304 | Not Modified (ETag match) |
| 404 | Tenant-scoped finding not found; typed producer/recovery metadata is returned without echoing the requested identifier |
Example Request
curl -X GET \
"https://api.stellaops.example/api/v1/triage/findings/10000000-0000-0000-0000-000000000001/evidence" \
-H "Authorization: ${STELLAOPS_AUTH_HEADER}" \
-H "If-None-Match: \"sha256:abc123...\""
Example Response (200 OK)
{
"findingId": "10000000-0000-0000-0000-000000000001",
"cveId": "CVE-2024-1234",
"componentPurl": "pkg:npm/lodash@4.17.15",
"sbom": {
"format": "cyclonedx",
"version": "1.5",
"documentUri": "/sboms/sha256:abc123",
"digest": "sha256:abc123...",
"component": {
"purl": "pkg:npm/lodash@4.17.15",
"name": "lodash",
"version": "4.17.15",
"ecosystem": "npm"
}
},
"reachability": null,
"vexClaims": [...],
"attestations": [...],
"deltas": {...},
"policy": {...},
"manifests": {
"artifactDigest": "sha256:a1b2c3...",
"manifestHash": "sha256:def456...",
"feedSnapshotHash": "sha256:feed789...",
"policyHash": "sha256:policy321..."
},
"scan": {
"scanId": "20000000-0000-0000-0000-000000000001",
"status": "completed",
"imageReference": "registry.example/app@sha256:a1b2c3...",
"imageDigest": "sha256:a1b2c3...",
"startedAt": "2026-07-11T10:00:00Z",
"completedAt": "2026-07-11T10:01:00Z"
},
"findingTimestamps": {
"firstSeenAt": "2026-07-11T10:01:00Z",
"lastSeenAt": "2026-07-11T10:01:00Z",
"updatedAt": "2026-07-11T10:01:00Z"
},
"availability": {
"status": "partial",
"missing": [
{
"type": "reachability",
"code": "scanner.triage.reachability_not_produced",
"producer": "scanner.reachability",
"recovery": "Run reachability analysis for the finding's scan and retry."
}
]
},
"verification": {
"status": "unknown",
"hashesVerified": false,
"attestationsVerified": false,
"evidenceComplete": false,
"verifiedAt": null
},
"replayCommand": null,
"shortReplayCommand": null,
"evidenceBundleUrl": "/api/v1/triage/findings/10000000-0000-0000-0000-000000000001/evidence/export",
"generatedAt": "2025-01-15T10:30:00Z",
"cacheKey": "sha256:unique123..."
}
The unified response is a stored-fact projection. Missing hashes, SBOM or policy versions, verification results, and replay inputs are returned as null or unknown; the endpoint does not derive production-looking substitutes. The artifact digest selects one or more inbox rows and is not accepted as a findingId. Findings-service matcher tokens are a separate identity namespace.
Get Replay Command
Retrieves the replay command for a finding.
GET /findings/{findingId}/replay-command
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
findingId | string | Yes | Finding identifier |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
shells | string[] | ["bash"] | Target shells: bash, powershell, cmd |
includeOffline | boolean | false | Include offline replay variant |
generateBundle | boolean | false | Generate evidence bundle |
Response Codes
| Code | Description |
|---|---|
| 200 | Success - replay command returned |
| 404 | Finding not found |
Example Response
{
"findingId": "f-abc123",
"commands": {
"bash": "stella scan replay --artifact sha256:a1b2c3... --manifest sha256:def456... --feeds sha256:feed789... --policy sha256:policy321...",
"powershell": "stella scan replay --artifact sha256:a1b2c3... --manifest sha256:def456... --feeds sha256:feed789... --policy sha256:policy321..."
},
"shortCommand": "stella replay snapshot --verdict V-12345",
"inputHashes": {
"artifactDigest": "sha256:a1b2c3...",
"manifestHash": "sha256:def456...",
"feedSnapshotHash": "sha256:feed789...",
"policyHash": "sha256:policy321..."
},
"bundleUrl": "/api/v1/triage/findings/f-abc123/evidence/export",
"generatedAt": "2025-01-15T10:30:00Z"
}
Get Scan Replay Command
Retrieves the replay command for an entire scan.
GET /scans/{scanId}/replay-command
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
scanId | string | Yes | Scan identifier |
Query Parameters
Same as finding replay command endpoint.
Response Codes
| Code | Description |
|---|---|
| 200 | Success - replay command returned |
| 404 | Scan not found |
ETag Caching
The unified evidence endpoint supports HTTP caching via ETag/If-None-Match:
- Initial request: Returns evidence with
ETagheader - Subsequent requests: Include
If-None-Match: "{etag}"header - If unchanged: Returns
304 Not Modified(no body) - If changed: Returns
200 OKwith new evidence and ETag
Example flow:
# Initial request
curl -i "https://api.stellaops.example/api/v1/triage/findings/f-abc123/evidence"
# Response: 200 OK, ETag: "sha256:abc123..."
# Conditional request
curl -i "https://api.stellaops.example/api/v1/triage/findings/f-abc123/evidence" \
-H 'If-None-Match: "sha256:abc123..."'
# Response: 304 Not Modified (if unchanged)
Archive Integrity
To verify downloaded archives:
# Get expected digest from header
EXPECTED=$(curl -sI ".../evidence/export" | grep X-Archive-Digest | cut -d: -f2-)
# Download and verify
curl -o evidence.zip ".../evidence/export"
ACTUAL=$(sha256sum evidence.zip | cut -d' ' -f1)
if [ "sha256:$ACTUAL" = "$EXPECTED" ]; then
echo "Archive verified"
else
echo "Verification failed!"
exit 1
fi
Evidence Card Format (v1.1)
For single-file evidence exports with offline verification support, use the Evidence Pack API’s evidence-card format:
GET /v1/evidence-packs/{packId}/export?format=evidence-card
Formats
| Format | Content-Type | Description |
|---|---|---|
evidence-card | application/vnd.stellaops.evidence-card+json | Full evidence card with SBOM excerpt, DSSE envelope, and Rekor receipt |
card-compact | application/vnd.stellaops.evidence-card-compact+json | Compact card without full SBOM |
Planned receipt headers
As of 2026-07-18, the AdvisoryAI evidence-card route returns the card content type and download filename but does not emit the receipt headers below. They remain a target contract, not a current runtime guarantee. EvidenceLocker owns separate JSON/gzip bundle and verdict APIs; it does not implement this AdvisoryAI route. See the run-002 reconciliation evidence.
| Header | Description |
|---|---|
X-Evidence-Pack-Id | Pack identifier |
X-Content-Digest | SHA-256 content digest |
X-Evidence-Card-Version | Schema version (e.g., “1.0.0”) |
X-Rekor-Log-Index | Rekor transparency log index (when available) |
See Evidence Decision API for complete schema.
