Files
git.stella-ops.org/docs/contracts/risk-scoring.md
master cc69d332e3
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Add unit tests for RabbitMq and Udp transport servers and clients
- Implemented comprehensive unit tests for RabbitMqTransportServer, covering constructor, disposal, connection management, event handlers, and exception handling.
- Added configuration tests for RabbitMqTransportServer to validate SSL, durable queues, auto-recovery, and custom virtual host options.
- Created unit tests for UdpFrameProtocol, including frame parsing and serialization, header size validation, and round-trip data preservation.
- Developed tests for UdpTransportClient, focusing on connection handling, event subscriptions, and exception scenarios.
- Established tests for UdpTransportServer, ensuring proper start/stop behavior, connection state management, and event handling.
- Included tests for UdpTransportOptions to verify default values and modification capabilities.
- Enhanced service registration tests for Udp transport services in the dependency injection container.
2025-12-05 19:01:12 +02:00

6.2 KiB
Raw Permalink Blame History

Risk Scoring Contract (66-002)

Contract ID: CONTRACT-RISK-SCORING-002 Version: 1.0 Status: Published Last Updated: 2025-12-05

Overview

This contract defines the risk scoring interface used by the Policy Engine to calculate and prioritize vulnerability findings. It covers job requests, results, risk profiles, and signal definitions.

Implementation References

  • Scoring Models: src/Policy/StellaOps.Policy.Engine/Scoring/RiskScoringModels.cs
  • Risk Profile: src/Policy/StellaOps.Policy.RiskProfile/Models/RiskProfileModel.cs
  • Attestation Schema: src/Attestor/StellaOps.Attestor.Types/schemas/stellaops-risk-profile.v1.schema.json

Data Models

RiskScoringJobRequest

Request to create a risk scoring job.

{
  "tenant_id": "string",
  "context_id": "string",
  "profile_id": "string",
  "findings": [
    {
      "finding_id": "string",
      "component_purl": "pkg:npm/lodash@4.17.20",
      "advisory_id": "CVE-2024-1234",
      "trigger": "created|updated|enriched|vex_applied"
    }
  ],
  "priority": "low|normal|high|emergency",
  "correlation_id": "string (optional)",
  "requested_at": "2025-12-05T00:00:00Z (optional)"
}

RiskScoringJob

A queued or completed risk scoring job.

{
  "job_id": "string",
  "tenant_id": "string",
  "context_id": "string",
  "profile_id": "string",
  "profile_hash": "sha256:...",
  "findings": [...],
  "priority": "normal",
  "status": "queued|running|completed|failed|cancelled",
  "requested_at": "2025-12-05T00:00:00Z",
  "started_at": "2025-12-05T00:00:01Z (optional)",
  "completed_at": "2025-12-05T00:00:02Z (optional)",
  "correlation_id": "string (optional)",
  "error_message": "string (optional)"
}

RiskScoringResult

Result of scoring a single finding.

{
  "finding_id": "string",
  "profile_id": "string",
  "profile_version": "1.0.0",
  "raw_score": 0.75,
  "normalized_score": 0.85,
  "severity": "high",
  "signal_values": {
    "cvss": 7.5,
    "kev": true,
    "reachability": 0.9
  },
  "signal_contributions": {
    "cvss": 0.4,
    "kev": 0.3,
    "reachability": 0.3
  },
  "override_applied": "kev-boost (optional)",
  "override_reason": "Known Exploited Vulnerability (optional)",
  "scored_at": "2025-12-05T00:00:02Z"
}

Risk Profile Model

RiskProfileModel

Defines how findings are scored and prioritized.

{
  "id": "default-profile",
  "version": "1.0.0",
  "description": "Default risk profile for vulnerability prioritization",
  "extends": "base-profile (optional)",
  "signals": [
    {
      "name": "cvss",
      "source": "nvd",
      "type": "numeric",
      "path": "/cvss/base_score",
      "transform": "normalize_10",
      "unit": "score"
    },
    {
      "name": "kev",
      "source": "cisa",
      "type": "boolean",
      "path": "/kev/in_catalog"
    },
    {
      "name": "reachability",
      "source": "scanner",
      "type": "numeric",
      "path": "/reachability/score"
    }
  ],
  "weights": {
    "cvss": 0.4,
    "kev": 0.3,
    "reachability": 0.3
  },
  "overrides": {
    "severity": [
      {
        "when": { "kev": true },
        "set": "critical"
      }
    ],
    "decisions": [
      {
        "when": { "kev": true, "reachability": { "$gt": 0.8 } },
        "action": "deny",
        "reason": "KEV with high reachability"
      }
    ]
  },
  "metadata": {}
}

Signal Types

Type Description Value Range
boolean True/false signal true / false
numeric Numeric signal 0.0 to 1.0 (normalized)
categorical Categorical signal String values

Severity Levels

Level JSON Value Priority
Critical "critical" 1 (highest)
High "high" 2
Medium "medium" 3
Low "low" 4
Informational "informational" 5 (lowest)

Decision Actions

Action Description
allow Finding is acceptable, no action required
review Finding requires manual review
deny Finding is not acceptable, blocks promotion

Scoring Algorithm

Score Calculation

raw_score = Σ(signal_value × weight) for all signals
normalized_score = clamp(raw_score, 0.0, 1.0)

VEX Gate Provider

The VEX gate provider short-circuits scoring when a VEX denial is present:

if (signals.HasVexDenial)
    return 0.0;  // Fully mitigated

return Math.Max(signals.Values);  // Otherwise, max signal

CVSS + KEV Provider

score = clamp01((cvss / 10.0) + kevBonus)
where kevBonus = kev ? 0.2 : 0.0

API Endpoints

Submit Scoring Job

POST /api/v1/risk/jobs
Content-Type: application/json

{
  "tenant_id": "...",
  "context_id": "...",
  "profile_id": "...",
  "findings": [...]
}

Response: 202 Accepted
{
  "job_id": "...",
  "status": "queued"
}

Get Job Status

GET /api/v1/risk/jobs/{job_id}

Response: 200 OK
{
  "job_id": "...",
  "status": "completed",
  "results": [...]
}

Get Finding Score

GET /api/v1/risk/findings/{finding_id}/score

Response: 200 OK
{
  "finding_id": "...",
  "normalized_score": 0.85,
  "severity": "high",
  ...
}

Finding Change Events

Events that trigger rescoring:

Event JSON Value Description
Created "created" New finding discovered
Updated "updated" Finding metadata changed
Enriched "enriched" New signals available
VEX Applied "vex_applied" VEX status changed

Determinism Guarantees

  1. Reproducible scores: Same inputs always produce same outputs
  2. Profile versioning: Profile hash included in results for traceability
  3. Signal ordering: Signals processed in deterministic order
  4. Timestamp precision: UTC ISO-8601 with millisecond precision

Unblocks

This contract unblocks the following tasks:

  • LEDGER-RISK-67-001
  • LEDGER-RISK-68-001
  • LEDGER-RISK-69-001
  • POLICY-RISK-67-003
  • POLICY-RISK-68-001
  • POLICY-RISK-68-002