UNPKG

@syntropysoft/praetorian

Version:

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

275 lines 8.38 kB
"use strict"; /** * @file src/application/services/rule-loading/RuleComposer.ts * @description Pure functions for composing and manipulating validation rules */ Object.defineProperty(exports, "__esModule", { value: true }); exports.getUniqueTags = exports.getUniqueCategories = exports.getDisabledRules = exports.getEnabledRules = exports.getRulesBySeverity = exports.getRulesByTags = exports.getRulesByCategory = exports.validateRuleSpecificProperties = exports.validateLoadedRules = exports.applyRuleOverrides = exports.addCustomRules = exports.composeRules = void 0; /** * Composes rules from configuration * @param baseRules - Base rules to start with * @param config - Rule configuration * @param options - Composition options * @returns Composed rules */ const composeRules = (baseRules, config, options = {}) => { // Guard clause: no config if (!config) { return baseRules; } // Guard clause: no base rules if (!baseRules || baseRules.length === 0) { return []; } let rules = [...baseRules]; // Add custom rules if (config.customRules && config.customRules.length > 0) { rules = (0, exports.addCustomRules)(rules, config.customRules); } // Apply overrides if (config.overrideRules && config.overrideRules.length > 0) { rules = (0, exports.applyRuleOverrides)(rules, config.overrideRules); } return rules; }; exports.composeRules = composeRules; /** * Adds custom rules to existing rules * @param existingRules - Existing rules * @param customRules - Custom rules to add * @returns Combined rules */ const addCustomRules = (existingRules, customRules) => { // Guard clause: no existing rules if (!existingRules || existingRules.length === 0) { return customRules || []; } // Guard clause: no custom rules if (!customRules || customRules.length === 0) { return existingRules; } return [...existingRules, ...customRules]; }; exports.addCustomRules = addCustomRules; /** * Applies rule overrides to existing rules * @param rules - Existing rules * @param overrides - Rule overrides * @returns Updated rules */ const applyRuleOverrides = (rules, overrides) => { // Guard clause: no rules if (!rules || rules.length === 0) { return []; } // Guard clause: no overrides if (!overrides || overrides.length === 0) { return rules; } const rulesMap = new Map(rules.map(rule => [rule.id, rule])); for (const override of overrides) { // Guard clause: no ID in override if (!override.id) { continue; } const existingRule = rulesMap.get(override.id); if (existingRule) { // Update existing rule const updatedRule = { ...existingRule, ...override, }; rulesMap.set(override.id, updatedRule); } else { // Add new rule (treat as custom rule) rulesMap.set(override.id, override); } } return Array.from(rulesMap.values()); }; exports.applyRuleOverrides = applyRuleOverrides; /** * Validates loaded rules for consistency * @param rules - Rules to validate * @returns Validation warnings */ const validateLoadedRules = (rules) => { // Guard clause: no rules if (!rules || rules.length === 0) { return []; } const warnings = []; const ruleIds = new Set(); for (const rule of rules) { // Check for duplicate IDs if (ruleIds.has(rule.id)) { warnings.push(`Duplicate rule ID found: ${rule.id}`); } ruleIds.add(rule.id); // Check for required fields if (!rule.name || !rule.description) { warnings.push(`Rule ${rule.id} missing required fields`); } // Validate rule-specific properties const ruleValidationWarnings = (0, exports.validateRuleSpecificProperties)(rule); warnings.push(...ruleValidationWarnings); } return warnings; }; exports.validateLoadedRules = validateLoadedRules; /** * Validates rule-specific properties * @param rule - Rule to validate * @returns Validation warnings for this rule */ const validateRuleSpecificProperties = (rule) => { // Guard clause: no rule if (!rule) { return ['Rule is null or undefined']; } const warnings = []; switch (rule.type) { case 'format': if (!rule.format && !rule.pattern) { warnings.push(`Format rule ${rule.id} missing format or pattern`); } break; case 'structure': // Structure rules don't have specific requirements break; case 'security': if (!rule.securityType) { warnings.push(`Security rule ${rule.id} missing securityType`); } break; case 'schema': if (!rule.validateSchema) { warnings.push(`Schema rule ${rule.id} has validateSchema set to false`); } break; } return warnings; }; exports.validateRuleSpecificProperties = validateRuleSpecificProperties; /** * Gets rules by category * @param rules - Rules to filter * @param category - Category to filter by * @returns Filtered rules */ const getRulesByCategory = (rules, category) => { // Guard clause: no rules if (!rules || rules.length === 0) { return []; } // Guard clause: no category if (!category || category.trim().length === 0) { return rules; } return rules.filter(rule => rule.category === category); }; exports.getRulesByCategory = getRulesByCategory; /** * Gets rules by tags * @param rules - Rules to filter * @param tags - Tags to filter by * @returns Filtered rules */ const getRulesByTags = (rules, tags) => { // Guard clause: no rules if (!rules || rules.length === 0) { return []; } // Guard clause: no tags if (!tags || tags.length === 0) { return rules; } return rules.filter(rule => rule.tags && tags.every(tag => rule.tags.includes(tag))); }; exports.getRulesByTags = getRulesByTags; /** * Gets rules by severity * @param rules - Rules to filter * @param severity - Severity to filter by * @returns Filtered rules */ const getRulesBySeverity = (rules, severity) => { // Guard clause: no rules if (!rules || rules.length === 0) { return []; } // Guard clause: no severity if (!severity || severity.trim().length === 0) { return rules; } return rules.filter(rule => rule.severity === severity); }; exports.getRulesBySeverity = getRulesBySeverity; /** * Gets enabled rules only * @param rules - Rules to filter * @returns Enabled rules */ const getEnabledRules = (rules) => { // Guard clause: no rules if (!rules || rules.length === 0) { return []; } return rules.filter(rule => rule.enabled); }; exports.getEnabledRules = getEnabledRules; /** * Gets disabled rules only * @param rules - Rules to filter * @returns Disabled rules */ const getDisabledRules = (rules) => { // Guard clause: no rules if (!rules || rules.length === 0) { return []; } return rules.filter(rule => !rule.enabled); }; exports.getDisabledRules = getDisabledRules; /** * Gets unique categories from rules * @param rules - Rules to analyze * @returns Array of unique categories */ const getUniqueCategories = (rules) => { // Guard clause: no rules if (!rules || rules.length === 0) { return []; } const categories = new Set(); for (const rule of rules) { if (rule.category) { categories.add(rule.category); } } return Array.from(categories); }; exports.getUniqueCategories = getUniqueCategories; /** * Gets unique tags from rules * @param rules - Rules to analyze * @returns Array of unique tags */ const getUniqueTags = (rules) => { // Guard clause: no rules if (!rules || rules.length === 0) { return []; } const tags = new Set(); for (const rule of rules) { if (rule.tags) { for (const tag of rule.tags) { tags.add(tag); } } } return Array.from(tags); }; exports.getUniqueTags = getUniqueTags; //# sourceMappingURL=RuleComposer.js.map