UNPKG

secret-scan-cli

Version:

A tool to scan codebases for potential secrets and sensitive information

110 lines (99 loc) 3.64 kB
// src/main.js import { Worker } from 'worker_threads'; import fs from 'fs'; import path from 'path'; import chalk from 'chalk'; import { execSync } from 'child_process'; import { patterns, ignorePaths } from './config.js'; // Function to scan files in parallel function scanFilesInParallel(files) { return new Promise((resolve, reject) => { const worker = new Worker(new URL('./worker.js', import.meta.url), { workerData: files, }); worker.on('message', resolve); worker.on('error', reject); worker.on('exit', (code) => { if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`)); }); }); } // Function to recursively get all files in a folder function getAllFiles(dirPath, fileList = []) { const files = fs.readdirSync(dirPath); files.forEach((file) => { const fullPath = path.join(dirPath, file); if (ignorePaths.includes(file)) { console.log(chalk.gray(`Skipping ignored path: ${fullPath}`)); return; // Skip ignored paths } if (fs.statSync(fullPath).isDirectory()) { getAllFiles(fullPath, fileList); } else { fileList.push(fullPath); } }); return fileList; } // Function to scan a specific folder export async function scanFolder(folderPath) { try { const files = getAllFiles(folderPath); const results = await scanFilesInParallel(files); let foundSecrets = false; results.forEach((result) => { if (result.secrets.length > 0) { console.log(chalk.red.bold(`Secrets found in ${result.file}:`)); result.secrets.forEach((secret) => { console.log(chalk.yellow(`- ${secret.type}: ${secret.matches.join(', ')}`)); // Show the affected lines const content = fs.readFileSync(result.file, 'utf8').split('\n'); secret.lineNumbers.forEach(lineNum => { console.log(chalk.gray(` Line ${lineNum}: ${content[lineNum - 1].trim()}`)); }); }); foundSecrets = true; } }); if (foundSecrets) { console.log(chalk.red.bold('Secrets detected. Scan failed.')); process.exit(1); } else { console.log(chalk.green('No secrets detected.')); } } catch (error) { console.error(chalk.red.bold(`Error: ${error.message}`)); process.exit(1); } } // Function to scan all tracked files in the repository export async function scanRepository() { try { const files = execSync('git ls-files').toString().trim().split('\n').filter(Boolean); const results = await scanFilesInParallel(files); let foundSecrets = false; results.forEach((result) => { if (result.secrets.length > 0) { console.log(chalk.red.bold(`Secrets found in ${result.file}:`)); result.secrets.forEach((secret) => { console.log(chalk.yellow(`- ${secret.type}: ${secret.matches.join(', ')}`)); // Show the affected lines const content = fs.readFileSync(result.file, 'utf8').split('\n'); secret.lineNumbers.forEach(lineNum => { console.log(chalk.gray(` Line ${lineNum}: ${content[lineNum - 1].trim()}`)); }); }); foundSecrets = true; } }); if (foundSecrets) { console.log(chalk.red.bold('Secrets detected. Commit blocked.')); process.exit(1); } else { console.log(chalk.green('No secrets detected. Commit allowed.')); } } catch (error) { console.error(chalk.red.bold(`Error scanning repository: ${error.message}`)); process.exit(1); } }