diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9874058 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +# Hand-curated dependency pins; this project does not have a lockfile. +python-telegram-bot==22.8 +feedparser==6.0.14 +aiohttp==3.14.3 +beautifulsoup4==4.15.0 diff --git a/validation/review.py b/validation/review.py index b391c59..366ce13 100644 --- a/validation/review.py +++ b/validation/review.py @@ -5,7 +5,6 @@ Review validation results โ€” pretty-prints results.jsonl with optional filters. Usage: python3 validation/review.py # all results python3 validation/review.py --category research # filter by category - python3 validation/review.py --severity critical # filter by severity python3 validation/review.py --has cves # only articles with CVEs python3 validation/review.py --has malware # only articles with malware hits python3 validation/review.py --has actors # only articles with threat actors @@ -20,13 +19,10 @@ from datetime import datetime, timezone RESULTS_FILE = Path(__file__).parent / "results.jsonl" -SEVERITY_ORDER = {"critical": 0, "high": 1, "medium": 2, "low": 3, "unknown": 4} - def parse_args(): p = argparse.ArgumentParser() p.add_argument("--category", help="Filter by category (news, malware, threat_intel, osint, research)") - p.add_argument("--severity", help="Filter by severity (critical, high, medium, low)") p.add_argument("--has", choices=["cves", "malware", "actors"], help="Only show articles with these detections") p.add_argument("--today", action="store_true", help="Only show results from today") p.add_argument("--limit", type=int, default=0, help="Max articles to show (0 = all)") @@ -55,8 +51,6 @@ def load_results(args): continue if args.category and r.get("category") != args.category: continue - if args.severity and r.get("severity") != args.severity: - continue if args.has == "cves" and not r.get("cves"): continue if args.has == "malware" and not r.get("malware_families"): @@ -66,18 +60,13 @@ def load_results(args): records.append(r) - records.sort(key=lambda x: SEVERITY_ORDER.get(x.get("severity", "unknown"), 4)) return records def print_record(r): - sev = r.get("severity", "unknown").upper() - sev_icons = {"CRITICAL": "๐Ÿšจ", "HIGH": "๐Ÿ”ด", "MEDIUM": "๐ŸŸ ", "LOW": "๐ŸŸก"} - icon = sev_icons.get(sev, "โšช") - print(f"\n{'โ”€' * 80}") - print(f"{icon} [{r.get('category', '?').upper()}] {r.get('title', 'No title')}") - print(f" ๐Ÿ“ก {r.get('source')} ยท {r.get('published')} ยท Score: {r.get('quality_score', '?')}/100") + print(f"[{r.get('category', '?').upper()}] {r.get('title', 'No title')}") + print(f" ๐Ÿ“ก {r.get('source')} ยท {r.get('published')}") if r.get("cves"): print(f" ๐Ÿ†” {', '.join(r['cves'])}") @@ -104,13 +93,7 @@ def main(): records = records[:args.limit] total = len(records) - sev_counts = {} - for r in records: - s = r.get("severity", "unknown") - sev_counts[s] = sev_counts.get(s, 0) + 1 - print(f"\n=== Validation Results ({total} articles) ===") - print(" " + " ".join(f"{s.upper()}: {c}" for s, c in sorted(sev_counts.items(), key=lambda x: SEVERITY_ORDER.get(x[0], 4)))) for r in records: print_record(r)