UNPKG

ctrlshiftleft

Version:

AI-powered toolkit for embedding QA and security testing into development workflows

238 lines (231 loc) 7.88 kB
"use strict"; /** * Config Loader * * Loads custom validation patterns and configuration from the .ctrlshiftleft/config.js file * allowing users to customize the security analyzer behavior. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.loadConfig = loadConfig; exports.createSampleConfig = createSampleConfig; const fs = __importStar(require("fs")); const path = __importStar(require("path")); // Default configuration const DEFAULT_CONFIG = { security: { customPatterns: [], disabledPatterns: [], frameworks: { react: { enabled: true }, nextjs: { enabled: true }, express: { enabled: true } }, output: { format: 'markdown', directory: './security-reports' } }, testing: { performance: { enabled: true, reportDir: './performance-reports' }, generation: { framework: 'playwright', outputDir: './tests' } }, global: { lineEndings: 'auto', createDirs: true } }; /** * Loads the configuration from .ctrlshiftleft/config.js * Falls back to defaults if configuration doesn't exist */ function loadConfig(projectRoot = process.cwd()) { const configPath = path.join(projectRoot, '.ctrlshiftleft', 'config.js'); try { if (fs.existsSync(configPath)) { // Delete require cache to ensure we get the latest version delete require.cache[require.resolve(configPath)]; // Load the user's configuration const userConfig = require(configPath); // Convert string patterns to RegExp if (userConfig.security?.customPatterns) { userConfig.security.customPatterns = userConfig.security.customPatterns.map((pattern) => ({ ...pattern, pattern: typeof pattern.pattern === 'string' ? new RegExp(pattern.pattern) : pattern.pattern })); } Object.keys(userConfig.security?.frameworks || {}).forEach(framework => { if (userConfig.security?.frameworks?.[framework]?.customPatterns) { userConfig.security.frameworks[framework].customPatterns = userConfig.security.frameworks[framework].customPatterns.map((pattern) => ({ ...pattern, pattern: typeof pattern.pattern === 'string' ? new RegExp(pattern.pattern) : pattern.pattern })); } }); // Merge with default configuration return deepMerge(DEFAULT_CONFIG, userConfig); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.warn(`Error loading configuration: ${errorMessage}`); console.warn('Using default configuration instead'); } return { ...DEFAULT_CONFIG }; } /** * Creates a sample configuration file if one doesn't exist */ function createSampleConfig(projectRoot = process.cwd()) { const configDir = path.join(projectRoot, '.ctrlshiftleft'); const configPath = path.join(configDir, 'config.js'); // Create the .ctrlshiftleft directory if it doesn't exist if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir, { recursive: true }); } // Only create the sample config if it doesn't already exist if (!fs.existsSync(configPath)) { const sampleConfig = `/** * ctrl.shift.left Configuration * * This file configures the behavior of ctrl.shift.left tools * including security analysis, test generation, and performance tracking. */ module.exports = { // Security analyzer configuration security: { // Add your custom security patterns customPatterns: [ { id: 'custom-react-error', pattern: /componentDidCatch\\s*\\(\\s*error\\s*\\)\\s*{[^}]*console\\.log/, severity: 'HIGH', title: 'Unhandled Error in componentDidCatch', description: 'Errors should be properly handled in componentDidCatch, not just logged', remediation: 'Implement proper error handling and user feedback in componentDidCatch', category: 'react-errors', frameworks: ['react'] } ], // Disable specific built-in patterns by ID if needed disabledPatterns: [ // 'react-keys', 'unsafe-innerhtml' ], // Framework-specific settings frameworks: { react: { enabled: true, // Add React-specific patterns here customPatterns: [] }, nextjs: { enabled: true, // Add Next.js-specific patterns here customPatterns: [] }, express: { enabled: true, // Add Express-specific patterns here customPatterns: [] } }, // Output configuration output: { format: 'markdown', directory: './security-reports' } }, // Test generation configuration testing: { // Performance tracking settings performance: { enabled: true, reportDir: './performance-reports' }, // Test generation settings generation: { framework: 'playwright', outputDir: './tests' } }, // Global settings global: { // Line endings to use in generated files (auto, lf, crlf) lineEndings: 'auto', // Whether to create directories if they don't exist createDirs: true } }; `; fs.writeFileSync(configPath, sampleConfig); console.log(`Created sample configuration at ${configPath}`); } } /** * Helper function to deeply merge objects */ function deepMerge(target, source) { const output = { ...target }; if (isObject(target) && isObject(source)) { Object.keys(source).forEach(key => { if (isObject(source[key])) { if (!(key in target)) { Object.assign(output, { [key]: source[key] }); } else { output[key] = deepMerge(target[key], source[key]); } } else { Object.assign(output, { [key]: source[key] }); } }); } return output; } /** * Helper function to check if a value is an object */ function isObject(item) { return (item && typeof item === 'object' && !Array.isArray(item)); } //# sourceMappingURL=configLoader.js.map