Skip to content

feat(redact): add Groq, Tavily and Notion API key patterns - #2730

Open
schienbiz wants to merge 1 commit into
garrytan:mainfrom
schienbiz:add-groq-tavily-notion-key-patterns
Open

feat(redact): add Groq, Tavily and Notion API key patterns#2730
schienbiz wants to merge 1 commit into
garrytan:mainfrom
schienbiz:add-groq-tavily-notion-key-patterns

Conversation

@schienbiz

Copy link
Copy Markdown
Contributor

The gap

Three provider key shapes have no pattern, so a bare key — one not written as NAME=value — is not detected at all.

Measured against b5a951e with bin/gstack-redact --from-file, one shape per file:

input finding
gsk_… on its own none
tvly-dev-… on its own none
ntn_… on its own none
GROQ_API_KEY=gsk_… MEDIUM env.kv
NOTION_TOKEN=ntn_… MEDIUM env.kv

env.kv covers the assignment form, which is the common case in a .env — but it keys on the variable name, so a key in a comment, a URL, a JSON blob or a test fixture is invisible. That is the shape a key most often escapes in, and it is why the prefixed provider patterns (openai.key, anthropic.key, huggingface.token, npm.token, …) exist alongside env.kv rather than instead of it.

The change

Three patterns, in the shape of the existing provider entries:

{ id: "groq.key",     tier: "HIGH", regex: /\b(gsk_[A-Za-z0-9]{20,})\b/ },
{ id: "tavily.key",   tier: "HIGH", regex: /\b(tvly-(?:dev-|prod-)?[A-Za-z0-9]{16,})\b/ },
{ id: "notion.token", tier: "HIGH", regex: /\b(ntn_[A-Za-z0-9]{40,}|secret_[A-Za-z0-9]{40,})\b/ },

HIGH follows the taxonomy's own calibration rather than my preference: every provider-prefixed secret credential in the file is HIGH (openai.key, anthropic.key, github.pat, sendgrid.key, slack.token, huggingface.token, npm.token, digitalocean.token, twilio.auth_token), and the two MEDIUM exceptions are there for stated reasons that do not apply here — stripe.publishable is public by design, google.api_key is context-variable. These three are single-purpose secret tokens with distinctive prefixes; a gsk_-prefixed 40-character token is not context-variable.

Notes on the specific regexes:

  • Tavily spells its environment infixes out ((?:dev-|prod-)?) rather than using a globally-optional segment, for the same reason openai.key does — an optional segment would also match separator-less tvly-devabc….
  • Notion carries two explicit shapes: ntn_ (current) and secret_ (legacy, still in circulation). The legacy prefix is an ordinary English word, so the {40,} floor is what makes it a credential rather than prose — secret_value does not match, and there is a negative test for exactly that.
  • No nested unbounded quantifiers; test/redact-pattern-lint.test.ts passes.

Tests

Positive cases added to the redact-engine table, negatives to the #1946 pattern negatives block (gsk_key, tvly-key, ntn_token, secret_value must not fire).

bun test test/redact-engine.test.ts test/redact-pattern-lint.test.ts \
         test/redact-engine-autoredact.test.ts test/gstack-redact-cli.test.ts \
         test/redact-prepush-hook.test.ts test/redact-doc-resolver.test.ts
→ 201 pass, 0 fail

bun test test/document-skills-redaction.test.ts test/ship-template-redaction.test.ts \
         test/gstack-config-redact-keys.test.ts
→ 20 pass, 0 fail

The generated docs pick the descriptions up from the taxonomy, so nothing was hand-edited.

Context

Found while auditing a sixteen-repo fleet where every one of these three is a live key. Not related to #2358 (chained pre-push.local stdin) — that is a separate wrapper bug with its own PR, and this change is independent of it.

I have no way to verify Groq/Tavily/Notion key lengths beyond published formats and live keys I hold, so the floors are deliberately conservative: they are false-positive guards, and the prefix carries the signal. Happy to tighten them to exact lengths if you would rather pin them.

@trunk-io

trunk-io Bot commented Aug 29, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant