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")