88 lines
2.8 KiB
Python
88 lines
2.8 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any, Literal
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
Severity = Literal['info', 'low', 'medium', 'high', 'critical']
|
|
Confidence = Literal['low', 'medium', 'high']
|
|
ReviewStatus = Literal['healthy', 'warning', 'critical', 'partial', 'unknown']
|
|
FindingStatus = Literal['open', 'acknowledged', 'dismissed', 'resolved']
|
|
RecommendationStatus = Literal['open', 'snoozed', 'dismissed', 'accepted']
|
|
SecurityReviewScope = Literal['all', 'exposure', 'auth', 'secrets', 'policies', 'connectors', 'audit', 'unraid', 'media']
|
|
|
|
|
|
class SecurityEvidence(BaseModel):
|
|
source: str
|
|
label: str
|
|
value: Any = None
|
|
observed: Any = None
|
|
expected: Any = None
|
|
referenceId: str | None = None
|
|
redacted: bool = False
|
|
|
|
|
|
class SecuritySuggestedAction(BaseModel):
|
|
label: str
|
|
type: Literal['link', 'policy_draft', 'approval_request', 'open_page', 'run_readonly_check']
|
|
actionId: str | None = None
|
|
target: str | None = None
|
|
policyDecision: str = 'allowed'
|
|
risk: str = 'low'
|
|
href: str | None = None
|
|
executable: bool = False
|
|
|
|
|
|
class SecurityFinding(BaseModel):
|
|
id: str
|
|
title: str
|
|
description: str
|
|
severity: Severity
|
|
confidence: Confidence
|
|
category: Literal['exposure', 'auth_coverage', 'coverage', 'connector_config', 'secrets', 'policies', 'connectors', 'audit', 'inventory', 'unraid', 'media']
|
|
affectedResources: list[str] = Field(default_factory=list)
|
|
evidence: list[SecurityEvidence] = Field(default_factory=list)
|
|
suggestedActions: list[SecuritySuggestedAction] = Field(default_factory=list)
|
|
status: FindingStatus = 'open'
|
|
createdAt: str
|
|
riskReason: str
|
|
links: list[dict[str, Any]] = Field(default_factory=list)
|
|
|
|
|
|
class SecurityRecommendation(BaseModel):
|
|
id: str
|
|
title: str
|
|
description: str
|
|
severity: Severity
|
|
confidence: Confidence
|
|
evidence: list[SecurityEvidence] = Field(default_factory=list)
|
|
affectedResources: list[str] = Field(default_factory=list)
|
|
suggestedAction: str
|
|
suggestedActions: list[SecuritySuggestedAction] = Field(default_factory=list)
|
|
policyDecision: str = 'allowed'
|
|
actionTarget: str | None = None
|
|
canAutoApply: bool = False
|
|
status: RecommendationStatus = 'open'
|
|
|
|
|
|
class SecurityReviewSummary(BaseModel):
|
|
status: ReviewStatus
|
|
score: int
|
|
generatedAt: str
|
|
dataCompleteness: dict[str, Any]
|
|
criticalFindings: int
|
|
highFindings: int = 0
|
|
mediumFindings: int = 0
|
|
warningFindings: int
|
|
infoFindings: int
|
|
recommendationsCount: int
|
|
connectedSources: list[str]
|
|
scoreBreakdown: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class SecurityReviewResult(BaseModel):
|
|
summary: SecurityReviewSummary
|
|
findings: list[SecurityFinding]
|
|
recommendations: list[SecurityRecommendation]
|