diff --git a/docs/update.md b/docs/update.md new file mode 100644 index 0000000..1d0dadc --- /dev/null +++ b/docs/update.md @@ -0,0 +1,136 @@ +# ThreatHunt — Session Update (February 19, 2026) + +## Summary + +This session covered 6 feature improvements and bug fixes across the ThreatHunt platform, all deployed via Docker Compose. + +--- + +## 1. Network Map — Clickable Type Filters (IP / Host / Domain / URL) + +**Request:** "IP, Host, Domain, URL on the network map… can I click on these and they would be filtered in or out" + +**Changes (`NetworkMap.tsx`):** +- Legend chips (IP, Host, Domain, URL) are now clickable toggle filters +- Added `visibleTypes` state (`Set`) and `filteredGraph` useMemo that filters nodes + edges by visible types +- Active chips: filled background with type color, fully opaque +- Inactive chips: outlined with type color, dimmed at 50% opacity +- Each chip shows node count for that type, e.g. `IP (42)` +- At least one type must stay visible (can't disable all four) +- Stats chips (nodes/edges) update to reflect the filtered view +- All mouse handlers (pan, hover, click, wheel zoom) updated to use `filteredGraph` instead of raw `graph` + +--- + +## 2. Network Map — Cleaner Nodes (Brighter Colors, 20% Smaller) + +**Request:** "Clean up the icons, the colours are dull and the icons are too big in the map… shrink by 20%" + +**Changes (`NetworkMap.tsx`):** +- Colors bumped to more saturated variants: + - IP: `#60a5fa` → `#3b82f6` + - Host: `#10b981` → `#22c55e` + - Domain: `#f59e0b` → `#eab308` + - URL: `#a78bfa` → `#8b5cf6` +- Node radius shrunk ~20%: + - Max: 22 → 18 + - Base: 5 → 4 + - Multiplier: 2.0 → 1.6 + +--- + +## 3. Dataset Viewer — IOC Column Highlighting + +**Request:** "I'm looking at one of the datasets and 4 IOCs are showing… but I can't see it… is there a way to highlight that" + +**Changes (`DatasetViewer.tsx`):** +- IOC columns in the DataGrid are now visually highlighted +- **Header:** colored background tint + bold colored text + IOC type label (e.g. `src_ip ◆ IP`) +- **Cells:** subtle colored background + left border stripe +- Color-coded by IOC type matching the Network Map palette: + - IP — blue (`#3b82f6`) + - Hostname — green (`#22c55e`) + - Domain — amber (`#eab308`) + - URL — purple (`#8b5cf6`) + - Hashes (MD5/SHA1/SHA256) — rose (`#f43f5e`) +- Added `IOC_COLORS` mapping, `iocTypeFor()` helper, and dynamic `headerClassName`/`cellClassName` on DataGrid columns +- CSS-in-JS styles injected via DataGrid `sx` prop + +--- + +## 4. AUP Scanner — "Social Media (Personal)" → "Social Media" Rename + +**Request:** "On the AUP page there is Social Media (Personal) — can we remove personal, it's messing up with the formatting" + +**Changes (`keyword_defaults.py`):** +- Default theme key renamed from `"Social Media (Personal)"` to `"Social Media"` +- Added rename migration in `seed_defaults()`: checks for old name in DB, if found renames via SQL UPDATE + commit before normal seeding +- Backend log confirmed: `Renamed AUP theme 'Social Media (Personal)' → 'Social Media'` + +--- + +## 5. AUP Scanner — Hunt Dropdown (previous session, deployed) + +- Replaced individual dataset checkboxes with a hunt selector dropdown +- Selecting a hunt auto-loads and selects all its datasets +- Shows dataset/row counts below the dropdown + +--- + +## 6. Network Map — Hunt-Scoped Interactive Map (previous session, deployed) + +- Hunt selector dropdown loads only that hunt's datasets +- Enriched nodes with hostname, IP, OS metadata +- Click-to-inspect MUI Popover showing node details +- Zoom (wheel + buttons) and pan (drag) with full viewport transform +- Force-directed layout with co-occurrence edges + +--- + +## 7. Agent Assist — "Failed to Fetch" Diagnosis + +**Request:** "AI assist failed: Error: Failed to fetch" + +**Diagnosis:** +- Backend agent endpoint works correctly (tested via PowerShell `Invoke-RestMethod` through nginx proxy) +- Health endpoint healthy — both LLM nodes (Wile + Roadrunner) available +- Extra fields sent by frontend (`mode`, `hunt_id`, `conversation_id`) are accepted by Pydantic v2 (ignored, not rejected) +- "Failed to fetch" was a transient browser-level network error, not a backend issue +- Response time ~5s from LLM — within nginx 120s proxy timeout +- **Resolution:** Hard refresh (Ctrl+Shift+R) resolves the issue + +--- + +## 8. Performance Fix — /api/hunts Timeout (previous session) + +- Root cause: `Dataset.rows` relationship had `lazy="selectin"` causing SQLAlchemy to cascade-load every DatasetRow when listing hunts +- Fix: Changed `Dataset.rows` and `DatasetRow.annotations` to `lazy="noload"` in `backend/app/db/models.py` +- Result: Hunts endpoint returns instantly + +--- + +## Files Modified This Session + +| File | Change | +|------|--------| +| `frontend/src/components/NetworkMap.tsx` | Type filter toggles, brighter colors, smaller nodes | +| `frontend/src/components/DatasetViewer.tsx` | IOC column highlighting in DataGrid | +| `backend/app/services/keyword_defaults.py` | Theme rename + DB migration | + +## Deployment + +All changes built and deployed via Docker Compose: +``` +docker compose build --no-cache frontend +docker compose up -d frontend +docker compose build --no-cache backend +docker compose up -d backend +``` + +## Git + +Committed and pushed to GitHub (`main` branch): +``` +92 files changed, 13050 insertions(+), 1097 deletions(-) +d0c9f88..9b98ab9 main -> main +```