- Add RateLimitConfig for configuration management with YAML binding support. - Introduce RateLimitDecision to encapsulate the result of rate limit checks. - Implement RateLimitMetrics for OpenTelemetry metrics tracking. - Create RateLimitMiddleware for enforcing rate limits on incoming requests. - Develop RateLimitService to orchestrate instance and environment rate limit checks. - Add RateLimitServiceCollectionExtensions for dependency injection registration.
7.2 KiB
Proof Chain API Reference
Version: 1.0.0
OpenAPI Spec:proofs-openapi.yaml
The Proof Chain API provides endpoints for creating and verifying cryptographic proof bundles that link SBOM entries to vulnerability assessments through attestable DSSE envelopes.
Overview
The proof chain creates an auditable, cryptographically-verifiable trail from vulnerability evidence through policy reasoning to VEX verdicts. Each component is signed with DSSE envelopes and aggregated into a merkle-rooted proof spine.
Proof Chain Components
| Component | Predicate Type | Purpose |
|---|---|---|
| Evidence | evidence.stella/v1 |
Raw findings from scanners/feeds |
| Reasoning | reasoning.stella/v1 |
Policy evaluation trace |
| VEX Verdict | cdx-vex.stella/v1 |
Final VEX status determination |
| Proof Spine | proofspine.stella/v1 |
Merkle aggregation of all components |
| Verdict Receipt | verdict.stella/v1 |
Human-readable verification receipt |
Content-Addressed IDs
All proof chain components use content-addressed identifiers:
Format: sha256:<64-hex-chars>
Example: sha256:e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6...
IDs are computed by:
- Canonicalizing the JSON payload (RFC 8785/JCS)
- Computing SHA-256 hash
- Prefixing with
sha256:
Authentication
All endpoints require authentication via:
- Bearer Token: Authority-issued OpToken with appropriate scopes
- mTLS: Mutual TLS with client certificate (service-to-service)
Required scopes:
proofs.read- Read proof bundles and receiptsproofs.write- Create proof spinesanchors.manage- Manage trust anchorsproofs.verify- Perform verification
Endpoints
Proofs
POST /proofs/{entry}/spine
Create a proof spine for an SBOM entry.
Parameters:
entry(path, required): SBOMEntryID in formatsha256:<hash>:pkg:<purl>
Request Body:
{
"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"
}
Errors:
400 Bad Request: Invalid SBOM entry ID format404 Not Found: Evidence, reasoning, or VEX verdict not found422 Unprocessable Entity: Validation error
GET /proofs/{entry}/spine
Get the proof spine for an SBOM entry.
Parameters:
entry(path, required): SBOMEntryID
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"
}
GET /proofs/{entry}/receipt
Get the verification receipt for an SBOM entry's proof spine.
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
}
GET /proofs/{entry}/vex
Get the VEX attestation for an SBOM entry.
Response (200 OK):
{
"sbomEntryId": "sha256:abc123:pkg:npm/lodash@4.17.21",
"vulnerabilityId": "CVE-2025-1234",
"status": "not_affected",
"justification": "vulnerable_code_not_present",
"policyVersion": "v1.2.3",
"reasoningId": "sha256:f0e1d2c3...",
"vexVerdictId": "sha256:d4c5b6a7..."
}
Trust Anchors
GET /anchors
List all configured trust anchors.
Response (200 OK):
{
"anchors": [
{
"id": "anchor-001",
"keyId": "sha256:abc123...",
"algorithm": "ECDSA-P256",
"status": "active",
"createdAt": "2025-01-01T00:00:00Z"
}
]
}
POST /anchors
Create a new trust anchor.
Request Body:
{
"keyId": "sha256:abc123...",
"algorithm": "ECDSA-P256",
"publicKey": "-----BEGIN PUBLIC KEY-----\n..."
}
Response (201 Created):
{
"id": "anchor-002",
"keyId": "sha256:abc123...",
"algorithm": "ECDSA-P256",
"status": "active",
"createdAt": "2025-12-17T10:00:00Z"
}
DELETE /anchors/{anchorId}
Delete (revoke) a trust anchor.
Response: 204 No Content
Verification
POST /verify
Perform full verification of a proof bundle.
Request Body:
{
"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:
- Signature Verification: Verify DSSE envelope signatures against trust anchors
- ID Recomputation: Recompute content-addressed IDs and compare
- Merkle Path Verification: Verify proof bundle merkle tree construction
- Rekor Inclusion: Verify transparency log inclusion proof (if enabled)
POST /verify/batch
Verify multiple proof bundles in a single request.
Request Body:
{
"bundles": [
{ "proofBundleId": "sha256:1a2b3c4d...", "checkRekor": true },
{ "proofBundleId": "sha256:5e6f7g8h...", "checkRekor": false }
]
}
Response (200 OK):
{
"results": [
{ "proofBundleId": "sha256:1a2b3c4d...", "verified": true, "checks": {...} },
{ "proofBundleId": "sha256:5e6f7g8h...", "verified": false, "errors": ["..."] }
]
}
Error Handling
All errors follow RFC 7807 Problem Details format:
{
"title": "Validation Error",
"detail": "Evidence ID sha256:abc... not found",
"status": 422,
"errors": {
"evidenceIds[0]": ["Evidence not found"]
}
}
Common Error Codes
| Status | Meaning |
|---|---|
| 400 | Invalid request format or parameters |
| 401 | Authentication required |
| 403 | Insufficient permissions |
| 404 | Resource not found |
| 409 | Conflict (e.g., anchor already exists) |
| 422 | Validation error |
| 500 | Internal server error |
Offline Verification
For air-gapped environments, verification can be performed without Rekor:
{
"proofBundleId": "sha256:1a2b3c4d...",
"checkRekor": false
}
This skips Rekor inclusion proof verification but still performs:
- DSSE signature verification
- Content-addressed ID recomputation
- Merkle path verification
Related Documentation
- Proof Chain Predicates - DSSE predicate type specifications
- Content-Addressed IDs - ID generation rules
- Attestor Architecture - Full attestor module documentation