envspect 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +148 -0
- package/dist/cli.js +721 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +174 -0
- package/dist/index.js +692 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/scan.ts","../src/types/index.ts","../src/core/parser.ts","../src/core/differ.ts","../src/utils/logger.ts","../src/core/reporter.ts","../src/utils/config.ts","../src/commands/audit.ts","../src/core/scanner.ts","../src/rules/default-rules.ts","../src/commands/sync.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { runScan } from './commands/scan.js';\nimport { runAudit } from './commands/audit.js';\nimport { runSync } from './commands/sync.js';\nimport type { OutputFormat } from './types/index.js';\n\nconst program = new Command();\n\nprogram\n .name('envspect')\n .description('Zero-config .env validation, secret leak detection, and team sync CLI')\n .version('0.1.0')\n .option('-f, --format <type>', 'Output format (table, json, minimal)', 'table')\n .option('-s, --silent', 'Suppress non-essential output', false)\n .option('--cwd <path>', 'Working directory', process.cwd());\n\nprogram\n .command('scan')\n .description('Compare .env against .env.example')\n .option('--env <file>', 'Path to .env file', '.env')\n .option('--example <file>', 'Path to .env.example file', '.env.example')\n .option('--strict', 'Enable strict mode (fails on extra variables in .env)', false)\n .action(async (options) => {\n const globalOpts = program.opts();\n await runScan({\n ...globalOpts,\n envFile: options.env,\n exampleFile: options.example,\n strict: options.strict,\n format: globalOpts.format as OutputFormat,\n });\n });\n\nprogram\n .command('audit')\n .description('Scan codebase for hardcoded secrets')\n .option('--include <globs...>', 'Glob patterns to include')\n .option('--exclude <globs...>', 'Glob patterns to exclude')\n .option('--severity <level>', 'Minimum severity level to report', 'low')\n .action(async (options) => {\n const globalOpts = program.opts();\n await runAudit({\n ...globalOpts,\n ...options,\n format: globalOpts.format as OutputFormat,\n });\n });\n\nprogram\n .command('sync')\n .description('Encrypted .env sync for teams (coming soon)')\n .action(async () => {\n await runSync();\n });\n\nif (process.argv.length <= 2) {\n program.help();\n}\n\nprogram.parse();\n","import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { createSpinner } from 'nanospinner';\nimport type { ScanOptions, OutputFormat } from '../types/index.js';\nimport { ExitCode } from '../types/index.js';\nimport { parseEnvFile } from '../core/parser.js';\nimport { diffEnvFiles } from '../core/differ.js';\nimport { formatScanResult } from '../core/reporter.js';\nimport { log } from '../utils/logger.js';\nimport { loadConfig, defaults } from '../utils/config.js';\n\nexport async function runScan(options: Partial<ScanOptions>): Promise<void> {\n const cwd = options.cwd || process.cwd();\n const config = await loadConfig(cwd);\n const finalOptions: ScanOptions = {\n envFile: options.envFile ?? config.envFile ?? defaults.envFile,\n exampleFile: options.exampleFile ?? config.exampleFile ?? defaults.exampleFile,\n strict: options.strict ?? config.scan?.strict ?? defaults.scan.strict,\n format: (options.format ?? config.format ?? defaults.format) as OutputFormat,\n silent: options.silent ?? false,\n cwd,\n };\n\n const envPath = resolve(cwd, finalOptions.envFile);\n const examplePath = resolve(cwd, finalOptions.exampleFile);\n\n if (!existsSync(envPath)) {\n log.error(`Missing .env file at ${envPath}`);\n process.exit(ExitCode.FILE_NOT_FOUND);\n }\n\n if (!existsSync(examplePath)) {\n log.error(`Missing .env.example file at ${examplePath}`);\n process.exit(ExitCode.FILE_NOT_FOUND);\n }\n\n const spinner = createSpinner('Scanning environment files...').start();\n\n try {\n const start = performance.now();\n const envResult = await parseEnvFile(envPath);\n const exampleResult = await parseEnvFile(examplePath);\n\n if (envResult.errors.length > 0 || exampleResult.errors.length > 0) {\n spinner.error({ text: 'Failed to parse environment files' });\n process.exit(ExitCode.ERROR);\n }\n\n const diff = diffEnvFiles(exampleResult.entries, envResult.entries, {\n strict: finalOptions.strict,\n });\n\n // Set actual file paths on the diff result\n diff.sourceFile = examplePath;\n diff.targetFile = envPath;\n\n const duration = performance.now() - start;\n\n spinner.success({ text: 'Scan complete' });\n\n const output = formatScanResult({ diff, duration }, finalOptions.format);\n console.log(output);\n\n if (diff.missing.length > 0 || diff.extra.length > 0) {\n process.exit(ExitCode.SCAN_ISSUES_FOUND);\n } else {\n process.exit(ExitCode.SUCCESS);\n }\n } catch (error) {\n spinner.error({ text: 'An unexpected error occurred during scan' });\n if (error instanceof Error) {\n log.error(error.message);\n }\n process.exit(ExitCode.ERROR);\n }\n}\n","/**\n * Parsed environment variable entry\n */\nexport interface EnvEntry {\n key: string;\n value: string;\n line: number;\n comment?: string;\n isComment: boolean;\n raw: string;\n}\n\n/**\n * Result of parsing an env file\n */\nexport interface ParseResult {\n entries: EnvEntry[];\n filePath: string;\n errors: ParseError[];\n}\n\nexport interface ParseError {\n line: number;\n message: string;\n raw: string;\n}\n\n/**\n * Diff results between two env files\n */\nexport interface DiffResult {\n missing: EnvEntry[]; // In example but not in .env\n extra: EnvEntry[]; // In .env but not in example\n empty: EnvEntry[]; // In .env but has empty value\n matched: number; // Count of matching keys\n sourceFile: string;\n targetFile: string;\n}\n\n/**\n * Secret detection rule\n */\nexport interface AuditRule {\n id: string;\n name: string;\n description: string;\n pattern: RegExp;\n severity: 'critical' | 'high' | 'medium' | 'low';\n allowInEnvFiles: boolean;\n}\n\n/**\n * A single audit finding\n */\nexport interface AuditFinding {\n rule: AuditRule;\n filePath: string;\n line: number;\n match: string;\n context: string;\n}\n\n/**\n * Complete audit report\n */\nexport interface AuditReport {\n findings: AuditFinding[];\n filesScanned: number;\n rulesApplied: number;\n duration: number;\n}\n\n/**\n * Scan command result\n */\nexport interface ScanResult {\n diff: DiffResult;\n duration: number;\n success: boolean;\n}\n\n/**\n * Output format options\n */\nexport type OutputFormat = 'table' | 'json' | 'minimal';\n\n/**\n * Global CLI options\n */\nexport interface GlobalOptions {\n format: OutputFormat;\n silent: boolean;\n cwd: string;\n}\n\n/**\n * Scan command options\n */\nexport interface ScanOptions extends GlobalOptions {\n envFile: string;\n exampleFile: string;\n strict: boolean;\n}\n\n/**\n * Audit command options\n */\nexport interface AuditOptions extends GlobalOptions {\n include: string[];\n exclude: string[];\n severity: AuditRule['severity'];\n}\n\n/**\n * Config file shape (.envspectrc)\n */\nexport interface EnvspectConfig {\n envFile?: string;\n exampleFile?: string;\n scan?: {\n strict?: boolean;\n };\n audit?: {\n include?: string[];\n exclude?: string[];\n severity?: AuditRule['severity'];\n customRules?: Partial<AuditRule>[];\n };\n format?: OutputFormat;\n}\n\n/**\n * Exit codes for CLI\n */\nexport const ExitCode = {\n SUCCESS: 0,\n SCAN_ISSUES_FOUND: 1,\n AUDIT_SECRETS_FOUND: 2,\n FILE_NOT_FOUND: 3,\n CONFIG_ERROR: 4,\n ERROR: 5,\n} as const;\n\nexport type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode];\n","import { readFile } from 'node:fs/promises';\nimport { EnvEntry, ParseResult, ParseError } from '../types/index.js';\n\n/**\n * Parses an environment file from the given file path.\n */\nexport async function parseEnvFile(filePath: string): Promise<ParseResult> {\n try {\n const content = await readFile(filePath, 'utf8');\n return parseEnvContent(content, filePath);\n } catch (error: any) {\n throw new Error(`Failed to read file at ${filePath}: ${error.message}`);\n }\n}\n\n/**\n * Parses environment content into a structured ParseResult.\n */\nexport function parseEnvContent(content: string, filePath: string = 'unknown'): ParseResult {\n const entries: EnvEntry[] = [];\n const errors: ParseError[] = [];\n const lines = content.split(/\\r?\\n/);\n \n let i = 0;\n while (i < lines.length) {\n const rawLine = lines[i];\n const trimmed = rawLine.trim();\n \n // Skip empty lines\n if (!trimmed) {\n i++;\n continue;\n }\n\n // Handle full line comments\n if (trimmed.startsWith('#')) {\n entries.push({\n key: '',\n value: '',\n line: i + 1,\n isComment: true,\n comment: trimmed.substring(1).trim(),\n raw: rawLine\n });\n i++;\n continue;\n }\n\n // Strip optional export prefix\n const matchLine = trimmed.startsWith('export ') ? trimmed.substring(7).trimStart() : trimmed;\n \n const eqIdx = matchLine.indexOf('=');\n if (eqIdx === -1) {\n errors.push({ line: i + 1, message: 'Malformed line, missing \"=\"', raw: rawLine });\n i++;\n continue;\n }\n\n const key = matchLine.substring(0, eqIdx).trim();\n let valueStr = matchLine.substring(eqIdx + 1).trim();\n let comment: string | undefined = undefined;\n \n // Check for quoted values\n if (valueStr.startsWith('\"') || valueStr.startsWith(\"'\") || valueStr.startsWith('`')) {\n const quoteChar = valueStr[0];\n \n // Multiline check for double quotes or backticks\n if (quoteChar === '\"' || quoteChar === '`') {\n let endIndex = valueStr.indexOf(quoteChar, 1);\n let valueLines = [valueStr];\n let multilineRaw = [rawLine];\n let currentLineIdx = i;\n \n while (endIndex === -1 && currentLineIdx < lines.length - 1) {\n currentLineIdx++;\n const nextLine = lines[currentLineIdx];\n valueLines.push(nextLine);\n multilineRaw.push(nextLine);\n endIndex = nextLine.indexOf(quoteChar);\n }\n \n if (endIndex === -1) {\n errors.push({ line: i + 1, message: `Unmatched ${quoteChar}`, raw: multilineRaw.join('\\n') });\n i = currentLineIdx + 1;\n continue;\n } else {\n valueStr = valueLines.join('\\n');\n const finalRaw = multilineRaw.join('\\n');\n // Extract the value without quotes\n const extractedValue = valueStr.substring(1, valueStr.lastIndexOf(quoteChar));\n \n // Check for inline comment after quote\n const afterQuote = valueStr.substring(valueStr.lastIndexOf(quoteChar) + 1).trim();\n if (afterQuote.startsWith('#')) {\n comment = afterQuote.substring(1).trim();\n }\n\n entries.push({\n key,\n value: extractedValue,\n line: i + 1,\n isComment: false,\n comment,\n raw: finalRaw\n });\n i = currentLineIdx + 1;\n continue;\n }\n } else {\n // Single quotes don't support multiline\n const endIndex = valueStr.indexOf(quoteChar, 1);\n if (endIndex === -1) {\n errors.push({ line: i + 1, message: 'Unmatched single quote', raw: rawLine });\n i++;\n continue;\n }\n const extractedValue = valueStr.substring(1, endIndex);\n const afterQuote = valueStr.substring(endIndex + 1).trim();\n if (afterQuote.startsWith('#')) {\n comment = afterQuote.substring(1).trim();\n }\n entries.push({\n key,\n value: extractedValue,\n line: i + 1,\n isComment: false,\n comment,\n raw: rawLine\n });\n i++;\n continue;\n }\n }\n\n // Unquoted value: check for inline comment\n const hashIdx = valueStr.indexOf('#');\n let value = valueStr;\n if (hashIdx !== -1) {\n value = valueStr.substring(0, hashIdx).trim();\n comment = valueStr.substring(hashIdx + 1).trim();\n }\n\n entries.push({\n key,\n value,\n line: i + 1,\n isComment: false,\n comment,\n raw: rawLine\n });\n \n i++;\n }\n\n return { entries, filePath, errors };\n}\n","import { EnvEntry, DiffResult } from '../types/index.js';\n\nexport interface DiffOptions {\n strict?: boolean;\n}\n\n/**\n * Compares two sets of parsed environment entries and returns the differences.\n * @param source - entries from .env.example (the reference/template)\n * @param target - entries from .env (the actual file)\n * @param options - optional diff options\n */\nexport function diffEnvFiles(source: EnvEntry[], target: EnvEntry[], options: DiffOptions = {}): DiffResult {\n const sourceMap = new Map<string, EnvEntry>();\n const targetMap = new Map<string, EnvEntry>();\n\n // Map source keys, ignoring comments\n for (const entry of source) {\n if (!entry.isComment && entry.key) {\n sourceMap.set(entry.key, entry);\n }\n }\n\n // Map target keys, ignoring comments\n for (const entry of target) {\n if (!entry.isComment && entry.key) {\n targetMap.set(entry.key, entry);\n }\n }\n\n const missing: EnvEntry[] = [];\n const extra: EnvEntry[] = [];\n const empty: EnvEntry[] = [];\n let matched = 0;\n\n // Check for missing keys (in source/example but not in target/.env)\n for (const [key, entry] of sourceMap.entries()) {\n if (!targetMap.has(key)) {\n missing.push(entry);\n } else {\n matched++;\n }\n }\n\n // Check for extra and empty keys (in target/.env but not in source/example)\n for (const [key, entry] of targetMap.entries()) {\n if (!sourceMap.has(key)) {\n extra.push(entry);\n }\n if (entry.value.trim() === '') {\n empty.push(entry);\n }\n }\n\n return {\n missing,\n extra,\n empty,\n matched,\n sourceFile: 'source',\n targetFile: 'target',\n };\n}\n\n","import pc from 'picocolors';\n\n/**\n * Centralized logger with consistent formatting and color coding.\n * Wraps picocolors for a unified output style across all commands.\n */\nexport const log = {\n /** Informational message */\n info: (msg: string) => console.log(pc.cyan('ℹ'), msg),\n\n /** Success message */\n success: (msg: string) => console.log(pc.green('✔'), msg),\n\n /** Warning message */\n warn: (msg: string) => console.log(pc.yellow('⚠'), msg),\n\n /** Error message */\n error: (msg: string) => console.error(pc.red('✖'), msg),\n\n /** Debug message (only when ENVSPECT_DEBUG is set) */\n debug: (msg: string) => {\n if (process.env.ENVSPECT_DEBUG) {\n console.log(pc.gray(`[debug] ${msg}`));\n }\n },\n\n /** Dim/muted text */\n dim: (msg: string) => console.log(pc.dim(msg)),\n\n /** Bold header */\n header: (msg: string) => console.log(`\\n${pc.bold(pc.underline(msg))}\\n`),\n\n /** Raw console.log (no prefix) */\n raw: (msg: string) => console.log(msg),\n\n /** Blank line */\n newline: () => console.log(),\n} as const;\n\n/** Color helpers for inline use */\nexport const c = {\n red: pc.red,\n green: pc.green,\n yellow: pc.yellow,\n cyan: pc.cyan,\n dim: pc.dim,\n bold: pc.bold,\n underline: pc.underline,\n gray: pc.gray,\n} as const;\n","import { DiffResult, AuditReport, OutputFormat } from '../types/index.js';\nimport { c } from '../utils/logger.js';\n\n/**\n * Formats a scan/diff result for terminal output.\n */\nexport function formatScanResult(result: { diff: DiffResult; duration: number }, format: OutputFormat): string {\n const { diff, duration } = result;\n\n if (format === 'json') {\n return JSON.stringify(result, null, 2);\n }\n\n if (format === 'minimal') {\n let out = '';\n diff.missing.forEach(m => out += `MISSING: ${m.key}\\n`);\n diff.extra.forEach(e => out += `EXTRA: ${e.key}\\n`);\n diff.empty.forEach(e => out += `EMPTY: ${e.key}\\n`);\n return out.trim();\n }\n\n // 'table' output\n let out = c.bold(`┌─ Env Diff Report ─────────────────┐\\n`);\n out += `│ Source: ${diff.sourceFile}\\n`;\n out += `│ Target: ${diff.targetFile}\\n`;\n out += `└───────────────────────────────────┘\\n\\n`;\n\n if (diff.missing.length > 0) {\n out += c.red(c.bold(`Missing Keys (${diff.missing.length}):\\n`));\n diff.missing.forEach(m => out += ` - ${c.red(m.key)}\\n`);\n }\n\n if (diff.extra.length > 0) {\n out += c.yellow(c.bold(`\\nExtra Keys (${diff.extra.length}):\\n`));\n diff.extra.forEach(e => out += ` - ${c.yellow(e.key)}\\n`);\n }\n\n if (diff.empty.length > 0) {\n out += c.cyan(c.bold(`\\nEmpty Keys (${diff.empty.length}):\\n`));\n diff.empty.forEach(e => out += ` - ${c.cyan(e.key)}\\n`);\n }\n\n out += c.gray(`\\nMatched: ${diff.matched} | Duration: ${duration.toFixed(2)}ms\\n`);\n return out;\n}\n\n/**\n * Formats an audit report for terminal output.\n */\nexport function formatAuditReport(report: AuditReport, format: OutputFormat): string {\n if (format === 'json') {\n return JSON.stringify(report, null, 2);\n }\n\n if (format === 'minimal') {\n return report.findings\n .map(f => `${f.filePath}:${f.line} [${f.rule.severity}] ${f.rule.name} - ${f.match}`)\n .join('\\n');\n }\n\n // 'table' output\n let out = c.bold(`┌─ Audit Report ────────────────────┐\\n`);\n out += `│ Files Scanned: ${report.filesScanned}\\n`;\n out += `│ Findings: ${report.findings.length}\\n`;\n out += `└───────────────────────────────────┘\\n\\n`;\n\n if (report.findings.length === 0) {\n out += c.green('No secrets or issues found. ✨\\n');\n } else {\n report.findings.forEach(f => {\n let colorFn = c.cyan;\n if (f.rule.severity === 'critical') colorFn = c.red;\n else if (f.rule.severity === 'high') colorFn = c.yellow;\n \n out += `${colorFn(c.bold(`[${f.rule.severity.toUpperCase()}]`))} ${f.rule.name} in ${f.filePath}:${f.line}\\n`;\n out += ` Match: ${f.match}\\n`;\n out += ` Context: ${c.dim(f.context)}\\n\\n`;\n });\n }\n\n out += c.gray(`Duration: ${report.duration.toFixed(2)}ms\\n`);\n return out;\n}\n","import { readFile } from 'node:fs/promises';\nimport { resolve, join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type { EnvspectConfig } from '../types/index.js';\nimport { log } from './logger.js';\n\n/** Config file names to search for, in priority order */\nconst CONFIG_FILES = [\n '.envspectrc',\n '.envspectrc.json',\n 'envspect.config.json',\n] as const;\n\n/**\n * Loads the envspect config file from the project root.\n * Searches for config files in priority order and returns the first found.\n * Returns an empty config object if no config file exists.\n */\nexport async function loadConfig(cwd?: string): Promise<EnvspectConfig> {\n const root = resolve(cwd || process.cwd());\n\n for (const fileName of CONFIG_FILES) {\n const filePath = join(root, fileName);\n\n if (!existsSync(filePath)) continue;\n\n try {\n const content = await readFile(filePath, 'utf-8');\n const config: EnvspectConfig = JSON.parse(content);\n log.debug(`Loaded config from ${fileName}`);\n return config;\n } catch (err) {\n log.warn(`Failed to parse config file: ${fileName}`);\n log.debug(String(err));\n return {};\n }\n }\n\n log.debug('No config file found, using defaults');\n return {};\n}\n\n/** Default config values */\nexport const defaults: Required<Pick<EnvspectConfig, 'envFile' | 'exampleFile' | 'format'>> & {\n scan: Required<NonNullable<EnvspectConfig['scan']>>;\n audit: Required<Pick<NonNullable<EnvspectConfig['audit']>, 'include' | 'exclude' | 'severity'>>;\n} = {\n envFile: '.env',\n exampleFile: '.env.example',\n format: 'table',\n scan: {\n strict: false,\n },\n audit: {\n include: ['**/*.{ts,tsx,js,jsx,py,rb,go,java,php,rs,yaml,yml,toml,json,xml,sh}'],\n exclude: [\n '**/node_modules/**',\n '**/dist/**',\n '**/build/**',\n '**/.git/**',\n '**/coverage/**',\n '**/*.min.js',\n '**/vendor/**',\n '**/package-lock.json',\n '**/pnpm-lock.yaml',\n '**/yarn.lock',\n ],\n severity: 'low',\n },\n};\n","import { resolve } from 'node:path';\nimport { createSpinner } from 'nanospinner';\nimport type { AuditOptions, OutputFormat } from '../types/index.js';\nimport { ExitCode } from '../types/index.js';\nimport { scanDirectory } from '../core/scanner.js';\nimport { formatAuditReport } from '../core/reporter.js';\nimport { defaultRules } from '../rules/default-rules.js';\nimport { log } from '../utils/logger.js';\nimport { loadConfig, defaults } from '../utils/config.js';\n\nexport async function runAudit(options: Partial<AuditOptions>): Promise<void> {\n const cwd = options.cwd || process.cwd();\n const config = await loadConfig(cwd);\n const finalOptions: AuditOptions = {\n include: options.include ?? config.audit?.include ?? defaults.audit.include,\n exclude: options.exclude ?? config.audit?.exclude ?? defaults.audit.exclude,\n severity: options.severity ?? config.audit?.severity ?? defaults.audit.severity,\n format: (options.format ?? config.format ?? defaults.format) as OutputFormat,\n silent: options.silent ?? false,\n cwd,\n };\n\n const spinner = createSpinner('Auditing codebase for secrets...').start();\n\n try {\n const report = await scanDirectory({\n cwd: resolve(cwd),\n rules: defaultRules,\n include: finalOptions.include,\n exclude: finalOptions.exclude,\n minSeverity: finalOptions.severity,\n });\n\n spinner.success({ text: 'Audit complete' });\n\n const output = formatAuditReport(report, finalOptions.format);\n console.log(output);\n\n if (report.findings.length > 0) {\n process.exit(ExitCode.AUDIT_SECRETS_FOUND);\n } else {\n process.exit(ExitCode.SUCCESS);\n }\n } catch (error) {\n spinner.error({ text: 'An unexpected error occurred during audit' });\n if (error instanceof Error) {\n log.error(error.message);\n }\n process.exit(ExitCode.ERROR);\n }\n}\n","import { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { AuditRule, AuditFinding, AuditReport } from '../types/index.js';\n\nexport interface ScanDirectoryOptions {\n cwd: string;\n rules: AuditRule[];\n include: string[];\n exclude: string[];\n minSeverity: 'critical' | 'high' | 'medium' | 'low';\n}\n\nconst severityLevels: Record<string, number> = { \n critical: 4, \n high: 3, \n medium: 2, \n low: 1 \n};\n\n/**\n * Converts a simple glob pattern to a RegExp.\n */\nfunction globToRegex(glob: string): RegExp {\n const escaped = glob\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&') // Escape regex special chars\n .replace(/\\*/g, '.*') // Convert * to .*\n .replace(/\\?/g, '.'); // Convert ? to .\n return new RegExp(`^${escaped}$`);\n}\n\n/**\n * Checks if a path matches any of the given glob patterns.\n */\nfunction matchGlobs(path: string, globs: string[]): boolean {\n if (globs.length === 0) return true;\n return globs.some(glob => globToRegex(glob).test(path));\n}\n\n/**\n * Recursively walks a directory and returns files matching globs.\n */\nasync function walkDir(dir: string, includeGlobs: string[], excludeGlobs: string[], fileList: string[] = [], cwd: string = dir): Promise<string[]> {\n try {\n const files = await readdir(dir, { withFileTypes: true });\n for (const file of files) {\n const res = join(dir, file.name);\n // Normalize to forward slashes for glob matching\n const relPath = res.substring(cwd.length + 1).replace(/\\\\/g, '/');\n \n if (file.isDirectory()) {\n if (!matchGlobs(relPath, excludeGlobs)) {\n await walkDir(res, includeGlobs, excludeGlobs, fileList, cwd);\n }\n } else {\n if (matchGlobs(relPath, includeGlobs) && !matchGlobs(relPath, excludeGlobs)) {\n fileList.push(res);\n }\n }\n }\n } catch (error) {\n // Ignore read errors for inaccessible directories\n }\n return fileList;\n}\n\n/**\n * Scans a directory for secrets and audit issues based on rules.\n */\nexport async function scanDirectory(options: ScanDirectoryOptions): Promise<AuditReport> {\n const start = performance.now();\n const findings: AuditFinding[] = [];\n let filesScanned = 0;\n \n const targetFiles = await walkDir(options.cwd, options.include, options.exclude, [], options.cwd);\n const minSevLevel = severityLevels[options.minSeverity];\n \n for (const file of targetFiles) {\n filesScanned++;\n try {\n const content = await readFile(file, 'utf8');\n const lines = content.split(/\\r?\\n/);\n const fileName = file.replace(/\\\\/g, '/').split('/').pop() || '';\n const isEnvFile = fileName.endsWith('.env') || fileName.startsWith('.env');\n \n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n \n for (const rule of options.rules) {\n if (severityLevels[rule.severity] < minSevLevel) {\n continue;\n }\n if (isEnvFile && !rule.allowInEnvFiles) {\n continue;\n }\n \n const match = rule.pattern.exec(line);\n if (match) {\n const matchedText = match[0];\n // Redact matched secret\n const redacted = matchedText.length > 4 \n ? matchedText.substring(0, 4) + '*'.repeat(matchedText.length - 4)\n : '****';\n \n findings.push({\n rule,\n filePath: file.substring(options.cwd.length + 1), // relative path\n line: i + 1,\n match: redacted,\n context: line.trim().substring(0, 100) // max 100 chars\n });\n }\n }\n }\n } catch (e) {\n // Skip files that cannot be read\n }\n }\n\n return {\n findings,\n filesScanned,\n rulesApplied: options.rules.length,\n duration: performance.now() - start\n };\n}\n","import type { AuditRule } from '../types/index.js';\n\n/**\n * Built-in secret detection rules.\n * Each rule defines a regex pattern to detect potentially leaked secrets.\n */\nexport const defaultRules: AuditRule[] = [\n // ── AWS ──\n {\n id: 'aws-access-key',\n name: 'AWS Access Key ID',\n description: 'Detects AWS Access Key IDs (starts with AKIA)',\n pattern: /(?:^|[^A-Za-z0-9/+=])AKIA[0-9A-Z]{16}(?:[^A-Za-z0-9/+=]|$)/,\n severity: 'critical',\n allowInEnvFiles: true,\n },\n {\n id: 'aws-secret-key',\n name: 'AWS Secret Access Key',\n description: 'Detects AWS Secret Access Keys (40 char base64)',\n pattern: /(?:aws_secret_access_key|aws_secret)\\s*[=:]\\s*['\"]?[A-Za-z0-9/+=]{40}['\"]?/i,\n severity: 'critical',\n allowInEnvFiles: true,\n },\n // ── API Keys (Generic) ──\n {\n id: 'generic-api-key',\n name: 'Generic API Key Assignment',\n description: 'Detects hardcoded API key assignments in source code',\n pattern: /(?:api_key|apikey|api_secret|apisecret)\\s*[=:]\\s*['\"][A-Za-z0-9_\\-]{16,}['\"]/i,\n severity: 'high',\n allowInEnvFiles: true,\n },\n // ── Private Keys ──\n {\n id: 'private-key',\n name: 'Private Key',\n description: 'Detects PEM-encoded private keys',\n pattern: /-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/,\n severity: 'critical',\n allowInEnvFiles: false,\n },\n // ── GitHub ──\n {\n id: 'github-token',\n name: 'GitHub Token',\n description: 'Detects GitHub personal access tokens and fine-grained tokens',\n pattern: /(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,}/,\n severity: 'critical',\n allowInEnvFiles: true,\n },\n // ── Stripe ──\n {\n id: 'stripe-key',\n name: 'Stripe API Key',\n description: 'Detects Stripe secret and publishable keys',\n pattern: /(?:sk|pk)_(?:test|live)_[A-Za-z0-9]{24,}/,\n severity: 'critical',\n allowInEnvFiles: true,\n },\n // ── JWT ──\n {\n id: 'jwt-token',\n name: 'JWT Token',\n description: 'Detects hardcoded JWT tokens',\n pattern: /eyJ[A-Za-z0-9_-]{10,}\\.eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}/,\n severity: 'high',\n allowInEnvFiles: true,\n },\n // ── Database URLs ──\n {\n id: 'database-url',\n name: 'Database Connection String',\n description: 'Detects database connection strings with credentials',\n pattern: /(?:mongodb(?:\\+srv)?|postgres(?:ql)?|mysql|redis|amqp):\\/\\/[^\\s'\"]+:[^\\s'\"]+@[^\\s'\"]+/i,\n severity: 'high',\n allowInEnvFiles: true,\n },\n // ── Passwords ──\n {\n id: 'password-assignment',\n name: 'Password Assignment',\n description: 'Detects hardcoded password assignments in source code',\n pattern: /(?:password|passwd|pwd|secret)\\s*[=:]\\s*['\"][^'\"]{8,}['\"]/i,\n severity: 'high',\n allowInEnvFiles: true,\n },\n // ── Google ──\n {\n id: 'google-api-key',\n name: 'Google API Key',\n description: 'Detects Google API keys',\n pattern: /AIza[0-9A-Za-z_-]{35}/,\n severity: 'high',\n allowInEnvFiles: true,\n },\n // ── Slack ──\n {\n id: 'slack-token',\n name: 'Slack Token',\n description: 'Detects Slack bot and user tokens',\n pattern: /xox[bporsca]-[0-9]{10,}-[A-Za-z0-9-]+/,\n severity: 'high',\n allowInEnvFiles: true,\n },\n // ── SendGrid ──\n {\n id: 'sendgrid-key',\n name: 'SendGrid API Key',\n description: 'Detects SendGrid API keys',\n pattern: /SG\\.[A-Za-z0-9_-]{22}\\.[A-Za-z0-9_-]{43}/,\n severity: 'high',\n allowInEnvFiles: true,\n },\n // ── Twilio ──\n {\n id: 'twilio-key',\n name: 'Twilio API Key',\n description: 'Detects Twilio Account SID and Auth tokens',\n pattern: /(?:AC[a-z0-9]{32}|SK[a-z0-9]{32})/,\n severity: 'high',\n allowInEnvFiles: true,\n },\n // ── npm ──\n {\n id: 'npm-token',\n name: 'npm Access Token',\n description: 'Detects npm access tokens',\n pattern: /npm_[A-Za-z0-9]{36}/,\n severity: 'critical',\n allowInEnvFiles: true,\n },\n // ── Discord ──\n {\n id: 'discord-token',\n name: 'Discord Bot Token',\n description: 'Detects Discord bot tokens',\n pattern: /[MN][A-Za-z\\d]{23,}\\.[\\w-]{6}\\.[\\w-]{27,}/,\n severity: 'critical',\n allowInEnvFiles: true,\n },\n];\n","import { log, c } from '../utils/logger.js';\n\nexport async function runSync(): Promise<void> {\n log.info(`Sync feature is coming in ${c.bold('v1.0')}!`);\n log.dim('This will allow you to share encrypted .env files securely with your team.');\n}\n"],"mappings":";;;AAAA,SAAS,eAAe;;;ACAxB,SAAS,cAAAA,mBAAkB;AAC3B,SAAS,WAAAC,gBAAe;AACxB,SAAS,qBAAqB;;;ACoIvB,IAAM,WAAW;AAAA,EACtB,SAAS;AAAA,EACT,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,OAAO;AACT;;;AC7IA,SAAS,gBAAgB;AAMzB,eAAsB,aAAa,UAAwC;AACzE,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,UAAU,MAAM;AAC/C,WAAO,gBAAgB,SAAS,QAAQ;AAAA,EAC1C,SAAS,OAAY;AACnB,UAAM,IAAI,MAAM,0BAA0B,QAAQ,KAAK,MAAM,OAAO,EAAE;AAAA,EACxE;AACF;AAKO,SAAS,gBAAgB,SAAiB,WAAmB,WAAwB;AAC1F,QAAM,UAAsB,CAAC;AAC7B,QAAM,SAAuB,CAAC;AAC9B,QAAM,QAAQ,QAAQ,MAAM,OAAO;AAEnC,MAAI,IAAI;AACR,SAAO,IAAI,MAAM,QAAQ;AACvB,UAAM,UAAU,MAAM,CAAC;AACvB,UAAM,UAAU,QAAQ,KAAK;AAG7B,QAAI,CAAC,SAAS;AACZ;AACA;AAAA,IACF;AAGA,QAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,cAAQ,KAAK;AAAA,QACX,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM,IAAI;AAAA,QACV,WAAW;AAAA,QACX,SAAS,QAAQ,UAAU,CAAC,EAAE,KAAK;AAAA,QACnC,KAAK;AAAA,MACP,CAAC;AACD;AACA;AAAA,IACF;AAGA,UAAM,YAAY,QAAQ,WAAW,SAAS,IAAI,QAAQ,UAAU,CAAC,EAAE,UAAU,IAAI;AAErF,UAAM,QAAQ,UAAU,QAAQ,GAAG;AACnC,QAAI,UAAU,IAAI;AAChB,aAAO,KAAK,EAAE,MAAM,IAAI,GAAG,SAAS,+BAA+B,KAAK,QAAQ,CAAC;AACjF;AACA;AAAA,IACF;AAEA,UAAM,MAAM,UAAU,UAAU,GAAG,KAAK,EAAE,KAAK;AAC/C,QAAI,WAAW,UAAU,UAAU,QAAQ,CAAC,EAAE,KAAK;AACnD,QAAI,UAA8B;AAGlC,QAAI,SAAS,WAAW,GAAG,KAAK,SAAS,WAAW,GAAG,KAAK,SAAS,WAAW,GAAG,GAAG;AACpF,YAAM,YAAY,SAAS,CAAC;AAG5B,UAAI,cAAc,OAAO,cAAc,KAAK;AAC1C,YAAI,WAAW,SAAS,QAAQ,WAAW,CAAC;AAC5C,YAAI,aAAa,CAAC,QAAQ;AAC1B,YAAI,eAAe,CAAC,OAAO;AAC3B,YAAI,iBAAiB;AAErB,eAAO,aAAa,MAAM,iBAAiB,MAAM,SAAS,GAAG;AAC3D;AACA,gBAAM,WAAW,MAAM,cAAc;AACrC,qBAAW,KAAK,QAAQ;AACxB,uBAAa,KAAK,QAAQ;AAC1B,qBAAW,SAAS,QAAQ,SAAS;AAAA,QACvC;AAEA,YAAI,aAAa,IAAI;AACnB,iBAAO,KAAK,EAAE,MAAM,IAAI,GAAG,SAAS,aAAa,SAAS,IAAI,KAAK,aAAa,KAAK,IAAI,EAAE,CAAC;AAC5F,cAAI,iBAAiB;AACrB;AAAA,QACF,OAAO;AACL,qBAAW,WAAW,KAAK,IAAI;AAC/B,gBAAM,WAAW,aAAa,KAAK,IAAI;AAEvC,gBAAM,iBAAiB,SAAS,UAAU,GAAG,SAAS,YAAY,SAAS,CAAC;AAG5E,gBAAM,aAAa,SAAS,UAAU,SAAS,YAAY,SAAS,IAAI,CAAC,EAAE,KAAK;AAChF,cAAI,WAAW,WAAW,GAAG,GAAG;AAC7B,sBAAU,WAAW,UAAU,CAAC,EAAE,KAAK;AAAA,UAC1C;AAEA,kBAAQ,KAAK;AAAA,YACX;AAAA,YACA,OAAO;AAAA,YACP,MAAM,IAAI;AAAA,YACV,WAAW;AAAA,YACX;AAAA,YACA,KAAK;AAAA,UACP,CAAC;AACD,cAAI,iBAAiB;AACrB;AAAA,QACF;AAAA,MACF,OAAO;AAEJ,cAAM,WAAW,SAAS,QAAQ,WAAW,CAAC;AAC9C,YAAI,aAAa,IAAI;AACjB,iBAAO,KAAK,EAAE,MAAM,IAAI,GAAG,SAAS,0BAA0B,KAAK,QAAQ,CAAC;AAC5E;AACA;AAAA,QACJ;AACA,cAAM,iBAAiB,SAAS,UAAU,GAAG,QAAQ;AACrD,cAAM,aAAa,SAAS,UAAU,WAAW,CAAC,EAAE,KAAK;AACzD,YAAI,WAAW,WAAW,GAAG,GAAG;AAC5B,oBAAU,WAAW,UAAU,CAAC,EAAE,KAAK;AAAA,QAC3C;AACA,gBAAQ,KAAK;AAAA,UACT;AAAA,UACA,OAAO;AAAA,UACP,MAAM,IAAI;AAAA,UACV,WAAW;AAAA,UACX;AAAA,UACA,KAAK;AAAA,QACT,CAAC;AACD;AACA;AAAA,MACH;AAAA,IACF;AAGA,UAAM,UAAU,SAAS,QAAQ,GAAG;AACpC,QAAI,QAAQ;AACZ,QAAI,YAAY,IAAI;AAClB,cAAQ,SAAS,UAAU,GAAG,OAAO,EAAE,KAAK;AAC5C,gBAAU,SAAS,UAAU,UAAU,CAAC,EAAE,KAAK;AAAA,IACjD;AAEA,YAAQ,KAAK;AAAA,MACX;AAAA,MACA;AAAA,MACA,MAAM,IAAI;AAAA,MACV,WAAW;AAAA,MACX;AAAA,MACA,KAAK;AAAA,IACP,CAAC;AAED;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,UAAU,OAAO;AACrC;;;AC/IO,SAAS,aAAa,QAAoB,QAAoB,UAAuB,CAAC,GAAe;AAC1G,QAAM,YAAY,oBAAI,IAAsB;AAC5C,QAAM,YAAY,oBAAI,IAAsB;AAG5C,aAAW,SAAS,QAAQ;AAC1B,QAAI,CAAC,MAAM,aAAa,MAAM,KAAK;AACjC,gBAAU,IAAI,MAAM,KAAK,KAAK;AAAA,IAChC;AAAA,EACF;AAGA,aAAW,SAAS,QAAQ;AAC1B,QAAI,CAAC,MAAM,aAAa,MAAM,KAAK;AACjC,gBAAU,IAAI,MAAM,KAAK,KAAK;AAAA,IAChC;AAAA,EACF;AAEA,QAAM,UAAsB,CAAC;AAC7B,QAAM,QAAoB,CAAC;AAC3B,QAAM,QAAoB,CAAC;AAC3B,MAAI,UAAU;AAGd,aAAW,CAAC,KAAK,KAAK,KAAK,UAAU,QAAQ,GAAG;AAC9C,QAAI,CAAC,UAAU,IAAI,GAAG,GAAG;AACvB,cAAQ,KAAK,KAAK;AAAA,IACpB,OAAO;AACL;AAAA,IACF;AAAA,EACF;AAGA,aAAW,CAAC,KAAK,KAAK,KAAK,UAAU,QAAQ,GAAG;AAC9C,QAAI,CAAC,UAAU,IAAI,GAAG,GAAG;AACvB,YAAM,KAAK,KAAK;AAAA,IAClB;AACA,QAAI,MAAM,MAAM,KAAK,MAAM,IAAI;AAC7B,YAAM,KAAK,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AACF;;;AC9DA,OAAO,QAAQ;AAMR,IAAM,MAAM;AAAA;AAAA,EAEjB,MAAM,CAAC,QAAgB,QAAQ,IAAI,GAAG,KAAK,QAAG,GAAG,GAAG;AAAA;AAAA,EAGpD,SAAS,CAAC,QAAgB,QAAQ,IAAI,GAAG,MAAM,QAAG,GAAG,GAAG;AAAA;AAAA,EAGxD,MAAM,CAAC,QAAgB,QAAQ,IAAI,GAAG,OAAO,QAAG,GAAG,GAAG;AAAA;AAAA,EAGtD,OAAO,CAAC,QAAgB,QAAQ,MAAM,GAAG,IAAI,QAAG,GAAG,GAAG;AAAA;AAAA,EAGtD,OAAO,CAAC,QAAgB;AACtB,QAAI,QAAQ,IAAI,gBAAgB;AAC9B,cAAQ,IAAI,GAAG,KAAK,WAAW,GAAG,EAAE,CAAC;AAAA,IACvC;AAAA,EACF;AAAA;AAAA,EAGA,KAAK,CAAC,QAAgB,QAAQ,IAAI,GAAG,IAAI,GAAG,CAAC;AAAA;AAAA,EAG7C,QAAQ,CAAC,QAAgB,QAAQ,IAAI;AAAA,EAAK,GAAG,KAAK,GAAG,UAAU,GAAG,CAAC,CAAC;AAAA,CAAI;AAAA;AAAA,EAGxE,KAAK,CAAC,QAAgB,QAAQ,IAAI,GAAG;AAAA;AAAA,EAGrC,SAAS,MAAM,QAAQ,IAAI;AAC7B;AAGO,IAAM,IAAI;AAAA,EACf,KAAK,GAAG;AAAA,EACR,OAAO,GAAG;AAAA,EACV,QAAQ,GAAG;AAAA,EACX,MAAM,GAAG;AAAA,EACT,KAAK,GAAG;AAAA,EACR,MAAM,GAAG;AAAA,EACT,WAAW,GAAG;AAAA,EACd,MAAM,GAAG;AACX;;;AC3CO,SAAS,iBAAiB,QAAgD,QAA8B;AAC7G,QAAM,EAAE,MAAM,SAAS,IAAI;AAE3B,MAAI,WAAW,QAAQ;AACrB,WAAO,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,EACvC;AAEA,MAAI,WAAW,WAAW;AACxB,QAAIC,OAAM;AACV,SAAK,QAAQ,QAAQ,OAAKA,QAAO,YAAY,EAAE,GAAG;AAAA,CAAI;AACtD,SAAK,MAAM,QAAQ,OAAKA,QAAO,UAAU,EAAE,GAAG;AAAA,CAAI;AAClD,SAAK,MAAM,QAAQ,OAAKA,QAAO,UAAU,EAAE,GAAG;AAAA,CAAI;AAClD,WAAOA,KAAI,KAAK;AAAA,EAClB;AAGA,MAAI,MAAM,EAAE,KAAK;AAAA,CAAyC;AAC1D,SAAO,kBAAa,KAAK,UAAU;AAAA;AACnC,SAAO,kBAAa,KAAK,UAAU;AAAA;AACnC,SAAO;AAAA;AAAA;AAEP,MAAI,KAAK,QAAQ,SAAS,GAAG;AAC3B,WAAO,EAAE,IAAI,EAAE,KAAK,iBAAiB,KAAK,QAAQ,MAAM;AAAA,CAAM,CAAC;AAC/D,SAAK,QAAQ,QAAQ,OAAK,OAAO,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC;AAAA,CAAI;AAAA,EAC1D;AAEA,MAAI,KAAK,MAAM,SAAS,GAAG;AACzB,WAAO,EAAE,OAAO,EAAE,KAAK;AAAA,cAAiB,KAAK,MAAM,MAAM;AAAA,CAAM,CAAC;AAChE,SAAK,MAAM,QAAQ,OAAK,OAAO,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC;AAAA,CAAI;AAAA,EAC3D;AAEA,MAAI,KAAK,MAAM,SAAS,GAAG;AACzB,WAAO,EAAE,KAAK,EAAE,KAAK;AAAA,cAAiB,KAAK,MAAM,MAAM;AAAA,CAAM,CAAC;AAC9D,SAAK,MAAM,QAAQ,OAAK,OAAO,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC;AAAA,CAAI;AAAA,EACzD;AAEA,SAAO,EAAE,KAAK;AAAA,WAAc,KAAK,OAAO,gBAAgB,SAAS,QAAQ,CAAC,CAAC;AAAA,CAAM;AACjF,SAAO;AACT;AAKO,SAAS,kBAAkB,QAAqB,QAA8B;AACnF,MAAI,WAAW,QAAQ;AACrB,WAAO,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,EACvC;AAEA,MAAI,WAAW,WAAW;AACxB,WAAO,OAAO,SACX,IAAI,OAAK,GAAG,EAAE,QAAQ,IAAI,EAAE,IAAI,KAAK,EAAE,KAAK,QAAQ,KAAK,EAAE,KAAK,IAAI,MAAM,EAAE,KAAK,EAAE,EACnF,KAAK,IAAI;AAAA,EACd;AAGA,MAAI,MAAM,EAAE,KAAK;AAAA,CAAyC;AAC1D,SAAO,yBAAoB,OAAO,YAAY;AAAA;AAC9C,SAAO,oBAAe,OAAO,SAAS,MAAM;AAAA;AAC5C,SAAO;AAAA;AAAA;AAEP,MAAI,OAAO,SAAS,WAAW,GAAG;AAChC,WAAO,EAAE,MAAM,sCAAiC;AAAA,EAClD,OAAO;AACL,WAAO,SAAS,QAAQ,OAAK;AAC3B,UAAI,UAAU,EAAE;AAChB,UAAI,EAAE,KAAK,aAAa,WAAY,WAAU,EAAE;AAAA,eACvC,EAAE,KAAK,aAAa,OAAQ,WAAU,EAAE;AAEjD,aAAO,GAAG,QAAQ,EAAE,KAAK,IAAI,EAAE,KAAK,SAAS,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,OAAO,EAAE,QAAQ,IAAI,EAAE,IAAI;AAAA;AACzG,aAAO,cAAc,EAAE,KAAK;AAAA;AAC5B,aAAO,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC;AAAA;AAAA;AAAA,IACvC,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,KAAK,aAAa,OAAO,SAAS,QAAQ,CAAC,CAAC;AAAA,CAAM;AAC3D,SAAO;AACT;;;AClFA,SAAS,YAAAC,iBAAgB;AACzB,SAAS,SAAS,YAAY;AAC9B,SAAS,kBAAkB;AAK3B,IAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF;AAOA,eAAsB,WAAW,KAAuC;AACtE,QAAM,OAAO,QAAQ,OAAO,QAAQ,IAAI,CAAC;AAEzC,aAAW,YAAY,cAAc;AACnC,UAAM,WAAW,KAAK,MAAM,QAAQ;AAEpC,QAAI,CAAC,WAAW,QAAQ,EAAG;AAE3B,QAAI;AACF,YAAM,UAAU,MAAMC,UAAS,UAAU,OAAO;AAChD,YAAM,SAAyB,KAAK,MAAM,OAAO;AACjD,UAAI,MAAM,sBAAsB,QAAQ,EAAE;AAC1C,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,KAAK,gCAAgC,QAAQ,EAAE;AACnD,UAAI,MAAM,OAAO,GAAG,CAAC;AACrB,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAEA,MAAI,MAAM,sCAAsC;AAChD,SAAO,CAAC;AACV;AAGO,IAAM,WAGT;AAAA,EACF,SAAS;AAAA,EACT,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,MAAM;AAAA,IACJ,QAAQ;AAAA,EACV;AAAA,EACA,OAAO;AAAA,IACL,SAAS,CAAC,qEAAqE;AAAA,IAC/E,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,UAAU;AAAA,EACZ;AACF;;;AN1DA,eAAsB,QAAQ,SAA8C;AAC1E,QAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;AACvC,QAAM,SAAS,MAAM,WAAW,GAAG;AACnC,QAAM,eAA4B;AAAA,IAChC,SAAS,QAAQ,WAAW,OAAO,WAAW,SAAS;AAAA,IACvD,aAAa,QAAQ,eAAe,OAAO,eAAe,SAAS;AAAA,IACnE,QAAQ,QAAQ,UAAU,OAAO,MAAM,UAAU,SAAS,KAAK;AAAA,IAC/D,QAAS,QAAQ,UAAU,OAAO,UAAU,SAAS;AAAA,IACrD,QAAQ,QAAQ,UAAU;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,UAAUC,SAAQ,KAAK,aAAa,OAAO;AACjD,QAAM,cAAcA,SAAQ,KAAK,aAAa,WAAW;AAEzD,MAAI,CAACC,YAAW,OAAO,GAAG;AACxB,QAAI,MAAM,wBAAwB,OAAO,EAAE;AAC3C,YAAQ,KAAK,SAAS,cAAc;AAAA,EACtC;AAEA,MAAI,CAACA,YAAW,WAAW,GAAG;AAC5B,QAAI,MAAM,gCAAgC,WAAW,EAAE;AACvD,YAAQ,KAAK,SAAS,cAAc;AAAA,EACtC;AAEA,QAAM,UAAU,cAAc,+BAA+B,EAAE,MAAM;AAErE,MAAI;AACF,UAAM,QAAQ,YAAY,IAAI;AAC9B,UAAM,YAAY,MAAM,aAAa,OAAO;AAC5C,UAAM,gBAAgB,MAAM,aAAa,WAAW;AAEpD,QAAI,UAAU,OAAO,SAAS,KAAK,cAAc,OAAO,SAAS,GAAG;AAClE,cAAQ,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAC3D,cAAQ,KAAK,SAAS,KAAK;AAAA,IAC7B;AAEA,UAAM,OAAO,aAAa,cAAc,SAAS,UAAU,SAAS;AAAA,MAClE,QAAQ,aAAa;AAAA,IACvB,CAAC;AAGD,SAAK,aAAa;AAClB,SAAK,aAAa;AAElB,UAAM,WAAW,YAAY,IAAI,IAAI;AAErC,YAAQ,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAEzC,UAAM,SAAS,iBAAiB,EAAE,MAAM,SAAS,GAAG,aAAa,MAAM;AACvE,YAAQ,IAAI,MAAM;AAElB,QAAI,KAAK,QAAQ,SAAS,KAAK,KAAK,MAAM,SAAS,GAAG;AACpD,cAAQ,KAAK,SAAS,iBAAiB;AAAA,IACzC,OAAO;AACL,cAAQ,KAAK,SAAS,OAAO;AAAA,IAC/B;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAClE,QAAI,iBAAiB,OAAO;AAC1B,UAAI,MAAM,MAAM,OAAO;AAAA,IACzB;AACA,YAAQ,KAAK,SAAS,KAAK;AAAA,EAC7B;AACF;;;AO3EA,SAAS,WAAAC,gBAAe;AACxB,SAAS,iBAAAC,sBAAqB;;;ACD9B,SAAS,SAAS,YAAAC,iBAAgB;AAClC,SAAS,QAAAC,aAAY;AAWrB,IAAM,iBAAyC;AAAA,EAC7C,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,KAAK;AACP;AAKA,SAAS,YAAY,MAAsB;AACzC,QAAM,UAAU,KACb,QAAQ,qBAAqB,MAAM,EACnC,QAAQ,OAAO,IAAI,EACnB,QAAQ,OAAO,GAAG;AACrB,SAAO,IAAI,OAAO,IAAI,OAAO,GAAG;AAClC;AAKA,SAAS,WAAW,MAAc,OAA0B;AAC1D,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO,MAAM,KAAK,UAAQ,YAAY,IAAI,EAAE,KAAK,IAAI,CAAC;AACxD;AAKA,eAAe,QAAQ,KAAa,cAAwB,cAAwB,WAAqB,CAAC,GAAG,MAAc,KAAwB;AACjJ,MAAI;AACF,UAAM,QAAQ,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AACxD,eAAW,QAAQ,OAAO;AACxB,YAAM,MAAMA,MAAK,KAAK,KAAK,IAAI;AAE/B,YAAM,UAAU,IAAI,UAAU,IAAI,SAAS,CAAC,EAAE,QAAQ,OAAO,GAAG;AAEhE,UAAI,KAAK,YAAY,GAAG;AACtB,YAAI,CAAC,WAAW,SAAS,YAAY,GAAG;AACtC,gBAAM,QAAQ,KAAK,cAAc,cAAc,UAAU,GAAG;AAAA,QAC9D;AAAA,MACF,OAAO;AACL,YAAI,WAAW,SAAS,YAAY,KAAK,CAAC,WAAW,SAAS,YAAY,GAAG;AAC3E,mBAAS,KAAK,GAAG;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AAAA,EAEhB;AACA,SAAO;AACT;AAKA,eAAsB,cAAc,SAAqD;AACvF,QAAM,QAAQ,YAAY,IAAI;AAC9B,QAAM,WAA2B,CAAC;AAClC,MAAI,eAAe;AAEnB,QAAM,cAAc,MAAM,QAAQ,QAAQ,KAAK,QAAQ,SAAS,QAAQ,SAAS,CAAC,GAAG,QAAQ,GAAG;AAChG,QAAM,cAAc,eAAe,QAAQ,WAAW;AAEtD,aAAW,QAAQ,aAAa;AAC9B;AACA,QAAI;AACF,YAAM,UAAU,MAAMD,UAAS,MAAM,MAAM;AAC3C,YAAM,QAAQ,QAAQ,MAAM,OAAO;AACnC,YAAM,WAAW,KAAK,QAAQ,OAAO,GAAG,EAAE,MAAM,GAAG,EAAE,IAAI,KAAK;AAC9D,YAAM,YAAY,SAAS,SAAS,MAAM,KAAK,SAAS,WAAW,MAAM;AAEzE,eAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAM,OAAO,MAAM,CAAC;AAEpB,mBAAW,QAAQ,QAAQ,OAAO;AAChC,cAAI,eAAe,KAAK,QAAQ,IAAI,aAAa;AAC/C;AAAA,UACF;AACA,cAAI,aAAa,CAAC,KAAK,iBAAiB;AACtC;AAAA,UACF;AAEA,gBAAM,QAAQ,KAAK,QAAQ,KAAK,IAAI;AACpC,cAAI,OAAO;AACT,kBAAM,cAAc,MAAM,CAAC;AAE3B,kBAAM,WAAW,YAAY,SAAS,IAClC,YAAY,UAAU,GAAG,CAAC,IAAI,IAAI,OAAO,YAAY,SAAS,CAAC,IAC/D;AAEJ,qBAAS,KAAK;AAAA,cACZ;AAAA,cACA,UAAU,KAAK,UAAU,QAAQ,IAAI,SAAS,CAAC;AAAA;AAAA,cAC/C,MAAM,IAAI;AAAA,cACV,OAAO;AAAA,cACP,SAAS,KAAK,KAAK,EAAE,UAAU,GAAG,GAAG;AAAA;AAAA,YACvC,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,GAAG;AAAA,IAEZ;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,cAAc,QAAQ,MAAM;AAAA,IAC5B,UAAU,YAAY,IAAI,IAAI;AAAA,EAChC;AACF;;;ACtHO,IAAM,eAA4B;AAAA;AAAA,EAEvC;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AACF;;;AFnIA,eAAsB,SAAS,SAA+C;AAC5E,QAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;AACvC,QAAM,SAAS,MAAM,WAAW,GAAG;AACnC,QAAM,eAA6B;AAAA,IACjC,SAAS,QAAQ,WAAW,OAAO,OAAO,WAAW,SAAS,MAAM;AAAA,IACpE,SAAS,QAAQ,WAAW,OAAO,OAAO,WAAW,SAAS,MAAM;AAAA,IACpE,UAAU,QAAQ,YAAY,OAAO,OAAO,YAAY,SAAS,MAAM;AAAA,IACvE,QAAS,QAAQ,UAAU,OAAO,UAAU,SAAS;AAAA,IACrD,QAAQ,QAAQ,UAAU;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,UAAUE,eAAc,kCAAkC,EAAE,MAAM;AAExE,MAAI;AACF,UAAM,SAAS,MAAM,cAAc;AAAA,MACjC,KAAKC,SAAQ,GAAG;AAAA,MAChB,OAAO;AAAA,MACP,SAAS,aAAa;AAAA,MACtB,SAAS,aAAa;AAAA,MACtB,aAAa,aAAa;AAAA,IAC5B,CAAC;AAED,YAAQ,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE1C,UAAM,SAAS,kBAAkB,QAAQ,aAAa,MAAM;AAC5D,YAAQ,IAAI,MAAM;AAElB,QAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,cAAQ,KAAK,SAAS,mBAAmB;AAAA,IAC3C,OAAO;AACL,cAAQ,KAAK,SAAS,OAAO;AAAA,IAC/B;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,EAAE,MAAM,4CAA4C,CAAC;AACnE,QAAI,iBAAiB,OAAO;AAC1B,UAAI,MAAM,MAAM,OAAO;AAAA,IACzB;AACA,YAAQ,KAAK,SAAS,KAAK;AAAA,EAC7B;AACF;;;AGhDA,eAAsB,UAAyB;AAC7C,MAAI,KAAK,6BAA6B,EAAE,KAAK,MAAM,CAAC,GAAG;AACvD,MAAI,IAAI,4EAA4E;AACtF;;;AXCA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,UAAU,EACf,YAAY,uEAAuE,EACnF,QAAQ,OAAO,EACf,OAAO,uBAAuB,wCAAwC,OAAO,EAC7E,OAAO,gBAAgB,iCAAiC,KAAK,EAC7D,OAAO,gBAAgB,qBAAqB,QAAQ,IAAI,CAAC;AAE5D,QACG,QAAQ,MAAM,EACd,YAAY,mCAAmC,EAC/C,OAAO,gBAAgB,qBAAqB,MAAM,EAClD,OAAO,oBAAoB,6BAA6B,cAAc,EACtE,OAAO,YAAY,yDAAyD,KAAK,EACjF,OAAO,OAAO,YAAY;AACzB,QAAM,aAAa,QAAQ,KAAK;AAChC,QAAM,QAAQ;AAAA,IACZ,GAAG;AAAA,IACH,SAAS,QAAQ;AAAA,IACjB,aAAa,QAAQ;AAAA,IACrB,QAAQ,QAAQ;AAAA,IAChB,QAAQ,WAAW;AAAA,EACrB,CAAC;AACH,CAAC;AAEH,QACG,QAAQ,OAAO,EACf,YAAY,qCAAqC,EACjD,OAAO,wBAAwB,0BAA0B,EACzD,OAAO,wBAAwB,0BAA0B,EACzD,OAAO,sBAAsB,oCAAoC,KAAK,EACtE,OAAO,OAAO,YAAY;AACzB,QAAM,aAAa,QAAQ,KAAK;AAChC,QAAM,SAAS;AAAA,IACb,GAAG;AAAA,IACH,GAAG;AAAA,IACH,QAAQ,WAAW;AAAA,EACrB,CAAC;AACH,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,6CAA6C,EACzD,OAAO,YAAY;AAClB,QAAM,QAAQ;AAChB,CAAC;AAEH,IAAI,QAAQ,KAAK,UAAU,GAAG;AAC5B,UAAQ,KAAK;AACf;AAEA,QAAQ,MAAM;","names":["existsSync","resolve","out","readFile","readFile","resolve","existsSync","resolve","createSpinner","readFile","join","createSpinner","resolve"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsed environment variable entry
|
|
3
|
+
*/
|
|
4
|
+
interface EnvEntry {
|
|
5
|
+
key: string;
|
|
6
|
+
value: string;
|
|
7
|
+
line: number;
|
|
8
|
+
comment?: string;
|
|
9
|
+
isComment: boolean;
|
|
10
|
+
raw: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Result of parsing an env file
|
|
14
|
+
*/
|
|
15
|
+
interface ParseResult {
|
|
16
|
+
entries: EnvEntry[];
|
|
17
|
+
filePath: string;
|
|
18
|
+
errors: ParseError[];
|
|
19
|
+
}
|
|
20
|
+
interface ParseError {
|
|
21
|
+
line: number;
|
|
22
|
+
message: string;
|
|
23
|
+
raw: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Diff results between two env files
|
|
27
|
+
*/
|
|
28
|
+
interface DiffResult {
|
|
29
|
+
missing: EnvEntry[];
|
|
30
|
+
extra: EnvEntry[];
|
|
31
|
+
empty: EnvEntry[];
|
|
32
|
+
matched: number;
|
|
33
|
+
sourceFile: string;
|
|
34
|
+
targetFile: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Secret detection rule
|
|
38
|
+
*/
|
|
39
|
+
interface AuditRule {
|
|
40
|
+
id: string;
|
|
41
|
+
name: string;
|
|
42
|
+
description: string;
|
|
43
|
+
pattern: RegExp;
|
|
44
|
+
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
45
|
+
allowInEnvFiles: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A single audit finding
|
|
49
|
+
*/
|
|
50
|
+
interface AuditFinding {
|
|
51
|
+
rule: AuditRule;
|
|
52
|
+
filePath: string;
|
|
53
|
+
line: number;
|
|
54
|
+
match: string;
|
|
55
|
+
context: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Complete audit report
|
|
59
|
+
*/
|
|
60
|
+
interface AuditReport {
|
|
61
|
+
findings: AuditFinding[];
|
|
62
|
+
filesScanned: number;
|
|
63
|
+
rulesApplied: number;
|
|
64
|
+
duration: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Scan command result
|
|
68
|
+
*/
|
|
69
|
+
interface ScanResult {
|
|
70
|
+
diff: DiffResult;
|
|
71
|
+
duration: number;
|
|
72
|
+
success: boolean;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Output format options
|
|
76
|
+
*/
|
|
77
|
+
type OutputFormat = 'table' | 'json' | 'minimal';
|
|
78
|
+
/**
|
|
79
|
+
* Global CLI options
|
|
80
|
+
*/
|
|
81
|
+
interface GlobalOptions {
|
|
82
|
+
format: OutputFormat;
|
|
83
|
+
silent: boolean;
|
|
84
|
+
cwd: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Scan command options
|
|
88
|
+
*/
|
|
89
|
+
interface ScanOptions extends GlobalOptions {
|
|
90
|
+
envFile: string;
|
|
91
|
+
exampleFile: string;
|
|
92
|
+
strict: boolean;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Audit command options
|
|
96
|
+
*/
|
|
97
|
+
interface AuditOptions extends GlobalOptions {
|
|
98
|
+
include: string[];
|
|
99
|
+
exclude: string[];
|
|
100
|
+
severity: AuditRule['severity'];
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Config file shape (.envspectrc)
|
|
104
|
+
*/
|
|
105
|
+
interface EnvspectConfig {
|
|
106
|
+
envFile?: string;
|
|
107
|
+
exampleFile?: string;
|
|
108
|
+
scan?: {
|
|
109
|
+
strict?: boolean;
|
|
110
|
+
};
|
|
111
|
+
audit?: {
|
|
112
|
+
include?: string[];
|
|
113
|
+
exclude?: string[];
|
|
114
|
+
severity?: AuditRule['severity'];
|
|
115
|
+
customRules?: Partial<AuditRule>[];
|
|
116
|
+
};
|
|
117
|
+
format?: OutputFormat;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Parses an environment file from the given file path.
|
|
122
|
+
*/
|
|
123
|
+
declare function parseEnvFile(filePath: string): Promise<ParseResult>;
|
|
124
|
+
/**
|
|
125
|
+
* Parses environment content into a structured ParseResult.
|
|
126
|
+
*/
|
|
127
|
+
declare function parseEnvContent(content: string, filePath?: string): ParseResult;
|
|
128
|
+
|
|
129
|
+
interface DiffOptions {
|
|
130
|
+
strict?: boolean;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Compares two sets of parsed environment entries and returns the differences.
|
|
134
|
+
* @param source - entries from .env.example (the reference/template)
|
|
135
|
+
* @param target - entries from .env (the actual file)
|
|
136
|
+
* @param options - optional diff options
|
|
137
|
+
*/
|
|
138
|
+
declare function diffEnvFiles(source: EnvEntry[], target: EnvEntry[], options?: DiffOptions): DiffResult;
|
|
139
|
+
|
|
140
|
+
interface ScanDirectoryOptions {
|
|
141
|
+
cwd: string;
|
|
142
|
+
rules: AuditRule[];
|
|
143
|
+
include: string[];
|
|
144
|
+
exclude: string[];
|
|
145
|
+
minSeverity: 'critical' | 'high' | 'medium' | 'low';
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Scans a directory for secrets and audit issues based on rules.
|
|
149
|
+
*/
|
|
150
|
+
declare function scanDirectory(options: ScanDirectoryOptions): Promise<AuditReport>;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Formats a scan/diff result for terminal output.
|
|
154
|
+
*/
|
|
155
|
+
declare function formatScanResult(result: {
|
|
156
|
+
diff: DiffResult;
|
|
157
|
+
duration: number;
|
|
158
|
+
}, format: OutputFormat): string;
|
|
159
|
+
/**
|
|
160
|
+
* Formats an audit report for terminal output.
|
|
161
|
+
*/
|
|
162
|
+
declare function formatAuditReport(report: AuditReport, format: OutputFormat): string;
|
|
163
|
+
|
|
164
|
+
declare function runScan(options: Partial<ScanOptions>): Promise<void>;
|
|
165
|
+
|
|
166
|
+
declare function runAudit(options: Partial<AuditOptions>): Promise<void>;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Built-in secret detection rules.
|
|
170
|
+
* Each rule defines a regex pattern to detect potentially leaked secrets.
|
|
171
|
+
*/
|
|
172
|
+
declare const defaultRules: AuditRule[];
|
|
173
|
+
|
|
174
|
+
export { type AuditFinding, type AuditOptions, type AuditReport, type AuditRule, type DiffResult, type EnvEntry, type EnvspectConfig, type OutputFormat, type ParseError, type ParseResult, type ScanOptions, type ScanResult, defaultRules, diffEnvFiles, formatAuditReport, formatScanResult, parseEnvContent, parseEnvFile, runAudit, runScan, scanDirectory };
|