Files
2026-05-07 22:32:20 +05:30

148 lines
3.4 KiB
Python

from datetime import datetime
from typing import Optional
from pydantic import BaseModel, Field
# Import the ThreatIntelReport schema from the service layer.
# We import it here for use in ScanResponse so the schema stays clean.
from app.services.threat_intel import ThreatIntelReport
class ScanRequest(BaseModel):
url: str = Field(..., description="The URL of the website to scan")
class Issue(BaseModel):
issue: str
severity: str
layer: str
fix: str
contextual_severity: str | None = None
explanation: str | None = None
remediation_snippet: str | None = None
class LayerStatus(BaseModel):
issues: int = 0
status: str = "green"
class ScanResponse(BaseModel):
id: str | None = None
url: str
security_score: int
layers: dict[str, LayerStatus]
issues: list[Issue]
created_at: datetime | None = None
# Step 3: Threat intelligence enrichment (optional — only present when API keys are set)
threat_intel: Optional[ThreatIntelReport] = None
class ScanHistoryItem(BaseModel):
id: str
url: str
security_score: int
created_at: datetime
model_config = {"from_attributes": True}
class ScanHistoryResponse(BaseModel):
scans: list[ScanHistoryItem]
total: int
page: int
per_page: int
class DashboardTrendsResponse(BaseModel):
total_scans: int
average_score: float
recent_scans: list[ScanHistoryItem]
class ChatRequest(BaseModel):
message: str
class ChatResponse(BaseModel):
reply: str
class ThreatNarrativeResponse(BaseModel):
narrative: str
class ScanDiffResponse(BaseModel):
resolved_issues: list[Issue]
new_issues: list[Issue]
persisting_issues: list[Issue]
score_change: int
# AI-generated plain-English summary of what changed between the two scans.
# None when the AI key is not configured.
narrative: str | None = None
class ScheduledScanCreate(BaseModel):
url: str = Field(..., description="The URL to scan on a schedule")
schedule: str = Field(
"daily",
description="How often to run the scan. Options: 'daily', 'weekly'",
)
class ScheduledScanResponse(BaseModel):
id: str
url: str
schedule: str
is_active: bool
last_run_at: datetime | None = None
last_score: int | None = None
created_at: datetime
model_config = {"from_attributes": True}
# ---------------------------------------------------------------------------
# Nuclei Active Scan Schemas
# ---------------------------------------------------------------------------
class NucleiFinding(BaseModel):
template_id: str
name: str
severity: str
matched_at: str
description: str | None = None
class NucleiResultResponse(BaseModel):
id: str
scan_result_id: str
url: str
findings: list[NucleiFinding]
# status: "completed" | "skipped" | "timeout" | "error"
status: str
completed_at: datetime | None = None
created_at: datetime
model_config = {"from_attributes": True}
# ---------------------------------------------------------------------------
# AI Remediation Plan Schemas
# ---------------------------------------------------------------------------
class RemediationStep(BaseModel):
priority: int
issue: str
severity: str
effort: str # Easy | Medium | Hard
fix_summary: str
code_snippet: str | None = None
class RemediationPlan(BaseModel):
summary: str
steps: list[RemediationStep]
estimated_total_effort: str