Files
keyhunter-parser/_smoke_patterns.py

144 lines
7.8 KiB
Python

import key_patterns as kp
names = [p for p, _ in kp.PATTERNS]
old = ['ZAI', 'KIMI', 'SAKANA', 'OPENROUTER', 'DASHSCOPE', 'MINIMAX', 'DEEPSEEK',
'TWOCAPTCHA', 'CAPSOLVER', 'ANTICAPTCHA', 'WEBSHARE', 'IPROYAL', 'BRIGHTDATA',
'TELEGRAM', 'DISCORD', 'OPENAI', 'ANTHROPIC', 'ANTHROPIC_OAT', 'GOOGLE',
'MISTRAL', 'TOGETHER', 'REPLICATE', 'SILICONFLOW', 'FIREWORKS', 'GROQ',
'COHERE', 'NOVITA', 'PERPLEXITY', 'ELEVENLABS', 'STABILITY', 'ALIYUN',
'NVIDIA', 'HUGGINGFACE']
missing = [p for p in old if p not in names]
assert not missing, f'missing: {missing}'
assert 'GROK' in names, 'GROK missing'
print('PATTERNS entries:', len(names), '(was 36), distinct provs:', len(set(names)))
new_env = ['FIREWORKS_AI_API_KEY', 'NOVITA_API_KEY', 'GROQ_API_KEY', 'GROQ_TOKEN',
'GROQ_LLM_API_KEY', 'NVIDIA_NIM_API_KEY', 'NVIDIA_NIM', 'MINIMAX_API_KEY',
'COHERE_API_KEY', 'ELEVENLABS_API_KEY', 'XI_API_KEY',
'HUGGINGFACEHUB_API_TOKEN', 'XAI_API_KEY']
env_set = set(v for v, _ in kp._ENV_VARS)
for v in new_env:
assert v in env_set, f'{v} missing'
assert set(kp._ALT.split('|')) == env_set, '_ALT != _ENV_VARS set'
print('ENV vars:', len(kp._ENV_VARS), '(was 142), _ALT in sync')
text = (
'XAI_API_KEY=xai-Abc123' + '9' * 40 + '\n'
'GROQ_API_KEY=gsk_' + 'a' * 48 + '\n'
'NOVITA_API_KEY=sk_OneRealNovitaStyleKeyValue1234\n'
'FIREWORKS_API_KEY=fw_' + 'b' * 48 + '\n'
# BOTH sides were wrong here, and the smoke read green for the wrong reason:
# (a) the value regex was nvapi-{80,120} while real keys are prefix+64 - it
# matched 0/263 real rows and 4/4 run-ons in data/keys.db (now {40,80}
# plus a negative lookahead); (b) the line below carries an env-var name,
# so it is labelled through ENV_VARS and never exercises that regex.
# 'n'*90 was also dropped by the low-entropy filter, masking both facts.
# The bare-value and run-on assertions after this block are the real cover.
'NVIDIA_NIM_API_KEY=nvapi-' + 'Kx7Qm2Zp9Rt4Wv6Yb1Nc8Hj3Lf5Sd0Ga' * 2 + '\n'
'nvapi-' + 'Zt8Rk3Vm6Qp1Xw9Yb1Nc8Hj3Lf5Sd0Ga' * 2 + '\n'
'nvapi-' + 'Kx7Qm2Zp9Rt4Wv6Yb1Nc8Hj3Lf5Sd0Ga' * 3 + '\n'
'MINIMAX_API_KEY=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.aaaa.aaaa\n'
'COHERE_API_KEY=cohere' + 'aBcDeFgH' * 5 + '\n'
'ELEVENLABS_API_KEY=' + 'eA1b2C3d' * 4 + '\n'
'XI_API_KEY=xi' + 'aBcDeFgHiJk' * 3 + '\n'
'HUGGINGFACEHUB_API_TOKEN=hf_' + 'g' * 34 + '\n'
'GROQ_TOKEN=gsk_' + 'h' * 50 + '\n'
'old: TOGETHER_API_KEY=tgp-' + 'c' * 45 + '\n'
'MISTRAL_API_KEY=' + 'm1A2b3C4' * 4 + '\n'
'pplx-' + 'd' * 56 + '\n'
'DEEPSEEK_API_KEY=sk-' + 'aB3cD5eF' * 4 + '\n'
)
res = kp.scan_text(text)
for r in res:
print(r)
provs = [p for p, _ in res]
for expect in ['GROK', 'GROQ', 'NOVITA', 'FIREWORKS', 'NVIDIA', 'MINIMAX', 'COHERE',
'ELEVENLABS', 'HUGGINGFACE', 'TOGETHER', 'MISTRAL', 'PERPLEXITY', 'DEEPSEEK']:
assert expect in provs, f'scan missed {expect}'
assert ('GROK', 'xai-Abc123' + '9' * 40) in res
assert ('FIREWORKS', 'fw_' + 'b' * 48) in res
# bare value (no env name) => this is the only assertion covering the value regex
NV_BARE = 'nvapi-' + 'Zt8Rk3Vm6Qp1Xw9Yb1Nc8Hj3Lf5Sd0Ga' * 2
assert ('NVIDIA', NV_BARE) in res, 'value regex missed a real 64-char nvapi key'
assert not any(v.startswith('nvapi-') and len(v) - 6 > 80 for _, v in res), \
'run-on junk matched: {40,80} + negative lookahead must reject it'
print('OK')
# ---- v6 wave: new provider patterns (must exist + match samples) ----
v6 = {
'NEON': 'napi_' + 'A1b2C3' * 7,
'DROPBOX': 'sl.' + 'AbCdEfGhIjKlMnOp' * 8,
'TWITTER': 'AAAAAAAAAA' + 'aBcDeFgHiJkLmNoPqRsTuVwXyZ01234' * 2,
'BREVO': 'xkeysib-' + 'aB1' * 9 + '-' + 'cD2' * 9,
'RESEND': 're_' + 'aB1cD2eF3' * 4,
'MAILGUN': 'key-' + 'a1b2c3d4' * 4,
'SHOPIFY': 'shpat_' + 'a1b2c3d4' * 4,
'SQUARE': 'sq0atp-' + 'aB1cD2eF3g' * 4,
'STRIPE_WEBHOOK': 'whsec_' + 'aB1cD2eF3' * 4,
'STRIPE_RESTRICTED': 'rk_live_' + 'aB1cD2eF3' * 4,
'DIGITALOCEAN': 'dop_v1_' + 'a1b2c3d4' * 8,
'DOCKER': 'dckr_pat_' + 'aB1cD2eF3' * 4,
'KAKAO': 'KakaoAK ' + 'a1b2c3d4' * 4,
'RUBYGEMS_PAT': 'rubygems_' + 'aB1cD2eF3' * 4,
'SONARQUBE': 'squ_' + 'aB1cD2eF3' * 5,
'GRAFANA': 'glc_' + 'aB1cD2eF3' * 5,
'LANGSMITH': 'lsv2_pt_' + 'aB1cD2eF3' * 5,
'TAVILY': 'tvly-' + 'aB1cD2eF3' * 4,
'FIRECRAWL': 'fc-' + 'a1b2c3d4' * 4,
'NETLIFY': 'nfp_' + 'aB1cD2eF3' * 5,
'RENDER': 'rnd_' + 'aB1cD2eF3' * 4,
'MAPBOX_SECRET': 'sk.eyJ' + 'aB1cD2eF3' * 6,
'HUBSPOT': 'pat-na1-' + 'aB1cD2eF3' * 4,
'AIRTABLE': 'pat' + 'aB1cD2eF3' + '.' + 'aB1cD2eF3' * 5,
'SENTRY_DSN': 'https://' + 'a1b2c3d4' * 4 + '@o12345.ingest.sentry.io/67890',
'PRIVATE_KEY': '-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA' + 'aB1cD2eF3' * 10 + '\n-----END RSA PRIVATE KEY-----',
}
for prov, sample in v6.items():
assert prov in names, f'v6 pattern missing: {prov}'
got = kp.scan_text('ctx ' + sample + ' ctx')
assert (prov, sample) in got, f'{prov} sample not matched: {got[:3]}'
print('v6 patterns:', len(v6), 'all matched')
v6_env = ['TAVILY_API_KEY', 'FIRECRAWL_API_KEY', 'RESEND_API_KEY', 'BREVO_API_KEY',
'SENDINBLUE_API_KEY', 'SHOPIFY_ACCESS_TOKEN', 'SHOPIFY_ADMIN_ACCESS_TOKEN',
'SONAR_TOKEN', 'SONARQUBE_TOKEN', 'GRAFANA_TOKEN', 'GRAFANA_API_TOKEN',
'RUBYGEMS_AUTH_TOKEN', 'NEON_API_KEY', 'TWITTER_BEARER_TOKEN',
'MAPBOX_ACCESS_TOKEN', 'MAPBOX_TOKEN', 'DOCKER_HUB_TOKEN', 'NETLIFY_TOKEN']
env_set = set(v for v, _ in kp._ENV_VARS)
missing_env = [v for v in v6_env if v not in env_set]
assert not missing_env, f'v6 env missing: {missing_env}'
for v, exp in [('TAVILY_API_KEY', 'TAVILY'), ('FIRECRAWL_API_KEY', 'FIRECRAWL'),
('SONAR_TOKEN', 'SONARQUBE'), ('NEON_API_KEY', 'NEON')]:
assert kp._VAR2PROV[v] == exp, f'{v} -> {kp._VAR2PROV[v]}'
print('v6 env vars added, _ALT in sync')
# --- v7.5: Discord snowflake gate fixtures (bare regex + base64-snowflake gate) ---
import base64 as _b64
import random as _rnd
import string as _string
_head_ok = _b64.b64encode(b"123456789012345678").decode() # 18 digits -> 'M...' head
_tail27 = "Z9kQ2mXpL7vR4tW1nB6cD8eF0gH" # 27 chars
_real_tok = _head_ok + ".aB3xYz." + _tail27
_blob_head = _b64.b64encode(b"5ure-but-not-a-snowflake-id!").decode() # 'N...' head, non-digit decode
_blob_tok = _blob_head + ".aB3xYz." + _tail27
assert any(p == "DISCORD" for p, _ in kp.scan_text("token " + _real_tok)), \
"real-shaped discord token must pass snowflake gate"
assert not any(k == _blob_tok for _, k in kp.scan_text("blob " + _blob_tok)), \
"base64 blob must FAIL snowflake gate"
_mfa = "mfa." + "".join(_rnd.choice(_string.ascii_letters + _string.digits) for _ in range(40))
assert any(p == "DISCORD" for p, _ in kp.scan_text(_mfa)), "bare mfa still hits"
# GARBAGE-in-scan_text pin: sequential-alphabet body IS silently dropped (real assert)
assert kp.scan_text("mfa.abcdefghijklmnopqrstuvwx123456") == [], \
"GARBAGE must drop sequential-alphabet mfa body"
# realistic high-entropy mfa (40-char body, within {24,80}) must hit
_mfa2 = "mfa." + "".join(_rnd.choice(_string.ascii_letters + _string.digits) for _ in range(40))
assert any(p == "DISCORD" for p, _ in kp.scan_text("t=" + _mfa2)), "realistic mfa must hit"
print("v7.5+v7.6 discord gate fixtures OK")
# v7.10: mfa bound raised {24,120} - real 84-char tails must round-trip full length
_mfa84 = "mfa." + "".join(_rnd.choice(_string.ascii_letters + _string.digits) for _ in range(84))
_hits84 = [k for p, k in kp.scan_text(_mfa84) if p == "DISCORD"]
assert any(len(k) == 88 for k in _hits84), f"mfa 84-char tail truncated: {[len(k) for k in _hits84]}"
print("mfa-84 round-trip OK")