save progress
This commit is contained in:
354
docs/api/vex-proof-schema.md
Normal file
354
docs/api/vex-proof-schema.md
Normal file
@@ -0,0 +1,354 @@
|
||||
# VEX Proof Object Schema Reference
|
||||
|
||||
Version: 1.0 (stellaops.vex-proof.v1)
|
||||
Last Updated: 2026-01-03
|
||||
|
||||
## Overview
|
||||
|
||||
VEX Proof Objects provide a cryptographically verifiable audit trail of how VEX consensus verdicts are computed. Every VEX resolution in StellaOps produces a proof object that documents the inputs, merge process, and decision rationale.
|
||||
|
||||
## JSON Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "VEX Proof Object",
|
||||
"type": "object",
|
||||
"required": ["schema", "proofId", "computedAt", "verdict", "inputs", "mergeTrace", "confidence"],
|
||||
"properties": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"const": "stellaops.vex-proof.v1"
|
||||
},
|
||||
"proofId": {
|
||||
"type": "string",
|
||||
"description": "Unique identifier for this proof"
|
||||
},
|
||||
"computedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO 8601 timestamp of proof computation"
|
||||
},
|
||||
"digest": {
|
||||
"type": "object",
|
||||
"description": "Content-addressed hash of the proof"
|
||||
},
|
||||
"verdict": {
|
||||
"$ref": "#/definitions/verdict"
|
||||
},
|
||||
"inputs": {
|
||||
"$ref": "#/definitions/inputs"
|
||||
},
|
||||
"mergeTrace": {
|
||||
"$ref": "#/definitions/mergeTrace"
|
||||
},
|
||||
"propagation": {
|
||||
"$ref": "#/definitions/propagation"
|
||||
},
|
||||
"conditions": {
|
||||
"$ref": "#/definitions/conditions"
|
||||
},
|
||||
"confidence": {
|
||||
"$ref": "#/definitions/confidence"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Object Definitions
|
||||
|
||||
### Verdict
|
||||
|
||||
The final consensus result.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `vulnerabilityId` | string | Yes | CVE or vulnerability identifier |
|
||||
| `productKey` | string | Yes | Product identifier (typically a PURL) |
|
||||
| `status` | enum | Yes | VEX status: `affected`, `not_affected`, `fixed`, `under_investigation` |
|
||||
| `justification` | enum | No | Justification code if status is `not_affected` |
|
||||
| `confidence` | number | Yes | Confidence score [0.0, 1.0] |
|
||||
|
||||
```json
|
||||
{
|
||||
"vulnerabilityId": "CVE-2023-12345",
|
||||
"productKey": "pkg:npm/lodash@4.17.21",
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"confidence": 0.78
|
||||
}
|
||||
```
|
||||
|
||||
### Inputs
|
||||
|
||||
All VEX statements considered in the consensus.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `qualifiedCount` | integer | Yes | Number of statements meeting weight threshold |
|
||||
| `disqualifiedCount` | integer | Yes | Number of statements filtered out |
|
||||
| `statements` | array | Yes | Array of input statements |
|
||||
| `disqualified` | array | No | Array of disqualified statements with reasons |
|
||||
|
||||
#### Statement Object
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `id` | string | Yes | Statement identifier |
|
||||
| `source` | string | Yes | Source document identifier |
|
||||
| `issuer` | object | Yes | Issuer information |
|
||||
| `status` | enum | Yes | VEX status from this statement |
|
||||
| `justification` | enum | No | Justification if not_affected |
|
||||
| `weight` | object | Yes | Weight calculation details |
|
||||
| `timestamp` | datetime | Yes | Statement timestamp |
|
||||
| `signatureVerified` | boolean | Yes | Whether signature was verified |
|
||||
|
||||
#### Issuer Object
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `id` | string | Yes | Issuer identifier |
|
||||
| `category` | enum | Yes | `vendor`, `distributor`, `community`, `internal`, `aggregator` |
|
||||
| `trustTier` | enum | Yes | `authoritative`, `trusted`, `untrusted`, `unknown` |
|
||||
|
||||
#### Weight Object
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `composite` | number | Yes | Final composite weight [0.0, 1.0] |
|
||||
| `factors` | object | Yes | Individual weight factors |
|
||||
|
||||
Weight factors:
|
||||
- `issuer`: Issuer trust weight
|
||||
- `signature`: Signature verification weight
|
||||
- `freshness`: Statement age weight
|
||||
- `format`: Source format weight (OpenVEX vs CSAF vs CycloneDX)
|
||||
- `specificity`: Status specificity weight
|
||||
|
||||
### MergeTrace
|
||||
|
||||
Step-by-step documentation of the merge algorithm.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `mode` | enum | Yes | Consensus mode used |
|
||||
| `latticeOrdering` | array | No | Status lattice order (for Lattice mode) |
|
||||
| `steps` | array | Yes | Array of merge steps |
|
||||
| `conflicts` | array | No | Array of detected conflicts |
|
||||
|
||||
#### Consensus Modes
|
||||
|
||||
- `highest_weight`: Select statement with highest trust weight
|
||||
- `weighted_vote`: Weighted voting across all statements
|
||||
- `lattice`: Lattice-based conservative consensus
|
||||
- `authoritative_first`: Prefer vendor/authoritative sources
|
||||
|
||||
#### Merge Step
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `stepNumber` | integer | Yes | Sequential step number |
|
||||
| `statementId` | string | Yes | Statement being processed |
|
||||
| `inputStatus` | enum | Yes | Status from this statement |
|
||||
| `inputWeight` | number | Yes | Weight of this statement |
|
||||
| `action` | enum | Yes | `initialize`, `merge`, `skip` |
|
||||
| `conflictDetected` | boolean | Yes | Whether conflict was detected |
|
||||
| `resolution` | string | No | How conflict was resolved |
|
||||
| `positionAfter` | enum | Yes | Current consensus position after step |
|
||||
|
||||
#### Conflict
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `statement1Id` | string | Yes | First conflicting statement |
|
||||
| `statement2Id` | string | Yes | Second conflicting statement |
|
||||
| `status1` | enum | Yes | Status of first statement |
|
||||
| `status2` | enum | Yes | Status of second statement |
|
||||
| `severity` | enum | Yes | `critical`, `high`, `medium`, `low` |
|
||||
| `resolution` | string | Yes | Resolution method |
|
||||
| `winnerId` | string | No | Winning statement ID |
|
||||
|
||||
### Propagation
|
||||
|
||||
Dependency propagation analysis (optional).
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `applied` | boolean | Yes | Whether propagation was applied |
|
||||
| `rules` | array | Yes | Propagation rules evaluated |
|
||||
| `paths` | array | No | Analyzed dependency paths |
|
||||
| `inheritedStatus` | enum | No | Status inherited via propagation |
|
||||
| `overrideApplied` | boolean | No | Whether propagation overrode consensus |
|
||||
|
||||
#### Propagation Rules
|
||||
|
||||
- `direct_dependency_affected`: Affected status propagates to direct dependents
|
||||
- `transitive_dependency`: Transitive propagation through dependency tree
|
||||
- `dependency_fixed`: Fixed status doesn't propagate transitively
|
||||
- `dependency_not_affected`: NotAffected can propagate under conditions
|
||||
|
||||
### Conditions
|
||||
|
||||
Condition evaluation results (optional).
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `results` | array | Yes | Condition evaluation results |
|
||||
| `unevaluated` | array | No | Conditions that couldn't be evaluated |
|
||||
| `coverage` | number | Yes | Percentage of conditions evaluated |
|
||||
|
||||
#### Condition Result
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `conditionId` | string | Yes | Condition identifier |
|
||||
| `expression` | string | Yes | Condition expression |
|
||||
| `result` | enum | Yes | `true`, `false`, `unknown` |
|
||||
| `contextValue` | string | No | Evaluated context value |
|
||||
|
||||
#### Condition Types
|
||||
|
||||
- `platform`: OS/architecture (e.g., `linux/amd64`)
|
||||
- `distro`: Distribution (e.g., `rhel:9`)
|
||||
- `feature`: Feature flag condition
|
||||
- `build_flag`: Compile-time flag
|
||||
- `environment`: Environment variable
|
||||
|
||||
### Confidence
|
||||
|
||||
Confidence score breakdown.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `score` | number | Yes | Overall confidence [0.0, 1.0] |
|
||||
| `tier` | enum | Yes | `high`, `medium`, `low` |
|
||||
| `components` | object | Yes | Score components |
|
||||
| `improvements` | array | No | Suggestions for improving confidence |
|
||||
|
||||
Score component contributions:
|
||||
- `weightSpread`: Statement weight distribution
|
||||
- `freshnessBonus`: Bonus for recent statements
|
||||
- `signatureBonus`: Bonus for signed statements
|
||||
- `conflictPenalty`: Penalty for conflicts
|
||||
- `conditionCoverage`: Condition evaluation coverage
|
||||
|
||||
## Digest Computation
|
||||
|
||||
The proof digest is computed using RFC 8785 canonical JSON serialization:
|
||||
|
||||
1. Serialize proof object to canonical JSON (sorted keys, minimal escaping)
|
||||
2. Compute SHA-256 hash of canonical JSON bytes
|
||||
3. Encode as hexadecimal
|
||||
|
||||
```json
|
||||
{
|
||||
"digest": {
|
||||
"algorithm": "sha256",
|
||||
"value": "a1b2c3d4..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Example Proof Object
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "stellaops.vex-proof.v1",
|
||||
"proofId": "proof-2026-01-02T10:30:00Z-abc123",
|
||||
"computedAt": "2026-01-02T10:30:00Z",
|
||||
"digest": {
|
||||
"algorithm": "sha256",
|
||||
"value": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"verdict": {
|
||||
"vulnerabilityId": "CVE-2023-12345",
|
||||
"productKey": "pkg:npm/lodash@4.17.21",
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"confidence": 0.78
|
||||
},
|
||||
"inputs": {
|
||||
"qualifiedCount": 2,
|
||||
"disqualifiedCount": 0,
|
||||
"statements": [
|
||||
{
|
||||
"id": "stmt-001",
|
||||
"source": "openvex",
|
||||
"issuer": {
|
||||
"id": "lodash-maintainers",
|
||||
"category": "vendor",
|
||||
"trustTier": "authoritative"
|
||||
},
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"weight": {
|
||||
"composite": 0.85,
|
||||
"factors": {
|
||||
"issuer": 0.90,
|
||||
"signature": 1.00,
|
||||
"freshness": 0.95,
|
||||
"format": 1.00,
|
||||
"specificity": 0.70
|
||||
}
|
||||
},
|
||||
"timestamp": "2023-06-15T10:30:00Z",
|
||||
"signatureVerified": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"mergeTrace": {
|
||||
"mode": "lattice",
|
||||
"latticeOrdering": ["affected", "under_investigation", "fixed", "not_affected"],
|
||||
"steps": [
|
||||
{
|
||||
"stepNumber": 1,
|
||||
"statementId": "stmt-001",
|
||||
"inputStatus": "not_affected",
|
||||
"inputWeight": 0.85,
|
||||
"action": "initialize",
|
||||
"conflictDetected": false,
|
||||
"positionAfter": "not_affected"
|
||||
}
|
||||
],
|
||||
"conflicts": []
|
||||
},
|
||||
"confidence": {
|
||||
"score": 0.78,
|
||||
"tier": "medium",
|
||||
"components": {
|
||||
"weightSpread": 0.80,
|
||||
"freshnessBonus": 0.05,
|
||||
"signatureBonus": 0.05,
|
||||
"conflictPenalty": 0.00,
|
||||
"conditionCoverage": 0.00
|
||||
},
|
||||
"improvements": [
|
||||
"Add statements from additional authoritative sources",
|
||||
"Evaluate platform-specific conditions"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Policy Integration
|
||||
|
||||
VEX proofs integrate with the policy gate system via `VexProofGate`:
|
||||
|
||||
| Setting | Type | Default | Description |
|
||||
|---------|------|---------|-------------|
|
||||
| `Enabled` | bool | true | Enable/disable gate |
|
||||
| `MinimumConfidenceTier` | string | medium | Required confidence tier |
|
||||
| `RequireProofForNotAffected` | bool | true | Require proof for NotAffected |
|
||||
| `RequireProofForFixed` | bool | false | Require proof for Fixed |
|
||||
| `MaxAllowedConflicts` | int | 5 | Maximum allowed conflicts |
|
||||
| `MaxProofAgeHours` | int | 168 | Maximum proof age (hours) |
|
||||
| `RequireSignedStatements` | bool | false | Require all statements signed |
|
||||
| `MinimumInputStatements` | int | 1 | Minimum input statement count |
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [VEX Consensus Guide](../16_VEX_CONSENSUS_GUIDE.md)
|
||||
- [Trust Weight Configuration](../trust-weights.md)
|
||||
- [Policy Gates Reference](../policy-gates.md)
|
||||
- [OpenVEX Specification](https://github.com/openvex/spec)
|
||||
- [CycloneDX VEX](https://cyclonedx.org/use-cases/vulnerability-exploitability/)
|
||||
Reference in New Issue
Block a user