{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://stella-ops.org/schemas/risk-api.schema.json", "title": "StellaOps Risk API Schema", "description": "Schema for Risk API endpoints, scoring models, and factor weights. Unblocks DOCS-RISK-67-002 through 68-002 (5+ tasks).", "type": "object", "definitions": { "RiskScore": { "type": "object", "description": "Computed risk score", "required": ["score", "rating", "computed_at"], "properties": { "score": { "type": "number", "minimum": 0, "maximum": 100, "description": "Numeric risk score (0-100)" }, "rating": { "type": "string", "enum": ["critical", "high", "medium", "low", "info", "none"], "description": "Risk rating category" }, "computed_at": { "type": "string", "format": "date-time" }, "confidence": { "type": "number", "minimum": 0, "maximum": 1, "description": "Confidence level in the score (0-1)" }, "factors": { "type": "array", "items": { "$ref": "#/definitions/RiskFactor" } }, "trend": { "$ref": "#/definitions/RiskTrend" } } }, "RiskFactor": { "type": "object", "description": "Individual risk factor contribution", "required": ["factor_id", "name", "value", "weight", "contribution"], "properties": { "factor_id": { "type": "string" }, "name": { "type": "string" }, "category": { "type": "string", "enum": ["vulnerability", "exposure", "asset", "context", "temporal", "environmental"] }, "value": { "type": "number", "description": "Raw factor value" }, "normalized_value": { "type": "number", "minimum": 0, "maximum": 1, "description": "Normalized value (0-1)" }, "weight": { "type": "number", "minimum": 0, "maximum": 1, "description": "Factor weight in scoring model" }, "contribution": { "type": "number", "description": "Contribution to final score" }, "source": { "type": "string", "description": "Data source for this factor" }, "evidence": { "type": "array", "items": { "type": "string" }, "description": "Evidence supporting this factor" } } }, "RiskTrend": { "type": "object", "description": "Risk score trend over time", "properties": { "direction": { "type": "string", "enum": ["improving", "stable", "degrading"] }, "change_percent": { "type": "number", "description": "Percent change from previous period" }, "period": { "type": "string", "enum": ["24h", "7d", "30d"] }, "previous_score": { "type": "number" } } }, "RiskProfile": { "type": "object", "description": "Risk profile configuration", "required": ["profile_id", "name"], "properties": { "profile_id": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "scoring_model": { "$ref": "#/definitions/ScoringModel" }, "thresholds": { "$ref": "#/definitions/RiskThresholds" }, "factor_weights": { "type": "object", "additionalProperties": { "type": "number", "minimum": 0, "maximum": 1 } }, "enabled_factors": { "type": "array", "items": { "type": "string" } }, "metadata": { "type": "object", "additionalProperties": true } } }, "ScoringModel": { "type": "object", "description": "Risk scoring model configuration", "required": ["model_id", "name"], "properties": { "model_id": { "type": "string" }, "name": { "type": "string" }, "version": { "type": "string" }, "type": { "type": "string", "enum": ["weighted_sum", "geometric_mean", "max_severity", "custom"], "description": "Scoring algorithm type" }, "base_score_source": { "type": "string", "enum": ["cvss_v3", "cvss_v4", "epss", "custom"], "description": "Primary score source" }, "modifiers": { "type": "array", "items": { "$ref": "#/definitions/ScoreModifier" } } } }, "ScoreModifier": { "type": "object", "description": "Score modifier rule", "required": ["modifier_id", "condition", "adjustment"], "properties": { "modifier_id": { "type": "string" }, "name": { "type": "string" }, "condition": { "type": "string", "description": "Condition expression (e.g., 'kev == true')" }, "adjustment": { "type": "number", "description": "Score adjustment (can be positive or negative)" }, "adjustment_type": { "type": "string", "enum": ["absolute", "percent", "multiply"], "default": "absolute" }, "priority": { "type": "integer", "description": "Order of modifier application" } } }, "RiskThresholds": { "type": "object", "description": "Risk rating thresholds", "properties": { "critical": { "type": "number", "default": 90, "description": "Score >= this is Critical" }, "high": { "type": "number", "default": 70, "description": "Score >= this is High" }, "medium": { "type": "number", "default": 40, "description": "Score >= this is Medium" }, "low": { "type": "number", "default": 10, "description": "Score >= this is Low" }, "info": { "type": "number", "default": 0, "description": "Score >= this is Info" } } }, "RiskAssessmentRequest": { "type": "object", "description": "Request to compute risk for an entity", "required": ["entity_type", "entity_id"], "properties": { "entity_type": { "type": "string", "enum": ["vulnerability", "asset", "component", "project", "tenant"] }, "entity_id": { "type": "string" }, "profile_id": { "type": "string", "description": "Risk profile to use (uses default if not specified)" }, "include_factors": { "type": "boolean", "default": true, "description": "Include factor breakdown in response" }, "include_trend": { "type": "boolean", "default": false, "description": "Include trend analysis" }, "context": { "type": "object", "additionalProperties": true, "description": "Additional context for scoring" } } }, "RiskAssessmentResponse": { "type": "object", "description": "Risk assessment result", "required": ["assessment_id", "entity_type", "entity_id", "score"], "properties": { "assessment_id": { "type": "string", "format": "uuid" }, "entity_type": { "type": "string" }, "entity_id": { "type": "string" }, "profile_id": { "type": "string" }, "score": { "$ref": "#/definitions/RiskScore" }, "explainability": { "$ref": "#/definitions/RiskExplainability" }, "recommendations": { "type": "array", "items": { "$ref": "#/definitions/RiskRecommendation" } } } }, "RiskExplainability": { "type": "object", "description": "Human-readable explanation of risk score", "properties": { "summary": { "type": "string", "description": "One-line summary" }, "narrative": { "type": "string", "description": "Detailed explanation" }, "top_factors": { "type": "array", "items": { "type": "object", "properties": { "factor": { "type": "string" }, "impact": { "type": "string", "enum": ["major", "moderate", "minor"] }, "explanation": { "type": "string" } } }, "description": "Top contributing factors" }, "comparisons": { "type": "object", "properties": { "org_percentile": { "type": "number", "description": "Percentile within organization" }, "industry_percentile": { "type": "number", "description": "Percentile within industry" } } } } }, "RiskRecommendation": { "type": "object", "description": "Risk mitigation recommendation", "required": ["recommendation_id", "action"], "properties": { "recommendation_id": { "type": "string" }, "action": { "type": "string", "description": "Recommended action" }, "priority": { "type": "string", "enum": ["critical", "high", "medium", "low"] }, "impact_estimate": { "type": "number", "description": "Estimated score reduction if implemented" }, "effort": { "type": "string", "enum": ["minimal", "moderate", "significant"] }, "related_factors": { "type": "array", "items": { "type": "string" } } } }, "RiskAggregation": { "type": "object", "description": "Aggregated risk across multiple entities", "required": ["aggregation_id", "entity_type", "count", "scores"], "properties": { "aggregation_id": { "type": "string" }, "entity_type": { "type": "string" }, "scope": { "type": "string", "description": "Aggregation scope (e.g., project, tenant)" }, "count": { "type": "integer", "description": "Number of entities aggregated" }, "scores": { "type": "object", "properties": { "average": { "type": "number" }, "median": { "type": "number" }, "max": { "type": "number" }, "min": { "type": "number" }, "p95": { "type": "number" } } }, "distribution": { "type": "object", "properties": { "critical": { "type": "integer" }, "high": { "type": "integer" }, "medium": { "type": "integer" }, "low": { "type": "integer" }, "info": { "type": "integer" } } }, "trend": { "$ref": "#/definitions/RiskTrend" } } }, "RiskApiEndpoint": { "type": "object", "description": "Risk API endpoint definition", "required": ["path", "method", "operation_id"], "properties": { "path": { "type": "string" }, "method": { "type": "string", "enum": ["GET", "POST", "PUT", "DELETE"] }, "operation_id": { "type": "string" }, "summary": { "type": "string" }, "request_schema": { "type": "string", "description": "Reference to request schema" }, "response_schema": { "type": "string", "description": "Reference to response schema" }, "scopes": { "type": "array", "items": { "type": "string" }, "description": "Required OAuth scopes" } } } }, "properties": { "endpoints": { "type": "array", "items": { "$ref": "#/definitions/RiskApiEndpoint" } }, "profiles": { "type": "array", "items": { "$ref": "#/definitions/RiskProfile" } } }, "examples": [ { "endpoints": [ { "path": "/api/v1/risk/assess", "method": "POST", "operation_id": "assessRisk", "summary": "Compute risk score for an entity", "request_schema": "RiskAssessmentRequest", "response_schema": "RiskAssessmentResponse", "scopes": ["risk:read"] }, { "path": "/api/v1/risk/profiles", "method": "GET", "operation_id": "listRiskProfiles", "summary": "List available risk profiles", "response_schema": "RiskProfile[]", "scopes": ["risk:read"] }, { "path": "/api/v1/risk/aggregate", "method": "POST", "operation_id": "aggregateRisk", "summary": "Compute aggregated risk across entities", "response_schema": "RiskAggregation", "scopes": ["risk:read"] }, { "path": "/api/v1/risk/profiles/{profile_id}", "method": "PUT", "operation_id": "updateRiskProfile", "summary": "Update a risk profile", "request_schema": "RiskProfile", "scopes": ["risk:write", "admin"] }, { "path": "/api/v1/risk/explain/{assessment_id}", "method": "GET", "operation_id": "explainRisk", "summary": "Get detailed explanation for a risk assessment", "response_schema": "RiskExplainability", "scopes": ["risk:read"] } ], "profiles": [ { "profile_id": "default", "name": "Default Risk Profile", "description": "Standard risk scoring with balanced factor weights", "scoring_model": { "model_id": "weighted-sum-v1", "name": "Weighted Sum Model", "version": "1.0.0", "type": "weighted_sum", "base_score_source": "cvss_v3", "modifiers": [ { "modifier_id": "kev-boost", "name": "KEV Exploit Known", "condition": "kev == true", "adjustment": 15, "adjustment_type": "absolute", "priority": 1 }, { "modifier_id": "reachability-reduction", "name": "Not Reachable", "condition": "reachability == 'not_reachable'", "adjustment": -30, "adjustment_type": "absolute", "priority": 2 }, { "modifier_id": "vex-not-affected", "name": "VEX Not Affected", "condition": "vex_status == 'not_affected'", "adjustment": -50, "adjustment_type": "absolute", "priority": 3 } ] }, "thresholds": { "critical": 90, "high": 70, "medium": 40, "low": 10, "info": 0 }, "factor_weights": { "cvss_base": 0.35, "exploitability": 0.25, "reachability": 0.20, "asset_criticality": 0.10, "exposure": 0.10 }, "enabled_factors": [ "cvss_base", "exploitability", "kev", "epss", "reachability", "vex_status", "asset_criticality", "exposure", "age" ] } ] } ] }