@@ -528,6 +528,81 @@ def _download_tasks(
528528 azcopy_sync (to_download [name ], outdir )
529529
530530
531+ class Repro (Endpoint ):
532+ """Interact with repro files"""
533+
534+ endpoint = "repro_vms"
535+
536+ def get_files (
537+ self ,
538+ report_container : primitives .Container ,
539+ report_name : str ,
540+ include_setup : bool = False ,
541+ output_dir : primitives .Directory = primitives .Directory ("." ),
542+ ) -> None :
543+ """downloads the files necessary to locally repro the crash from given report"""
544+ report_bytes = self .onefuzz .containers .files .get (report_container , report_name )
545+ report = json .loads (report_bytes )
546+
547+ crash_info = {
548+ "input_blob_container" : primitives .Container ("" ),
549+ "input_blob_name" : "" ,
550+ "job_id" : "" ,
551+ }
552+ if "input_blob" in report :
553+ crash_info ["input_blob_container" ] = report ["input_blob" ]["container" ]
554+ crash_info ["input_blob_name" ] = report ["input_blob" ]["name" ]
555+ crash_info ["job_id" ] = report ["job_id" ]
556+ elif "crash_test_result" in report and "original_crash_test_result" in report :
557+ if report ["original_crash_test_result" ]["crash_report" ] is None :
558+ self .logger .error (
559+ "No crash report found in the original crash test result, repro files cannot be retrieved"
560+ )
561+ return
562+ elif report ["crash_test_result" ]["crash_report" ] is None :
563+ self .logger .info (
564+ "No crash report found in the new crash test result, falling back on the original crash test result for job_id"
565+ "Note: if using --include_setup, the downloaded fuzzer binaries may be out-of-date"
566+ )
567+
568+ original_report = report ["original_crash_test_result" ]["crash_report" ]
569+ new_report = (
570+ report ["crash_test_result" ]["crash_report" ] or original_report
571+ ) # fallback on original_report
572+
573+ crash_info ["input_blob_container" ] = original_report ["input_blob" ][
574+ "container"
575+ ]
576+ crash_info ["input_blob_name" ] = original_report ["input_blob" ]["name" ]
577+ crash_info ["job_id" ] = new_report ["job_id" ]
578+ else :
579+ self .logger .error (
580+ "Encountered an unhandled report format, repro files cannot be retrieved"
581+ )
582+ return
583+
584+ self .logger .info (
585+ "downloading files necessary to locally repro crash %s" ,
586+ crash_info ["input_blob_name" ],
587+ )
588+ self .onefuzz .containers .files .download (
589+ primitives .Container (crash_info ["input_blob_container" ]),
590+ crash_info ["input_blob_name" ],
591+ os .path .join (output_dir , crash_info ["input_blob_name" ]),
592+ )
593+
594+ if include_setup :
595+ setup_container = list (
596+ self .onefuzz .jobs .containers .list (
597+ crash_info ["job_id" ], enums .ContainerType .setup
598+ )
599+ )[0 ]
600+
601+ self .onefuzz .containers .files .download_dir (
602+ primitives .Container (setup_container ), output_dir
603+ )
604+
605+
531606class Notifications (Endpoint ):
532607 """Interact with models.Notifications"""
533608
0 commit comments