Files
git.stella-ops.org/docs/api/score-proofs-reachability-api-reference.md
StellaOps Bot efe9bd8cfe Add integration tests for Proof Chain and Reachability workflows
- Implement ProofChainTestFixture for PostgreSQL-backed integration tests.
- Create StellaOps.Integration.ProofChain project with necessary dependencies.
- Add ReachabilityIntegrationTests to validate call graph extraction and reachability analysis.
- Introduce ReachabilityTestFixture for managing corpus and fixture paths.
- Establish StellaOps.Integration.Reachability project with required references.
- Develop UnknownsWorkflowTests to cover the unknowns lifecycle: detection, ranking, escalation, and resolution.
- Create StellaOps.Integration.Unknowns project with dependencies for unknowns workflow.
2025-12-20 22:19:26 +02:00

24 KiB

Score Proofs & Reachability API Reference

Version: 1.0.0
Sprint: 3500.0004.0004
Status: Complete

This document provides the complete API reference for Score Proofs, Reachability Analysis, and Unknowns management features. It consolidates documentation from multiple source files into a single reference.


Table of Contents

  1. Overview
  2. Authentication
  3. Score Proofs API
  4. Reachability API
  5. Unknowns API
  6. Proof Chain API
  7. Data Models
  8. Error Handling
  9. Rate Limiting
  10. Examples

1. Overview

Design Principles

  • Deterministic: All outputs use canonical JSON serialization (RFC 8785/JCS)
  • Verifiable: DSSE signatures on all proof artifacts
  • Idempotent: Content-Digest headers enable safe retries
  • Offline-First: All bundles downloadable for air-gap verification

Base URLs

Service Base URL Description
Scanner /api/v1/scanner Scan management, reachability
Proofs /api/v1/proofs Proof chain creation/verification
Unknowns /api/v1/unknowns Unknowns triage and escalation

Supported Content Types

Type Description
application/json Standard JSON (responses are canonical)
application/x-ndjson Streaming NDJSON for large call graphs
application/zip Proof bundle archives

2. Authentication

All endpoints require OAuth 2.0 Bearer token authentication.

Token Request

POST /connect/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&
client_id=ci-bot&
client_secret=REDACTED&
scope=scanner.scans scanner.proofs scanner.unknowns

Response

{
  "access_token": "eyJraWQi...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Required Scopes

Scope Description
scanner.scans Create/read scans and manifests
scanner.proofs Access proof bundles
scanner.unknowns Read/manage unknowns
scanner.unknowns:write Escalate unknowns
proofs.read Read proof chains
proofs.write Create proof spines
proofs.verify Verify proofs
anchors.manage Manage trust anchors

3. Score Proofs API

3.1 Create Scan with Manifest

POST /api/v1/scanner/scans

Creates a new scan with deterministic manifest for replay.

Request

{
  "artifactDigest": "sha256:abc123...",
  "artifactPurl": "pkg:oci/myapp@sha256:abc123...",
  "scannerVersion": "1.0.0",
  "workerVersion": "1.0.0",
  "concelierSnapshotHash": "sha256:feed123...",
  "excititorSnapshotHash": "sha256:vex456...",
  "latticePolicyHash": "sha256:policy789...",
  "deterministic": true,
  "seed": "AQIDBA==",
  "knobs": {
    "maxDepth": "10",
    "indirectCallResolution": "conservative"
  }
}

Response (201 Created)

{
  "scanId": "550e8400-e29b-41d4-a716-446655440000",
  "manifestHash": "sha256:manifest123...",
  "createdAt": "2025-12-17T12:00:00Z",
  "_links": {
    "self": "/api/v1/scanner/scans/550e8400-e29b-41d4-a716-446655440000",
    "manifest": "/api/v1/scanner/scans/550e8400-e29b-41d4-a716-446655440000/manifest"
  }
}

Headers

Header Description
Content-Digest sha256=<base64> - Idempotency key
Location URL of created scan

Errors

Code Type Description
400 invalid-manifest Manifest validation failed
409 duplicate-scan Scan with same manifest hash exists
422 snapshot-not-found Feed/VEX snapshot not found

3.2 Get Scan Manifest

GET /api/v1/scanner/scans/{scanId}/manifest

Retrieves canonical JSON manifest with DSSE signature.

Response (200 OK)

{
  "manifest": {
    "scanId": "550e8400-e29b-41d4-a716-446655440000",
    "createdAtUtc": "2025-12-17T12:00:00Z",
    "artifactDigest": "sha256:abc123...",
    "artifactPurl": "pkg:oci/myapp@sha256:abc123...",
    "scannerVersion": "1.0.0",
    "workerVersion": "1.0.0",
    "concelierSnapshotHash": "sha256:feed123...",
    "excititorSnapshotHash": "sha256:vex456...",
    "latticePolicyHash": "sha256:policy789...",
    "deterministic": true,
    "seed": "AQIDBA==",
    "knobs": {"maxDepth": "10"}
  },
  "manifestHash": "sha256:manifest123...",
  "dsseEnvelope": {
    "payloadType": "application/vnd.stellaops.scan-manifest.v1+json",
    "payload": "eyJzY2FuSWQiOiIuLi4ifQ==",
    "signatures": [
      {"keyid": "ecdsa-p256-key-001", "sig": "MEUCIQDx..."}
    ]
  }
}

3.3 Replay Score Computation

POST /api/v1/scanner/scans/{scanId}/score/replay

Recomputes score proofs using updated feeds/policies without rescanning.

Request

{
  "overrides": {
    "concelierSnapshotHash": "sha256:newfeed...",
    "excititorSnapshotHash": "sha256:newvex...",
    "latticePolicyHash": "sha256:newpolicy..."
  }
}

Response (200 OK)

{
  "scanId": "550e8400-e29b-41d4-a716-446655440000",
  "replayedAt": "2025-12-17T13:00:00Z",
  "scoreProof": {
    "rootHash": "sha256:proof123...",
    "nodes": [
      {
        "id": "input-1",
        "kind": "Input",
        "ruleId": "inputs.v1",
        "delta": 0.0,
        "total": 0.0,
        "nodeHash": "sha256:node1..."
      },
      {
        "id": "delta-cvss",
        "kind": "Delta",
        "ruleId": "score.cvss_base.weighted",
        "parentIds": ["input-1"],
        "evidenceRefs": ["cvss:9.1"],
        "delta": 0.50,
        "total": 0.50,
        "nodeHash": "sha256:node2..."
      }
    ]
  },
  "proofBundleUri": "/api/v1/scanner/scans/.../proofs/sha256:proof123..."
}

3.4 Fetch Proof Bundle

GET /api/v1/scanner/scans/{scanId}/proofs/{rootHash}

Downloads proof bundle ZIP archive for offline verification.

Response Headers

Header Value
Content-Type application/zip
Content-Disposition attachment; filename="proof-{scanId}-{rootHash}.zip"
X-Proof-Root-Hash Proof root hash
X-Manifest-Hash Manifest hash

Bundle Contents

File Description
manifest.json Canonical scan manifest
manifest.dsse.json DSSE signature of manifest
score_proof.json Proof ledger (ProofNode array)
proof_root.dsse.json DSSE signature of proof root
meta.json Metadata (timestamps, versions)

4. Reachability API

4.1 Upload Call Graph

POST /api/v1/scanner/scans/{scanId}/callgraphs

Uploads language-specific call graph extracted by workers.

Request

{
  "schema": "stella.callgraph.v1",
  "language": "dotnet",
  "artifacts": [
    {
      "artifactKey": "MyApp.WebApi.dll",
      "kind": "assembly",
      "sha256": "sha256:artifact123..."
    }
  ],
  "nodes": [
    {
      "nodeId": "sha256:node1...",
      "artifactKey": "MyApp.WebApi.dll",
      "symbolKey": "MyApp.Controllers.OrdersController::Get(System.Guid)",
      "visibility": "public",
      "isEntrypointCandidate": true
    }
  ],
  "edges": [
    {
      "from": "sha256:node1...",
      "to": "sha256:node2...",
      "kind": "static",
      "reason": "direct_call",
      "weight": 1.0
    }
  ],
  "entrypoints": [
    {
      "nodeId": "sha256:node1...",
      "kind": "http",
      "route": "/api/orders/{id}",
      "framework": "aspnetcore"
    }
  ]
}

Response (202 Accepted)

{
  "scanId": "550e8400-e29b-41d4-a716-446655440000",
  "callGraphDigest": "sha256:cg123...",
  "nodesCount": 1234,
  "edgesCount": 5678,
  "entrypointsCount": 12,
  "status": "accepted"
}

4.2 Compute Reachability

POST /api/v1/scanner/scans/{scanId}/reachability/compute

Triggers reachability analysis for uploaded call graph.

Response (202 Accepted)

{
  "scanId": "550e8400-e29b-41d4-a716-446655440000",
  "jobId": "reachability-job-001",
  "status": "queued",
  "estimatedDuration": "30s",
  "_links": {
    "status": "/api/v1/scanner/jobs/reachability-job-001",
    "results": "/api/v1/scanner/scans/.../reachability/findings"
  }
}

4.3 Get Reachability Findings

GET /api/v1/scanner/scans/{scanId}/reachability/findings

Retrieves reachability verdicts for all vulnerabilities.

Query Parameters

Parameter Type Description
status string Filter: REACHABLE, UNREACHABLE, POSSIBLY_REACHABLE, UNKNOWN
cveId string Filter by CVE ID

Response (200 OK)

{
  "scanId": "550e8400-e29b-41d4-a716-446655440000",
  "computedAt": "2025-12-17T12:30:00Z",
  "findings": [
    {
      "cveId": "CVE-2024-1234",
      "purl": "pkg:npm/lodash@4.17.20",
      "status": "REACHABLE_STATIC",
      "confidence": 0.70,
      "path": [
        {
          "nodeId": "sha256:entrypoint...",
          "symbolKey": "MyApp.Controllers.OrdersController::Get(System.Guid)"
        },
        {
          "nodeId": "sha256:vuln...",
          "symbolKey": "Lodash.merge(Object, Object)"
        }
      ],
      "evidence": {
        "pathLength": 3,
        "staticEdgesOnly": true,
        "runtimeConfirmed": false
      }
    }
  ],
  "summary": {
    "total": 45,
    "reachable": 3,
    "unreachable": 38,
    "possiblyReachable": 4,
    "unknown": 0
  }
}

4.4 Explain Reachability

GET /api/v1/scanner/scans/{scanId}/reachability/explain

Provides detailed explanation for a reachability verdict.

Query Parameters

Parameter Required Description
cve Yes CVE ID
purl Yes Package URL

Response (200 OK)

{
  "cveId": "CVE-2024-1234",
  "purl": "pkg:npm/lodash@4.17.20",
  "status": "REACHABLE_STATIC",
  "confidence": 0.70,
  "explanation": {
    "shortestPath": [
      {
        "depth": 0,
        "nodeId": "sha256:entry...",
        "symbolKey": "MyApp.Controllers.OrdersController::Get(System.Guid)",
        "entrypointKind": "http",
        "route": "/api/orders/{id}"
      },
      {
        "depth": 1,
        "nodeId": "sha256:inter...",
        "symbolKey": "MyApp.Services.OrderService::Process(Order)",
        "edgeKind": "static",
        "edgeReason": "direct_call"
      },
      {
        "depth": 2,
        "nodeId": "sha256:vuln...",
        "symbolKey": "Lodash.merge(Object, Object)",
        "edgeKind": "static",
        "vulnerableFunction": true
      }
    ],
    "whyReachable": [
      "Static call path exists from HTTP entrypoint /api/orders/{id}",
      "All edges are statically proven (no heuristics)",
      "Vulnerable function Lodash.merge() is directly invoked"
    ],
    "confidenceFactors": {
      "staticPathExists": 0.50,
      "noHeuristicEdges": 0.20,
      "runtimeConfirmed": 0.00
    }
  },
  "alternativePaths": 2
}

5. Unknowns API

5.1 List Unknowns

GET /api/v1/unknowns

Returns paginated list of unknowns ranked by priority score.

Query Parameters

Parameter Type Default Description
sort string score Sort field: score, created_at, blast_dependents
order string desc Sort order: asc, desc
page int 1 Page number (1-indexed)
pageSize int 50 Items per page (max 200)
artifact string Filter by artifact digest
reason string Filter by reason code
minScore float Minimum score threshold (0-1)
maxScore float Maximum score threshold (0-1)
kev bool Filter by KEV status
seccomp string Filter by seccomp: enforced, permissive, unknown

Response (200 OK)

{
  "items": [
    {
      "id": "unk-12345678-abcd-1234-5678-abcdef123456",
      "artifactDigest": "sha256:abc123...",
      "artifactPurl": "pkg:oci/myapp@sha256:abc123",
      "reasons": ["missing_vex", "ambiguous_indirect_call"],
      "blastRadius": {
        "dependents": 15,
        "netFacing": true,
        "privilege": "user"
      },
      "evidenceScarcity": 0.7,
      "exploitPressure": {
        "epss": 0.45,
        "kev": false
      },
      "containment": {
        "seccomp": "enforced",
        "fs": "ro"
      },
      "score": 0.62,
      "proofRef": "proofs/unknowns/unk-12345678/tree.json",
      "createdAt": "2025-01-15T10:30:00Z",
      "updatedAt": "2025-01-15T10:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 50,
    "totalItems": 142,
    "totalPages": 3
  }
}

5.2 Get Unknown by ID

GET /api/v1/unknowns/{id}

Returns detailed information about a specific unknown.

Response (200 OK)

{
  "id": "unk-12345678-abcd-1234-5678-abcdef123456",
  "artifactDigest": "sha256:abc123...",
  "artifactPurl": "pkg:oci/myapp@sha256:abc123",
  "reasons": ["missing_vex", "ambiguous_indirect_call"],
  "reasonDetails": [
    {
      "code": "missing_vex",
      "message": "No VEX statement found for CVE-2024-1234",
      "component": "pkg:npm/lodash@4.17.20"
    },
    {
      "code": "ambiguous_indirect_call",
      "message": "Indirect call target could not be resolved",
      "location": "src/utils.js:42"
    }
  ],
  "blastRadius": {
    "dependents": 15,
    "netFacing": true,
    "privilege": "user"
  },
  "score": 0.62,
  "scoreBreakdown": {
    "blastComponent": 0.35,
    "scarcityComponent": 0.21,
    "pressureComponent": 0.26,
    "containmentDeduction": -0.20
  },
  "createdAt": "2025-01-15T10:30:00Z",
  "updatedAt": "2025-01-15T10:30:00Z"
}

5.3 Get Unknown Proof

GET /api/v1/unknowns/{id}/proof

Returns the proof tree explaining the ranking decision.

Response (200 OK)

{
  "version": "1.0",
  "unknownId": "unk-12345678-abcd-1234-5678-abcdef123456",
  "nodes": [
    {
      "kind": "input",
      "hash": "sha256:abc...",
      "data": {
        "reasons": ["missing_vex"],
        "evidenceScarcity": 0.7
      }
    },
    {
      "kind": "delta",
      "hash": "sha256:def...",
      "factor": "blast_radius",
      "contribution": 0.35
    },
    {
      "kind": "delta",
      "hash": "sha256:ghi...",
      "factor": "containment_seccomp",
      "contribution": -0.10
    },
    {
      "kind": "score",
      "hash": "sha256:jkl...",
      "finalScore": 0.62
    }
  ],
  "rootHash": "sha256:mno..."
}

5.4 Escalate Unknown

POST /api/v1/unknowns/{id}/escalate

Escalates an unknown to trigger immediate rescan/re-analysis.

Response (202 Accepted)

{
  "unknownId": "unk-001",
  "escalatedAt": "2025-12-17T12:00:00Z",
  "rescanJobId": "rescan-job-001",
  "status": "queued"
}

Errors

Code Description
404 Unknown ID not found
409 Unknown already escalated (rescan in progress)

5.5 Resolve Unknown

POST /api/v1/unknowns/{id}/resolve

Marks an unknown as resolved with resolution details.

Request

{
  "resolution": "not_affected",
  "justification": "vulnerable_code_not_present",
  "notes": "Manual analysis confirmed vulnerable function not used"
}

Response (200 OK)

{
  "unknownId": "unk-001",
  "resolvedAt": "2025-12-17T12:00:00Z",
  "resolution": "not_affected",
  "resolvedBy": "analyst@example.com"
}

5.6 Get Unknowns Summary

GET /api/v1/unknowns/summary

Returns aggregate statistics about unknowns.

Response (200 OK)

{
  "totalCount": 142,
  "byReason": {
    "missing_vex": 45,
    "ambiguous_indirect_call": 32,
    "incomplete_sbom": 28,
    "unknown_platform": 15,
    "other": 22
  },
  "byScoreBucket": {
    "critical": 12,
    "high": 35,
    "medium": 48,
    "low": 47
  },
  "byContainment": {
    "enforced": 45,
    "permissive": 32,
    "unknown": 65
  },
  "kevCount": 8,
  "avgScore": 0.52
}

6. Proof Chain API

6.1 Create Proof Spine

POST /api/v1/proofs/{entry}/spine

Creates a proof spine for an SBOM entry.

Path Parameters

Parameter Format Example
entry sha256:<hash>:pkg:<purl> sha256:abc:pkg:npm/lodash@4.17.21

Request

{
  "evidenceIds": ["sha256:e7f8a9b0..."],
  "reasoningId": "sha256:f0e1d2c3...",
  "vexVerdictId": "sha256:d4c5b6a7...",
  "policyVersion": "v1.2.3"
}

Response (201 Created)

{
  "proofBundleId": "sha256:1a2b3c4d...",
  "receiptUrl": "/proofs/sha256:abc:pkg:npm/lodash@4.17.21/receipt"
}

6.2 Get Proof Spine

GET /api/v1/proofs/{entry}/spine

Gets the proof spine for an SBOM entry.

Response (200 OK)

{
  "sbomEntryId": "sha256:abc123:pkg:npm/lodash@4.17.21",
  "proofBundleId": "sha256:1a2b3c4d...",
  "evidenceIds": ["sha256:e7f8a9b0..."],
  "reasoningId": "sha256:f0e1d2c3...",
  "vexVerdictId": "sha256:d4c5b6a7...",
  "policyVersion": "v1.2.3",
  "createdAt": "2025-12-17T10:00:00Z"
}

6.3 Get Verification Receipt

GET /api/v1/proofs/{entry}/receipt

Gets the human-readable verification receipt.

Response (200 OK)

{
  "graphRevisionId": "grv_sha256:9f8e7d6c...",
  "findingKey": {
    "sbomEntryId": "sha256:abc123:pkg:npm/lodash@4.17.21",
    "vulnerabilityId": "CVE-2025-1234"
  },
  "rule": {
    "id": "critical-vuln-block",
    "version": "v1.0.0"
  },
  "decision": {
    "verdict": "pass",
    "severity": "none",
    "reasoning": "Not affected - vulnerable code not present"
  },
  "createdAt": "2025-12-17T10:00:00Z",
  "verified": true
}

6.4 Verify Proof Bundle

POST /api/v1/proofs/verify

Performs full verification of a proof bundle.

Request

{
  "proofBundleId": "sha256:1a2b3c4d...",
  "checkRekor": true,
  "anchorIds": ["anchor-001"]
}

Response (200 OK)

{
  "proofBundleId": "sha256:1a2b3c4d...",
  "verified": true,
  "checks": {
    "signatureValid": true,
    "idRecomputed": true,
    "merklePathValid": true,
    "rekorInclusionValid": true
  },
  "errors": [],
  "verifiedAt": "2025-12-17T10:00:00Z"
}

Verification Steps

  1. Signature Verification: Verify DSSE envelope against trust anchors
  2. ID Recomputation: Recompute content-addressed IDs and compare
  3. Merkle Path: Verify merkle tree construction
  4. Rekor Inclusion: Verify transparency log proof (if enabled)

7. Data Models

ScanManifest

interface ScanManifest {
  scanId: string;
  createdAtUtc: string;           // ISO 8601
  artifactDigest: string;         // sha256:...
  artifactPurl: string;           // pkg:oci/...
  scannerVersion: string;
  workerVersion: string;
  concelierSnapshotHash: string;
  excititorSnapshotHash: string;
  latticePolicyHash: string;
  deterministic: boolean;
  seed: string;                   // base64
  knobs: Record<string, string>;
}

ProofNode

interface ProofNode {
  id: string;
  kind: "Input" | "Transform" | "Delta" | "Score";
  ruleId: string;
  parentIds: string[];
  evidenceRefs: string[];
  delta: number;
  total: number;
  actor: string;
  tsUtc: string;
  seed: string;
  nodeHash: string;
}

DsseEnvelope

interface DsseEnvelope {
  payloadType: string;
  payload: string;                // base64 canonical JSON
  signatures: DsseSignature[];
}

interface DsseSignature {
  keyid: string;
  sig: string;                    // base64
}

ReachabilityStatus

enum ReachabilityStatus {
  UNREACHABLE = "UNREACHABLE",
  POSSIBLY_REACHABLE = "POSSIBLY_REACHABLE",
  REACHABLE_STATIC = "REACHABLE_STATIC",
  REACHABLE_PROVEN = "REACHABLE_PROVEN",
  UNKNOWN = "UNKNOWN"
}

UnknownReasonCode

Code Description
missing_vex No VEX statement for vulnerability
ambiguous_indirect_call Indirect call target unresolved
incomplete_sbom SBOM missing component data
unknown_platform Platform not recognized
missing_advisory No advisory data for CVE
conflicting_evidence Multiple conflicting data sources
stale_data Data exceeds freshness threshold

8. Error Handling

All errors follow RFC 7807 Problem Details format.

Error Response

{
  "type": "https://stella-ops.org/errors/scan-not-found",
  "title": "Scan Not Found",
  "status": 404,
  "detail": "Scan ID '550e8400...' does not exist.",
  "instance": "/api/v1/scanner/scans/550e8400...",
  "traceId": "trace-001"
}

Error Types

Type Status Description
scan-not-found 404 Scan ID not found
invalid-manifest 400 Manifest validation failed
duplicate-scan 409 Scan with same manifest hash exists
snapshot-not-found 422 Feed/VEX snapshot not found
callgraph-not-uploaded 422 Call graph required before reachability
payload-too-large 413 Request body exceeds size limit
proof-not-found 404 Proof root hash not found
unknown-not-found 404 Unknown ID not found
escalation-conflict 409 Unknown already escalated
rate-limit-exceeded 429 Rate limit exceeded

9. Rate Limiting

Limits by Endpoint

Endpoint Limit Window
POST /scans 100 1 hour
POST /scans/{id}/score/replay 1000 1 hour
POST /callgraphs 100 1 hour
POST /reachability/compute 100 1 hour
GET endpoints 10,000 1 hour
GET /unknowns 100 1 minute
GET /unknowns/{id} 300 1 minute

Response Headers

Header Description
X-RateLimit-Limit Maximum requests per window
X-RateLimit-Remaining Remaining requests
X-RateLimit-Reset Unix timestamp when limit resets

Rate Limit Error (429)

{
  "type": "https://stella-ops.org/errors/rate-limit-exceeded",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "Exceeded 100 requests/hour for POST /scans.",
  "retryAfter": 1234567890
}

10. Examples

Example 1: Complete Scan Workflow

# 1. Create scan with manifest
SCAN_RESP=$(curl -X POST https://scanner.example.com/api/v1/scanner/scans \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "artifactDigest": "sha256:abc123...",
    "artifactPurl": "pkg:oci/myapp@sha256:abc123...",
    "concelierSnapshotHash": "sha256:feed...",
    "excititorSnapshotHash": "sha256:vex...",
    "latticePolicyHash": "sha256:policy...",
    "deterministic": true
  }')

SCAN_ID=$(echo $SCAN_RESP | jq -r '.scanId')

# 2. Upload call graph
curl -X POST "https://scanner.example.com/api/v1/scanner/scans/$SCAN_ID/callgraphs" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Content-Digest: sha256=abc123..." \
  -d @callgraph.json

# 3. Compute reachability
curl -X POST "https://scanner.example.com/api/v1/scanner/scans/$SCAN_ID/reachability/compute" \
  -H "Authorization: Bearer $TOKEN"

# 4. Get findings
curl "https://scanner.example.com/api/v1/scanner/scans/$SCAN_ID/reachability/findings" \
  -H "Authorization: Bearer $TOKEN"

Example 2: Score Replay

# Replay with updated feeds
curl -X POST "https://scanner.example.com/api/v1/scanner/scans/$SCAN_ID/score/replay" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "overrides": {
      "concelierSnapshotHash": "sha256:newfeed..."
    }
  }'

Example 3: Unknowns Management

# List high-priority unknowns
curl "https://scanner.example.com/api/v1/unknowns?minScore=0.7&sort=score&order=desc" \
  -H "Authorization: Bearer $TOKEN"

# Escalate for rescan
curl -X POST "https://scanner.example.com/api/v1/unknowns/unk-001/escalate" \
  -H "Authorization: Bearer $TOKEN"

Example 4: Proof Verification

# Download proof bundle
curl -o proof.zip \
  "https://scanner.example.com/api/v1/scanner/scans/$SCAN_ID/proofs/sha256:proof123..."

# Verify bundle
curl -X POST "https://scanner.example.com/api/v1/proofs/verify" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "proofBundleId": "sha256:1a2b3c4d...",
    "checkRekor": true
  }'


Last Updated: 2025-12-20
API Version: 1.0.0
Sprint: 3500.0004.0004