From 3181cbb26c9ca4dcbc63d55d1a421014944bb4ae Mon Sep 17 00:00:00 2001 From: bohdansolovie Date: Sun, 5 Jul 2026 02:16:25 +0200 Subject: [PATCH] feat(enrichment): detect Pinecone and Tavily API keys in secret-scan Add high-confidence pcsk_{label}_{secret} and tvly- token patterns with identifier-continuation tail guards and dedicated regression tests. Co-authored-by: Cursor --- .../src/analyzers/secret-scan.ts | 12 +++++++ review-enrichment/test/secret-scan.test.ts | 36 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/review-enrichment/src/analyzers/secret-scan.ts b/review-enrichment/src/analyzers/secret-scan.ts index d2588fd40c..03773a0e3f 100644 --- a/review-enrichment/src/analyzers/secret-scan.ts +++ b/review-enrichment/src/analyzers/secret-scan.ts @@ -223,6 +223,18 @@ const RULES: Rule[] = [ re: /\b(?:fw|fpk)_[A-Za-z0-9]{20,}(?![A-Za-z0-9_])/, confidence: "high", }, + { + // Pinecone API key: `pcsk_{5-6 char label}_{63 char secret}`. + kind: "pinecone_api_key", + re: /\bpcsk_[A-Za-z0-9]{5,6}_[A-Za-z0-9]{63}(?![A-Za-z0-9_])/, + confidence: "high", + }, + { + // Tavily API key: `tvly-` + base62 body (alnum only; reject hyphen-continued identifiers). + kind: "tavily_api_key", + re: /\btvly-[A-Za-z0-9]{16,}(?![A-Za-z0-9_-])/, + confidence: "high", + }, { // Google OAuth 2.0 client secret: `GOCSPX-` + 28 base64url chars. kind: "google_oauth_client_secret", diff --git a/review-enrichment/test/secret-scan.test.ts b/review-enrichment/test/secret-scan.test.ts index bb18b5a8fd..d6445ec4b2 100644 --- a/review-enrichment/test/secret-scan.test.ts +++ b/review-enrichment/test/secret-scan.test.ts @@ -563,6 +563,42 @@ test("scanPatch does not flag truncated Together/Fireworks keys or identifier co assert.equal(scanPatch("src/config.ts", hunk([`const firepass = "fpk_${"b".repeat(19)}";`])).length, 0); }); +test("scanPatch flags Pinecone and Tavily API keys with high confidence", () => { + const fakePineconeKey = ["pcsk_", "T5Afk6", "_", "a".repeat(63)].join(""); + const pineconeFindings = scanPatch("src/config.ts", hunk([`const pinecone = "${fakePineconeKey}";`])); + assert.equal(pineconeFindings.length, 1); + assert.equal(pineconeFindings[0].kind, "pinecone_api_key"); + assert.equal(pineconeFindings[0].confidence, "high"); + + const fakeTavilyKey = "tvly-" + "a".repeat(16); + const tavilyFindings = scanPatch("src/config.ts", hunk([`const tavily = "${fakeTavilyKey}";`])); + assert.equal(tavilyFindings.length, 1); + assert.equal(tavilyFindings[0].kind, "tavily_api_key"); + assert.equal(tavilyFindings[0].confidence, "high"); +}); + +test("scanPatch does not flag malformed Pinecone/Tavily keys or identifier continuation", () => { + const shortLabel = ["pcsk_", "abcd", "_", "a".repeat(63)].join(""); + assert.equal(scanPatch("src/config.ts", hunk([`const pinecone = "${shortLabel}";`])).length, 0); + const shortSecret = ["pcsk_", "T5Afk6", "_", "a".repeat(62)].join(""); + assert.equal(scanPatch("src/config.ts", hunk([`const pinecone = "${shortSecret}";`])).length, 0); + const pineconeEmbedded = ["pcsk_", "T5Afk6", "_", "a".repeat(63), "X"].join(""); + assert.equal( + scanPatch("src/config.ts", hunk([`const pinecone = "${pineconeEmbedded}";`])).some((f) => f.kind === "pinecone_api_key"), + false, + ); + + assert.equal(scanPatch("src/config.ts", hunk([`const tavily = "tvly-${"a".repeat(15)}";`])).length, 0); + assert.equal( + scanPatch("src/config.ts", hunk([`const tavily = "tvly-${"a".repeat(16)}_suffix";`])).some((f) => f.kind === "tavily_api_key"), + false, + ); + assert.equal( + scanPatch("src/config.ts", hunk([`const tavily = "tvly-${"a".repeat(16)}-suffix";`])).some((f) => f.kind === "tavily_api_key"), + false, + ); +}); + test("scanPatch flags additional high-confidence SaaS/cloud/CI credential formats", () => { const cases = [ ["google_oauth_client_secret", "GOCSPX-" + b62(28)],