UNPKG

@syntropysoft/praetorian

Version:

Praetorian CLI – A universal multi-environment configuration validator for DevSecOps teams. Validate, compare, and secure YAML/ENV files with ease.

272 lines 10.3 kB
"use strict"; /** * TODO: IMPERATIVE PROGRAMMING PATTERN - NEEDS REFACTORING * * This file demonstrates imperative programming practices that make testing difficult: * - Imperative for loops (lines 200-210, 250-260, 280-290) * - Mutable state handling with object mutations * - Complex nested conditionals * - Multiple responsibilities in single methods * - Side effects in loops and object mutations * * Mutation Score: 32.04% - Imperative patterns make testing fragile! * * RECOMMENDATION: Refactor to use: * - Functional array methods (map, filter, reduce) * - Immutable data transformations * - Pure functions with clear contracts * - Composition over mutation * - Recursive functional patterns for object traversal */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValidationOrchestrator = void 0; exports.runValidation = runValidation; const fs_1 = __importDefault(require("fs")); const yaml_1 = __importDefault(require("yaml")); const EqualityRule_1 = require("../../domain/rules/EqualityRule"); const EnvironmentManager_1 = require("../../shared/utils/EnvironmentManager"); class ValidationOrchestrator { constructor() { this.environmentManager = new EnvironmentManager_1.EnvironmentManager(); } /** * Orchestrate validation based on options */ async orchestrateValidation(configPath, options) { if (options.all || options.env) { return await this.validateByEnvironments(options); } else { return await this.validateSingleFile(configPath, options); } } /** * Validate using environment-based approach */ async validateByEnvironments(options) { const environmentsFile = options.environments || 'environments.yaml'; const environmentConfig = this.environmentManager.loadEnvironmentConfig(environmentsFile); const validationFunction = this.createValidationFunction(options); if (options.all) { return await this.validateAllEnvironments(environmentConfig, validationFunction, options); } else if (options.env) { return await this.validateSpecificEnvironment(options.env, environmentConfig, validationFunction, options); } return { success: false, error: 'No validation mode specified' }; } /** * Validate all environments */ async validateAllEnvironments(environmentConfig, validationFunction, options) { const results = await this.environmentManager.validateAllEnvironments(environmentConfig, validationFunction); const summary = this.environmentManager.getEnvironmentSummary(results); return { success: summary.passed === summary.total, results, summary }; } /** * Validate specific environment */ async validateSpecificEnvironment(envName, environmentConfig, validationFunction, options) { const result = await this.environmentManager.validateEnvironment(envName, environmentConfig, validationFunction); return { success: result.success, errors: result.errors, warnings: result.warnings }; } /** * Validate single file */ async validateSingleFile(configPath, options) { const praetorianConfig = this.loadPraetorianConfig(configPath); const { existingFiles, missingFiles } = this.separateExistingAndMissingFiles(praetorianConfig.files); if (missingFiles.length > 0) { await this.handleMissingFiles(missingFiles, existingFiles, praetorianConfig); } const allFiles = this.loadAllConfigurationFiles(praetorianConfig.files); const validationFunction = this.createValidationFunction(options); const result = await validationFunction(allFiles); // Funcional: usar operador de coalescencia nula para manejar undefined return { success: result?.success ?? false, errors: result?.errors ?? [], warnings: result?.warnings ?? [] }; } /** * Load Praetorian configuration */ loadPraetorianConfig(configPath) { const configContent = fs_1.default.readFileSync(configPath, 'utf8'); return yaml_1.default.parse(configContent); } /** * Separate existing and missing files */ separateExistingAndMissingFiles(files) { // Funcional: usar operador de coalescencia nula y verificación de array const fileArray = files ?? []; const existingFiles = fileArray.filter(file => fs_1.default.existsSync(file)); const missingFiles = fileArray.filter(file => !fs_1.default.existsSync(file)); return { existingFiles, missingFiles }; } /** * Handle missing files by creating empty structures */ async handleMissingFiles(missingFiles, existingFiles, praetorianConfig) { for (const missingFile of missingFiles) { await this.createEmptyStructureFile(missingFile, existingFiles, praetorianConfig); } } /** * Load all configuration files */ loadAllConfigurationFiles(files) { // Funcional: usar operador de coalescencia nula y verificación de array const fileArray = files ?? []; return fileArray.map(file => ({ path: file, content: this.loadFileContent(file), format: this.determineFileFormat(file) })); } /** * Load file content */ loadFileContent(filePath) { const content = fs_1.default.readFileSync(filePath, 'utf8'); const format = this.determineFileFormat(filePath); if (format === 'yaml') { return yaml_1.default.parse(content); } else { return JSON.parse(content); } } /** * Determine file format */ determineFileFormat(filePath) { return filePath.endsWith('.yaml') || filePath.endsWith('.yml') ? 'yaml' : 'json'; } /** * Create validation function */ createValidationFunction(options) { return async (files) => { const equalityRule = new EqualityRule_1.EqualityRule(); const context = { strict: options.strict, ignoreKeys: options.ignore_keys, requiredKeys: options.required_keys }; return await equalityRule.execute(files, context); }; } /** * Create empty structure file */ async createEmptyStructureFile(missingFilePath, existingFiles, praetorianConfig) { const existingStructures = existingFiles.map(file => this.loadFileContent(file)); const emptyStructure = this.createEmptyStructureFromExisting(existingStructures, praetorianConfig); const format = this.determineFileFormat(missingFilePath); const content = format === 'yaml' ? yaml_1.default.stringify(emptyStructure) : JSON.stringify(emptyStructure, null, 2); fs_1.default.writeFileSync(missingFilePath, content); } /** * Create empty structure from existing files */ createEmptyStructureFromExisting(existingStructures, praetorianConfig) { if (praetorianConfig.required_keys && praetorianConfig.required_keys.length > 0) { return this.createStructureFromRequiredKeys(praetorianConfig.required_keys); } else { return this.createStructureFromExistingFiles(existingStructures); } } /** * Create structure from required keys */ createStructureFromRequiredKeys(requiredKeys) { const structure = {}; for (const key of requiredKeys) { const keys = key.split('.'); let current = structure; for (let i = 0; i < keys.length - 1; i++) { if (!current[keys[i]]) { current[keys[i]] = {}; } current = current[keys[i]]; } current[keys[keys.length - 1]] = null; } return structure; } /** * Create structure from existing files */ createStructureFromExistingFiles(existingStructures) { if (existingStructures.length === 0) { return {}; } const mergedStructure = { ...existingStructures[0] }; for (let i = 1; i < existingStructures.length; i++) { this.mergeStructure(mergedStructure, existingStructures[i]); } return this.replaceValuesWithNull(mergedStructure); } /** * Merge structure */ mergeStructure(target, source) { for (const key in source) { if (source.hasOwnProperty(key)) { if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) { if (!target[key] || typeof target[key] !== 'object' || Array.isArray(target[key])) { target[key] = {}; } this.mergeStructure(target[key], source[key]); } else { target[key] = source[key]; } } } } /** * Replace values with null */ replaceValuesWithNull(obj) { if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) { return null; } const result = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) { result[key] = this.replaceValuesWithNull(obj[key]); } else { result[key] = null; } } } return result; } } exports.ValidationOrchestrator = ValidationOrchestrator; /** * Run validation with the orchestrator */ async function runValidation(configPath, options = {}) { const orchestrator = new ValidationOrchestrator(); return await orchestrator.orchestrateValidation(configPath, options); } //# sourceMappingURL=ValidationOrchestrator.js.map