mirror of
https://github.com/iimp0ster/detection-chokepoints
synced 2026-08-09 12:41:00 +00:00
fix(trends): use AS handle when the provenance org label overflows
transform_provenance.py short() hard-truncated the AS org description at 28 chars, cutting mid-word -- the top provider read "Emil Vitukhnovskii trading a". Fall back to the AS handle when the org would overflow, so the label reads the recognizable "GreatFlower". Labels that already fit are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bx33CDbC3G8DQMQMARewof
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
810f810d85
commit
2e45a13223
@@ -12,6 +12,7 @@ Source: Defused Cyber honeypot telemetry, two manual console exports. A May 20 -
|
||||
- `trends/edge-exploits/index.html` — refreshed the volume callout, target-distribution intro, and the CitrixBleed 2 / Next.js / cPanel sections to the new totals and the May 26 single-source surge; extended the CitrixBleed 2 daily chart through Jul 16 (it stopped at the Apr 13 baseline before). Removed the now-dormant `partial`-day chart styling, superseded by the gap treatment below.
|
||||
- `scripts/transform_defused_csv.py` — four changes: (1) day merge is now per-day MAX-wins instead of newest-wins, so a newer export's partial window-start day can no longer overwrite an older export's complete count (fixed a Jun 16 undercount, 10 vs the true 139); (2) a row-capped export's truncated oldest day now renders as a GAP rather than a flagged partial bar (supersedes the 2026-07-03 partial approach; Jun 10 is the first such gap), fillable later by a narrow uncapped export that wins the max; (3) strips the source `:port` that newer exports append to the Attacker IP field, so unique-IP counts stay consistent across the two export formats; (4) the CitrixBleed 2 daily series now includes the live window, not just the frozen baseline.
|
||||
- `_data/edge_exploits_provenance.yml` — regenerated to the Apr - Jul 2026 window (was Jul 3), 2,998 cumulative unique source IPs. The local (gitignored) `enrich_asns.py` got the same per-day MAX-wins merge + Jun 10 gap + `:port` strip: it had been raw-summing overlapping exports, inflating June 6.6x (105,888 vs the correct 16,113) and floating one ASN (datacampus, the truncated Jun 10 spike's host) into the top purely as a double-counting artifact. Deduped per-month ASN totals now match the event page exactly (May 50,016 / Jun 16,113 / Jul 3,537).
|
||||
- `scripts/transform_provenance.py` — `short()` now falls back to the AS handle when the org description would overflow the label, instead of a mid-word cut (top provider reads `GreatFlower`, not `Emil Vitukhnovskii trading a`). Other labels unchanged.
|
||||
|
||||
### Notes
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ month_labels:
|
||||
- Jun 2026
|
||||
- Jul 2026
|
||||
providers:
|
||||
- name: Emil Vitukhnovskii trading a
|
||||
- name: GreatFlower
|
||||
asn: 202226
|
||||
bulletproof: false
|
||||
total: 33999
|
||||
@@ -85,7 +85,7 @@ providers:
|
||||
- 5270
|
||||
- 1856
|
||||
asn_totals:
|
||||
- name: Emil Vitukhnovskii trading a
|
||||
- name: GreatFlower
|
||||
asn: 202226
|
||||
bulletproof: false
|
||||
events: 33999
|
||||
|
||||
@@ -49,10 +49,19 @@ def month_label(ym: str) -> str: # "2026-04" -> "Apr 2026"
|
||||
|
||||
def short(name: str) -> str:
|
||||
"""Readable provider label from a Cymru AS name or a bulletproof-map name.
|
||||
'H2NEXUS-AS - H2NEXUS LTD, GB' -> 'H2NEXUS LTD'."""
|
||||
s = name.split(" - ", 1)[-1].strip()
|
||||
s = re.sub(r",\s*[A-Z]{2}$", "", s) # drop trailing country code
|
||||
return s[:28]
|
||||
Cymru gives 'HANDLE - Org Description, CC'. Prefer the org (usually the
|
||||
recognizable company: 'H2NEXUS-AS - H2NEXUS LTD, GB' -> 'H2NEXUS LTD'), but
|
||||
fall back to the short AS handle when the org would overflow the label, so a
|
||||
long trade name isn't cut mid-word ('GreatFlower - Emil Vitukhnovskii trading
|
||||
as Great Flower, IL' -> 'GreatFlower', not 'Emil Vitukhnovskii trading a')."""
|
||||
LIMIT = 28
|
||||
handle = name.split(" - ", 1)[0].strip()
|
||||
org = re.sub(r",\s*[A-Z]{2}$", "", name.split(" - ", 1)[-1].strip())
|
||||
if len(org) <= LIMIT:
|
||||
return org
|
||||
if 0 < len(handle) <= LIMIT and handle != org:
|
||||
return handle # long org -> use the clean AS handle instead
|
||||
return org[:LIMIT].rsplit(" ", 1)[0] or org[:LIMIT] # last resort: trim at a word
|
||||
|
||||
|
||||
def key(rec) -> str:
|
||||
|
||||
Reference in New Issue
Block a user