# Contract: Triage Auto-Suppress Predicate (v1) ## Status - Status: DRAFT (2026-02-19) - Owner: Signals Guild, VexLens Guild - Sprint: SPRINT_20260219_012 ## Purpose Define the `stella.ops/triageSuppress@v1` predicate type used when a runtime micro-witness DSSE confirms that a vulnerability's `canonical_id` matches a VEX `not_affected` consensus, enabling automatic triage suppression with full auditability. ## Predicate Type URI ``` stella.ops/triageSuppress@v1 ``` ## When This Predicate Is Emitted The TriageSuppressJoinService emits this predicate when ALL of the following conditions are met: 1. A micro-witness DSSE exists for `(canonical_id, cve_id)` with observation type `RuntimeUnobserved` or a path witness with lattice state `ConfirmedUnreachable` or `StaticallyUnreachable` 2. VexLens consensus for `(canonical_id, cve_id)` has status `not_affected` 3. VexLens consensus confidence score >= configured threshold (default: 0.75 for production) ## Suppression Rules Truth Table | VEX Status | Reachability State | Action | Requires Human Review | |---|---|---|---| | `not_affected` | `ConfirmedUnreachable` (CU) | **AUTO-SUPPRESS** | No | | `not_affected` | `StaticallyUnreachable` (SU) | **AUTO-SUPPRESS** | No | | `not_affected` | `RuntimeUnobserved` (RU) | **AUTO-SUPPRESS** | No | | `not_affected` | `Unknown` (U) | LOG ONLY | Yes | | `not_affected` | `StaticallyReachable` (SR) | LOG ONLY | Yes | | `not_affected` | `RuntimeObserved` (RO) | LOG ONLY, FLAG CONFLICT | Yes | | `not_affected` | `ConfirmedReachable` (CR) | LOG ONLY, FLAG CONFLICT | Yes | | `not_affected` | `Contested` (X) | LOG ONLY, FLAG CONFLICT | Yes | | `affected` | any | NEVER SUPPRESS | Yes | | `under_investigation` | any | NEVER SUPPRESS | Yes | | `fixed` | any | NEVER SUPPRESS (separate workflow) | No | ## Predicate Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Triage Suppress Predicate v1", "type": "object", "required": ["cve_id", "suppress_reason", "vex_consensus", "witness_evidence", "reachability_state", "timestamp"], "properties": { "cve_id": { "type": "string", "description": "CVE identifier (e.g., CVE-2025-0001)", "pattern": "^CVE-\\d{4}-\\d{4,}$" }, "suppress_reason": { "type": "string", "enum": ["vex_not_affected_with_unreachability_confirmation"], "description": "Machine-readable reason for suppression" }, "vex_consensus": { "type": "object", "required": ["status", "confidence_score", "consensus_digest", "computed_at"], "properties": { "status": { "type": "string", "enum": ["not_affected"] }, "justification": { "type": "string" }, "confidence_score": { "type": "number", "minimum": 0, "maximum": 1 }, "consensus_digest": { "type": "string", "description": "SHA-256 of the VexLens consensus record" }, "source_count": { "type": "integer", "description": "Number of VEX sources contributing" }, "computed_at": { "type": "string", "format": "date-time" } } }, "witness_evidence": { "type": "object", "required": ["witness_id", "dsse_digest", "observation_type"], "properties": { "witness_id": { "type": "string", "description": "Witness ID (wit:sha256:...)" }, "dsse_digest": { "type": "string", "description": "SHA-256 of the witness DSSE envelope" }, "observation_type": { "type": "string", "enum": ["RuntimeUnobserved", "ConfirmedUnreachable", "StaticallyUnreachable"] }, "predicate_type": { "type": "string", "description": "URI of the witness predicate type" } } }, "reachability_state": { "type": "string", "enum": ["ConfirmedUnreachable", "StaticallyUnreachable", "RuntimeUnobserved"], "description": "Lattice state from the 8-state reachability model" }, "timestamp": { "type": "string", "format": "date-time", "description": "UTC timestamp of suppression evaluation" }, "deterministic_replay_inputs": { "type": "object", "description": "Inputs sufficient to replay this suppression decision", "properties": { "canonical_id": { "type": "string" }, "vex_consensus_digest": { "type": "string" }, "witness_id": { "type": "string" } } } } } ``` ## DSSE Envelope Shape ```json { "_type": "https://in-toto.io/Statement/v1", "subject": [ { "name": "artifact", "digest": { "sha256": "" } } ], "predicateType": "stella.ops/triageSuppress@v1", "predicate": { "cve_id": "CVE-2025-0001", "suppress_reason": "vex_not_affected_with_unreachability_confirmation", "vex_consensus": { "status": "not_affected", "justification": "vulnerable_code_not_in_execute_path", "confidence_score": 0.92, "consensus_digest": "sha256:abc123...", "source_count": 3, "computed_at": "2026-02-19T12:00:00Z" }, "witness_evidence": { "witness_id": "wit:sha256:def456...", "dsse_digest": "sha256:789abc...", "observation_type": "ConfirmedUnreachable", "predicate_type": "https://stella.ops/predicates/path-witness/v1" }, "reachability_state": "ConfirmedUnreachable", "timestamp": "2026-02-19T12:05:00Z", "deterministic_replay_inputs": { "canonical_id": "sha256:...", "vex_consensus_digest": "sha256:abc123...", "witness_id": "wit:sha256:def456..." } } } ``` ## Idempotency Given the same `(canonical_id, cve_id, vex_consensus_digest, witness_id)`, the service MUST produce byte-identical DSSE output. This is enforced by: - Deterministic JSON serialization (RFC 8785 / JCS) - Deterministic timestamp: use the latest of `vex_consensus.computed_at` and witness `observed_at` - No random or time-varying fields ## Policy Opt-In Auto-suppress is disabled by default. Operators must enable it via policy configuration: ```json { "triage_suppress": { "enabled": true, "minimum_vex_confidence": 0.75, "allowed_reachability_states": ["ConfirmedUnreachable", "StaticallyUnreachable", "RuntimeUnobserved"], "require_rekor_anchor": true } } ``` ## Audit Trail Every suppression evaluation (whether it results in suppression or not) is logged: - Suppressed: triageSuppress@v1 DSSE → Signer → Attestor → Rekor - Not suppressed: audit log entry with reason (e.g., "vex_status=affected", "reachability=Contested") ## References - SPRINT_20260219_012 - Reachability Lattice: `docs/modules/reach-graph/guides/lattice.md` - VexLens Consensus: `docs/modules/vex-lens/architecture.md` - Witness Contract: `docs/contracts/witness-v1.md`