diff --git a/src/macaron/config/defaults.ini b/src/macaron/config/defaults.ini index a58d375c3..4b56dac48 100644 --- a/src/macaron/config/defaults.ini +++ b/src/macaron/config/defaults.ini @@ -429,6 +429,7 @@ entry_conf = [slsa.verifier] provenance_extensions = intoto.jsonl + intoto.jsonl.gz # This is the acceptable maximum size (in bytes) to download an asset. max_download_size = 70000000 # This is the timeout (in seconds) to run the SLSA verifier. diff --git a/src/macaron/slsa_analyzer/provenance/loader.py b/src/macaron/slsa_analyzer/provenance/loader.py index 34c4b88f7..329daa9f0 100644 --- a/src/macaron/slsa_analyzer/provenance/loader.py +++ b/src/macaron/slsa_analyzer/provenance/loader.py @@ -4,7 +4,9 @@ """This module contains the loaders for SLSA provenances.""" import base64 +import gzip import json +import zlib from macaron.slsa_analyzer.provenance.intoto import InTotoPayload, validate_intoto_payload from macaron.slsa_analyzer.provenance.intoto.errors import LoadIntotoAttestationError, ValidateInTotoPayloadError @@ -16,6 +18,7 @@ def load_provenance_file(filepath: str) -> dict[str, JsonType]: Inside a provenance file is a DSSE envelope containing a base64-encoded provenance JSON payload. See: https://github.com/secure-systems-lab/dsse. + If the file is gzipped, it will be transparently decompressed. Parameters ---------- @@ -33,9 +36,13 @@ def load_provenance_file(filepath: str) -> dict[str, JsonType]: If there is an error loading the provenance JSON payload. """ try: - with open(filepath, encoding="utf-8") as file: - provenance = json.load(file) - except (json.JSONDecodeError, TypeError) as error: + try: + with gzip.open(filepath, mode="rt", encoding="utf-8") as file: + provenance = json.load(file) + except (gzip.BadGzipFile, EOFError, zlib.error): + with open(filepath, encoding="utf-8") as file: + provenance = json.load(file) + except (OSError, json.JSONDecodeError, TypeError) as error: raise LoadIntotoAttestationError( "Cannot deserialize the file content as JSON.", ) from error diff --git a/tests/slsa_analyzer/checks/test_provenance_l3_content_check.py b/tests/slsa_analyzer/checks/test_provenance_l3_content_check.py index 296d2dac2..a49cdf3f4 100644 --- a/tests/slsa_analyzer/checks/test_provenance_l3_content_check.py +++ b/tests/slsa_analyzer/checks/test_provenance_l3_content_check.py @@ -133,3 +133,19 @@ def test_expectation_check(self) -> None: # Test GitLab CI. ci_info["service"] = gitlab_ci assert check.run_check(ctx, check_result) == CheckResultType.PASSED + + # Repo has a (gzipped) provenance and valid expectation, and expectation passes. + ci_info["service"] = github_actions + ci_info["provenances"] = [ + load_provenance_payload(os.path.join(prov_dir, "slsa-verifier-linux-amd64.intoto.jsonl.gz")), + ] + ctx.dynamic_data["expectation"] = CUEExpectation.make_expectation( + os.path.join(expectation_dir, "valid_expectations", "slsa_verifier_PASS.cue") + ) + assert check.run_check(ctx, check_result) == CheckResultType.PASSED + + # Repo has a (gzipped) provenance and valid expectation, but expectation fails. + ctx.dynamic_data["expectation"] = CUEExpectation.make_expectation( + os.path.join(expectation_dir, "valid_expectations", "slsa_verifier_FAIL.cue") + ) + assert check.run_check(ctx, check_result) == CheckResultType.FAILED diff --git a/tests/slsa_analyzer/provenance/resources/valid_provenances/slsa-verifier-linux-amd64.intoto.jsonl.gz b/tests/slsa_analyzer/provenance/resources/valid_provenances/slsa-verifier-linux-amd64.intoto.jsonl.gz new file mode 100644 index 000000000..ee19422f3 Binary files /dev/null and b/tests/slsa_analyzer/provenance/resources/valid_provenances/slsa-verifier-linux-amd64.intoto.jsonl.gz differ