1111- deprecatevar: Grammar expects ID, docs show complex syntax (var=time/lifetime)
1212- setuid/setsid/setrsc: Grammar expects STRING, may cause quoting issues
1313
14- Reference: https://github.com/SpiderLabs /ModSecurity/wiki/Reference-Manual-(v2.x)-Actions
14+ Reference: https://github.com/owasp-modsecurity /ModSecurity/wiki/Reference-Manual-(v2.x)-Actions
1515"""
16+ import pytest
1617from secrules_parsing import parser
1718
1819
@@ -591,6 +592,7 @@ def test_action_sanitise_matched() -> None:
591592 assert matches == 1
592593
593594
595+ @pytest .mark .xfail (reason = "Grammar limitation: sanitiseMatchedBytes only accepts INT, docs show ranges (1/4) or standalone" )
594596def test_action_sanitise_matched_bytes () -> None :
595597 """
596598 Test sanitiseMatchedBytes action
@@ -601,16 +603,16 @@ def test_action_sanitise_matched_bytes() -> None:
601603 SecRule ARGS "@rx secret" "id:1,sanitiseMatchedBytes:10,deny"
602604 """
603605 parsed_rule = parser .process_from_str (rule_text )
604- if isinstance ( parsed_rule , dict ):
605- # Grammar doesn't support this correctly, skip
606- assert True , "Grammar limitation - sanitiseMatchedBytes needs fixing "
607- else :
608- matches = 0
609- for rule in parsed_rule .rules :
610- for action in rule .actions :
611- if hasattr (action , 'sanitizematchedbytes' ) and action .sanitizematchedbytes == 10 :
612- matches += 1
613- assert matches == 1
606+ # Assert parse success - will fail if grammar doesn't support this
607+ assert not isinstance ( parsed_rule , dict ), \
608+ f"Parse failed: { parsed_rule . get ( 'message' , 'Unknown error' ) } "
609+
610+ matches = 0
611+ for rule in parsed_rule .rules :
612+ for action in rule .actions :
613+ if hasattr (action , 'sanitizematchedbytes' ) and action .sanitizematchedbytes == 10 :
614+ matches += 1
615+ assert matches == 1
614616
615617
616618def test_action_sanitise_arg () -> None :
@@ -627,6 +629,7 @@ def test_action_sanitise_arg() -> None:
627629 assert matches == 1
628630
629631
632+ @pytest .mark .xfail (reason = "Grammar bug: sanitiseRequestHeader expects STRING but docs show unquoted" )
630633def test_action_sanitise_request_header () -> None :
631634 """
632635 Test sanitiseRequestHeader action
@@ -637,18 +640,19 @@ def test_action_sanitise_request_header() -> None:
637640 SecRule ARGS "@rx attack" "id:1,sanitiseRequestHeader:\\ \" Authorization\\ \" ,deny"
638641 """
639642 parsed_rule = parser .process_from_str (rule_text )
640- if isinstance ( parsed_rule , dict ):
641- # Grammar bug - mark as known issue
642- assert True , "Grammar issue with sanitiseRequestHeader - needs STRING quoting fix "
643- else :
644- matches = 0
645- for rule in parsed_rule .rules :
646- for action in rule .actions :
647- if hasattr (action , 'sanitizerequestheader' ):
648- matches += 1
649- assert matches == 1
643+ # Assert parse success - will fail due to grammar bug
644+ assert not isinstance ( parsed_rule , dict ), \
645+ f"Parse failed: { parsed_rule . get ( 'message' , 'Unknown error' ) } "
646+
647+ matches = 0
648+ for rule in parsed_rule .rules :
649+ for action in rule .actions :
650+ if hasattr (action , 'sanitizerequestheader' ):
651+ matches += 1
652+ assert matches == 1
650653
651654
655+ @pytest .mark .xfail (reason = "Grammar bug: sanitiseResponseHeader expects STRING but docs show unquoted" )
652656def test_action_sanitise_response_header () -> None :
653657 """
654658 Test sanitiseResponseHeader action
@@ -659,16 +663,16 @@ def test_action_sanitise_response_header() -> None:
659663 SecRule ARGS "@rx attack" "id:1,sanitiseResponseHeader:\\ \" Set-Cookie\\ \" ,deny"
660664 """
661665 parsed_rule = parser .process_from_str (rule_text )
662- if isinstance ( parsed_rule , dict ):
663- # Grammar bug - mark as known issue
664- assert True , "Grammar issue with sanitiseResponseHeader - needs STRING quoting fix "
665- else :
666- matches = 0
667- for rule in parsed_rule .rules :
668- for action in rule .actions :
669- if hasattr (action , 'sanitizeresponseheader' ):
670- matches += 1
671- assert matches == 1
666+ # Assert parse success - will fail due to grammar bug
667+ assert not isinstance ( parsed_rule , dict ), \
668+ f"Parse failed: { parsed_rule . get ( 'message' , 'Unknown error' ) } "
669+
670+ matches = 0
671+ for rule in parsed_rule .rules :
672+ for action in rule .actions :
673+ if hasattr (action , 'sanitizeresponseheader' ):
674+ matches += 1
675+ assert matches == 1
672676
673677
674678# Response Actions
@@ -688,6 +692,7 @@ def test_action_status() -> None:
688692 assert matches == 1
689693
690694
695+ @pytest .mark .xfail (reason = "Grammar bug: redirect action parsing issue with escaped quotes" )
691696def test_action_redirect () -> None :
692697 """
693698 Test redirect action
@@ -697,17 +702,19 @@ def test_action_redirect() -> None:
697702 SecRule ARGS "@rx attack" "id:1,redirect:\\ \" https://example.com/blocked\\ \" ,deny"
698703 """
699704 parsed_rule = parser .process_from_str (rule_text )
700- if isinstance (parsed_rule , dict ):
701- assert True , "Grammar may need STRING quoting adjustment for redirect"
702- else :
703- matches = 0
704- for rule in parsed_rule .rules :
705- for action in rule .actions :
706- if hasattr (action , 'redirect' ):
707- matches += 1
708- assert matches == 1
705+ # Assert parse success - will fail due to grammar bug
706+ assert not isinstance (parsed_rule , dict ), \
707+ f"Parse failed: { parsed_rule .get ('message' , 'Unknown error' )} "
708+
709+ matches = 0
710+ for rule in parsed_rule .rules :
711+ for action in rule .actions :
712+ if hasattr (action , 'redirect' ):
713+ matches += 1
714+ assert matches == 1
709715
710716
717+ @pytest .mark .xfail (reason = "Grammar bug: proxy action parsing issue with escaped quotes" )
711718def test_action_proxy () -> None :
712719 """
713720 Test proxy action
@@ -717,20 +724,22 @@ def test_action_proxy() -> None:
717724 SecRule ARGS "@rx safe" "id:1,proxy:\\ \" http://backend.example.com\\ \" ,pass"
718725 """
719726 parsed_rule = parser .process_from_str (rule_text )
720- if isinstance (parsed_rule , dict ):
721- assert True , "Grammar may need STRING quoting adjustment for proxy"
722- else :
723- matches = 0
724- for rule in parsed_rule .rules :
725- for action in rule .actions :
726- if hasattr (action , 'proxy' ):
727- matches += 1
728- assert matches == 1
727+ # Assert parse success - will fail due to grammar bug
728+ assert not isinstance (parsed_rule , dict ), \
729+ f"Parse failed: { parsed_rule .get ('message' , 'Unknown error' )} "
730+
731+ matches = 0
732+ for rule in parsed_rule .rules :
733+ for action in rule .actions :
734+ if hasattr (action , 'proxy' ):
735+ matches += 1
736+ assert matches == 1
729737
730738
731739# Execution Actions
732740
733741
742+ @pytest .mark .xfail (reason = "Grammar bug: exec expects STRING (quoted), docs show unquoted paths" )
734743def test_action_exec () -> None :
735744 """
736745 Test exec action
@@ -741,15 +750,16 @@ def test_action_exec() -> None:
741750 SecRule ARGS "@rx attack" "id:1,exec:\\ \" /usr/local/bin/alert.sh\\ \" ,deny"
742751 """
743752 parsed_rule = parser .process_from_str (rule_text )
744- if isinstance (parsed_rule , dict ):
745- assert True , "Grammar bug - exec expects STRING but should accept unquoted paths per ModSecurity docs"
746- else :
747- matches = 0
748- for rule in parsed_rule .rules :
749- for action in rule .actions :
750- if hasattr (action , 'exec' ):
751- matches += 1
752- assert matches == 1
753+ # Assert parse success - will fail due to grammar bug
754+ assert not isinstance (parsed_rule , dict ), \
755+ f"Parse failed: { parsed_rule .get ('message' , 'Unknown error' )} "
756+
757+ matches = 0
758+ for rule in parsed_rule .rules :
759+ for action in rule .actions :
760+ if hasattr (action , 'exec' ):
761+ matches += 1
762+ assert matches == 1
753763
754764
755765# Special Actions
@@ -797,6 +807,7 @@ def test_action_append() -> None:
797807 assert matches == 1
798808
799809
810+ @pytest .mark .xfail (reason = "Grammar bug: prepend action parsing issue with escaped quotes" )
800811def test_action_prepend () -> None :
801812 """
802813 Test prepend action
@@ -807,17 +818,19 @@ def test_action_prepend() -> None:
807818 SecRule ARGS "@rx attack" "id:1,prepend:\\ \" <!-- Blocked -->\\ \" ,deny"
808819 """
809820 parsed_rule = parser .process_from_str (rule_text )
810- if isinstance (parsed_rule , dict ):
811- assert True , "Grammar may need adjustment for prepend STRING handling"
812- else :
813- matches = 0
814- for rule in parsed_rule .rules :
815- for action in rule .actions :
816- if hasattr (action , 'prepend' ):
817- matches += 1
818- assert matches == 1
821+ # Assert parse success - will fail due to grammar bug
822+ assert not isinstance (parsed_rule , dict ), \
823+ f"Parse failed: { parsed_rule .get ('message' , 'Unknown error' )} "
824+
825+ matches = 0
826+ for rule in parsed_rule .rules :
827+ for action in rule .actions :
828+ if hasattr (action , 'prepend' ):
829+ matches += 1
830+ assert matches == 1
819831
820832
833+ @pytest .mark .xfail (reason = "Grammar bug: setuid action parsing issue with escaped quotes" )
821834def test_action_setuid () -> None :
822835 """
823836 Test setuid action
@@ -828,17 +841,19 @@ def test_action_setuid() -> None:
828841 SecRule ARGS "@rx attack" "id:1,setuid:\\ \" user123\\ \" ,deny"
829842 """
830843 parsed_rule = parser .process_from_str (rule_text )
831- if isinstance (parsed_rule , dict ):
832- assert True , "Grammar may need STRING quoting adjustment for setuid"
833- else :
834- matches = 0
835- for rule in parsed_rule .rules :
836- for action in rule .actions :
837- if hasattr (action , 'setuid' ):
838- matches += 1
839- assert matches == 1
844+ # Assert parse success - will fail due to grammar bug
845+ assert not isinstance (parsed_rule , dict ), \
846+ f"Parse failed: { parsed_rule .get ('message' , 'Unknown error' )} "
847+
848+ matches = 0
849+ for rule in parsed_rule .rules :
850+ for action in rule .actions :
851+ if hasattr (action , 'setuid' ):
852+ matches += 1
853+ assert matches == 1
840854
841855
856+ @pytest .mark .xfail (reason = "Grammar bug: setsid action parsing issue with escaped quotes" )
842857def test_action_setsid () -> None :
843858 """
844859 Test setsid action
@@ -849,17 +864,19 @@ def test_action_setsid() -> None:
849864 SecRule ARGS "@rx attack" "id:1,setsid:\\ \" session456\\ \" ,deny"
850865 """
851866 parsed_rule = parser .process_from_str (rule_text )
852- if isinstance (parsed_rule , dict ):
853- assert True , "Grammar may need STRING quoting adjustment for setsid"
854- else :
855- matches = 0
856- for rule in parsed_rule .rules :
857- for action in rule .actions :
858- if hasattr (action , 'setsid' ):
859- matches += 1
860- assert matches == 1
867+ # Assert parse success - will fail due to grammar bug
868+ assert not isinstance (parsed_rule , dict ), \
869+ f"Parse failed: { parsed_rule .get ('message' , 'Unknown error' )} "
870+
871+ matches = 0
872+ for rule in parsed_rule .rules :
873+ for action in rule .actions :
874+ if hasattr (action , 'setsid' ):
875+ matches += 1
876+ assert matches == 1
861877
862878
879+ @pytest .mark .xfail (reason = "Grammar bug: setrsc action parsing issue with escaped quotes" )
863880def test_action_setrsc () -> None :
864881 """
865882 Test setrsc action
@@ -869,17 +886,19 @@ def test_action_setrsc() -> None:
869886 SecRule ARGS "@rx attack" "id:1,setrsc:\\ \" resource789\\ \" ,deny"
870887 """
871888 parsed_rule = parser .process_from_str (rule_text )
872- if isinstance (parsed_rule , dict ):
873- assert True , "Grammar may need STRING quoting adjustment for setrsc"
874- else :
875- matches = 0
876- for rule in parsed_rule .rules :
877- for action in rule .actions :
878- if hasattr (action , 'setrsc' ):
879- matches += 1
880- assert matches == 1
889+ # Assert parse success - will fail due to grammar bug
890+ assert not isinstance (parsed_rule , dict ), \
891+ f"Parse failed: { parsed_rule .get ('message' , 'Unknown error' )} "
892+
893+ matches = 0
894+ for rule in parsed_rule .rules :
895+ for action in rule .actions :
896+ if hasattr (action , 'setrsc' ):
897+ matches += 1
898+ assert matches == 1
881899
882900
901+ @pytest .mark .xfail (reason = "Grammar bug: xmlns action parsing issue with escaped quotes" )
883902def test_action_xmlns () -> None :
884903 """
885904 Test xmlns action
@@ -890,15 +909,16 @@ def test_action_xmlns() -> None:
890909 SecRule ARGS "@rx attack" "id:1,xmlns:\\ \" http://example.com/ns\\ \" ,deny"
891910 """
892911 parsed_rule = parser .process_from_str (rule_text )
893- if isinstance (parsed_rule , dict ):
894- assert True , "Grammar may need adjustment for xmlns - should support namespace=URI syntax"
895- else :
896- matches = 0
897- for rule in parsed_rule .rules :
898- for action in rule .actions :
899- if hasattr (action , 'xmlns' ):
900- matches += 1
901- assert matches == 1
912+ # Assert parse success - will fail due to grammar bug
913+ assert not isinstance (parsed_rule , dict ), \
914+ f"Parse failed: { parsed_rule .get ('message' , 'Unknown error' )} "
915+
916+ matches = 0
917+ for rule in parsed_rule .rules :
918+ for action in rule .actions :
919+ if hasattr (action , 'xmlns' ):
920+ matches += 1
921+ assert matches == 1
902922
903923
904924# Transient (ctl:) Actions
0 commit comments