Files
git.stella-ops.org/docs/api/unknowns-api.md

359 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Unknowns API Reference
**Sprint:** SPRINT_3600_0002_0001
**Task:** UNK-RANK-011 - Update unknowns API documentation
## Overview
The Unknowns API provides access to items that could not be fully classified due to missing evidence, ambiguous data, or incomplete intelligence. Unknowns are ranked by blast radius, exploit pressure, and containment signals.
## Base URL
```
/api/v1/unknowns
```
## Authentication
All endpoints require Bearer token authentication:
```http
Authorization: Bearer <token>
```
Required scope: `scanner:unknowns:read`
## Endpoints
### List Unknowns
```http
GET /api/v1/unknowns
```
Returns paginated list of unknowns, optionally sorted by 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 state: `enforced`, `permissive`, `unknown` |
#### Response
```json
{
"items": [
{
"id": "unk-12345678-abcd-1234-5678-abcdef123456",
"artifactDigest": "sha256:abc123...",
"artifactPurl": "pkg:oci/myapp@sha256:abc123",
"reasonCode": "Reachability",
"reasonCodeShort": "U-RCH",
"remediationHint": "Run reachability analysis",
"detailedHint": "Execute call-graph analysis to determine if vulnerable code paths are reachable from application entrypoints.",
"automationCommand": "stella analyze --reachability",
"evidenceRefs": [
{
"type": "reachability",
"uri": "proofs/unknowns/unk-12345678/evidence.json",
"digest": "sha256:0a1b2c..."
}
],
"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
}
}
```
#### Example
```bash
# Get top 10 highest-scored unknowns
curl -H "Authorization: Bearer $TOKEN" \
"https://scanner.example.com/api/v1/unknowns?sort=score&order=desc&pageSize=10"
# Filter by KEV and minimum score
curl -H "Authorization: Bearer $TOKEN" \
"https://scanner.example.com/api/v1/unknowns?kev=true&minScore=0.5"
# Filter by artifact
curl -H "Authorization: Bearer $TOKEN" \
"https://scanner.example.com/api/v1/unknowns?artifact=sha256:abc123"
```
### Get Unknown by ID
```http
GET /api/v1/unknowns/{id}
```
Returns detailed information about a specific unknown.
#### Response
```json
{
"id": "unk-12345678-abcd-1234-5678-abcdef123456",
"artifactDigest": "sha256:abc123...",
"artifactPurl": "pkg:oci/myapp@sha256:abc123",
"reasonCode": "Reachability",
"reasonCodeShort": "U-RCH",
"remediationHint": "Run reachability analysis",
"detailedHint": "Execute call-graph analysis to determine if vulnerable code paths are reachable from application entrypoints.",
"automationCommand": "stella analyze --reachability",
"evidenceRefs": [
{
"type": "reachability",
"uri": "proofs/unknowns/unk-12345678/evidence.json",
"digest": "sha256:0a1b2c..."
}
],
"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"
},
"evidenceScarcity": 0.7,
"exploitPressure": {
"epss": 0.45,
"kev": false
},
"containment": {
"seccomp": "enforced",
"fs": "ro"
},
"score": 0.62,
"scoreBreakdown": {
"blastComponent": 0.35,
"scarcityComponent": 0.21,
"pressureComponent": 0.26,
"containmentDeduction": -0.20
},
"proofRef": "proofs/unknowns/unk-12345678/tree.json",
"createdAt": "2025-01-15T10:30:00Z",
"updatedAt": "2025-01-15T10:30:00Z"
}
```
### Get Unknown Proof
```http
GET /api/v1/unknowns/{id}/proof
```
Returns the proof tree explaining the ranking decision.
#### Response
```json
{
"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..."
}
```
### Batch Get Unknowns
```http
POST /api/v1/unknowns/batch
```
Get multiple unknowns by ID in a single request.
#### Request Body
```json
{
"ids": [
"unk-12345678-abcd-1234-5678-abcdef123456",
"unk-87654321-dcba-4321-8765-654321fedcba"
]
}
```
#### Response
Same format as list response with matching items.
### Get Unknowns Summary
```http
GET /api/v1/unknowns/summary
```
Returns aggregate statistics about unknowns.
#### Query Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `artifact` | string | Filter by artifact digest |
#### Response
```json
{
"totalCount": 142,
"byReason": {
"missing_vex": 45,
"ambiguous_indirect_call": 32,
"incomplete_sbom": 28,
"unknown_platform": 15,
"other": 22
},
"byScoreBucket": {
"critical": 12, // score >= 0.8
"high": 35, // 0.6 <= score < 0.8
"medium": 48, // 0.4 <= score < 0.6
"low": 47 // score < 0.4
},
"byContainment": {
"enforced": 45,
"permissive": 32,
"unknown": 65
},
"kevCount": 8,
"avgScore": 0.52
}
```
## Reason Codes
| Code | Short Code | Description |
|------|------------|-------------|
| `Reachability` | `U-RCH` | Call path analysis is indeterminate. |
| `Identity` | `U-ID` | Ambiguous package identity or missing digest. |
| `Provenance` | `U-PROV` | Cannot map binary artifact to source repository. |
| `VexConflict` | `U-VEX` | VEX statements conflict or applicability data is missing. |
| `FeedGap` | `U-FEED` | Required advisory/feed coverage missing or stale. |
| `ConfigUnknown` | `U-CONFIG` | Runtime configuration or feature flags not observable. |
| `AnalyzerLimit` | `U-ANALYZER` | Language or framework not supported by analyzer. |
## Score Calculation
The unknown score is calculated as:
```
score = 0.60 × blast + 0.30 × scarcity + 0.30 × pressure + containment_deduction
```
Where:
- `blast` = normalized blast radius (0-1)
- `scarcity` = evidence scarcity factor (0-1)
- `pressure` = exploit pressure (EPSS + KEV factor)
- `containment_deduction` = -0.10 for enforced seccomp, -0.10 for read-only FS
### Blast Radius Normalization
```
dependents_normalized = min(dependents / 50, 1.0)
net_factor = 0.5 if net_facing else 0.0
priv_factor = 0.5 if privilege == "root" else 0.0
blast = min((dependents_normalized + net_factor + priv_factor) / 2, 1.0)
```
### Exploit Pressure
```
epss_normalized = epss ?? 0.35 // Default if unknown
kev_factor = 0.30 if kev else 0.0
pressure = min(epss_normalized + kev_factor, 1.0)
```
## Error Responses
| Status | Code | Description |
|--------|------|-------------|
| 400 | `INVALID_PARAMETER` | Invalid query parameter |
| 401 | `UNAUTHORIZED` | Missing or invalid token |
| 403 | `FORBIDDEN` | Insufficient permissions |
| 404 | `NOT_FOUND` | Unknown not found |
| 429 | `RATE_LIMITED` | Too many requests |
## Rate Limits
- List: 100 requests/minute
- Get by ID: 300 requests/minute
- Summary: 60 requests/minute
## Related Documentation
- [Unknowns Ranking Technical Reference](../product-advisories/14-Dec-2025%20-%20Triage%20and%20Unknowns%20Technical%20Reference.md)
- [Scanner Architecture](../modules/scanner/architecture.md)
- [Proof Bundle Format](../api/proof-bundle-format.md)