@@ -1031,6 +1031,89 @@ describe('Tests for runRules', () => {
10311031 } ) ;
10321032} ) ;
10331033
1034+ describe ( 'Tests for regex_ignore' , ( ) => {
1035+ it ( 'regex_ignore should exclude matches that match the negative pattern' , async ( ) => {
1036+ const customRulesWithNegativePattern : RegexRules = {
1037+ EmailHeaderInjection : {
1038+ regex : '/(To|From|Subject|In-Reply-To|References):\\s*\\$\\([^)]+\\)/gi' ,
1039+ regex_ignore : '/\\$\\(\\s*validatedMessageId\\s*\\)/gi' ,
1040+ description : "Detects user input in email headers, excluding validatedMessageId" ,
1041+ file_extensions : [ ".dwl" ] ,
1042+ violation_message : "User input detected in email header" ,
1043+ severity : SeverityLevel . Critical ,
1044+ tags : [ "Security" ]
1045+ }
1046+ } ;
1047+
1048+ const testEngine = new RegexEngine ( customRulesWithNegativePattern , RULE_RESOURCE_URLS ) ;
1049+ const runOptions : RunOptions = createRunOptions (
1050+ new Workspace ( 'id' , [ path . resolve ( __dirname , "test-data" , "patternNotRegex" ) ] ) ) ;
1051+ const runResults : EngineRunResults = await testEngine . runRules ( [ "EmailHeaderInjection" ] , runOptions ) ;
1052+
1053+ // emailHeaders_WithValidatedId.dwl has $(validatedMessageId) - should be excluded
1054+ // emailHeaders_WithUnsanitizedPayload.dwl has $(payload.x) - should be violations
1055+ const validatedIdViolations = runResults . violations . filter ( v =>
1056+ v . codeLocations [ 0 ] . file . includes ( 'emailHeaders_WithValidatedId.dwl' ) ) ;
1057+ const unsanitizedViolations = runResults . violations . filter ( v =>
1058+ v . codeLocations [ 0 ] . file . includes ( 'emailHeaders_WithUnsanitizedPayload.dwl' ) ) ;
1059+
1060+ expect ( validatedIdViolations ) . toHaveLength ( 0 ) ; // Should be excluded by regex_ignore
1061+ expect ( unsanitizedViolations . length ) . toBeGreaterThan ( 0 ) ; // Should have violations
1062+ } ) ;
1063+
1064+ it ( 'Rule without regex_ignore should behave normally' , async ( ) => {
1065+ const customRulesWithoutNegativePattern : RegexRules = {
1066+ EmailHeaderInjection : {
1067+ regex : '/(To|From|Subject|In-Reply-To|References):\\s*\\$\\([^)]+\\)/gi' ,
1068+ description : "Detects user input in email headers" ,
1069+ file_extensions : [ ".dwl" ] ,
1070+ violation_message : "User input detected in email header" ,
1071+ severity : SeverityLevel . Critical ,
1072+ tags : [ "Security" ]
1073+ }
1074+ } ;
1075+
1076+ const testEngine = new RegexEngine ( customRulesWithoutNegativePattern , RULE_RESOURCE_URLS ) ;
1077+ const runOptions : RunOptions = createRunOptions (
1078+ new Workspace ( 'id' , [ path . resolve ( __dirname , "test-data" , "patternNotRegex" ) ] ) ) ;
1079+ const runResults : EngineRunResults = await testEngine . runRules ( [ "EmailHeaderInjection" ] , runOptions ) ;
1080+
1081+ // Without regex_ignore, both files should have violations
1082+ const validatedIdViolations = runResults . violations . filter ( v =>
1083+ v . codeLocations [ 0 ] . file . includes ( 'emailHeaders_WithValidatedId.dwl' ) ) ;
1084+ const unsanitizedViolations = runResults . violations . filter ( v =>
1085+ v . codeLocations [ 0 ] . file . includes ( 'emailHeaders_WithUnsanitizedPayload.dwl' ) ) ;
1086+
1087+ expect ( validatedIdViolations . length ) . toBeGreaterThan ( 0 ) ; // Should have violations
1088+ expect ( unsanitizedViolations . length ) . toBeGreaterThan ( 0 ) ; // Should have violations
1089+ } ) ;
1090+
1091+ it ( 'regex_ignore with multiple exclusion patterns' , async ( ) => {
1092+ const customRulesWithMultipleExclusions : RegexRules = {
1093+ EmailHeaderInjection : {
1094+ regex : '/(To|From|Subject):\\s*\\$\\([^)]+\\)/gi' ,
1095+ regex_ignore : '/\\$\\((validatedMessageId|sanitizeHeader|getSafeEmailHeader)\\s*[^)]*\\)/gi' ,
1096+ description : "Detects user input in email headers, excluding safe functions" ,
1097+ file_extensions : [ ".dwl" ] ,
1098+ violation_message : "User input detected in email header" ,
1099+ severity : SeverityLevel . Critical ,
1100+ tags : [ "Security" ]
1101+ }
1102+ } ;
1103+
1104+ const testEngine = new RegexEngine ( customRulesWithMultipleExclusions , RULE_RESOURCE_URLS ) ;
1105+ const runOptions : RunOptions = createRunOptions (
1106+ new Workspace ( 'id' , [ path . resolve ( __dirname , "test-data" , "patternNotRegex" ) ] ) ) ;
1107+ const runResults : EngineRunResults = await testEngine . runRules ( [ "EmailHeaderInjection" ] , runOptions ) ;
1108+
1109+ // validatedMessageId should still be excluded
1110+ const validatedIdViolations = runResults . violations . filter ( v =>
1111+ v . codeLocations [ 0 ] . file . includes ( 'emailHeaders_WithValidatedId.dwl' ) ) ;
1112+
1113+ expect ( validatedIdViolations ) . toHaveLength ( 0 ) ;
1114+ } ) ;
1115+ } ) ;
1116+
10341117describe ( 'Tests for getEngineVersion' , ( ) => {
10351118 it ( 'Outputs something resembling a Semantic Version' , async ( ) => {
10361119 const version : string = await engine . getEngineVersion ( ) ;
0 commit comments