@syntropysoft/praetorian
Version:
Praetorian CLI – A universal multi-environment configuration validator for DevSecOps teams. Validate, compare, and secure YAML/ENV files with ease.
184 lines • 8.15 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@oclif/core");
const chalk_1 = __importDefault(require("chalk"));
const ConfigParser_1 = require("../infrastructure/parsers/ConfigParser");
const EqualityRule_1 = require("../domain/rules/EqualityRule");
const FileReaderService_1 = require("../infrastructure/adapters/FileReaderService");
class Validate extends core_1.Command {
async run() {
const { args, flags } = await this.parse(Validate);
try {
// Determine files to compare
let filesToCompare;
if (args.files && args.files.length > 0) {
// Use files from command line arguments
filesToCompare = Array.isArray(args.files) ? args.files : [args.files];
}
else {
// Use configuration file
const configParser = new ConfigParser_1.ConfigParser(flags.config);
if (!configParser.exists()) {
this.error(`Configuration file not found: ${flags.config}`);
this.log(chalk_1.default.yellow('\nCreate a configuration file with:'));
this.log(chalk_1.default.gray('praetorian init'));
return;
}
if (flags.env) {
filesToCompare = configParser.getEnvironmentFiles(flags.env);
}
else {
filesToCompare = configParser.getFilesToCompare();
}
}
// Load and parse files
const configFiles = await this.loadFiles(filesToCompare);
// Run validation
const rule = new EqualityRule_1.EqualityRule();
const result = await rule.execute(configFiles);
// Display results
this.displayResults(result, flags.output, flags.pipeline);
// Exit with appropriate code
if (!result.success) {
this.exit(1);
}
}
catch (error) {
this.error(error instanceof Error ? error.message : 'Unknown error');
this.exit(1);
}
}
async loadFiles(filePaths) {
const fileReaderService = new FileReaderService_1.FileReaderService();
// Validate files before reading
const { valid, invalid } = fileReaderService.validateFiles(filePaths);
if (invalid.length > 0) {
const supportedExtensions = fileReaderService.getSupportedExtensions().join(', ');
throw new Error(`Unsupported file formats: ${invalid.join(', ')}. ` +
`Supported extensions: ${supportedExtensions}`);
}
return await fileReaderService.readFiles(valid);
}
displayResults(result, outputFormat, isPipelineMode = false) {
if (outputFormat === 'json') {
console.log(JSON.stringify(result, null, 2));
return;
}
if (isPipelineMode) {
this.displayPipelineResults(result);
return;
}
this.displayUserResults(result);
}
displayPipelineResults(result) {
// Pipeline mode - concise output for CI/CD
if (result.success) {
console.log(chalk_1.default.green('✅ PRAETORIAN_VALIDATION: PASSED'));
}
else {
console.log(chalk_1.default.red('❌ PRAETORIAN_VALIDATION: FAILED'));
// Show only critical errors for pipeline
const criticalErrors = result.errors?.slice(0, 5) || [];
for (const error of criticalErrors) {
console.log(chalk_1.default.red(` • ${error.message}`));
}
if (result.errors?.length > 5) {
console.log(chalk_1.default.red(` • ... and ${result.errors.length - 5} more errors`));
}
}
// Pipeline summary - essential metrics only
if (result.metadata) {
const files = result.metadata.filesCompared || 0;
const errors = result.errors?.length || 0;
const warnings = result.warnings?.length || 0;
console.log(chalk_1.default.blue(`PRAETORIAN_SUMMARY: files=${files}, errors=${errors}, warnings=${warnings}, duration=${result.metadata.duration || 0}ms`));
}
}
displayUserResults(result) {
// User mode - detailed output with explanations
console.log(chalk_1.default.blue('\n📊 Validation Results:\n'));
if (result.success) {
console.log(chalk_1.default.green('✅ All files have consistent keys!'));
console.log(chalk_1.default.gray(' Your configuration files are properly synchronized across environments.'));
}
else {
console.log(chalk_1.default.red('❌ Key inconsistencies found:'));
console.log(chalk_1.default.gray(' The following keys are missing in some configuration files:'));
for (const error of result.errors) {
console.log(chalk_1.default.red(` • ${error.message}`));
}
console.log(chalk_1.default.yellow('\n💡 Tip: Use --pipeline flag for concise CI/CD output'));
}
if (result.warnings && result.warnings.length > 0) {
console.log(chalk_1.default.yellow(`\n⚠️ ${result.warnings.length} warning(s):`));
for (const warning of result.warnings) {
console.log(chalk_1.default.yellow(` • ${warning.message}`));
}
}
// Mostrar claves vacías como información (no afecta el pipeline)
if (result.info && result.info.length > 0) {
console.log(chalk_1.default.blue(`\nℹ️ ${result.info.length} empty key(s) found (informational):`));
for (const info of result.info) {
console.log(chalk_1.default.blue(` • ${info.message}`));
}
console.log(chalk_1.default.gray(' Note: Empty keys are informational only and do not affect validation success'));
}
// Summary
if (result.metadata) {
console.log(chalk_1.default.blue('\n📈 Summary:'));
console.log(` • Files compared: ${result.metadata.filesCompared || 0}`);
console.log(` • Total keys: ${result.metadata.totalKeys || 0}`);
console.log(` • Empty keys: ${result.metadata.emptyKeys || 0}`);
console.log(` • Duration: ${result.metadata.duration || 0}ms`);
if (result.success) {
console.log(chalk_1.default.green('\n🎉 Validation completed successfully!'));
}
else {
console.log(chalk_1.default.red('\n🔧 Fix the inconsistencies above and run validation again.'));
}
}
}
}
Validate.description = 'Validate configuration files for key consistency';
Validate.examples = [
'$ praetorian validate',
'$ praetorian validate --env dev',
'$ praetorian validate config-dev.yaml config-prod.yaml',
'$ praetorian validate --output json',
];
Validate.flags = {
env: core_1.Flags.string({
char: 'e',
description: 'Environment to validate (dev, staging, prod)',
required: false,
}),
output: core_1.Flags.string({
char: 'o',
description: 'Output format (pretty, json)',
options: ['pretty', 'json'],
default: 'pretty',
}),
config: core_1.Flags.string({
char: 'c',
description: 'Path to praetorian.yaml configuration file',
default: 'praetorian.yaml',
}),
pipeline: core_1.Flags.boolean({
char: 'p',
description: 'Pipeline mode - concise output for CI/CD',
default: false,
}),
help: core_1.Flags.help({ char: 'h' }),
};
Validate.args = {
files: core_1.Args.string({
description: 'Configuration files to compare',
required: false,
multiple: true,
}),
};
exports.default = Validate;
//# sourceMappingURL=validate.js.map