# 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](../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/)