{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://stella-ops.org/schemas/exception-lifecycle.schema.json", "title": "StellaOps Exception Lifecycle Schema", "description": "Schema for exception lifecycle, routing, approvals, and governance. Unblocks DOCS-EXC-25-001 through 25-006 (5 tasks).", "type": "object", "definitions": { "Exception": { "type": "object", "description": "Security exception request", "required": ["exception_id", "finding_id", "status", "justification", "requested_at", "requested_by"], "properties": { "exception_id": { "type": "string", "format": "uuid" }, "finding_id": { "type": "string", "format": "uuid", "description": "Finding this exception applies to" }, "finding_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "Multiple findings for bulk exception" }, "exception_type": { "type": "string", "enum": [ "false_positive", "risk_accepted", "compensating_control", "deferred_remediation", "not_applicable", "wont_fix" ] }, "status": { "$ref": "#/definitions/ExceptionStatus" }, "justification": { "type": "string", "minLength": 10, "description": "Business justification for exception" }, "compensating_controls": { "type": "array", "items": { "$ref": "#/definitions/CompensatingControl" } }, "scope": { "$ref": "#/definitions/ExceptionScope" }, "effective_at": { "type": "string", "format": "date-time" }, "expires_at": { "type": "string", "format": "date-time" }, "requested_at": { "type": "string", "format": "date-time" }, "requested_by": { "type": "string", "description": "User who requested exception" }, "approvals": { "type": "array", "items": { "$ref": "#/definitions/Approval" } }, "routing": { "$ref": "#/definitions/RoutingInfo" }, "audit_trail": { "type": "array", "items": { "$ref": "#/definitions/AuditEntry" } }, "risk_assessment": { "$ref": "#/definitions/RiskAssessment" }, "attachments": { "type": "array", "items": { "$ref": "#/definitions/Attachment" } }, "tags": { "type": "array", "items": { "type": "string" } }, "metadata": { "type": "object", "additionalProperties": true } } }, "ExceptionStatus": { "type": "string", "enum": [ "draft", "pending_review", "pending_approval", "approved", "rejected", "expired", "revoked", "superseded" ] }, "CompensatingControl": { "type": "object", "description": "Compensating control for accepted risk", "required": ["control_id", "description"], "properties": { "control_id": { "type": "string" }, "description": { "type": "string" }, "control_type": { "type": "string", "enum": ["technical", "administrative", "physical", "procedural"] }, "effectiveness": { "type": "string", "enum": ["high", "medium", "low"] }, "verification_method": { "type": "string" }, "last_verified_at": { "type": "string", "format": "date-time" } } }, "ExceptionScope": { "type": "object", "description": "Scope of the exception", "properties": { "scope_type": { "type": "string", "enum": ["finding", "component", "project", "organization"] }, "tenant_id": { "type": "string", "format": "uuid" }, "project_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } }, "component_patterns": { "type": "array", "items": { "type": "string" }, "description": "PURL patterns to match" }, "cve_patterns": { "type": "array", "items": { "type": "string" }, "description": "CVE patterns to match" } } }, "Approval": { "type": "object", "description": "Approval record", "required": ["approver_id", "decision", "decided_at"], "properties": { "approval_id": { "type": "string", "format": "uuid" }, "approver_id": { "type": "string" }, "approver_name": { "type": "string" }, "approver_role": { "type": "string" }, "decision": { "type": "string", "enum": ["approved", "rejected", "deferred"] }, "decided_at": { "type": "string", "format": "date-time" }, "comments": { "type": "string" }, "conditions": { "type": "array", "items": { "type": "string" }, "description": "Conditions attached to approval" }, "signature": { "type": "string", "description": "Digital signature of approval" } } }, "RoutingInfo": { "type": "object", "description": "Routing configuration for exception workflow", "properties": { "workflow_id": { "type": "string" }, "current_step": { "type": "string" }, "approval_chain": { "type": "array", "items": { "$ref": "#/definitions/ApprovalStep" } }, "escalation_policy": { "$ref": "#/definitions/EscalationPolicy" }, "notifications": { "type": "array", "items": { "$ref": "#/definitions/NotificationConfig" } } } }, "ApprovalStep": { "type": "object", "description": "Step in approval chain", "required": ["step_id", "approvers"], "properties": { "step_id": { "type": "string" }, "step_name": { "type": "string" }, "approvers": { "type": "array", "items": { "$ref": "#/definitions/ApproverConfig" } }, "approval_type": { "type": "string", "enum": ["any", "all", "quorum"], "default": "any" }, "quorum_count": { "type": "integer", "minimum": 1 }, "timeout_hours": { "type": "integer" }, "status": { "type": "string", "enum": ["pending", "completed", "skipped"] } } }, "ApproverConfig": { "type": "object", "description": "Approver configuration", "properties": { "type": { "type": "string", "enum": ["user", "role", "group", "dynamic"] }, "identifier": { "type": "string" }, "fallback_approvers": { "type": "array", "items": { "type": "string" } } } }, "EscalationPolicy": { "type": "object", "description": "Escalation policy for stalled approvals", "properties": { "enabled": { "type": "boolean", "default": true }, "escalation_after_hours": { "type": "integer", "default": 48 }, "max_escalation_levels": { "type": "integer", "default": 3 }, "escalation_targets": { "type": "array", "items": { "type": "string" } }, "auto_approve_on_timeout": { "type": "boolean", "default": false }, "auto_reject_on_timeout": { "type": "boolean", "default": false } } }, "NotificationConfig": { "type": "object", "description": "Notification configuration", "properties": { "event": { "type": "string", "enum": [ "exception_created", "pending_approval", "approved", "rejected", "expiring_soon", "expired", "escalated" ] }, "channels": { "type": "array", "items": { "type": "string", "enum": ["email", "slack", "teams", "webhook"] } }, "recipients": { "type": "array", "items": { "type": "string" } } } }, "AuditEntry": { "type": "object", "description": "Audit trail entry", "required": ["action", "actor", "timestamp"], "properties": { "entry_id": { "type": "string", "format": "uuid" }, "action": { "type": "string", "enum": [ "created", "updated", "submitted", "approved", "rejected", "revoked", "expired", "escalated", "comment_added" ] }, "actor": { "type": "string" }, "timestamp": { "type": "string", "format": "date-time" }, "details": { "type": "object", "additionalProperties": true }, "ip_address": { "type": "string" } } }, "RiskAssessment": { "type": "object", "description": "Risk assessment for exception", "properties": { "original_risk_score": { "type": "number", "minimum": 0, "maximum": 10 }, "residual_risk_score": { "type": "number", "minimum": 0, "maximum": 10, "description": "Risk after compensating controls" }, "risk_factors": { "type": "array", "items": { "$ref": "#/definitions/RiskFactor" } }, "business_impact": { "type": "string", "enum": ["critical", "high", "medium", "low", "minimal"] }, "data_sensitivity": { "type": "string", "enum": ["public", "internal", "confidential", "restricted"] }, "assessed_by": { "type": "string" }, "assessed_at": { "type": "string", "format": "date-time" } } }, "RiskFactor": { "type": "object", "description": "Individual risk factor", "properties": { "factor_name": { "type": "string" }, "impact": { "type": "string", "enum": ["increase", "decrease", "neutral"] }, "weight": { "type": "number", "minimum": 0, "maximum": 1 }, "rationale": { "type": "string" } } }, "Attachment": { "type": "object", "description": "Supporting attachment", "required": ["attachment_id", "filename"], "properties": { "attachment_id": { "type": "string", "format": "uuid" }, "filename": { "type": "string" }, "content_type": { "type": "string" }, "size_bytes": { "type": "integer" }, "storage_uri": { "type": "string", "format": "uri" }, "checksum": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" }, "uploaded_at": { "type": "string", "format": "date-time" }, "uploaded_by": { "type": "string" } } }, "ExceptionPolicy": { "type": "object", "description": "Exception governance policy", "required": ["policy_id", "name"], "properties": { "policy_id": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "max_exception_duration_days": { "type": "integer", "minimum": 1 }, "require_compensating_controls": { "type": "boolean", "default": false }, "require_risk_assessment": { "type": "boolean", "default": true }, "severity_thresholds": { "$ref": "#/definitions/SeverityThresholds" }, "auto_renewal": { "$ref": "#/definitions/AutoRenewalConfig" }, "compliance_frameworks": { "type": "array", "items": { "type": "string" }, "description": "Applicable compliance frameworks" } } }, "SeverityThresholds": { "type": "object", "description": "Approval thresholds by severity", "properties": { "critical": { "$ref": "#/definitions/ThresholdConfig" }, "high": { "$ref": "#/definitions/ThresholdConfig" }, "medium": { "$ref": "#/definitions/ThresholdConfig" }, "low": { "$ref": "#/definitions/ThresholdConfig" } } }, "ThresholdConfig": { "type": "object", "properties": { "max_duration_days": { "type": "integer" }, "required_approver_roles": { "type": "array", "items": { "type": "string" } }, "min_approvers": { "type": "integer", "minimum": 1 }, "allow_exception": { "type": "boolean", "default": true } } }, "AutoRenewalConfig": { "type": "object", "description": "Auto-renewal configuration", "properties": { "enabled": { "type": "boolean", "default": false }, "max_renewals": { "type": "integer" }, "renewal_review_required": { "type": "boolean", "default": true } } }, "ExceptionSearchQuery": { "type": "object", "description": "Query for searching exceptions", "properties": { "exception_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } }, "finding_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } }, "statuses": { "type": "array", "items": { "$ref": "#/definitions/ExceptionStatus" } }, "exception_types": { "type": "array", "items": { "type": "string" } }, "requested_by": { "type": "string" }, "approved_by": { "type": "string" }, "created_after": { "type": "string", "format": "date-time" }, "created_before": { "type": "string", "format": "date-time" }, "expiring_within_days": { "type": "integer" }, "page": { "type": "integer", "minimum": 1, "default": 1 }, "page_size": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } } }, "ExceptionSearchResult": { "type": "object", "description": "Search result", "required": ["exceptions", "total_count"], "properties": { "exceptions": { "type": "array", "items": { "$ref": "#/definitions/Exception" } }, "total_count": { "type": "integer", "minimum": 0 }, "page": { "type": "integer" }, "page_size": { "type": "integer" }, "next_page_token": { "type": "string" } } } }, "properties": { "exceptions": { "type": "array", "items": { "$ref": "#/definitions/Exception" } } }, "examples": [ { "exceptions": [ { "exception_id": "550e8400-e29b-41d4-a716-446655440000", "finding_id": "660e8400-e29b-41d4-a716-446655440001", "exception_type": "risk_accepted", "status": "approved", "justification": "This vulnerability exists in a test-only dependency that is not deployed to production. The affected code path is never executed in any deployed environment.", "compensating_controls": [ { "control_id": "CC-001", "description": "Network segmentation prevents access to affected component", "control_type": "technical", "effectiveness": "high" } ], "scope": { "scope_type": "component", "component_patterns": ["pkg:npm/test-lib@*"] }, "effective_at": "2025-12-06T00:00:00Z", "expires_at": "2026-06-06T00:00:00Z", "requested_at": "2025-12-01T10:00:00Z", "requested_by": "dev-team-lead@example.com", "approvals": [ { "approval_id": "770e8400-e29b-41d4-a716-446655440002", "approver_id": "security-manager@example.com", "approver_name": "Jane Security", "approver_role": "Security Manager", "decision": "approved", "decided_at": "2025-12-05T14:00:00Z", "comments": "Approved with 6-month duration due to low residual risk", "conditions": ["Re-evaluate if component moves to production"] } ], "risk_assessment": { "original_risk_score": 7.5, "residual_risk_score": 2.0, "business_impact": "low", "data_sensitivity": "internal" } } ] } ] }