Results from a scan or reconnaissance operation.
| 59 | |
| 60 | |
| 61 | class ScanResult(BaseModel): |
| 62 | """Results from a scan or reconnaissance operation.""" |
| 63 | |
| 64 | target: Target |
| 65 | module: str = Field(..., description="Module that performed the scan") |
| 66 | success: bool = True |
| 67 | started_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) |
| 68 | completed_at: datetime | None = None |
| 69 | findings: list[Finding] = Field(default_factory=list) |
| 70 | raw_data: dict[str, Any] = Field(default_factory=dict) |
| 71 | errors: list[str] = Field(default_factory=list) |
| 72 | |
| 73 | def add_finding( |
| 74 | self, |
| 75 | title: str, |
| 76 | description: str, |
| 77 | severity: Severity = Severity.INFO, |
| 78 | data: dict[str, Any] | None = None, |
| 79 | references: list[str] | None = None, |
| 80 | ) -> Finding: |
| 81 | """Add a finding to the result.""" |
| 82 | finding = Finding( |
| 83 | title=title, |
| 84 | description=description, |
| 85 | severity=severity, |
| 86 | source=self.module, |
| 87 | data=data or {}, |
| 88 | references=references or [], |
| 89 | ) |
| 90 | self.findings.append(finding) |
| 91 | return finding |
| 92 | |
| 93 | def complete(self) -> None: |
| 94 | """Mark the scan as complete.""" |
| 95 | self.completed_at = datetime.now(timezone.utc) |
| 96 | |
| 97 | @property |
| 98 | def duration_seconds(self) -> float | None: |
| 99 | """Get scan duration in seconds.""" |
| 100 | if self.completed_at and self.started_at: |
| 101 | return (self.completed_at - self.started_at).total_seconds() |
| 102 | return None |
no outgoing calls