← back to Dw Vendor Microsites
merge-work/leak-scan.py
90 lines
#!/usr/bin/env python3
# leak-scan.py <jsonl> <banned_json>
# Word-boundary aware leak scan (mirrors build-vendor.sh). Scans KEYS + string
# VALUES recursively. Reports EVERY distinct real leak (not just first).
# Preserves legit superwords like "twill" (a "TWIL" ban won't flag it).
import sys, json, re
path = sys.argv[1]
banned = [b for b in json.loads(sys.argv[2]) if b.strip()]
wpats = [(b, re.compile(r'\b' + re.escape(b) + r'\b', re.IGNORECASE)) for b in banned]
toks = [(b, re.sub(r'[^a-z0-9]', '', b.lower())) for b in banned]
toks = [(b, t) for (b, t) in toks if t]
# ---- place-name FALSE-POSITIVE guard (mirrors dw-leak-scanner/leak-match.mjs) ----
# A bare "York" ban (the malibu/phillipe_romano/hollywood houses source from the
# real York/Brewster and legitimately ban "York") must NOT flag "New York" NYC
# place names ("Concrete New York"), the "York Weave" pattern, or the internal
# "york-scrape"/"york_scrape" provenance token. It DOES still flag a standalone
# "York" brand form or "yorkwall". Only the bare-"york" term is guarded; all
# other banned brands (Brewster, WallQuest, …) have no place-name FP risk.
_YORK_STRIP_TEXT = re.compile(r'new york|nueva york|york weave', re.IGNORECASE)
_YORK_STRIP_TOK = re.compile(r'newyork|nuevayork|yorkweave|yorkscrape', re.IGNORECASE)
_YORK_WORD = re.compile(r'\byork\b', re.IGNORECASE)
_YORK_TOK = re.compile(r'york')
def _is_bare_york(b):
return re.sub(r'[^a-z0-9]', '', b.lower()) == 'york'
def _york_survives_text(s):
# strip the known place/pattern phrases, then re-test for a standalone York
return bool(_YORK_WORD.search(_YORK_STRIP_TEXT.sub(' ', s)))
def _york_survives_tok(low):
# low is already alnum-only lowercase; strip glued place forms then re-test
return bool(_YORK_TOK.search(_YORK_STRIP_TOK.sub('', low)))
def check_text(s):
for b, p in wpats:
if p.search(s):
if _is_bare_york(b) and not _york_survives_text(s): continue
return b
return None
def check_urlish(s):
low = re.sub(r'[^a-z0-9]', '', s.lower())
for b, t in toks:
if t in low:
if _is_bare_york(b) and not _york_survives_tok(low): continue
return b
return None
def is_slug_or_url(s):
if re.search(r'(https?:)?//|[./\\]', s): return True
if ' ' not in s and re.search(r'[-_]', s): return True
return False
def scan(line):
try: rec = json.loads(line)
except Exception: rec = None
if rec is None:
return check_text(line)
stack = [rec]
while stack:
o = stack.pop()
if isinstance(o, dict):
for k, v in o.items():
kt = re.sub(r'[^a-z0-9]', '', str(k).lower())
for b, t in toks:
if t and t in kt:
if _is_bare_york(b) and not _york_survives_tok(kt): continue
return b
stack.append(v)
elif isinstance(o, list):
stack.extend(o)
elif isinstance(o, str):
hit = check_urlish(o) if is_slug_or_url(o) else check_text(o)
if hit: return hit
return None
leaks = {}
n = 0
with open(path) as f:
for line in f:
line = line.strip()
if not line: continue
n += 1
hit = scan(line)
if hit:
leaks[hit] = leaks.get(hit, 0) + 1
print(json.dumps({"scanned": n, "leaks": leaks, "clean": len(leaks) == 0}))