KeyHunter parser v10 + 18 scanners + tests (synthetic fixtures only, no keys/db/tokens)
This commit is contained in:
142
tests/test_batch2_patterns.py
Normal file
142
tests/test_batch2_patterns.py
Normal file
@@ -0,0 +1,142 @@
|
||||
"""Batch-2 fixture tests (no network). Run: python tests/test_batch2_patterns.py
|
||||
|
||||
Batch-2 final scope: HEROKU + SUPABASE in canon src/key_patterns.py PATTERNS
|
||||
(fleet_update ships canon; patterns_extra is excluded from wave payload).
|
||||
REJECTED families asserted absent (doctrine: one label per key shape):
|
||||
CLERK — sk_(live|test)_ shape owned by canon STRIPE; second label =
|
||||
mislabel race on every real Stripe live key.
|
||||
BAIDU — bce-v3/ALTAK-{id}/{sig} is a per-request HMAC signature,
|
||||
not a reusable credential.
|
||||
Shape-ownership gate: each pos fixture must match EXACTLY ONE PATTERNS entry.
|
||||
Coupling gate: emitted prov must resolve in eternal_v10 (allowlist/PROVIDERS),
|
||||
else UNKNOWN -> DEAD terminal (KH_AWS graveyard lesson). Static parse only —
|
||||
eternal_v10 has module-level side effects + live HTTP in validate().
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(HERE), "src"))
|
||||
sys.path.insert(0, os.path.dirname(HERE))
|
||||
|
||||
FAILS = []
|
||||
|
||||
|
||||
def check(name, cond, detail=""):
|
||||
if cond:
|
||||
print(f"ok {name}")
|
||||
else:
|
||||
print(f"FAIL {name} {detail}")
|
||||
FAILS.append(name)
|
||||
|
||||
|
||||
import key_patterns as K # noqa: E402 (canon, src tree)
|
||||
import patterns_extra as PE # noqa: E402
|
||||
|
||||
CANON = dict(K.PATTERNS)
|
||||
P = PE.EXTRA_PATTERNS
|
||||
|
||||
# ---- fixtures (synthetic, valid shapes) ----
|
||||
HEROKU_POS = "token=HRKU-AA" + ("aB3xY7zK9mQ2wR5t" * 4)[:58] + " done"
|
||||
HEROKU_NEG1 = "token=HRKU-BB" + ("aB3xY7zK9mQ2wR5t" * 4)[:58]
|
||||
HEROKU_NEG2 = "token=HRKU-AA" + "aB3xY7zK9m" # too short
|
||||
|
||||
SUPABASE_POS = 'SB_TOKEN="sbp-1234567890abcdef1234567890abcdef12345678"'
|
||||
SUPABASE_NEG1 = "sbp-1234567890abcdef1234567890abcdef1234567" # 39 hex
|
||||
SUPABASE_NEG2 = "sbo-1234567890abcdef1234567890abcdef12345678" # wrong prefix
|
||||
|
||||
CLERK_SHAPE = "sk_" + "live_" + "aB3xY7zK9mQ2wR5tN8vJ1cL4hF6dG0sA"
|
||||
BAIDU_SHAPE = "BCE_AK=bce-v3/ALTAK-aB3xY7zK9m/0123456789abcdef0123456789abcdef"
|
||||
|
||||
SPECS = [
|
||||
("HEROKU", HEROKU_POS, [HEROKU_NEG1, HEROKU_NEG2]),
|
||||
("SUPABASE", SUPABASE_POS, [SUPABASE_NEG1, SUPABASE_NEG2]),
|
||||
]
|
||||
|
||||
for name, pos, negs in SPECS:
|
||||
rx = CANON.get(name)
|
||||
if rx is None:
|
||||
check(f"{name}:in-canon", False, "missing from PATTERNS")
|
||||
continue
|
||||
check(f"{name}:pos", rx.search(pos) is not None, f"no match in {pos[:40]}")
|
||||
for i, neg in enumerate(negs):
|
||||
check(f"{name}:neg{i}", rx.search(neg) is None, f"false match in {neg[:40]}")
|
||||
# shape ownership: exactly one canon entry may match the pos fixture
|
||||
owners = [n for n, r in CANON.items() if r.search(pos)]
|
||||
check(f"{name}:shape-owned-once", owners == [name],
|
||||
f"pos fixture matched by {owners} — one label per key shape")
|
||||
|
||||
# rejected families: no canon label, no extra label
|
||||
check("rejected:CLERK-not-in-canon", "CLERK" not in CANON)
|
||||
check("rejected:clerk-not-in-extras", "clerk" not in P)
|
||||
check("rejected:BAIDU-not-in-canon", "BAIDU" not in CANON)
|
||||
check("rejected:baidu-not-in-extras", "baidu" not in P)
|
||||
# clerk shape must stay owned by STRIPE alone
|
||||
stripe_owners = [n for n, r in CANON.items() if r.search(CLERK_SHAPE)]
|
||||
check("rejected:clerk-shape-stripe-only", "STRIPE" in stripe_owners
|
||||
and "CLERK" not in stripe_owners, f"owners={stripe_owners}")
|
||||
# baidu shape must not emit a credential label from canon batch-2
|
||||
baidu_owners = [n for n, r in CANON.items()
|
||||
if n in ("HEROKU", "SUPABASE") and r.search(BAIDU_SHAPE)]
|
||||
check("rejected:baidu-no-batch2-hit", not baidu_owners, f"owners={baidu_owners}")
|
||||
|
||||
# extras regression: kh_* intact, count floor
|
||||
check("regress:kh_google", "kh_google" in P and
|
||||
P["kh_google"].search("AIzaSy" + "A1234567890abcdefghijklmnopqrstuv"[:33]) is not None)
|
||||
check("regress:kh_grok", "kh_grok" in P and
|
||||
P["kh_grok"].search("xai-" + "aB3x" * 12) is not None)
|
||||
check("regress:count", len(P) >= 17, f"EXTRA_PATTERNS shrank: {len(P)}")
|
||||
|
||||
# scan_text end-to-end (junk-фильтр + first-wins dedup): высокоэнтропийные
|
||||
# нециклические фикстуры должны пройти весь тракт и выдать prov-лейблы.
|
||||
import random as _rnd
|
||||
_r = _rnd.Random(20261006)
|
||||
_hex40 = "".join(_r.choice("0123456789abcdef") for _ in range(40))
|
||||
_alnum58 = "".join(_r.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-") for _ in range(58))
|
||||
SB_E2E = 'SB_TOKEN="sbp-' + _hex40 + '"'
|
||||
HK_E2E = "HEROKU_API_KEY=HRKU-AA" + _alnum58
|
||||
for _fix, _want in ((SB_E2E, "SUPABASE"), (HK_E2E, "HEROKU")):
|
||||
_got = K.scan_text(_fix)
|
||||
_provs = {p for p, _ in _got}
|
||||
check(f"scan_text:{_want}", _want in _provs, f"provs={sorted(_provs)}")
|
||||
_v = [v for p, v in _got if p == _want]
|
||||
check(f"scan_text:{_want}-value", bool(_v) and _v[0] in _fix, f"vals={_v}")
|
||||
|
||||
# coupling gate: batch-2 provs resolvable in eternal_v10 (allowlist or PROVIDERS)
|
||||
import ast as _ast
|
||||
import re as _re
|
||||
_allow, _provs = None, set()
|
||||
for _p in (os.path.join(os.path.dirname(HERE), "src", "eternal_v10.py"),
|
||||
os.path.join(os.path.dirname(HERE), "eternal_v10.py")):
|
||||
if os.path.exists(_p):
|
||||
_src = open(_p, encoding="utf-8").read()
|
||||
_m = _re.search(r"if prov_name in \[([^\]]+)\]", _src)
|
||||
if _m:
|
||||
_allow = {s.strip().strip("'\"") for s in _m.group(1).split(",")}
|
||||
try:
|
||||
for _node in _ast.walk(_ast.parse(_src)):
|
||||
if isinstance(_node, (_ast.Assign, _ast.AnnAssign)):
|
||||
_tgt = _node.targets if isinstance(_node, _ast.Assign) else [_node.target]
|
||||
for _t in _tgt:
|
||||
if (isinstance(_t, _ast.Name) and _t.id == "PROVIDERS"
|
||||
and isinstance(_node.value, _ast.Dict)):
|
||||
for _k in _node.value.keys:
|
||||
if isinstance(_k, _ast.Constant) and isinstance(_k.value, str):
|
||||
_provs.add(_k.value)
|
||||
except SyntaxError:
|
||||
pass
|
||||
break
|
||||
if _allow is None and not _provs:
|
||||
check("coupling:allowlist-found", False, "eternal_v10 allowlist not parsed (no PROVIDERS)")
|
||||
else:
|
||||
for _name in ("HEROKU", "SUPABASE"):
|
||||
_resolved = (_allow and _name in _allow) or _name in _provs
|
||||
check(f"coupling:{_name}-resolvable",
|
||||
_resolved,
|
||||
f"{_name} absent -> UNKNOWN->DEAD destroys finds")
|
||||
|
||||
print()
|
||||
if FAILS:
|
||||
print(f"BATCH2 FAILURES: {len(FAILS)}: {FAILS}")
|
||||
sys.exit(1)
|
||||
print("BATCH2 ALL GREEN")
|
||||
Reference in New Issue
Block a user