@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
JavaScript
"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