feat: /actors.html — threat-actor coverage page#272
Merged
Conversation
New top-level page that answers "is this actor covered by HEARTH?" Search
by canonical name or any of 159 MITRE-mapped actors' aliases (e.g. "Cozy
Bear" resolves to APT29). For each actor, surfaces:
- matched hunts (technique overlap + name mentions in hunt prose)
- coverage percentage and tactic-by-tactic heatmap
- gap list with one-click submit links pre-tagged with the target technique
Also adds an empty-state showcase ("Most matched" / "Biggest open gaps")
and a live mini coverage card on the home page that rotates through the
top-matched actors per reload. Library deep-links (?hunt=<id>) are wired
through so matched-hunt rows open the right entry, and a banner on the
submit page surfaces the target technique when arriving from a gap link.
Data substrate is the existing context-graph + a new precomputed
public/actor-mentions.json (regenerated automatically by
rebuild_hunts_data.py). No backend; all matching runs client-side.
Spec: docs/plans/2026-05-23-actor-coverage-page-design.md
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
letswastetimee
approved these changes
May 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A new top-level page that answers a single question: "Is this threat actor covered by HEARTH?"
For a hunter prepping an engagement, the page returns a curated list of HEARTH hunts relevant to the chosen actor. For a defender doing coverage analysis, it also surfaces a coverage percentage, a tactic-level heatmap, and a gap list of techniques the actor uses for which HEARTH has no hunt yet — with one-click submit links pre-tagged with the target technique.
The substrate already existed:
public/context-graph-data.jsonhas 159 MITRE-mapped threat actors (with aliases) and 1,670EMPLOYSedges to MITRE techniques. This PR is a thin lookup + UI layer on top.Spec:
docs/plans/2026-05-23-actor-coverage-page-design.mdWhat's in the box
/actors.htmlwith three states: empty (search + suggested-actor chips + animated typewriter + showcase boards), result (header, coverage strip, tactic heatmap, matched-hunts list, gap list), and not-foundindex.html?hunt=<id>) wired into the React app so matched-hunt rows open the correct entrysubmit.html?technique=<id>) shows a banner + prepends[gap: T1234]to the GitHub issue title so Keepers know what gap a contributor was fillingscripts/build_actor_mentions.py— precomputespublic/actor-mentions.jsonfor name-mention matching (word-boundary, 4-char minimum, per-actor alias denylist). 13 passing tests. Wired intorebuild_hunts_data.pyand the existingupdate-hunts.ymlworkflowArchitecture notes
title/why/notes/references)TECH/MENTION) on each row so the user knows why a hunt surfacedKnown limitation worth flagging
context-graph-data.jsononly contains MITRE techniques HEARTH has at least one hunt for, so the per-actor coverage % is technically "% of mapped-and-touched techniques", not "% of the actor's full real-world TTP set." Honest within its frame, but worth a follow-up rename or caveat in the UI ("HEARTH coverage of mapped techniques") when we're ready.Test plan
npm install && npm run dev→ openhttp://localhost:4173/actors.html(port can vary)?actor=G0016→ APT29 with 51 matched hunts, 1 gap (T1587.003), heatmap renders?q=cozy%20bear→ redirects to?actor=G0016?q=zzznotreal→ graceful state with submit CTAsubmit.html?technique=T1587.003shows banner; submitted issue title starts with[gap: T1587.003]index.html?hunt=<id>with that hunt selected in the preview panepytest scripts/tests/test_build_actor_mentions.py→ 13/13 passnpm run type-check→ clean🤖 Generated with Claude Code