diff --git a/scripts/dev_scripts/copyright-checker.sh b/scripts/dev_scripts/copyright-checker.sh index 7e7a30d58..2a9b45cf6 100755 --- a/scripts/dev_scripts/copyright-checker.sh +++ b/scripts/dev_scripts/copyright-checker.sh @@ -1,12 +1,38 @@ #!/usr/bin/env bash -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. # # Checks if copyright header is valid. # + +# Get the existing start year of a file, by checking if there is already a copyright +# notice line and capturing the start year. +# +# Arguments: +# $1: The file to get the start year. +# Outputs: +# STDOUT: The start year if it exists; empty string otherwise. +get_existing_start_year() { + file="$1" + copyright_line=$(grep -i -e "Copyright (c) [0-9]* - [0-9]*, Oracle and/or its affiliates. All rights reserved." "$file") + + # Use bash regex matching since grep does not have + # Reference: https://stackoverflow.com/questions/1891797/capturing-groups-from-a-grep-regex + capture_pattern="Copyright \(c\) ([0-9]*) - [0-9]*, Oracle and/or its affiliates. All rights reserved." + + if [[ $copyright_line =~ $capture_pattern ]] + then + year="${BASH_REMATCH[1]}" + echo "$year" + else + echo "" + fi +} + + files=$(git diff --cached --name-only) currentyear=$(date +"%Y") missing_copyright_files=() @@ -17,11 +43,7 @@ for f in $files; do if [ ! -f "$f" ]; then continue fi - startyear=$(git log --format=%ad --date=format:%Y "$f" | tail -1) - if [[ -z "${startyear// }" ]]; then - startyear=$currentyear - fi - if ! grep -i -e "Copyright (c) $startyear - $currentyear, Oracle and/or its affiliates. All rights reserved." "$f" 1>/dev/null;then + if ! grep -i -e "Copyright (c) [0-9]* - $currentyear, Oracle and/or its affiliates. All rights reserved." "$f" 1>/dev/null;then if [[ $f =~ .*\.(js$|py$|java$|tf$|go$|sh$|dl$|yaml$|yml$|gradle$|kts$|ini$|toml$) ]] || [[ "${f##*/}" = "Dockerfile" ]] \ || [[ "${f##*/}" = "Makefile" ]] || [[ "${f##*/}" = "Jenkinsfile" ]];then missing_copyright_files+=("$f") @@ -38,7 +60,7 @@ if [ ${#missing_copyright_files[@]} -ne 0 ]; then exit 1 fi missing_license_note=$(grep -i "$license_note" "$f") - startyear=$(git log --format=%ad --date=format:%Y "$f" | tail -1) + startyear=$(get_existing_start_year "$f") if [[ -z "${startyear// }" ]]; then startyear=$currentyear fi diff --git a/src/macaron/slsa_analyzer/provenance/intoto/__init__.py b/src/macaron/intoto/__init__.py similarity index 95% rename from src/macaron/slsa_analyzer/provenance/intoto/__init__.py rename to src/macaron/intoto/__init__.py index a2984d97e..8dcff6750 100644 --- a/src/macaron/slsa_analyzer/provenance/intoto/__init__.py +++ b/src/macaron/intoto/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """In-toto provenance schemas and validation.""" @@ -8,8 +8,8 @@ from collections.abc import Mapping from typing import NamedTuple, TypeVar -from macaron.slsa_analyzer.provenance.intoto import v01, v1 -from macaron.slsa_analyzer.provenance.intoto.errors import ValidateInTotoPayloadError +from macaron.intoto import v01, v1 +from macaron.intoto.errors import ValidateInTotoPayloadError from macaron.util import JsonType # Type of an in-toto statement. diff --git a/src/macaron/intoto/encoder_decoder.py b/src/macaron/intoto/encoder_decoder.py new file mode 100644 index 000000000..da7f13395 --- /dev/null +++ b/src/macaron/intoto/encoder_decoder.py @@ -0,0 +1,68 @@ +# Copyright (c) 2024 - 2024, Oracle and/or its affiliates. All rights reserved. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. + +"""Functions to base64 encode/decode the in-toto attestation payload.""" + +import base64 +import json + +from macaron.intoto.errors import DecodeIntotoAttestationError +from macaron.util import JsonType + + +def encode_payload(payload: dict[str, JsonType]) -> str: + """Encode (base64 encoding) the payload of an in-toto attestation. + + For more details about the payload field, see: + https://github.com/in-toto/attestation/blob/main/spec/v1/envelope.md#fields. + + Parameters + ---------- + payload : dict + The unencoded payload. + + Returns + ------- + str + The encoded payload. + """ + return base64.b64encode(json.dumps(payload).encode()).decode("ascii") + + +def decode_payload(encoded_payload: str) -> dict: + """Decode (base64 decoding) the payload of an in-toto attestation. + + For more details about the payload field, see: + https://github.com/in-toto/attestation/blob/main/spec/v1/envelope.md#fields. + + Parameters + ---------- + encoded_payload : str + The encoded payload. + + Returns + ------- + dict + The decoded payload. + + Raises + ------ + DecodeIntotoAttestationError + If there is an error decoding the payload of an in-toto attestation. + """ + try: + decoded_string = base64.b64decode(encoded_payload) + except UnicodeDecodeError as error: + raise DecodeIntotoAttestationError("Cannot base64-decode the attestation payload.") from error + + try: + json_payload = json.loads(decoded_string) + except (json.JSONDecodeError, TypeError) as error: + raise DecodeIntotoAttestationError( + "Cannot deserialize the attestation payload as JSON.", + ) from error + + if not isinstance(json_payload, dict): + raise DecodeIntotoAttestationError("The provenance payload is not a JSON object.") + + return json_payload diff --git a/src/macaron/slsa_analyzer/provenance/intoto/errors.py b/src/macaron/intoto/errors.py similarity index 60% rename from src/macaron/slsa_analyzer/provenance/intoto/errors.py rename to src/macaron/intoto/errors.py index f999c1c66..617b0e2b4 100644 --- a/src/macaron/slsa_analyzer/provenance/intoto/errors.py +++ b/src/macaron/intoto/errors.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """Error types related to in-toto attestations.""" @@ -15,8 +15,12 @@ class ValidateInTotoPayloadError(InTotoAttestationError): class UnsupportedInTotoVersionError(InTotoAttestationError): - """Happens when encountering a provenance under an unsupported in-toto version.""" + """Happens when encountering an attestation under an unsupported in-toto version.""" + + +class DecodeIntotoAttestationError(InTotoAttestationError): + """Happens when there is an issue decoding the payload of an in-toto attestation.""" class LoadIntotoAttestationError(InTotoAttestationError): - """Happens when there is an issue decoding and loading the payload of an in-toto provenance.""" + """Happens when there is an issue loading the payload of an in-toto attestation.""" diff --git a/src/macaron/slsa_analyzer/provenance/intoto/v01/__init__.py b/src/macaron/intoto/v01/__init__.py similarity index 97% rename from src/macaron/slsa_analyzer/provenance/intoto/v01/__init__.py rename to src/macaron/intoto/v01/__init__.py index fc855e1da..a7dba42d3 100644 --- a/src/macaron/slsa_analyzer/provenance/intoto/v01/__init__.py +++ b/src/macaron/intoto/v01/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module handles in-toto version 0.1 attestations.""" @@ -7,7 +7,7 @@ from typing import TypedDict, TypeGuard -from macaron.slsa_analyzer.provenance.intoto.errors import ValidateInTotoPayloadError +from macaron.intoto.errors import ValidateInTotoPayloadError from macaron.util import JsonType diff --git a/src/macaron/slsa_analyzer/provenance/intoto/v1/__init__.py b/src/macaron/intoto/v1/__init__.py similarity index 87% rename from src/macaron/slsa_analyzer/provenance/intoto/v1/__init__.py rename to src/macaron/intoto/v1/__init__.py index 0f6d05eed..4a09baf4a 100644 --- a/src/macaron/slsa_analyzer/provenance/intoto/v1/__init__.py +++ b/src/macaron/intoto/v1/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module handles in-toto version version 1 attestations.""" diff --git a/src/macaron/slsa_analyzer/analyze_context.py b/src/macaron/slsa_analyzer/analyze_context.py index da6591929..bee19bbbb 100644 --- a/src/macaron/slsa_analyzer/analyze_context.py +++ b/src/macaron/slsa_analyzer/analyze_context.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module contains the Analyze Context class. @@ -12,13 +12,13 @@ from typing import TypedDict from macaron.database.table_definitions import Component, SLSALevel +from macaron.intoto.v01 import InTotoV01Statement +from macaron.intoto.v1 import InTotoV1Statement from macaron.slsa_analyzer.checks.check_result import CheckResult, CheckResultType from macaron.slsa_analyzer.git_service import BaseGitService from macaron.slsa_analyzer.git_service.base_git_service import NoneGitService from macaron.slsa_analyzer.levels import SLSALevels from macaron.slsa_analyzer.provenance.expectations.expectation import Expectation -from macaron.slsa_analyzer.provenance.intoto.v01 import InTotoV01Statement -from macaron.slsa_analyzer.provenance.intoto.v1 import InTotoV1Statement from macaron.slsa_analyzer.slsa_req import ReqName, SLSAReqStatus, create_requirement_status_dict from macaron.slsa_analyzer.specs.build_spec import BuildSpec from macaron.slsa_analyzer.specs.ci_spec import CIInfo diff --git a/src/macaron/slsa_analyzer/analyzer.py b/src/macaron/slsa_analyzer/analyzer.py index 035608221..e7b54a8ad 100644 --- a/src/macaron/slsa_analyzer/analyzer.py +++ b/src/macaron/slsa_analyzer/analyzer.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module handles the cloning and analyzing a Git repo.""" @@ -23,6 +23,7 @@ from macaron.database.table_definitions import Analysis, Component, Repository from macaron.dependency_analyzer import DependencyAnalyzer, DependencyInfo from macaron.errors import CloneError, DuplicateError, InvalidPURLError, PURLNotFoundError, RepoCheckOutError +from macaron.intoto import InTotoV01Payload from macaron.output_reporter.reporter import FileReporter from macaron.output_reporter.results import Record, Report, SCMStatus from macaron.repo_finder import repo_finder @@ -39,7 +40,6 @@ from macaron.slsa_analyzer.git_service.base_git_service import NoneGitService from macaron.slsa_analyzer.package_registry import PACKAGE_REGISTRIES from macaron.slsa_analyzer.provenance.expectations.expectation_registry import ExpectationRegistry -from macaron.slsa_analyzer.provenance.intoto import InTotoV01Payload from macaron.slsa_analyzer.registry import registry from macaron.slsa_analyzer.specs.ci_spec import CIInfo from macaron.slsa_analyzer.specs.inferred_provenance import Provenance diff --git a/src/macaron/slsa_analyzer/checks/build_as_code_check.py b/src/macaron/slsa_analyzer/checks/build_as_code_check.py index 3e59f36b2..dcd0daf1b 100644 --- a/src/macaron/slsa_analyzer/checks/build_as_code_check.py +++ b/src/macaron/slsa_analyzer/checks/build_as_code_check.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module contains the BuildAsCodeCheck class.""" @@ -12,6 +12,7 @@ from sqlalchemy.sql.sqltypes import String from macaron.database.table_definitions import CheckFacts +from macaron.intoto import InTotoV01Payload from macaron.slsa_analyzer.analyze_context import AnalyzeContext from macaron.slsa_analyzer.build_tool.base_build_tool import BaseBuildTool from macaron.slsa_analyzer.checks.base_check import BaseCheck @@ -22,7 +23,6 @@ from macaron.slsa_analyzer.ci_service.gitlab_ci import GitLabCI from macaron.slsa_analyzer.ci_service.jenkins import Jenkins from macaron.slsa_analyzer.ci_service.travis import Travis -from macaron.slsa_analyzer.provenance.intoto import InTotoV01Payload from macaron.slsa_analyzer.registry import registry from macaron.slsa_analyzer.slsa_req import ReqName from macaron.slsa_analyzer.specs.ci_spec import CIInfo diff --git a/src/macaron/slsa_analyzer/checks/build_service_check.py b/src/macaron/slsa_analyzer/checks/build_service_check.py index ea2273ea0..7ccce4c10 100644 --- a/src/macaron/slsa_analyzer/checks/build_service_check.py +++ b/src/macaron/slsa_analyzer/checks/build_service_check.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module contains the BuildServiceCheck class.""" @@ -12,6 +12,7 @@ from sqlalchemy.sql.sqltypes import String from macaron.database.table_definitions import CheckFacts +from macaron.intoto import InTotoV01Payload from macaron.slsa_analyzer.analyze_context import AnalyzeContext from macaron.slsa_analyzer.build_tool.base_build_tool import BaseBuildTool from macaron.slsa_analyzer.checks.base_check import BaseCheck @@ -21,7 +22,6 @@ from macaron.slsa_analyzer.ci_service.gitlab_ci import GitLabCI from macaron.slsa_analyzer.ci_service.jenkins import Jenkins from macaron.slsa_analyzer.ci_service.travis import Travis -from macaron.slsa_analyzer.provenance.intoto import InTotoV01Payload from macaron.slsa_analyzer.registry import registry from macaron.slsa_analyzer.slsa_req import ReqName from macaron.slsa_analyzer.specs.ci_spec import CIInfo diff --git a/src/macaron/slsa_analyzer/checks/infer_artifact_pipeline_check.py b/src/macaron/slsa_analyzer/checks/infer_artifact_pipeline_check.py index 67102ab31..2c7535a9b 100644 --- a/src/macaron/slsa_analyzer/checks/infer_artifact_pipeline_check.py +++ b/src/macaron/slsa_analyzer/checks/infer_artifact_pipeline_check.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module contains the InferArtifactPipelineCheck class to check if an artifact is published from a pipeline automatically.""" @@ -12,6 +12,7 @@ from macaron.config.defaults import defaults from macaron.database.table_definitions import CheckFacts from macaron.errors import InvalidHTTPResponseError +from macaron.intoto import InTotoV01Payload from macaron.slsa_analyzer.analyze_context import AnalyzeContext from macaron.slsa_analyzer.build_tool.gradle import Gradle from macaron.slsa_analyzer.build_tool.maven import Maven @@ -19,7 +20,6 @@ from macaron.slsa_analyzer.checks.check_result import CheckResultData, CheckResultType, Justification, ResultTables from macaron.slsa_analyzer.ci_service.base_ci_service import NoneCIService from macaron.slsa_analyzer.package_registry.maven_central_registry import MavenCentralRegistry -from macaron.slsa_analyzer.provenance.intoto import InTotoV01Payload from macaron.slsa_analyzer.registry import registry from macaron.slsa_analyzer.slsa_req import ReqName from macaron.slsa_analyzer.specs.package_registry_spec import PackageRegistryInfo diff --git a/src/macaron/slsa_analyzer/checks/provenance_available_check.py b/src/macaron/slsa_analyzer/checks/provenance_available_check.py index 659746c31..33fc04c69 100644 --- a/src/macaron/slsa_analyzer/checks/provenance_available_check.py +++ b/src/macaron/slsa_analyzer/checks/provenance_available_check.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module contains the implementation of the Provenance Available check.""" @@ -15,6 +15,7 @@ from macaron.config.defaults import defaults from macaron.database.table_definitions import CheckFacts, Component from macaron.errors import MacaronError +from macaron.intoto import InTotoPayload from macaron.slsa_analyzer.analyze_context import AnalyzeContext from macaron.slsa_analyzer.asset import AssetLocator from macaron.slsa_analyzer.build_tool.gradle import Gradle @@ -27,7 +28,6 @@ from macaron.slsa_analyzer.package_registry import JFrogMavenRegistry from macaron.slsa_analyzer.package_registry.jfrog_maven_registry import JFrogMavenAsset from macaron.slsa_analyzer.package_registry.npm_registry import NPMAttestationAsset, NPMRegistry -from macaron.slsa_analyzer.provenance.intoto import InTotoPayload from macaron.slsa_analyzer.provenance.loader import LoadIntotoAttestationError, load_provenance_payload from macaron.slsa_analyzer.provenance.slsa import SLSAProvenanceData from macaron.slsa_analyzer.provenance.witness import ( diff --git a/src/macaron/slsa_analyzer/checks/provenance_l3_check.py b/src/macaron/slsa_analyzer/checks/provenance_l3_check.py index d8d26a7fd..27005e7c7 100644 --- a/src/macaron/slsa_analyzer/checks/provenance_l3_check.py +++ b/src/macaron/slsa_analyzer/checks/provenance_l3_check.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This modules implements a check to verify a target repo has intoto provenance level 3.""" @@ -23,14 +23,14 @@ from macaron.config.defaults import defaults from macaron.config.global_config import global_config from macaron.database.table_definitions import CheckFacts, HashDigest, Provenance, ReleaseArtifact +from macaron.intoto import InTotoV01Payload, v01 +from macaron.intoto.errors import InTotoAttestationError, UnsupportedInTotoVersionError from macaron.slsa_analyzer.analyze_context import AnalyzeContext from macaron.slsa_analyzer.asset import AssetLocator from macaron.slsa_analyzer.checks.base_check import BaseCheck from macaron.slsa_analyzer.checks.check_result import CheckResultData, CheckResultType, Justification, ResultTables from macaron.slsa_analyzer.ci_service.base_ci_service import BaseCIService, NoneCIService from macaron.slsa_analyzer.git_url import get_repo_dir_name -from macaron.slsa_analyzer.provenance.intoto import InTotoV01Payload, v01 -from macaron.slsa_analyzer.provenance.intoto.errors import InTotoAttestationError, UnsupportedInTotoVersionError from macaron.slsa_analyzer.provenance.loader import load_provenance_payload from macaron.slsa_analyzer.registry import registry from macaron.slsa_analyzer.slsa_req import ReqName diff --git a/src/macaron/slsa_analyzer/checks/trusted_builder_l3_check.py b/src/macaron/slsa_analyzer/checks/trusted_builder_l3_check.py index 46e0aeba9..6bd3345d0 100644 --- a/src/macaron/slsa_analyzer/checks/trusted_builder_l3_check.py +++ b/src/macaron/slsa_analyzer/checks/trusted_builder_l3_check.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. @@ -14,11 +14,11 @@ from macaron.config.defaults import defaults from macaron.database.table_definitions import CheckFacts +from macaron.intoto import InTotoV01Payload from macaron.slsa_analyzer.analyze_context import AnalyzeContext from macaron.slsa_analyzer.checks.base_check import BaseCheck from macaron.slsa_analyzer.checks.check_result import CheckResultData, CheckResultType, Justification, ResultTables from macaron.slsa_analyzer.ci_service.github_actions import GHWorkflowType, GitHubActions -from macaron.slsa_analyzer.provenance.intoto import InTotoV01Payload from macaron.slsa_analyzer.registry import registry from macaron.slsa_analyzer.slsa_req import ReqName from macaron.slsa_analyzer.specs.inferred_provenance import Provenance diff --git a/src/macaron/slsa_analyzer/provenance/expectations/expectation.py b/src/macaron/slsa_analyzer/provenance/expectations/expectation.py index 9f9e8c797..81db7c9d0 100644 --- a/src/macaron/slsa_analyzer/provenance/expectations/expectation.py +++ b/src/macaron/slsa_analyzer/provenance/expectations/expectation.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module provides a base class for provenance expectation verifiers.""" @@ -9,7 +9,7 @@ from sqlalchemy.orm import Mapped, mapped_column from macaron.errors import ExpectationRuntimeError -from macaron.slsa_analyzer.provenance.intoto import InTotoPayload +from macaron.intoto import InTotoPayload ExpectationFn = Callable[[Any], bool] diff --git a/src/macaron/slsa_analyzer/provenance/loader.py b/src/macaron/slsa_analyzer/provenance/loader.py index 329daa9f0..32c64d659 100644 --- a/src/macaron/slsa_analyzer/provenance/loader.py +++ b/src/macaron/slsa_analyzer/provenance/loader.py @@ -1,15 +1,15 @@ -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """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 +from macaron.intoto import InTotoPayload, validate_intoto_payload +from macaron.intoto.encoder_decoder import decode_payload +from macaron.intoto.errors import DecodeIntotoAttestationError, LoadIntotoAttestationError, ValidateInTotoPayloadError from macaron.util import JsonType @@ -54,19 +54,9 @@ def load_provenance_file(filepath: str) -> dict[str, JsonType]: ) try: - decoded_payload = base64.b64decode(provenance_payload) - except UnicodeDecodeError as error: - raise LoadIntotoAttestationError("Cannot decode the payload.") from error - - try: - json_payload = json.loads(decoded_payload) - except (json.JSONDecodeError, TypeError) as error: - raise LoadIntotoAttestationError( - "Cannot deserialize the provenance payload as JSON.", - ) from error - - if not isinstance(json_payload, dict): - raise LoadIntotoAttestationError("The provenance payload is not a JSON object.") + json_payload = decode_payload(provenance_payload) + except DecodeIntotoAttestationError as err: + raise LoadIntotoAttestationError("Cannot decode the attestation payload") from err return json_payload diff --git a/src/macaron/slsa_analyzer/provenance/provenance.py b/src/macaron/slsa_analyzer/provenance/provenance.py index 4425cb1d5..fd5cd639e 100644 --- a/src/macaron/slsa_analyzer/provenance/provenance.py +++ b/src/macaron/slsa_analyzer/provenance/provenance.py @@ -1,12 +1,12 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module defines classes and interfaces related to provenances.""" from typing import Protocol +from macaron.intoto import InTotoPayload from macaron.slsa_analyzer.asset import AssetLocator -from macaron.slsa_analyzer.provenance.intoto import InTotoPayload class DownloadedProvenanceData(Protocol): diff --git a/src/macaron/slsa_analyzer/provenance/slsa/__init__.py b/src/macaron/slsa_analyzer/provenance/slsa/__init__.py index ce60d94ed..89d230184 100644 --- a/src/macaron/slsa_analyzer/provenance/slsa/__init__.py +++ b/src/macaron/slsa_analyzer/provenance/slsa/__init__.py @@ -1,12 +1,12 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module implements SLSA provenance abstractions.""" from typing import NamedTuple +from macaron.intoto import InTotoPayload from macaron.slsa_analyzer.asset import AssetLocator -from macaron.slsa_analyzer.provenance.intoto import InTotoPayload class SLSAProvenanceData(NamedTuple): diff --git a/src/macaron/slsa_analyzer/provenance/witness/__init__.py b/src/macaron/slsa_analyzer/provenance/witness/__init__.py index cbe1afe8e..90a27785c 100644 --- a/src/macaron/slsa_analyzer/provenance/witness/__init__.py +++ b/src/macaron/slsa_analyzer/provenance/witness/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """Witness provenance (https://github.com/testifysec/witness).""" @@ -7,8 +7,8 @@ from typing import NamedTuple from macaron.config.defaults import defaults +from macaron.intoto import InTotoPayload, InTotoV01Payload from macaron.slsa_analyzer.asset import AssetLocator -from macaron.slsa_analyzer.provenance.intoto import InTotoPayload, InTotoV01Payload from macaron.slsa_analyzer.provenance.witness.attestor import GitLabWitnessAttestor, RepoAttestor logger: logging.Logger = logging.getLogger(__name__) diff --git a/src/macaron/slsa_analyzer/provenance/witness/attestor.py b/src/macaron/slsa_analyzer/provenance/witness/attestor.py index 7fc2e3f24..89851ba61 100644 --- a/src/macaron/slsa_analyzer/provenance/witness/attestor.py +++ b/src/macaron/slsa_analyzer/provenance/witness/attestor.py @@ -1,11 +1,11 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """Witness Attestors.""" from typing import Protocol -from macaron.slsa_analyzer.provenance.intoto import InTotoPayload, InTotoV01Payload +from macaron.intoto import InTotoPayload, InTotoV01Payload class RepoAttestor(Protocol): diff --git a/src/macaron/slsa_analyzer/specs/ci_spec.py b/src/macaron/slsa_analyzer/specs/ci_spec.py index d1f2fde24..0fbdb912e 100644 --- a/src/macaron/slsa_analyzer/specs/ci_spec.py +++ b/src/macaron/slsa_analyzer/specs/ci_spec.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module contains the BuildSpec class.""" @@ -7,10 +7,10 @@ from typing import TypedDict from macaron.code_analyzer.call_graph import CallGraph +from macaron.intoto import InTotoPayload from macaron.parsers.bashparser import BashCommands from macaron.slsa_analyzer.asset import AssetLocator from macaron.slsa_analyzer.ci_service.base_ci_service import BaseCIService -from macaron.slsa_analyzer.provenance.intoto import InTotoPayload class CIInfo(TypedDict): diff --git a/src/macaron/slsa_analyzer/specs/inferred_provenance.py b/src/macaron/slsa_analyzer/specs/inferred_provenance.py index 6d5bba573..dec5b5568 100644 --- a/src/macaron/slsa_analyzer/specs/inferred_provenance.py +++ b/src/macaron/slsa_analyzer/specs/inferred_provenance.py @@ -1,10 +1,10 @@ -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """This module contains the inferred SLSA provenance spec.""" -from macaron.slsa_analyzer.provenance.intoto import v01 +from macaron.intoto import v01 class Provenance: diff --git a/tests/slsa_analyzer/provenance/intoto/v01/__init__.py b/tests/intoto/__init__.py similarity index 65% rename from tests/slsa_analyzer/provenance/intoto/v01/__init__.py rename to tests/intoto/__init__.py index 19aeac023..b00041535 100644 --- a/tests/slsa_analyzer/provenance/intoto/v01/__init__.py +++ b/tests/intoto/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. diff --git a/tests/intoto/test_encoder_decoder.py b/tests/intoto/test_encoder_decoder.py new file mode 100644 index 000000000..e0368c5c9 --- /dev/null +++ b/tests/intoto/test_encoder_decoder.py @@ -0,0 +1,31 @@ +# Copyright (c) 2024 - 2024, Oracle and/or its affiliates. All rights reserved. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. + +"""Tests for functions to base64 encode/decode the in-toto attestation payload.""" + + +from string import printable + +from hypothesis import given +from hypothesis import strategies as st + +from macaron.intoto.encoder_decoder import decode_payload, encode_payload +from macaron.util import JsonType + +json_values = st.recursive( + st.none() | st.booleans() | st.floats(allow_nan=False, allow_infinity=False) | st.text(printable), + lambda children: st.lists(children) | st.dictionaries(st.text(printable), children), + max_leaves=3, +) +json_payloads = st.dictionaries(st.text(printable), json_values) + + +@given(json_payload_before=json_payloads) +def test_round_trip(json_payload_before: dict[str, JsonType]) -> None: + """Test the round-trip property of the `encode_payload` and the `decode_payload` functions. + + After a round-trip of `encode_payload` and `decode_payload`, we should get the original payload. + """ + encoded = encode_payload(json_payload_before) + json_payload_after = decode_payload(encoded) + assert json_payload_before == json_payload_after diff --git a/tests/slsa_analyzer/provenance/intoto/__init__.py b/tests/intoto/v01/__init__.py similarity index 65% rename from tests/slsa_analyzer/provenance/intoto/__init__.py rename to tests/intoto/v01/__init__.py index 19aeac023..b00041535 100644 --- a/tests/slsa_analyzer/provenance/intoto/__init__.py +++ b/tests/intoto/v01/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. diff --git a/tests/slsa_analyzer/provenance/intoto/v01/test_validate.py b/tests/intoto/v01/test_validate.py similarity index 95% rename from tests/slsa_analyzer/provenance/intoto/v01/test_validate.py rename to tests/intoto/v01/test_validate.py index 2e438a484..ed0b6a651 100644 --- a/tests/slsa_analyzer/provenance/intoto/v01/test_validate.py +++ b/tests/intoto/v01/test_validate.py @@ -1,12 +1,12 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """Tests for validation of in-toto attestation version 0.1.""" import pytest -from macaron.slsa_analyzer.provenance.intoto.errors import ValidateInTotoPayloadError -from macaron.slsa_analyzer.provenance.intoto.v01 import validate_intoto_statement, validate_intoto_subject +from macaron.intoto.errors import ValidateInTotoPayloadError +from macaron.intoto.v01 import validate_intoto_statement, validate_intoto_subject from macaron.util import JsonType diff --git a/tests/slsa_analyzer/provenance/test_witness_provenance.py b/tests/slsa_analyzer/provenance/test_witness_provenance.py index 901c8f1db..795ed2ac4 100644 --- a/tests/slsa_analyzer/provenance/test_witness_provenance.py +++ b/tests/slsa_analyzer/provenance/test_witness_provenance.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """Tests for witness provenance.""" @@ -10,7 +10,7 @@ import pytest from macaron.config.defaults import load_defaults -from macaron.slsa_analyzer.provenance.intoto import InTotoV01Payload, v01 +from macaron.intoto import InTotoV01Payload, v01 from macaron.slsa_analyzer.provenance.witness import ( WitnessProvenanceSubject, WitnessVerifierConfig, diff --git a/tests/slsa_analyzer/test_analyze_context.py b/tests/slsa_analyzer/test_analyze_context.py index 582612334..1fd361f66 100644 --- a/tests/slsa_analyzer/test_analyze_context.py +++ b/tests/slsa_analyzer/test_analyze_context.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. """ @@ -9,8 +9,8 @@ from unittest.mock import MagicMock from macaron.code_analyzer.call_graph import BaseNode, CallGraph +from macaron.intoto import validate_intoto_payload from macaron.slsa_analyzer.ci_service.github_actions import GitHubActions -from macaron.slsa_analyzer.provenance.intoto import validate_intoto_payload from macaron.slsa_analyzer.slsa_req import ReqName, SLSAReqStatus from macaron.slsa_analyzer.specs.ci_spec import CIInfo from macaron.util import JsonType