Skip to content

Commit 37e598e

Browse files
DevOpsMadDogclaude
andcommitted
beast-mode(empty-endpoints): wire GET /threat-intel/ to ThreatIntelCorrelator, was 34 → now 33 stub endpoints
Replaced hardcoded `"items": []` with real call to `_correlator.get_active_threats(org_id)` which queries the SQLite threat_actors table. count now reflects actual active actors. 2 tests added (actor returned, empty list fallback). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a5e19e2 commit 37e598e

2 files changed

Lines changed: 67 additions & 5 deletions

File tree

suite-api/apps/api/threat_intel_router.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -802,10 +802,10 @@ async def get_ip_geo(ip: str) -> Dict[str, Any]:
802802

803803
@router.get("/", summary="Threat intel index", tags=["threat-intel"])
804804
async def threat_intel_index(org_id: str = Query("default")) -> Dict[str, Any]:
805-
"""Return threat intel summary for the org."""
805+
"""Return active threat actors and landscape summary for the org."""
806806
try:
807-
actors = _get_engine().list_actors(org_id=org_id) if hasattr(_get_engine(), "list_actors") else []
808-
count = len(actors)
807+
actors = _correlator.get_active_threats(org_id=org_id)
808+
items = [a.model_dump(mode="json") if hasattr(a, "model_dump") else dict(a) for a in actors]
809809
except Exception:
810-
count = 0
811-
return {"router": "threat-intel", "org_id": org_id, "items": [], "count": count}
810+
items = []
811+
return {"router": "threat-intel", "org_id": org_id, "items": items, "count": len(items)}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""Test: GET /api/v1/threat-intel/ wired to ThreatIntelCorrelator.get_active_threats"""
2+
import sys
3+
sys.path.insert(0, "/Users/devops.ai/fixops/Fixops")
4+
sys.path.insert(0, "/Users/devops.ai/fixops/Fixops/suite-core")
5+
sys.path.insert(0, "/Users/devops.ai/fixops/Fixops/suite-api")
6+
7+
from fastapi.testclient import TestClient
8+
9+
10+
def _make_app():
11+
from fastapi import FastAPI
12+
from apps.api.threat_intel_router import router
13+
app = FastAPI()
14+
app.include_router(router)
15+
return app
16+
17+
18+
def test_threat_intel_index_calls_get_active_threats():
19+
from core.threat_intel_correlator import ThreatActor
20+
fake_actor = ThreatActor(
21+
id="actor-1", name="APT-Test", aliases=["TestGroup"],
22+
ttps=["T1059"], motivation="espionage", origin_country="XX",
23+
active=True, associated_campaigns=[], iocs=[],
24+
)
25+
app = _make_app()
26+
client = TestClient(app)
27+
import apps.api.threat_intel_router as mod
28+
original = mod._correlator.get_active_threats
29+
mod._correlator.get_active_threats = lambda org_id: [fake_actor]
30+
try:
31+
resp = client.get("/api/v1/threat-intel/")
32+
assert resp.status_code == 200, f"Expected 200, got {resp.status_code}: {resp.text}"
33+
data = resp.json()
34+
assert data["count"] == 1, f"count={data['count']}"
35+
assert len(data["items"]) == 1, f"items len={len(data['items'])}"
36+
assert data["items"][0]["name"] == "APT-Test"
37+
print("PASS: items returned from real engine, not hardcoded []")
38+
finally:
39+
mod._correlator.get_active_threats = original
40+
41+
42+
def test_threat_intel_index_empty_when_no_actors():
43+
app = _make_app()
44+
client = TestClient(app)
45+
import apps.api.threat_intel_router as mod
46+
original = mod._correlator.get_active_threats
47+
mod._correlator.get_active_threats = lambda org_id: []
48+
try:
49+
resp = client.get("/api/v1/threat-intel/")
50+
assert resp.status_code == 200
51+
data = resp.json()
52+
assert data["count"] == 0
53+
assert data["items"] == []
54+
print("PASS: empty items when no actors")
55+
finally:
56+
mod._correlator.get_active_threats = original
57+
58+
59+
if __name__ == "__main__":
60+
test_threat_intel_index_calls_get_active_threats()
61+
test_threat_intel_index_empty_when_no_actors()
62+
print("ALL TESTS PASSED")

0 commit comments

Comments
 (0)