@@ -748,6 +748,118 @@ def test_cli_parser_run_error_cases(cli_env, common_args):
748748 os .unlink (parser_file )
749749
750750
751+ @pytest .mark .integration
752+ def test_cli_parser_run_evaluation_with_parsed_statedump (cli_env , common_args ):
753+ """
754+ Test the 'parser run' command functionality with parsed statedump, covering
755+ reading parser code and logs from files, and providing logs via multiple
756+ --log arguments.
757+ """
758+ test_log_type = f"RESERVED_LOG_TYPE_1"
759+
760+ # Sample YARA-L parser code
761+ sample_parser_code = r"""
762+ filter {
763+ mutate {
764+ replace => {
765+ "event1.idm.read_only_udm.metadata.event_type" => "GENERIC_EVENT"
766+ "event1.idm.read_only_udm.metadata.vendor_name" => "ACME Labs"
767+ }
768+ }
769+ grok {
770+ match => {
771+ "message" => ["^(?P<_firstWord>[^\s]+)\s.*$"]
772+ }
773+ on_error => "_grok_message_failed"
774+ }
775+ if ![_grok_message_failed] {
776+ mutate {
777+ replace => {
778+ "event1.idm.read_only_udm.metadata.description" => "%{_firstWord}"
779+ }
780+ }
781+ }
782+ mutate {
783+ merge => {
784+ "@output" => "event1"
785+ }
786+ }
787+ statedump{}
788+ }
789+ """
790+
791+ # Sample log data for --logs-file
792+ sample_logs_file_content = """
793+ {"appDisplayName":"Azure Active Directory PowerShell","appId":"1b730912-1644-4b74-9bfd-dac224a7b894","appliedConditionalAccessPolicies":[],"clientAppUsed":"Mobile Apps and Desktop clients","conditionalAccessStatus":"success","correlationId":"8bdadb11-5851-4ff2-ad57-799c0149f606","createdDateTime":"2025-06-15T04:31:56Z","deviceDetail":{"browser":"Rich Client 5.2.8.0","deviceId":"","displayName":"","isCompliant":false,"isManaged":false,"operatingSystem":"Windows 8","trustType":""},"id":"ba6e48d0-85e9-45b0-9ce4-83eb83432200","ipAddress":"79.116.213.193","isInteractive":true,"location":{"city":"Madrid","countryOrRegion":"ES","geoCoordinates":{"altitude":null,"latitude":40.416,"longitude":-3.703},"state":"Madrid"},"resourceDisplayName":"Windows Azure Active Directory","resourceId":"00000001-0000-0000-d000-000000000000","riskDetail":"none","riskEventTypes":[],"riskEventTypes_v2":[],"riskLevelAggregated":"none","riskLevelDuringSignIn":"none","riskState":"none","status":{"additionalDetails":null,"errorCode":0,"failureReason":"Other."},"userDisplayName":"Admin Read Only","userId":"6838ec00-f384-40d8-b288-989103aed42b","userPrincipalName":"reports@example.onmicrosoft.com"}
794+ """
795+
796+ parser_code_file_path = None
797+ logs_file_path = None
798+
799+ try :
800+ # Create temporary parser code file
801+ with tempfile .NamedTemporaryFile (
802+ suffix = ".yara" , mode = "w+" , delete = False
803+ ) as temp_file :
804+ temp_file .write (sample_parser_code )
805+ parser_code_file_path = temp_file .name
806+
807+ # Create temporary logs file
808+ with tempfile .NamedTemporaryFile (
809+ suffix = ".log" , mode = "w+" , delete = False
810+ ) as temp_file :
811+ temp_file .write (sample_logs_file_content )
812+ logs_file_path = temp_file .name
813+
814+ # --- Scenario 1: Using --parser-code-file and --logs-file ---
815+ run_cmd_file_input = (
816+ [
817+ "secops" , # Replace with your actual CLI entry point
818+ ]
819+ + common_args
820+ + [
821+ "parser" ,
822+ "run" ,
823+ "--log-type" ,
824+ test_log_type ,
825+ "--parser-code-file" ,
826+ parser_code_file_path ,
827+ "--logs-file" ,
828+ logs_file_path ,
829+ "--statedump-allowed" ,
830+ "--parse_statedump" ,
831+ ]
832+ )
833+
834+ run_result_file_input = subprocess .run (
835+ run_cmd_file_input , env = cli_env , capture_output = True , text = True
836+ )
837+
838+ # Assert CLI command execution success
839+ assert run_result_file_input .returncode == 0 , (
840+ "Parser run with files failed: "
841+ f"{ run_result_file_input .stderr } \n { run_result_file_input .stdout } "
842+ )
843+
844+ # Parse and assert the output
845+ run_output_file_input = json .loads (run_result_file_input .stdout )
846+ assert "parsedEvents" in run_output_file_input ["runParserResults" ][0 ]
847+
848+ statedump_results = run_output_file_input ["runParserResults" ][0 ].get (
849+ "statedumpResults"
850+ )
851+ assert len (statedump_results )
852+ assert statedump_results [0 ].get ("statedumpResult" )
853+ assert statedump_results [0 ].get ("statedumpResult" ).get ("state" )
854+
855+ finally :
856+ # Clean up temporary files regardless of test outcome
857+ if parser_code_file_path and os .path .exists (parser_code_file_path ):
858+ os .unlink (parser_code_file_path )
859+ if logs_file_path and os .path .exists (logs_file_path ):
860+ os .unlink (logs_file_path )
861+
862+
751863@pytest .mark .integration
752864def test_cli_rule_list (cli_env , common_args ):
753865 """Test the rule list command."""
0 commit comments