Files
psyc/tests/test_classify.py
m17hr1l d87bd710bb stage-19: ThreatFox + MalwareBazaar + OTX Scoutline sources
Three new feeds — biggest near-term data-diversity win. ThreatFox brings
multi-malware IOCs with threat_type signal (botnet_cc → BOTNET,
payload_delivery → MALWARE, phishing → PHISHING). MalwareBazaar brings
file-hash samples with signatures. OTX brings curated multi-source pulses
with paragraph-form descriptions — by far the richest real-prose source.

Auth: THREATFOX_AUTH_KEY (one abuse.ch key covers ThreatFox + MalwareBazaar)
and OTX_API_KEY. fetch-all skips keyed feeds cleanly with where-to-get-it
guidance instead of tracebacking. Proofline reliability table extended;
abuse.ch sources rated B/2, OTX rated C/3 (community-driven).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 22:14:18 +02:00

83 lines
3.1 KiB
Python

"""Classifyline rule tests."""
from __future__ import annotations
from psyc.lines.classify import classify
from psyc.models import IncidentType, InternalClass, Severity, TLP
from conftest import make_case
def test_urlhaus_feed_is_malware():
case = classify(make_case(feed="urlhaus", urls=["http://1.2.3.4/x"]))
assert case.classification.incident_type is IncidentType.MALWARE
assert case.classification.tlp is TLP.GREEN
def test_cisa_kev_feed_is_exploit():
case = classify(make_case(feed="cisa-kev", cves=["CVE-2026-0001"]))
assert case.classification.incident_type is IncidentType.EXPLOIT
def test_feodo_feed_is_botnet():
case = classify(make_case(feed="feodo", ips=["1.2.3.4"]))
assert case.classification.incident_type is IncidentType.BOTNET
def test_malware_severity_tracks_url_status():
online = make_case(feed="urlhaus", urls=["http://1.2.3.4/x"])
online.source_metadata["url_status"] = "online"
assert classify(online).classification.severity is Severity.HIGH
offline = make_case(feed="urlhaus", urls=["http://1.2.3.4/x"])
offline.source_metadata["url_status"] = "offline"
assert classify(offline).classification.severity is Severity.MEDIUM
def test_ransomware_kev_is_critical():
case = make_case(feed="cisa-kev", cves=["CVE-2026-0001"])
case.source_metadata["ransomware"] = "Known"
assert classify(case).classification.severity is Severity.CRITICAL
def test_critical_infrastructure_forces_critical():
case = make_case(feed="urlhaus", urls=["http://1.2.3.4/x"])
case.victim.critical_infrastructure = True
assert classify(case).classification.severity is Severity.CRITICAL
def test_internal_class_from_severity():
assert classify(make_case(feed="cisa-kev", cves=["CVE-2026-1"])).classification.internal_class is InternalClass.C
crit = make_case(feed="urlhaus", urls=["http://1.2.3.4/x"])
crit.victim.critical_infrastructure = True
assert classify(crit).classification.internal_class is InternalClass.A
def test_classify_is_idempotent():
case = classify(make_case(feed="urlhaus", urls=["http://1.2.3.4/x"]))
first = case.classification.model_copy(deep=True)
classify(case)
assert case.classification == first
def test_threatfox_botnet_cc_is_botnet():
case = make_case(feed="threatfox", ips=["1.2.3.4"])
case.source_metadata["threat_type"] = "botnet_cc"
assert classify(case).classification.incident_type is IncidentType.BOTNET
def test_threatfox_payload_delivery_is_malware():
case = make_case(feed="threatfox", urls=["http://1.2.3.4/x.bin"])
case.source_metadata["threat_type"] = "payload_delivery"
assert classify(case).classification.incident_type is IncidentType.MALWARE
def test_threatfox_phishing_threat_type_is_phishing():
case = make_case(feed="threatfox", urls=["http://login.bad/example"])
case.source_metadata["threat_type"] = "phishing"
assert classify(case).classification.incident_type is IncidentType.PHISHING
def test_malware_bazaar_is_malware():
case = make_case(feed="malware-bazaar", hashes=["a" * 64])
assert classify(case).classification.incident_type is IncidentType.MALWARE