mirror of
https://github.com/Rarebuffalo/securelens-backend.git
synced 2026-06-19 07:00:30 +00:00
148 lines
3.4 KiB
Python
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
|
|
|