Repository: microsoft/onefuzz
File: src/cli/onefuzz/api.py (Python)

Code before:
        self.logger.debug("get repro vm: %s", vm_id_expanded)
        return self._req_model(
            "GET", models.Repro, data=requests.ReproGet(vm_id=vm_id_expanded)
        )

    def get_files(
        self,
        report_container: primitives.Container,
        report_name: str,
        include_setup: bool = False,
        output_dir: primitives.Directory = primitives.Directory("."),
    ) -> None:
        """downloads the files necessary to locally repro the crash from a given report"""
        report_bytes = self.onefuzz.containers.files.get(report_container, report_name)
        report = json.loads(report_bytes)

        crash_info = {
            "input_blob_container": None,
            "input_blob_name": None,
            "job_id": None,
        }
        if "input_blob" in report:
            crash_info["input_blob_container"] = report["input_blob"]["container"]
            crash_info["input_blob_name"] = report["input_blob"]["name"]
            crash_info["job_id"] = report["job_id"]
        elif "original_crash_test_result" in report:
            original_report = report["original_crash_test_result"]["crash_report"]
            regression_report = (
                report["crash_test_result"]["crash_report"]
                if "crash_test_result" in report
                else None
            )
            crash_info["input_blob_container"] = original_report["input_blob"][
                "container"
            ]
            crash_info["input_blob_name"] = original_report["input_blob"]["name"]
            crash_info["job_id"] = (
                regression_report["job_id"]
                if regression_report
                else original_report["job_id"]
            )
        else:
            self.logger.error(
                "Encountered an unhandled report format, unable to retrieve repro files"
            )
            return

        self.logger.info(
            "downloading files necessary to locally repro crash %s",
            crash_info["input_blob_name"],
        )

Review comment (bug):
`original_crash_test_result` is optional while `crash_test_result` is required for a `RegressionReport`, see the model here:
https://github.com/microsoft/onefuzz/blob/62c3f079af465316f1f6e360142774847918ad29/src/ApiService/ApiService/OneFuzzTypes/Model.cs#L544-L548

But, since we need the input blob from the original report, we should just check that both crash_test_result and original_crash_test_result are present before continuing and reporting an error otherwise.

Ex:

```python
elif "original_crash_test_result" in report and "crash_test_result" in report:
    # assume both are present
else:
    # log error
```

Code after:
        self.logger.debug("get repro vm: %s", vm_id_expanded)
        return self._req_model(
            "GET", models.Repro, data=requests.ReproGet(vm_id=vm_id_expanded)
        )

    def get_files(
        self,
        report_container: primitives.Container,
        report_name: str,
        include_setup: bool = False,
        output_dir: primitives.Directory = primitives.Directory("."),
    ) -> None:
        """downloads the files necessary to locally repro the crash from a given report"""
        report_bytes = self.onefuzz.containers.files.get(report_container, report_name)
        report = json.loads(report_bytes)

        crash_info = {
            "input_blob_container": primitives.Container(""),
            "input_blob_name": "",
            "job_id": "",
        }
        if "input_blob" in report:
            crash_info["input_blob_container"] = report["input_blob"]["container"]
            crash_info["input_blob_name"] = report["input_blob"]["name"]
            crash_info["job_id"] = report["job_id"]
        elif "crash_test_result" in report and "original_crash_test_result" in report:
            if report["original_crash_test_result"]["crash_report"] is None:
                self.logger.error(
                    "No crash report found in the original crash test result, repro files cannot be retrieved"
                )
                return
            elif report["crash_test_result"]["crash_report"] is None:
                self.logger.info(
                    "No crash report found in the new crash test result, falling back on the original crash test result for job_id"
                    "Note: if using --include_setup, the downloaded fuzzer binaries may be out-of-date"
                )

            original_report = report["original_crash_test_result"]["crash_report"]
            new_report = (
                report["crash_test_result"]["crash_report"] or original_report
            )  # fallback on original_report

            crash_info["input_blob_container"] = original_report["input_blob"][
                "container"
            ]
            crash_info["input_blob_name"] = original_report["input_blob"]["name"]
            crash_info["job_id"] = new_report["job_id"]
        else:
            self.logger.error(
                "Encountered an unhandled report format, repro files cannot be retrieved"
            )