from datetime import datetime from typing import Literal from pydantic import BaseModel, Field class ScanOptions(BaseModel): port_range: str = "1-1000" include_web: bool = True include_brute: bool = False include_ssl: bool = True llm_model: str = "qwen2.5:14b" class ScanCreate(BaseModel): target: str profile: Literal["passive", "standard", "redteam"] options: ScanOptions = Field(default_factory=ScanOptions) authorized: bool = False class BulkScanCreate(BaseModel): targets: list[str] profile: Literal["passive", "standard", "redteam"] options: ScanOptions = Field(default_factory=ScanOptions) authorized: bool = False class Scan(BaseModel): id: str target: str profile: Literal["passive", "standard", "redteam"] options: ScanOptions status: Literal["queued", "running", "complete", "failed", "cancelled"] created_at: datetime completed_at: datetime | None = None llm_unavailable: bool = False bulk_id: str | None = None class BulkRun(BaseModel): id: str profile: Literal["passive", "standard", "redteam"] status: Literal["queued", "running", "complete", "cancelled"] created_at: datetime completed_at: datetime | None = None total: int = 0 complete: int = 0 failed: int = 0 running: int = 0 queued: int = 0 class Phase(BaseModel): id: str scan_id: str name: str tool: str command: str status: Literal["pending", "running", "complete", "failed", "skipped", "blocked", "inconclusive"] started_at: datetime | None = None completed_at: datetime | None = None raw_output: str = "" exit_code: int | None = None class Finding(BaseModel): id: str scan_id: str phase_id: str severity: Literal["critical", "high", "medium", "low", "info"] title: str description: str evidence: str recommendation: str cve_refs: list[str] = Field(default_factory=list) confidence: Literal["high", "medium", "low"] class ToolResult(BaseModel): stdout: str stderr: str exit_code: int duration: float