- 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.
334 lines
7.2 KiB
Markdown
334 lines
7.2 KiB
Markdown
# Proof Chain API Reference
|
|
|
|
> **Version**: 1.0.0
|
|
> **OpenAPI Spec**: [`proofs-openapi.yaml`](./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:
|
|
1. Canonicalizing the JSON payload (RFC 8785/JCS)
|
|
2. Computing SHA-256 hash
|
|
3. 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 receipts
|
|
- `proofs.write` - Create proof spines
|
|
- `anchors.manage` - Manage trust anchors
|
|
- `proofs.verify` - Perform verification
|
|
|
|
---
|
|
|
|
## Endpoints
|
|
|
|
### Proofs
|
|
|
|
#### POST /proofs/{entry}/spine
|
|
|
|
Create a proof spine for an SBOM entry.
|
|
|
|
**Parameters:**
|
|
- `entry` (path, required): SBOMEntryID in format `sha256:<hash>:pkg:<purl>`
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"evidenceIds": ["sha256:e7f8a9b0..."],
|
|
"reasoningId": "sha256:f0e1d2c3...",
|
|
"vexVerdictId": "sha256:d4c5b6a7...",
|
|
"policyVersion": "v1.2.3"
|
|
}
|
|
```
|
|
|
|
**Response (201 Created):**
|
|
```json
|
|
{
|
|
"proofBundleId": "sha256:1a2b3c4d...",
|
|
"receiptUrl": "/proofs/sha256:abc:pkg:npm/lodash@4.17.21/receipt"
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `400 Bad Request`: Invalid SBOM entry ID format
|
|
- `404 Not Found`: Evidence, reasoning, or VEX verdict not found
|
|
- `422 Unprocessable Entity`: Validation error
|
|
|
|
---
|
|
|
|
#### GET /proofs/{entry}/spine
|
|
|
|
Get the proof spine for an SBOM entry.
|
|
|
|
**Parameters:**
|
|
- `entry` (path, required): SBOMEntryID
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"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):**
|
|
```json
|
|
{
|
|
"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):**
|
|
```json
|
|
{
|
|
"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):**
|
|
```json
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"keyId": "sha256:abc123...",
|
|
"algorithm": "ECDSA-P256",
|
|
"publicKey": "-----BEGIN PUBLIC KEY-----\n..."
|
|
}
|
|
```
|
|
|
|
**Response (201 Created):**
|
|
```json
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"proofBundleId": "sha256:1a2b3c4d...",
|
|
"checkRekor": true,
|
|
"anchorIds": ["anchor-001"]
|
|
}
|
|
```
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"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 signatures against trust anchors
|
|
2. **ID Recomputation**: Recompute content-addressed IDs and compare
|
|
3. **Merkle Path Verification**: Verify proof bundle merkle tree construction
|
|
4. **Rekor Inclusion**: Verify transparency log inclusion proof (if enabled)
|
|
|
|
---
|
|
|
|
#### POST /verify/batch
|
|
|
|
Verify multiple proof bundles in a single request.
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"bundles": [
|
|
{ "proofBundleId": "sha256:1a2b3c4d...", "checkRekor": true },
|
|
{ "proofBundleId": "sha256:5e6f7g8h...", "checkRekor": false }
|
|
]
|
|
}
|
|
```
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"results": [
|
|
{ "proofBundleId": "sha256:1a2b3c4d...", "verified": true, "checks": {...} },
|
|
{ "proofBundleId": "sha256:5e6f7g8h...", "verified": false, "errors": ["..."] }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
All errors follow RFC 7807 Problem Details format:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{
|
|
"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](../modules/attestor/architecture.md#predicate-types) - DSSE predicate type specifications
|
|
- [Content-Addressed IDs](../modules/attestor/architecture.md#content-addressed-identifier-formats) - ID generation rules
|
|
- [Attestor Architecture](../modules/attestor/architecture.md) - Full attestor module documentation
|