Files
git.stella-ops.org/docs/api/proofs.md
master 8bbfe4d2d2 feat(rate-limiting): Implement core rate limiting functionality with configuration, decision-making, metrics, middleware, and service registration
- 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.
2025-12-17 18:02:37 +02:00

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