UNPKG

clienvy

Version:

Secret Detection → Validation → Environment Migration → Code Remediation

92 lines (78 loc) 3.15 kB
import chalk from 'chalk'; import fs from 'fs-extra'; import path from 'path'; import { findFiles } from '../core/scanners/fileScanner.js'; import { scanFiles } from '../core/scanners/contentScanner.js'; import { loadSecrets } from '../core/utils/secretsStore.js'; import { getEnvPath } from '../core/utils/paths.js'; import { filterValidated } from '../core/validators/Validate.js'; function parseEnvFile(content) { const keys = new Set(); for (const line of content.split('\n')) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith('#')) continue; const eq = trimmed.indexOf('='); if (eq > 0) keys.add(trimmed.slice(0, eq).trim()); } return keys; } function secretsRequireEnv(secrets) { if (!secrets.length) return false; const validated = filterValidated(secrets.filter((s) => s.confidence != null)); const extracted = secrets.filter((s) => s.confidence == null && s.value); return validated.length > 0 || extracted.length > 0; } export async function checkCommand(cwd = process.cwd()) { let failed = false; const envPath = getEnvPath(cwd); const envExists = await fs.pathExists(envPath); const secrets = await loadSecrets(cwd); const validated = filterValidated(secrets.filter((s) => s.confidence != null)); const requiresEnv = secretsRequireEnv(secrets); const files = await findFiles(cwd); const newMatches = await scanFiles(files, cwd); if (newMatches.length > 0) { const known = new Set(secrets.map((s) => `${s.file}:${s.line}:${s.value}`)); const unknown = newMatches.filter((m) => !known.has(`${m.file}:${m.line}:${m.value}`)); if (unknown.length > 0) { console.log(chalk.red(`New hardcoded secrets detected: ${unknown.length}`)); for (const u of unknown.slice(0, 5)) { console.log(chalk.red(` ${u.file}:${u.line} (${u.type})`)); } failed = true; } } if (requiresEnv && !envExists) { console.log( chalk.red('Secrets found in storage/secrets.json but .env is missing. Run: clenv generate') ); failed = true; } if (envExists && requiresEnv) { const envKeys = parseEnvFile(await fs.readFile(envPath, 'utf8')); const requiredKeys = new Set( secrets.filter((s) => s.envKey && (s.confidence ?? 0) >= 50).map((s) => s.envKey) ); for (const key of requiredKeys) { if (!envKeys.has(key)) { console.log(chalk.red(`Missing env var in .env: ${key}`)); failed = true; } } const secretKeys = new Set(secrets.map((s) => s.envKey).filter(Boolean)); for (const key of envKeys) { if (!secretKeys.has(key) && !key.startsWith('NODE_')) { console.log(chalk.yellow(`Unused env var: ${key}`)); } } } else if (!requiresEnv && !envExists) { console.log(chalk.gray('No secrets tracked — .env not required.')); } if (failed) { console.log(chalk.red('\nCheck failed — commit blocked.\n')); process.exitCode = 1; return false; } console.log(chalk.green('Check passed — no issues found.')); return true; }