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

ParameterTypeRequiredDescription
findingIdUUIDYesBare Scanner Triage UUID returned unchanged by /inbox?artifactDigest=... in paths[].findingIds[]

Query Parameters

ParameterTypeDefaultDescription
formatstringzipArchive format: zip, tar.gz, targz, tgz

Response Headers

HeaderDescription
Content-Typeapplication/zip or application/gzip
Content-Dispositionattachment; filename="evidence-{findingId}.zip"
X-Archive-DigestSHA-256 digest of the archive: sha256:{digest}

Response Codes

CodeDescription
200Success - archive stream returned
400Invalid format specified
404Finding 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

ParameterTypeRequiredDescription
findingIdUUIDYesBare Scanner Triage UUID returned unchanged by /inbox?artifactDigest=... in paths[].findingIds[]

Query Parameters

ParameterTypeDefaultDescription
includeSbombooleantrueInclude SBOM evidence
includeReachabilitybooleantrueInclude reachability evidence
includeVexbooleantrueInclude VEX claims
includeAttestationsbooleantrueInclude attestations
includeDeltasbooleantrueInclude delta evidence
includePolicybooleantrueInclude policy evidence
includeReplayCommandbooleantrueInclude replay command

Response Headers

HeaderDescription
ETagContent-addressed cache key: "{cacheKey}"
Cache-Controlprivate, max-age=300

Response Codes

CodeDescription
200Finding exists; complete or partial evidence returned with explicit availability
304Not Modified (ETag match)
404Tenant-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

ParameterTypeRequiredDescription
findingIdstringYesFinding identifier

Query Parameters

ParameterTypeDefaultDescription
shellsstring[]["bash"]Target shells: bash, powershell, cmd
includeOfflinebooleanfalseInclude offline replay variant
generateBundlebooleanfalseGenerate evidence bundle

Response Codes

CodeDescription
200Success - replay command returned
404Finding 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

ParameterTypeRequiredDescription
scanIdstringYesScan identifier

Query Parameters

Same as finding replay command endpoint.

Response Codes

CodeDescription
200Success - replay command returned
404Scan not found

ETag Caching

The unified evidence endpoint supports HTTP caching via ETag/If-None-Match:

  1. Initial request: Returns evidence with ETag header
  2. Subsequent requests: Include If-None-Match: "{etag}" header
  3. If unchanged: Returns 304 Not Modified (no body)
  4. If changed: Returns 200 OK with 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

FormatContent-TypeDescription
evidence-cardapplication/vnd.stellaops.evidence-card+jsonFull evidence card with SBOM excerpt, DSSE envelope, and Rekor receipt
card-compactapplication/vnd.stellaops.evidence-card-compact+jsonCompact 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.

HeaderDescription
X-Evidence-Pack-IdPack identifier
X-Content-DigestSHA-256 content digest
X-Evidence-Card-VersionSchema version (e.g., “1.0.0”)
X-Rekor-Log-IndexRekor transparency log index (when available)

See Evidence Decision API for complete schema.

See Also