Files
git.stella-ops.org/docs/contracts/triage-suppress-v1.md
2026-02-19 22:07:11 +02:00

6.5 KiB

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

{
  "$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

{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [
    {
      "name": "artifact",
      "digest": {
        "sha256": "<canonical_id_hex>"
      }
    }
  ],
  "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:

{
  "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