diff --git a/docs/source/assets/er-diagram.svg b/docs/source/assets/er-diagram.svg index 722d95027..10ec21837 100644 --- a/docs/source/assets/er-diagram.svg +++ b/docs/source/assets/er-diagram.svg @@ -4,229 +4,254 @@ - - - + + + _analysis - -_analysis - -id - - [INTEGER] - NOT NULL - -analysis_time - - [VARCHAR] - NOT NULL - -macaron_version - - [VARCHAR] - NOT NULL + +_analysis + +id + + [INTEGER] + NOT NULL + +analysis_time + + [VARCHAR] + NOT NULL + +macaron_version + + [VARCHAR] + NOT NULL _component - -_component - -id - - [INTEGER] - NOT NULL - -analysis_id - - [INTEGER] - NOT NULL - -name - - [VARCHAR(100)] - NOT NULL - -namespace - - [VARCHAR(255)] - -purl - - [VARCHAR] - NOT NULL - -qualifiers - - [VARCHAR(1024)] - -subpath - - [VARCHAR(200)] - -type - - [VARCHAR(16)] - NOT NULL - -version - - [VARCHAR(100)] + +_component + +id + + [INTEGER] + NOT NULL + +analysis_id + + [INTEGER] + NOT NULL + +name + + [VARCHAR(100)] + NOT NULL + +namespace + + [VARCHAR(255)] + +purl + + [VARCHAR] + NOT NULL + +qualifiers + + [VARCHAR(1024)] + +subpath + + [VARCHAR(200)] + +type + + [VARCHAR(16)] + NOT NULL + +version + + [VARCHAR(100)] _analysis--_component - -0..N -1 + +0..N +1 _check_facts - -_check_facts - -id - - [INTEGER] - NOT NULL - -check_result_id - - [INTEGER] - NOT NULL - -check_type - - [VARCHAR] - NOT NULL - -component_id - - [INTEGER] - NOT NULL - -confidence - - [FLOAT] - NOT NULL + +_check_facts + +id + + [INTEGER] + NOT NULL + +check_result_id + + [INTEGER] + NOT NULL + +check_type + + [VARCHAR] + NOT NULL + +component_id + + [INTEGER] + NOT NULL + +confidence + + [FLOAT] + NOT NULL - + _component--_check_facts - -0..N -1 + +0..N +1 - + _check_result - -_check_result - -id - - [INTEGER] - NOT NULL - -check_id - - [VARCHAR] - NOT NULL - -component_id - - [INTEGER] - NOT NULL - -passed - - [BOOLEAN] - NOT NULL + +_check_result + +id + + [INTEGER] + NOT NULL + +check_id + + [VARCHAR] + NOT NULL + +component_id + + [INTEGER] + NOT NULL + +passed + + [BOOLEAN] + NOT NULL - + _component--_check_result - -0..N -1 + +0..N +1 - + _dependency - -_dependency - -child_component - - [INTEGER] - NOT NULL - -parent_component - - [INTEGER] - NOT NULL + +_dependency + +child_component + + [INTEGER] + NOT NULL + +parent_component + + [INTEGER] + NOT NULL - + _component--_dependency - -1 -1 + +1 +1 - + _component--_dependency - -1 -1 + +1 +1 - + _provenance - -_provenance - -id - - [INTEGER] - NOT NULL - -component_id - - [INTEGER] - NOT NULL - -provenance_json - - [VARCHAR] - NOT NULL - -release_commit_sha - - [VARCHAR] - -release_tag - - [VARCHAR] - -version - - [VARCHAR] - NOT NULL + +_provenance + +id + + [INTEGER] + NOT NULL + +commit_sha + + [VARCHAR] + +component_id + + [INTEGER] + NOT NULL + +provenance_asset_name + + [VARCHAR] + +provenance_asset_url + + [VARCHAR] + +provenance_payload + + [VARCHAR] + NOT NULL + +release_commit_sha + + [VARCHAR] + +release_tag + + [VARCHAR] + +repository_url + + [VARCHAR] + +slsa_level + + [INTEGER] + NOT NULL + +slsa_version + + [VARCHAR] + +verified + + [BOOLEAN] + NOT NULL - + _component--_provenance - -0..N -1 + +0..N +1 - + _provenance_subject _provenance_subject @@ -247,14 +272,14 @@ NOT NULL - + _component--_provenance_subject - -0..N -1 + +0..N +1 - + _repo_finder_metadata _repo_finder_metadata @@ -290,14 +315,14 @@ NOT NULL - + _component--_repo_finder_metadata - -0..N -1 + +0..N +1 - + _repository _repository @@ -365,14 +390,14 @@ NOT NULL - + _component--_repository - -0..N -1 + +0..N +1 - + _slsa_level _slsa_level @@ -393,14 +418,14 @@ NOT NULL - + _component--_slsa_level - -1 -1 + +1 +1 - + _slsa_requirement _slsa_requirement @@ -429,645 +454,627 @@ [VARCHAR] - + _component--_slsa_requirement - -0..N -1 + +0..N +1 _artifact_pipeline_check - -_artifact_pipeline_check - -id - - [INTEGER] - NOT NULL - -deploy_job - - [VARCHAR] - -deploy_step - - [VARCHAR] - -deploy_workflow - - [VARCHAR] - -from_provenance - - [BOOLEAN] - NOT NULL - -published_before_commit - - [BOOLEAN] - NOT NULL - -run_deleted - - [BOOLEAN] - NOT NULL - -run_url - - [VARCHAR] + +_artifact_pipeline_check + +id + + [INTEGER] + NOT NULL + +deploy_job + + [VARCHAR] + +deploy_step + + [VARCHAR] + +deploy_workflow + + [VARCHAR] + +from_provenance + + [BOOLEAN] + NOT NULL + +published_before_commit + + [BOOLEAN] + NOT NULL + +run_deleted + + [BOOLEAN] + NOT NULL + +run_url + + [VARCHAR] _check_facts--_artifact_pipeline_check - -1 -1 + +1 +1 _build_as_code_check - -_build_as_code_check - -id - - [INTEGER] - NOT NULL - -build_tool_name - - [VARCHAR] - NOT NULL - -build_trigger - - [VARCHAR] - -ci_service_name - - [VARCHAR] - NOT NULL - -deploy_command - - [VARCHAR] - -language - - [VARCHAR] - NOT NULL - -language_distributions - - [VARCHAR] - -language_url - - [VARCHAR] - -language_versions - - [VARCHAR] + +_build_as_code_check + +id + + [INTEGER] + NOT NULL + +build_tool_name + + [VARCHAR] + NOT NULL + +build_trigger + + [VARCHAR] + +ci_service_name + + [VARCHAR] + NOT NULL + +deploy_command + + [VARCHAR] + +language + + [VARCHAR] + NOT NULL + +language_distributions + + [VARCHAR] + +language_url + + [VARCHAR] + +language_versions + + [VARCHAR] _check_facts--_build_as_code_check - -1 -1 + +1 +1 _build_script_check - -_build_script_check - -id - - [INTEGER] - NOT NULL - -build_tool_command - - [VARCHAR] - -build_tool_name - - [VARCHAR] - NOT NULL - -build_trigger - - [VARCHAR] - -ci_service_name - - [VARCHAR] - NOT NULL - -language - - [VARCHAR] - NOT NULL - -language_distributions - - [VARCHAR] - -language_url - - [VARCHAR] - -language_versions - - [VARCHAR] + +_build_script_check + +id + + [INTEGER] + NOT NULL + +build_tool_command + + [VARCHAR] + +build_tool_name + + [VARCHAR] + NOT NULL + +build_trigger + + [VARCHAR] + +ci_service_name + + [VARCHAR] + NOT NULL + +language + + [VARCHAR] + NOT NULL + +language_distributions + + [VARCHAR] + +language_url + + [VARCHAR] + +language_versions + + [VARCHAR] _check_facts--_build_script_check - -1 -1 + +1 +1 _build_service_check - -_build_service_check - -id - - [INTEGER] - NOT NULL - -build_command - - [VARCHAR] - -build_tool_name - - [VARCHAR] - NOT NULL - -build_trigger - - [VARCHAR] - -ci_service_name - - [VARCHAR] - NOT NULL - -language - - [VARCHAR] - NOT NULL - -language_distributions - - [VARCHAR] - -language_url - - [VARCHAR] - -language_versions - - [VARCHAR] + +_build_service_check + +id + + [INTEGER] + NOT NULL + +build_command + + [VARCHAR] + +build_tool_name + + [VARCHAR] + NOT NULL + +build_trigger + + [VARCHAR] + +ci_service_name + + [VARCHAR] + NOT NULL + +language + + [VARCHAR] + NOT NULL + +language_distributions + + [VARCHAR] + +language_url + + [VARCHAR] + +language_versions + + [VARCHAR] _check_facts--_build_service_check - -1 -1 + +1 +1 _build_tool_check - -_build_tool_check - -id - - [INTEGER] - NOT NULL - -build_tool_name - - [VARCHAR] - NOT NULL - -language - - [VARCHAR] - NOT NULL + +_build_tool_check + +id + + [INTEGER] + NOT NULL + +build_tool_name + + [VARCHAR] + NOT NULL + +language + + [VARCHAR] + NOT NULL _check_facts--_build_tool_check - -1 -1 + +1 +1 _cue_expectation - -_cue_expectation - -id - - [INTEGER] - NOT NULL - -asset_url - - [VARCHAR] - -description - - [VARCHAR] - NOT NULL - -expectation_type - - [VARCHAR] - NOT NULL - -path - - [VARCHAR] - NOT NULL - -sha - - [VARCHAR] - -target - - [VARCHAR] - NOT NULL - -text - - [VARCHAR] + +_cue_expectation + +id + + [INTEGER] + NOT NULL + +asset_url + + [VARCHAR] + +description + + [VARCHAR] + NOT NULL + +expectation_type + + [VARCHAR] + NOT NULL + +path + + [VARCHAR] + NOT NULL + +sha + + [VARCHAR] + +target + + [VARCHAR] + NOT NULL + +text + + [VARCHAR] _check_facts--_cue_expectation - -1 -1 + +1 +1 _detect_malicious_metadata_check - -_detect_malicious_metadata_check - -id - - [INTEGER] - NOT NULL - -detail_information - - [JSON] - NOT NULL - -known_malware - - [VARCHAR] - -result - - [JSON] - NOT NULL + +_detect_malicious_metadata_check + +id + + [INTEGER] + NOT NULL + +detail_information + + [JSON] + NOT NULL + +known_malware + + [VARCHAR] + +result + + [JSON] + NOT NULL _check_facts--_detect_malicious_metadata_check - -1 -1 + +1 +1 _provenance_available_check - -_provenance_available_check - -id - - [INTEGER] - NOT NULL - -asset_name - - [VARCHAR] - -asset_url - - [VARCHAR] + +_provenance_available_check + +id + + [INTEGER] + NOT NULL + +asset_name + + [VARCHAR] + +asset_url + + [VARCHAR] _check_facts--_provenance_available_check - -1 -1 + +1 +1 _provenance_derived_commit_check - -_provenance_derived_commit_check - -id - - [INTEGER] - NOT NULL - -commit_info - - [VARCHAR] + +_provenance_derived_commit_check + +id + + [INTEGER] + NOT NULL + +commit_info + + [VARCHAR] _check_facts--_provenance_derived_commit_check - -1 -1 + +1 +1 _provenance_derived_repo_check - -_provenance_derived_repo_check - -id - - [INTEGER] - NOT NULL - -repository_info - - [VARCHAR] + +_provenance_derived_repo_check + +id + + [INTEGER] + NOT NULL + +repository_info + + [VARCHAR] _check_facts--_provenance_derived_repo_check - -1 -1 - - - -_provenance_l3_check - -_provenance_l3_check - -id - - [INTEGER] - NOT NULL - - - -_check_facts--_provenance_l3_check - -1 -1 + +1 +1 - + _provenance_verified_check - -_provenance_verified_check - -id - - [INTEGER] - NOT NULL - -build_level - - [INTEGER] - NOT NULL - -build_type - - [VARCHAR] + +_provenance_verified_check + +id + + [INTEGER] + NOT NULL + +build_level + + [INTEGER] + NOT NULL + +build_type + + [VARCHAR] - + _check_facts--_provenance_verified_check - -1 -1 + +1 +1 - + _provenance_witness_l1_check - -_provenance_witness_l1_check - -id - - [INTEGER] - NOT NULL - -artifact_url - - [VARCHAR] - -provenance_name - - [VARCHAR] - NOT NULL - -provenance_url - - [VARCHAR] + +_provenance_witness_l1_check + +id + + [INTEGER] + NOT NULL + +artifact_url + + [VARCHAR] + +provenance_name + + [VARCHAR] + NOT NULL + +provenance_url + + [VARCHAR] - + _check_facts--_provenance_witness_l1_check - -1 -1 + +1 +1 - + _scm_authenticity_check - -_scm_authenticity_check - -id - - [INTEGER] - NOT NULL - -build_tool - - [VARCHAR] - NOT NULL - -fork_count - - [INTEGER] - -reason - - [VARCHAR] - NOT NULL - -repo_link - - [VARCHAR] - -stars_count - - [INTEGER] - -status - - [VARCHAR] - NOT NULL + +_scm_authenticity_check + +id + + [INTEGER] + NOT NULL + +build_tool + + [VARCHAR] + NOT NULL + +fork_count + + [INTEGER] + +reason + + [VARCHAR] + NOT NULL + +repo_link + + [VARCHAR] + +stars_count + + [INTEGER] + +status + + [VARCHAR] + NOT NULL - + _check_facts--_scm_authenticity_check - -1 -1 + +1 +1 - + _trusted_builder_check - -_trusted_builder_check - -id - - [INTEGER] - NOT NULL - -build_tool_name - - [VARCHAR] - NOT NULL - -build_trigger - - [VARCHAR] - -ci_service_name - - [VARCHAR] - NOT NULL + +_trusted_builder_check + +id + + [INTEGER] + NOT NULL + +build_tool_name + + [VARCHAR] + NOT NULL + +build_trigger + + [VARCHAR] + +ci_service_name + + [VARCHAR] + NOT NULL - + _check_facts--_trusted_builder_check - -1 -1 + +1 +1 - + _vcs_check - -_vcs_check - -id - - [INTEGER] - NOT NULL - -git_repo - - [VARCHAR] + +_vcs_check + +id + + [INTEGER] + NOT NULL + +git_repo + + [VARCHAR] - + _check_facts--_vcs_check - -1 -1 + +1 +1 - + _check_result--_check_facts - -0..N -1 + +0..N +1 - + _release_artifact - -_release_artifact - -id - - [INTEGER] - NOT NULL - -name - - [VARCHAR] - NOT NULL - -provenance_id - - [INTEGER] - -slsa_verified - - [BOOLEAN] + +_release_artifact + +id + + [INTEGER] + NOT NULL + +name + + [VARCHAR] + NOT NULL + +provenance_id + + [INTEGER] + +slsa_verified + + [BOOLEAN] - + _provenance--_release_artifact - -0..N -{0,1} + +0..N +{0,1} - + _hash_digest - -_hash_digest - -id - - [INTEGER] - NOT NULL - -artifact_id - - [INTEGER] - NOT NULL - -digest - - [VARCHAR] - NOT NULL - -digest_algorithm - - [VARCHAR] - NOT NULL + +_hash_digest + +id + + [INTEGER] + NOT NULL + +artifact_id + + [INTEGER] + NOT NULL + +digest + + [VARCHAR] + NOT NULL + +digest_algorithm + + [VARCHAR] + NOT NULL - + _release_artifact--_hash_digest - -0..N -1 + +0..N +1 diff --git a/src/macaron/database/table_definitions.py b/src/macaron/database/table_definitions.py index 2a7f1e95a..d91d55154 100644 --- a/src/macaron/database/table_definitions.py +++ b/src/macaron/database/table_definitions.py @@ -511,6 +511,12 @@ class Provenance(ORMBase): #: The provenance payload. provenance_payload: Mapped[InTotoPayload] = mapped_column(ProvenancePayload, nullable=False) + #: The name of the provenance asset. + provenance_asset_name: Mapped[str] = mapped_column(String, nullable=True) + + #: The URL of the provenance asset. + provenance_asset_url: Mapped[str] = mapped_column(String, nullable=True) + #: The verified status of the provenance. verified: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) diff --git a/src/macaron/provenance/provenance_finder.py b/src/macaron/provenance/provenance_finder.py index b02423eec..caf9a13fa 100644 --- a/src/macaron/provenance/provenance_finder.py +++ b/src/macaron/provenance/provenance_finder.py @@ -5,6 +5,7 @@ import logging import os import tempfile +from dataclasses import dataclass from functools import partial from packageurl import PackageURL @@ -28,6 +29,15 @@ logger: logging.Logger = logging.getLogger(__name__) +@dataclass(frozen=True) +class ProvenanceAsset: + """This class exists to hold a provenance payload with the original asset's name and URL.""" + + payload: InTotoPayload + name: str + url: str + + class ProvenanceFinder: """This class is used to find and retrieve provenance files from supported registries.""" @@ -42,7 +52,7 @@ def __init__(self) -> None: elif isinstance(registry, JFrogMavenRegistry): self.jfrog_registry = registry - def find_provenance(self, purl: PackageURL) -> list[InTotoPayload]: + def find_provenance(self, purl: PackageURL) -> list[ProvenanceAsset]: """Find the provenance file(s) of the passed PURL. Parameters @@ -52,8 +62,8 @@ def find_provenance(self, purl: PackageURL) -> list[InTotoPayload]: Returns ------- - list[InTotoPayload] - The provenance payload, or an empty list if not found. + list[ProvenanceAsset] + The provenance asset, or an empty list if not found. """ logger.debug("Seeking provenance of: %s", purl) @@ -82,7 +92,7 @@ def find_provenance(self, purl: PackageURL) -> list[InTotoPayload]: logger.debug("Provenance finding not supported for PURL type: %s", purl.type) return [] - def _find_provenance(self, discovery_functions: list[partial[list[InTotoPayload]]]) -> list[InTotoPayload]: + def _find_provenance(self, discovery_functions: list[partial[list[ProvenanceAsset]]]) -> list[ProvenanceAsset]: """Find the provenance file(s) using the passed discovery functions. Parameters @@ -93,7 +103,7 @@ def _find_provenance(self, discovery_functions: list[partial[list[InTotoPayload] Returns ------- list[InTotoPayload] - The provenance payload(s) from the first successful function, or an empty list if none were. + The provenance asset(s) from the first successful function, or an empty list if none were. """ if not discovery_functions: return [] @@ -108,7 +118,7 @@ def _find_provenance(self, discovery_functions: list[partial[list[InTotoPayload] return [] -def find_npm_provenance(purl: PackageURL, registry: NPMRegistry) -> list[InTotoPayload]: +def find_npm_provenance(purl: PackageURL, registry: NPMRegistry) -> list[ProvenanceAsset]: """Find and download the NPM based provenance for the passed PURL. Two kinds of attestation can be retrieved from npm: "Provenance" and "Publish". The "Provenance" attestation @@ -125,8 +135,8 @@ def find_npm_provenance(purl: PackageURL, registry: NPMRegistry) -> list[InTotoP Returns ------- - list[InTotoPayload] - The provenance payload(s), or an empty list if not found. + list[ProvenanceAsset] + The provenance asset(s), or an empty list if not found. """ if not registry.enabled: logger.debug("The npm registry is not enabled.") @@ -172,16 +182,19 @@ def find_npm_provenance(purl: PackageURL, registry: NPMRegistry) -> list[InTotoP publish_payload = load_provenance_payload(signed_download_path) except LoadIntotoAttestationError as error: logger.error("Error while loading publish attestation: %s", error) - return [provenance_payload] + return [ProvenanceAsset(provenance_payload, npm_provenance_asset.name, npm_provenance_asset.url)] - return [provenance_payload, publish_payload] + return [ + ProvenanceAsset(provenance_payload, npm_provenance_asset.name, npm_provenance_asset.url), + ProvenanceAsset(publish_payload, npm_provenance_asset.name, npm_provenance_asset.url), + ] except OSError as error: logger.error("Error while storing provenance in the temporary directory: %s", error) return [] -def find_gav_provenance(purl: PackageURL, registry: JFrogMavenRegistry) -> list[InTotoPayload]: +def find_gav_provenance(purl: PackageURL, registry: JFrogMavenRegistry) -> list[ProvenanceAsset]: """Find and download the GAV based provenance for the passed PURL. Parameters @@ -193,8 +206,8 @@ def find_gav_provenance(purl: PackageURL, registry: JFrogMavenRegistry) -> list[ Returns ------- - list[InTotoPayload] | None - The provenance payload if found, or an empty list otherwise. + list[ProvenanceAsset] | None + The provenance asset if found, or an empty list otherwise. Raises ------ @@ -263,7 +276,7 @@ def find_gav_provenance(purl: PackageURL, registry: JFrogMavenRegistry) -> list[ if not is_witness_provenance_payload(provenance_payload, witness_verifier_config.predicate_types): continue - provenances.append(provenance_payload) + provenances.append(ProvenanceAsset(provenance_payload, provenance_asset.name, provenance_asset.url)) except OSError as error: logger.error("Error while storing provenance in the temporary directory: %s", error) @@ -277,7 +290,7 @@ def find_gav_provenance(purl: PackageURL, registry: JFrogMavenRegistry) -> list[ def find_provenance_from_ci( analyze_ctx: AnalyzeContext, git_obj: Git | None, download_path: str -) -> InTotoPayload | None: +) -> ProvenanceAsset | None: """Try to find provenance from CI services of the repository. Note that we stop going through the CI services once we encounter a CI service @@ -372,7 +385,10 @@ def find_provenance_from_ci( download_provenances_from_ci_service(ci_info, download_path) # TODO consider how to handle multiple payloads here. - return ci_info["provenances"][0].payload if ci_info["provenances"] else None + if ci_info["provenances"]: + provenance = ci_info["provenances"][0] + return ProvenanceAsset(provenance.payload, provenance.asset.name, provenance.asset.url) + return None else: logger.debug("CI service not supported for provenance finding: %s", ci_service.name) diff --git a/src/macaron/provenance/provenance_verifier.py b/src/macaron/provenance/provenance_verifier.py index 18e090f0c..eda92171a 100644 --- a/src/macaron/provenance/provenance_verifier.py +++ b/src/macaron/provenance/provenance_verifier.py @@ -17,6 +17,7 @@ from macaron.config.defaults import defaults from macaron.config.global_config import global_config from macaron.provenance.provenance_extractor import ProvenancePredicate, SLSAGithubGenericBuildDefinitionV01 +from macaron.provenance.provenance_finder import ProvenanceAsset from macaron.repo_finder.commit_finder import AbstractPurlType, determine_abstract_purl_type from macaron.slsa_analyzer.analyze_context import AnalyzeContext from macaron.slsa_analyzer.asset import AssetLocator @@ -28,15 +29,15 @@ logger: logging.Logger = logging.getLogger(__name__) -def verify_provenance(purl: PackageURL, provenance: list[InTotoPayload]) -> bool: +def verify_provenance(purl: PackageURL, provenance_assets: list[ProvenanceAsset]) -> bool: """Verify the passed provenance. Parameters ---------- purl: PackageURL The PURL of the analysis target. - provenance: list[InTotoPayload] - The list of provenance. + provenance_assets: list[ProvenanceAsset] + The list of provenance assets. Returns ------- @@ -50,7 +51,7 @@ def verify_provenance(purl: PackageURL, provenance: list[InTotoPayload]) -> bool verification_function = None if purl.type == "npm": - verification_function = partial(verify_npm_provenance, purl, provenance) + verification_function = partial(verify_npm_provenance, purl, provenance_assets) # TODO other verification functions go here. @@ -61,30 +62,33 @@ def verify_provenance(purl: PackageURL, provenance: list[InTotoPayload]) -> bool return False -def verify_npm_provenance(purl: PackageURL, provenance: list[InTotoPayload]) -> bool: +def verify_npm_provenance(purl: PackageURL, provenance_assets: list[ProvenanceAsset]) -> bool: """Compare the unsigned payload subject digest with the signed payload digest, if available. Parameters ---------- purl: PackageURL The PURL of the analysis target. - provenance: list[InTotoPayload] - The provenances to verify. + provenance_assets: list[ProvenanceAsset] + The provenance assets to verify. Returns ------- bool True if the provenance was verified, or False otherwise. """ - if len(provenance) != 2: - logger.debug("Expected unsigned and signed provenance.") + if len(provenance_assets) != 2: + logger.debug("Expected unsigned and signed provenance assets.") return False - signed_subjects = provenance[1].statement.get("subject") + signed_provenance = provenance_assets[1].payload + unsigned_provenance = provenance_assets[0].payload + + signed_subjects = signed_provenance.statement.get("subject") if not signed_subjects: return False - unsigned_subjects = provenance[0].statement.get("subject") + unsigned_subjects = unsigned_provenance.statement.get("subject") if not unsigned_subjects: return False diff --git a/src/macaron/slsa_analyzer/analyzer.py b/src/macaron/slsa_analyzer/analyzer.py index d17567110..30b77b599 100644 --- a/src/macaron/slsa_analyzer/analyzer.py +++ b/src/macaron/slsa_analyzer/analyzer.py @@ -354,12 +354,14 @@ def run_single( ) provenance_is_verified = False + provenance_asset = None if not provenance_payload and parsed_purl: # Try to find the provenance file for the parsed PURL. provenance_finder = ProvenanceFinder() provenances = provenance_finder.find_provenance(parsed_purl) if provenances: - provenance_payload = provenances[0] + provenance_asset = provenances[0] + provenance_payload = provenance_asset.payload if verify_provenance: provenance_is_verified = provenance_verifier.verify_provenance(parsed_purl, provenances) @@ -480,10 +482,11 @@ def run_single( if not provenance_payload: # Look for provenance using the CI. with tempfile.TemporaryDirectory() as temp_dir: - provenance_payload = find_provenance_from_ci(analyze_ctx, git_obj, temp_dir) + provenance_asset = find_provenance_from_ci(analyze_ctx, git_obj, temp_dir) # If found, validate analysis target against new provenance. - if provenance_payload: + if provenance_asset: # If repository URL was not provided as input, check the one found during analysis. + provenance_payload = provenance_asset.payload if not repo_path_input and component.repository: repo_path_input = component.repository.remote_path provenance_repo_url = provenance_commit_digest = None @@ -528,6 +531,8 @@ def run_single( provenance_payload=provenance_payload, slsa_level=slsa_level, slsa_version=slsa_version, + provenance_asset_name=provenance_asset.name if provenance_asset else None, + provenance_asset_url=provenance_asset.url if provenance_asset else None, # TODO Add release tag, release digest. ) diff --git a/src/macaron/slsa_analyzer/checks/provenance_available_check.py b/src/macaron/slsa_analyzer/checks/provenance_available_check.py index 77fcf87fe..1da852955 100644 --- a/src/macaron/slsa_analyzer/checks/provenance_available_check.py +++ b/src/macaron/slsa_analyzer/checks/provenance_available_check.py @@ -74,18 +74,31 @@ def run_check(self, ctx: AnalyzeContext) -> CheckResultData: CheckResultData The result of the check. """ - available = ( - ctx.dynamic_data["provenance_info"] - and ctx.dynamic_data["provenance_info"].provenance_payload - and not ctx.dynamic_data["is_inferred_prov"] - ) + provenance_info = None + inferred = False + if ctx.dynamic_data["provenance_info"]: + provenance_info = ctx.dynamic_data["provenance_info"] + inferred = ctx.dynamic_data["is_inferred_prov"] + + if not provenance_info or not provenance_info.provenance_payload or inferred: + return CheckResultData( + result_tables=[ + ProvenanceAvailableFacts( + confidence=Confidence.HIGH, + ) + ], + result_type=CheckResultType.FAILED, + ) + return CheckResultData( result_tables=[ ProvenanceAvailableFacts( confidence=Confidence.HIGH, + asset_name=provenance_info.provenance_asset_name, + asset_url=provenance_info.provenance_asset_url, ) ], - result_type=CheckResultType.PASSED if available else CheckResultType.FAILED, + result_type=CheckResultType.PASSED, )