From 7dc0955635ddcb9ba65ffe910d8786a8fcac92bc Mon Sep 17 00:00:00 2001 From: Mick Grove Date: Wed, 11 Feb 2026 16:56:47 -0800 Subject: [PATCH] - Added Vercel credential rules for new token formats introduced February 2026: vcp_ (personal access), vci_ (integration), vca_ (app access), vcr_ (app refresh), vck_ (AI Gateway API key). All use CRC32/Base62 checksum validation. Legacy 24-char format retained as kingfisher.vercel.1. - Added revocation support for Vercel app tokens (vca_, vcr_) via https://api.vercel.com/login/oauth/token/revoke. Requires VERCEL_APP_CLIENT_ID (or NEXT_PUBLIC_VERCEL_APP_CLIENT_ID) and VERCEL_APP_CLIENT_SECRET. - Fixed validate/revoke command generation to omit regex named captures (e.g., BODY, CHECKSUM) when they are not used by validation/revocation templates, so rules like Vercel no longer produce unnecessary --var BODY=... arguments. --- crates/kingfisher-rules/data/rules/vercel.yml | 15 ++++++++++----- src/reporter.rs | 4 +--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/crates/kingfisher-rules/data/rules/vercel.yml b/crates/kingfisher-rules/data/rules/vercel.yml index 7538d47..49e6cad 100644 --- a/crates/kingfisher-rules/data/rules/vercel.yml +++ b/crates/kingfisher-rules/data/rules/vercel.yml @@ -268,24 +268,29 @@ rules: skip_if_missing: true confidence: medium min_entropy: 3.5 + # GET /v1/models returns the catalog without verifying the token (always 200). + # Use POST /v1/chat/completions with a minimal request instead; invalid/revoked + # keys return 401. validation: type: Http content: request: - method: GET - url: https://ai-gateway.vercel.sh/v1/models + method: POST + url: https://ai-gateway.vercel.sh/v1/chat/completions headers: Authorization: "Bearer {{TOKEN}}" Content-Type: application/json + body: '{"model":"openai/gpt-3.5-turbo","messages":[{"role":"user","content":"x"}],"max_tokens":1}' response_matcher: - report_response: true - type: StatusMatch - status: [200] + status: [200, 403] - type: JsonValid - type: WordMatch words: - - '"data"' - match_all_words: true + - '"choices"' + - 'valid credit card' + match_all_words: false references: - https://vercel.com/docs/ai-gateway/authentication-and-byok/authentication - https://vercel.com/docs/ai-gateway/openai-compat/rest-api diff --git a/src/reporter.rs b/src/reporter.rs index d91401a..79ddf99 100644 --- a/src/reporter.rs +++ b/src/reporter.rs @@ -48,9 +48,7 @@ fn extract_template_vars(text: &str) -> BTreeSet { // Match {{ VAR }} or {{ VAR | filter }} patterns; return VAR uppercased. let re = regex::Regex::new(r"\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*(?:\|[^}]*)?\}\}") .expect("template var regex should compile"); - re.captures_iter(text) - .filter_map(|cap| cap.get(1).map(|m| m.as_str().to_uppercase())) - .collect() + re.captures_iter(text).filter_map(|cap| cap.get(1).map(|m| m.as_str().to_uppercase())).collect() } fn required_vars_for_validation(validation: &crate::rules::Validation) -> BTreeSet {