@dawans/promptshield
Version:
Secure your LLM stack with enterprise-grade RulePacks for AI safety scanning
113 lines (112 loc) • 3.79 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Rule = void 0;
/**
* Represents a single rule in a rulepack
*/
class Rule {
constructor(id, description, matchRegex = [], matchKeywords = [], severity = 'medium', category = 'custom', enabled = true, caseSensitive = false) {
this.id = id;
this.description = description;
this.matchRegex = matchRegex;
this.matchKeywords = matchKeywords;
this.severity = severity;
this.category = category;
this.enabled = enabled;
this.caseSensitive = caseSensitive;
this.validate();
}
/**
* Validates the rule configuration
*/
validate() {
if (!this.id || this.id.trim() === '') {
throw new Error('Rule ID is required');
}
if (!this.description || this.description.trim() === '') {
throw new Error('Rule description is required');
}
if (this.matchRegex.length === 0 && this.matchKeywords.length === 0) {
throw new Error('Rule must have either match_regex or match_keywords');
}
// Validate regex patterns
this.matchRegex.forEach((pattern) => {
try {
new RegExp(pattern);
}
catch {
throw new Error(`Invalid regex pattern: ${pattern}`);
}
});
}
/**
* Checks if this rule has regex patterns
*/
hasRegexPatterns() {
return this.matchRegex.length > 0;
}
/**
* Checks if this rule has keyword patterns
*/
hasKeywordPatterns() {
return this.matchKeywords.length > 0;
}
/**
* Gets compiled regex patterns
*/
getCompiledRegexPatterns() {
const flags = this.caseSensitive ? 'g' : 'gi';
return this.matchRegex.map((pattern) => new RegExp(pattern, flags));
}
/**
* Gets normalized keywords for matching
*/
getNormalizedKeywords() {
return this.caseSensitive
? this.matchKeywords
: this.matchKeywords.map((k) => k.toLowerCase());
}
/**
* Creates a rule from YAML data
*/
static fromYaml(data) {
// Type guard to ensure data has required properties
if (!data || typeof data !== 'object') {
throw new Error('Invalid rule data: must be an object');
}
const ruleData = data;
if (typeof ruleData.id !== 'string') {
throw new Error('Invalid rule data: id must be a string');
}
if (typeof ruleData.description !== 'string') {
throw new Error('Invalid rule data: description must be a string');
}
return new Rule(ruleData.id, ruleData.description, Array.isArray(ruleData.match_regex)
? ruleData.match_regex
: [], Array.isArray(ruleData.match_keywords)
? ruleData.match_keywords
: [], (typeof ruleData.severity === 'string'
? ruleData.severity
: 'medium'), (typeof ruleData.category === 'string'
? ruleData.category
: 'custom'), ruleData.enabled !== false, Boolean(ruleData.case_sensitive));
}
/**
* Converts rule to YAML format
*/
toYaml() {
return {
id: this.id,
description: this.description,
...(this.matchRegex.length > 0 && { match_regex: this.matchRegex }),
...(this.matchKeywords.length > 0 && {
match_keywords: this.matchKeywords,
}),
severity: this.severity,
category: this.category,
enabled: this.enabled,
...(this.caseSensitive && { case_sensitive: this.caseSensitive }),
};
}
}
exports.Rule = Rule;