template restructure

This commit is contained in:
2025-10-21 21:00:48 -05:00
parent 583cbffeca
commit f394e268da
11 changed files with 512 additions and 126 deletions

View File

@@ -1,7 +1,7 @@
from __future__ import annotations
from dataclasses import dataclass, field
from typing import List, Optional
from dataclasses import dataclass, field, asdict
from typing import Dict, List, Set, Optional, Any
from ipaddress import ip_address
@dataclass
class PortFinding:
@@ -16,7 +16,6 @@ class PortFinding:
state: str
service: Optional[str] = None
@dataclass
class HostResult:
"""
@@ -28,3 +27,68 @@ class HostResult:
address: str
host: Optional[str] = None
ports: List[PortFinding] = field(default_factory=list)
@dataclass
class HostReport:
"""
Delta result for a single host.
"""
ip: str
unexpected_tcp: List[int]
missing_tcp: List[int]
unexpected_udp: List[int]
missing_udp: List[int]
def has_issues(self) -> bool:
"""
Returns True if any delta list is non-empty.
"""
if self.unexpected_tcp:
return True
if self.missing_tcp:
return True
if self.unexpected_udp:
return True
if self.missing_udp:
return True
return False
def to_dict(self) -> Dict[str, Any]:
"""
Convert to a plain dict for JSON/Jinja contexts.
"""
return asdict(self)
@dataclass
class GroupedReports:
"""
Final, template-friendly structure:
- issues: list of HostReport with any deltas (sorted by IP)
- expected: list of HostReport with no deltas (sorted by IP)
- by_ip: mapping for random access if needed
"""
issues: List[HostReport]
expected: List[HostReport]
by_ip: Dict[str, HostReport]
def to_context(self) -> Dict[str, Any]:
"""
Produce plain-dict context for Jinja render() if you prefer dicts.
"""
issues_dicts: List[Dict[str, Any]] = []
for hr in self.issues:
issues_dicts.append(hr.to_dict())
expected_dicts: List[Dict[str, Any]] = []
for hr in self.expected:
expected_dicts.append(hr.to_dict())
by_ip_dict: Dict[str, Dict[str, Any]] = {}
for ip, hr in self.by_ip.items():
by_ip_dict[ip] = hr.to_dict()
return {
"issues": issues_dicts,
"expected": expected_dicts,
"by_ip": by_ip_dict,
}