Skip to Content
APIRule Engine API Reference

Rule Engine API

The rule engine evaluates validation rules against parsed configuration AST. This page covers the API for running rules programmatically.

Installation

npm install @sentriflow/core npm install @sentriflow/rules-default # Optional: default rules

Basic Usage

import { parse, evaluate } from '@sentriflow/core'; import { allRules } from '@sentriflow/rules-default'; const config = ` hostname Router1 interface GigabitEthernet0/0 ip address 192.168.1.1 255.255.255.0 `; const ast = parse(config, 'cisco-ios'); const results = evaluate(ast, allRules); for (const result of results) { if (!result.passed) { console.log(`[${result.level}] ${result.ruleId}: ${result.message}`); } }

evaluate()

Evaluate rules against a parsed AST.

Signature

function evaluate( ast: ConfigNode[], rules: IRule[], options?: EvaluateOptions ): RuleResult[]

Parameters

ParameterTypeRequiredDescription
astConfigNode[]YesParsed configuration AST
rulesIRule[]YesRules to evaluate
optionsEvaluateOptionsNoEvaluation options

EvaluateOptions

interface EvaluateOptions { /** Vendor for filtering vendor-specific rules */ vendor?: RuleVendor; /** Minimum severity to include in results */ minimumSeverity?: 'error' | 'warning' | 'info'; /** Rule IDs to skip */ disabledRules?: string[]; /** Categories to skip */ disabledCategories?: string[]; /** Stop after first failure */ failFast?: boolean; /** Timeout per rule check in ms */ timeout?: number; /** Include passed results (not just failures) */ includePassedResults?: boolean; }

Returns

Returns an array of RuleResult objects.

Example

import { parse, evaluate } from '@sentriflow/core'; import { allRules, getRulesByVendor } from '@sentriflow/rules-default'; const config = loadConfig('./router.conf'); const ast = parse(config, 'cisco-ios'); // Evaluate all rules const allResults = evaluate(ast, allRules); // Evaluate only Cisco rules const ciscoRules = getRulesByVendor('cisco-ios'); const ciscoResults = evaluate(ast, ciscoRules); // Evaluate with options const filteredResults = evaluate(ast, allRules, { vendor: 'cisco-ios', minimumSeverity: 'warning', disabledRules: ['NET-DOC-001'], includePassedResults: false, });

RuleResult Interface

interface RuleResult { /** Whether the rule check passed */ passed: boolean; /** Result message */ message: string; /** Rule ID that generated this result */ ruleId: string; /** Node ID that was checked */ nodeId: string; /** Severity level */ level: 'error' | 'warning' | 'info'; /** Optional remediation text */ remediation?: string; /** Source location */ loc?: { startLine: number; endLine: number; }; }

evaluateFile()

Parse and evaluate a configuration file in one call.

Signature

async function evaluateFile( filePath: string, rules: IRule[], options?: EvaluateFileOptions ): Promise<RuleResult[]>

Example

import { evaluateFile } from '@sentriflow/core'; import { allRules } from '@sentriflow/rules-default'; const results = await evaluateFile('./router.conf', allRules, { vendor: 'cisco-ios', minimumSeverity: 'warning', }); console.log(`Found ${results.filter(r => !r.passed).length} issues`);

evaluateDirectory()

Evaluate all configuration files in a directory.

Signature

async function evaluateDirectory( dirPath: string, rules: IRule[], options?: EvaluateDirectoryOptions ): Promise<Map<string, RuleResult[]>>

EvaluateDirectoryOptions

interface EvaluateDirectoryOptions extends EvaluateOptions { /** Glob patterns to include */ include?: string[]; /** Glob patterns to exclude */ exclude?: string[]; /** Recurse into subdirectories */ recursive?: boolean; /** Max concurrent file evaluations */ concurrency?: number; }

Example

import { evaluateDirectory } from '@sentriflow/core'; import { allRules } from '@sentriflow/rules-default'; const results = await evaluateDirectory('./configs', allRules, { vendor: 'cisco-ios', include: ['**/*.conf', '**/*.cfg'], exclude: ['**/backup/**'], recursive: true, concurrency: 4, }); for (const [file, fileResults] of results) { const failures = fileResults.filter(r => !r.passed); if (failures.length > 0) { console.log(`\n${file}:`); for (const result of failures) { console.log(` [${result.level}] ${result.ruleId}: ${result.message}`); } } }

RuleEngine Class

For advanced use cases, use the RuleEngine class directly:

import { RuleEngine } from '@sentriflow/core'; import { allRules } from '@sentriflow/rules-default'; const engine = new RuleEngine({ rules: allRules, defaultVendor: 'cisco-ios', timeout: 100, }); // Add custom rules engine.addRule(myCustomRule); engine.addRules(myRulePack.rules); // Remove rules engine.removeRule('NET-DOC-001'); // Evaluate const results = engine.evaluate(ast); // Get rule info const rule = engine.getRule('NET-AUTH-001'); const rulesByCategory = engine.getRulesByCategory('Authentication');

RuleEngine Methods

MethodDescription
addRule(rule)Add a single rule
addRules(rules)Add multiple rules
removeRule(id)Remove a rule by ID
getRule(id)Get rule by ID
getRules()Get all rules
getRulesByVendor(vendor)Get rules for vendor
getRulesByCategory(cat)Get rules by category
evaluate(ast, options?)Evaluate rules against AST

Custom Rule Registration

Register custom rules programmatically:

import { RuleEngine } from '@sentriflow/core'; import type { IRule } from '@sentriflow/core'; const customRule: IRule = { id: 'ORG-SEC-001', selector: 'interface', vendor: 'cisco-ios', metadata: { level: 'warning', obu: 'Security', owner: 'security@example.com', description: 'Custom security check', }, check(node) { // Validation logic return { passed: true, /* ... */ }; }, }; const engine = new RuleEngine(); engine.addRule(customRule);

Rule Packs

Load rules from rule packs:

import { loadRulePack, RuleEngine } from '@sentriflow/core'; // Load from file const pack = await loadRulePack('./custom-rules.json'); // Load from package const pack2 = await loadRulePack('@myorg/security-rules'); // Use with engine const engine = new RuleEngine({ rules: pack.rules, }); // Handle rule conflicts engine.addRulePack(pack, { conflictResolution: 'override', // or 'skip', 'error' });

Sandboxed Execution

For untrusted rules, use sandboxed execution:

import { SandboxedExecutor } from '@sentriflow/core'; const executor = new SandboxedExecutor({ timeout: 100, // 100ms timeout per check memoryLimit: 50 * 1024 * 1024, // 50MB memory limit }); const results = await executor.evaluate(ast, untrustedRules);

Sandboxed execution has ~10x overhead. Only use for untrusted rules.

Result Formatting

Format results for different outputs:

import { formatResults } from '@sentriflow/core'; const results = evaluate(ast, rules); // Human-readable text const text = formatResults(results, 'text'); // JSON const json = formatResults(results, 'json'); // SARIF const sarif = formatResults(results, 'sarif', { tool: { name: 'SentriFlow', version: '1.0.0', }, });

Performance Tips

  1. Filter rules by vendor before evaluation
  2. Use failFast: true for quick validation checks
  3. Disable rules you don’t need with disabledRules
  4. Set appropriate timeout for custom rules
  5. Use streaming for large configurations

Next Steps

Last updated on