189 lines
5.5 KiB
YAML
189 lines
5.5 KiB
YAML
# Vuln Explorer API · v1 (draft 2025-11-25)
|
|
openapi: 3.0.3
|
|
info:
|
|
title: StellaOps Vuln Explorer API
|
|
version: "1.0.0-draft.2025-11-25"
|
|
description: >
|
|
Read-only vulnerability exploration surface. All responses are deterministic
|
|
under identical inputs and include policy version + rationale identifiers.
|
|
servers:
|
|
- url: https://{host}
|
|
variables:
|
|
host:
|
|
default: vuln-explorer.local
|
|
tags:
|
|
- name: Vulns
|
|
paths:
|
|
/vulns:
|
|
get:
|
|
summary: List vulnerabilities
|
|
tags: [Vulns]
|
|
parameters:
|
|
- $ref: '#/components/parameters/Tenant'
|
|
- $ref: '#/components/parameters/PolicyVersion'
|
|
- $ref: '#/components/parameters/PageSize'
|
|
- $ref: '#/components/parameters/PageToken'
|
|
- $ref: '#/components/parameters/Cve'
|
|
- $ref: '#/components/parameters/Purl'
|
|
- $ref: '#/components/parameters/Severity'
|
|
- $ref: '#/components/parameters/Exploitability'
|
|
- $ref: '#/components/parameters/FixAvailable'
|
|
responses:
|
|
'200':
|
|
description: Paged vulnerabilities ordered by (score desc, id asc).
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/VulnListResponse'
|
|
/vulns/{id}:
|
|
get:
|
|
summary: Get vulnerability by stable ID
|
|
tags: [Vulns]
|
|
parameters:
|
|
- $ref: '#/components/parameters/Tenant'
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
description: Stable vulnerability id (hash over source ids+purls).
|
|
responses:
|
|
'200':
|
|
description: Vulnerability detail with evidence/provenance.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Vuln'
|
|
'404':
|
|
description: Not found for tenant/policy scope.
|
|
|
|
components:
|
|
parameters:
|
|
Tenant:
|
|
name: x-stella-tenant
|
|
in: header
|
|
required: true
|
|
schema: { type: string }
|
|
description: Tenant identifier; required for all endpoints.
|
|
PolicyVersion:
|
|
name: policyVersion
|
|
in: query
|
|
schema: { type: string }
|
|
description: Policy version/rationale to contextualise scores.
|
|
PageSize:
|
|
name: pageSize
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 200
|
|
default: 50
|
|
description: Max items per page.
|
|
PageToken:
|
|
name: pageToken
|
|
in: query
|
|
schema: { type: string }
|
|
description: Opaque token encoding last (score,id) tuple.
|
|
Cve:
|
|
name: cve
|
|
in: query
|
|
schema: { type: array, items: { type: string }, minItems: 1 }
|
|
style: form
|
|
explode: true
|
|
description: Filter by CVE ids.
|
|
Purl:
|
|
name: purl
|
|
in: query
|
|
schema: { type: array, items: { type: string }, minItems: 1 }
|
|
style: form
|
|
explode: true
|
|
description: Filter by PURL(s); matches affected packages.
|
|
Severity:
|
|
name: severity
|
|
in: query
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum: [CRITICAL, HIGH, MEDIUM, LOW, NONE]
|
|
style: form
|
|
explode: true
|
|
description: Filter by normalized severity band.
|
|
Exploitability:
|
|
name: exploitability
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [known, likely, unknown, none]
|
|
description: Derived exploitability flag (from KEV + VEX + telemetry).
|
|
FixAvailable:
|
|
name: fixAvailable
|
|
in: query
|
|
schema: { type: boolean }
|
|
description: Whether at least one fix is available.
|
|
|
|
schemas:
|
|
VulnListResponse:
|
|
type: object
|
|
properties:
|
|
items:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/Vuln' }
|
|
nextPageToken:
|
|
type: string
|
|
description: Opaque token encoding last (score,id) tuple.
|
|
required: [items]
|
|
Vuln:
|
|
type: object
|
|
properties:
|
|
id: { type: string, description: Stable hash id }
|
|
source:
|
|
type: object
|
|
properties:
|
|
feed: { type: string, description: Original source/feed name }
|
|
advisoryId: { type: string }
|
|
cveIds:
|
|
type: array
|
|
items: { type: string }
|
|
ghsaIds:
|
|
type: array
|
|
items: { type: string }
|
|
purls:
|
|
type: array
|
|
items: { type: string }
|
|
severity: { type: string, enum: [CRITICAL, HIGH, MEDIUM, LOW, NONE] }
|
|
score: { type: number, format: double, minimum: 0, maximum: 10 }
|
|
kev: { type: boolean }
|
|
exploitability: { type: string, enum: [known, likely, unknown, none] }
|
|
fixAvailable: { type: boolean }
|
|
summary: { type: string }
|
|
affectedPackages:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
purl: { type: string }
|
|
versions: { type: array, items: { type: string } }
|
|
firstSeen: { type: string, format: date-time }
|
|
lastSeen: { type: string, format: date-time }
|
|
advisoryRefs:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
url: { type: string, format: uri }
|
|
title: { type: string }
|
|
policyVersion: { type: string }
|
|
rationaleId: { type: string }
|
|
provenance:
|
|
type: object
|
|
properties:
|
|
ledgerEntryId: { type: string }
|
|
evidenceBundleId: { type: string }
|
|
required:
|
|
- id
|
|
- severity
|
|
- score
|
|
- policyVersion
|
|
- rationaleId
|