@felixgeelhaar/cclint
Version:
Catch CLAUDE.md drift before Claude misbehaves. Lints CLAUDE.md, skills, subagents, and hooks for Claude Code projects.
63 lines • 2.97 kB
TypeScript
import type { Rule } from '../domain/Rule.js';
import { ContextFile } from '../domain/ContextFile.js';
import { Violation } from '../domain/Violation.js';
/**
* SecretDetectionRule — flags credentials pasted into CLAUDE.md.
*
* @remarks
* Committing a live API key into a context file is one of the most damaging
* authoring mistakes: CLAUDE.md is routinely shared, versioned, and fed to
* models, so a leaked key propagates widely. This rule detects the common
* provider key shapes (OpenAI, Anthropic, GitHub, AWS, Google, Slack), PEM
* private-key blocks, and a high-entropy heuristic for
* `KEY=`/`TOKEN=`/`SECRET=`/`PASSWORD=` assignments.
*
* Findings are ERROR severity. Messages name the kind of secret and mask the
* value (first four characters + `…`) so the linter never re-echoes the
* credential it is warning about.
*
* Scope: Markdown files only ({@link appliesTo}). Both prose and fenced code
* blocks are scanned — a pasted key is equally dangerous in either.
*/
export declare class SecretDetectionRule implements Rule {
readonly id = "secret-detection";
readonly description = "Detects likely API keys, tokens, and private keys committed to CLAUDE.md";
/**
* Ordered so more specific prefixes win before generic ones (Anthropic
* `sk-ant-` and OpenAI `sk-proj-` are matched before the classic OpenAI
* `sk-` shape). Hyphens in the specific prefixes already prevent the classic
* pattern from matching them, but the ordering keeps the intent explicit.
*/
private static readonly PATTERNS;
/** Substrings that mark a value as an obvious placeholder, not a secret. */
private static readonly PLACEHOLDER_TOKENS;
/**
* Env-style assignment keys that indicate a secret value is being set. The
* identifier is required to be upper-snake-case (e.g. `API_TOKEN`,
* `SECRET_KEY`) so ordinary prose like "here is a token: …" is not mistaken
* for an assignment.
*/
private static readonly ASSIGNMENT_KEY;
private static readonly MIN_ENTROPY_LENGTH;
private static readonly MIN_DISTINCT_CHARS;
private static readonly MIN_ENTROPY_BITS;
appliesTo(file: ContextFile): boolean;
lint(file: ContextFile): Violation[];
/** Match the known credential shapes on a single line. */
private collectPatternMatches;
/**
* Heuristic pass: a `KEY=`/`TOKEN=`/`SECRET=`/`PASSWORD=` assignment whose
* value is long, high-entropy, and mixed is very likely a real secret even
* when it carries no recognizable provider prefix.
*/
private collectEntropyMatches;
private violation;
/** Show only the first four characters, then an ellipsis. */
private static mask;
private static looksLikePlaceholder;
private static matchesKnownPattern;
private static isHighEntropySecret;
private static distinctChars;
private static shannonEntropy;
}
//# sourceMappingURL=SecretDetectionRule.d.ts.map