- 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.
This commit is contained in:
Mick Grove 2026-02-11 16:56:47 -08:00
commit 7dc0955635
2 changed files with 11 additions and 8 deletions

View file

@ -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

View file

@ -48,9 +48,7 @@ fn extract_template_vars(text: &str) -> BTreeSet<String> {
// 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<String> {