"""Exploit-DB matcher: parses real searchsploit JSON, never fabricates, fails soft.""" from __future__ import annotations import json from pathlib import Path from recon_triage.grounding.exploitdb import ground_report from recon_triage.schema import Host, Port, ReconReport, Service from recon_triage.tools import searchsploit FIXTURES = Path(__file__).parent / "fixtures" def _index() -> dict: return json.loads((FIXTURES / "searchsploit" / "index.json").read_text()) def test_normalize_parses_results(): doc = _index()["Apache httpd 2.4.49"] matches = searchsploit.normalize(json.dumps(doc), query="Apache httpd 2.4.49") assert {m.edb_id for m in matches} == {"50383", "50406"} assert all(m.verified is False for m in matches) assert all(m.source == "exploit-db" for m in matches) assert matches[0].url.endswith("/50383") def test_normalize_empty_results(): doc = _index()["nginx 1.18.0"] assert searchsploit.normalize(json.dumps(doc)) == [] def test_normalize_handles_garbage(): assert searchsploit.normalize("") == [] assert searchsploit.normalize("not json") == [] def test_ground_report_attaches_only_returned(fixture_search_fn): report = ReconReport( run_id="t", hosts=[ Host( hostname="api.example.com", ports=[ Port(number=443, service=Service(product="Apache httpd", version="2.4.49")), Port(number=22, service=Service(product="OpenSSH", version="8.2p1 Ubuntu 4ubuntu0.5")), ], ) ], ) attached = ground_report(report, fixture_search_fn) assert attached == 2 # only the Apache service yields 2 candidates apache = report.hosts[0].ports[0].service ssh = report.hosts[0].ports[1].service assert {m.edb_id for m in apache.exploitdb_candidates} == {"50383", "50406"} assert ssh.exploitdb_candidates == [] # nothing returned -> empty, not fabricated def test_ground_report_failsoft_on_search_error(): def boom(term: str): raise RuntimeError("searchsploit blew up") report = ReconReport( run_id="t", hosts=[Host(hostname="h", ports=[Port(number=443, service=Service(product="X", version="1"))])], ) attached = ground_report(report, boom) # must not raise assert attached == 0