diff --git a/src/macaron/database/table_definitions.py b/src/macaron/database/table_definitions.py index 61c90da2e..5f0e5593d 100644 --- a/src/macaron/database/table_definitions.py +++ b/src/macaron/database/table_definitions.py @@ -34,7 +34,7 @@ from macaron.artifact.maven import MavenSubjectPURLMatcher from macaron.database.database_manager import ORMBase -from macaron.database.db_custom_types import RFC3339DateTime +from macaron.database.db_custom_types import DBJsonDict, RFC3339DateTime from macaron.errors import InvalidPURLError from macaron.slsa_analyzer.provenance.intoto import InTotoPayload, ProvenanceSubjectPURLMatcher from macaron.slsa_analyzer.slsa_req import ReqName @@ -161,7 +161,7 @@ class Component(PackageURLMixin, ORMBase): checkfacts: Mapped[list["CheckFacts"]] = relationship(back_populates="component", lazy="immediate") #: The one-to-many relationship with provenances. - provenance: Mapped[list["Provenance"]] = relationship(back_populates="component", lazy="immediate") + provenance: Mapped[list["ProvenanceFacts"]] = relationship(back_populates="component", lazy="immediate") #: The bidirectional many-to-many relationship for component dependencies. dependencies: Mapped[list["Component"]] = relationship( @@ -464,7 +464,7 @@ class CheckFacts(ORMBase): } -class Provenance(ORMBase): +class ProvenanceFacts(ORMBase): """ORM class for a provenance document.""" __tablename__ = "_provenance" @@ -479,7 +479,7 @@ class Provenance(ORMBase): component: Mapped["Component"] = relationship(back_populates="provenance") #: The SLSA version. - version: Mapped[str] = mapped_column(String, nullable=False) + version: Mapped[str] = mapped_column(String, nullable=True) #: The release tag commit sha. release_commit_sha: Mapped[str] = mapped_column(String, nullable=True) @@ -488,12 +488,189 @@ class Provenance(ORMBase): release_tag: Mapped[str] = mapped_column(String, nullable=True) #: The provenance payload content in JSON format. - provenance_json: Mapped[str] = mapped_column(String, nullable=False) + provenance_json: Mapped[dict] = mapped_column(DBJsonDict, nullable=False) + + #: The provenance statement. + statement: Mapped["Statement"] = relationship(back_populates="provenance") #: A one-to-many relationship with the release artifacts. artifact: Mapped[list["ReleaseArtifact"]] = relationship(back_populates="provenance") +class Statement(ORMBase): + """The ORM class for provenance statement.""" + + __tablename__ = "_statement" + + #: The primary key. + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003 + + #: The foreign key to the software component. + provenance_id: Mapped[int] = mapped_column(Integer, ForeignKey(ProvenanceFacts.id), nullable=False) + + #: A one-to-one relationship with software components. + provenance: Mapped["ProvenanceFacts"] = relationship(back_populates="statement") + + #: Statement type. + _type: Mapped[str] = mapped_column(String, nullable=False) + + #: Predicate Type. + predicate_type: Mapped[str] = mapped_column(String, nullable=False) + + #: Provenance Subjects. + subject: Mapped[list["ProvenanceSubjectRaw"]] = relationship(back_populates="statement") + + #: Provenance predicate. + predicate: Mapped["Predicate"] = relationship(back_populates="statement") + + +class ProvenanceSubjectRaw(ORMBase): + """The ORM class for the provenance subject containing all the information.""" + + __tablename__ = "_subject" + + #: The primary key. + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003 + + #: The foreign key to the software component. + statement_id: Mapped[int] = mapped_column(Integer, ForeignKey(Statement.id), nullable=False) + + #: A one-to-one relationship with provenance statement. + statement: Mapped["Statement"] = relationship(back_populates="subject") + + #: Subject name. + name: Mapped[str] = mapped_column(String, nullable=False) + + #: Subject digests. + digest: Mapped["SubjectDigest"] = relationship(back_populates="subject") + + +class SubjectDigest(ORMBase): + """The ORM class for the provenance subject digest.""" + + __tablename__ = "_subject_digest" + + #: The primary key. + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003 + + #: The foreign key to the provenance subject. + subject_id: Mapped[int] = mapped_column(Integer, ForeignKey(ProvenanceSubjectRaw.id), nullable=False) + + #: A one-to-one relationship with provenance subject. + subject: Mapped["ProvenanceSubjectRaw"] = relationship(back_populates="digest") + + #: Digest. + sha512: Mapped[str] = mapped_column(String, nullable=False) + + +class Predicate(ORMBase): + """The ORM class for provenance predicate.""" + + __tablename__ = "_predicate" + + #: The primary key. + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003 + + #: The foreign key to the software component. + statement_id: Mapped[int] = mapped_column(Integer, ForeignKey(Statement.id), nullable=False) + + #: A one-to-one relationship with provenance statement. + statement: Mapped["Statement"] = relationship(back_populates="predicate") + + #: Build definition. + build_definition: Mapped["BuildDefinition"] = relationship(back_populates="predicate") + + +class BuildDefinition(ORMBase): + """The ORM class for provenance predicate build definition.""" + + __tablename__ = "_build_definition" + + #: The primary key. + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003 + + #: The foreign key to the software component. + predicate_id: Mapped[int] = mapped_column(Integer, ForeignKey(Predicate.id), nullable=False) + + #: A one-to-one relationship with provenance predicate. + predicate: Mapped["Predicate"] = relationship(back_populates="build_definition") + + #: Build type. + build_type: Mapped[str] = mapped_column(String, nullable=False) + + #: External parameters in build definitions. + external_parameters: Mapped["ExternalParameters"] = relationship(back_populates="build_definition") + + #: Internal parameters in build definitions. + internal_parameters: Mapped["InternalParameters"] = relationship(back_populates="build_definition") + + +class ExternalParameters(ORMBase): + """The ORM class for provenance predicate build definition external parameters.""" + + __tablename__ = "_external_parameters" + + #: The primary key. + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003 + + #: The foreign key to the software component. + build_definition_id: Mapped[int] = mapped_column(Integer, ForeignKey(BuildDefinition.id), nullable=False) + + #: A one-to-one relationship with build definition. + build_definition: Mapped["BuildDefinition"] = relationship(back_populates="external_parameters") + + #: External parameters in build definitions. + workflow: Mapped["Workflow"] = relationship(back_populates="external_parameters") + + +class Workflow(ORMBase): + """The ORM class for provenance predicate build definition external parameters workflows.""" + + __tablename__ = "_workflow" + + #: The primary key. + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003 + + #: The foreign key to the software component. + external_parameters_id: Mapped[int] = mapped_column(Integer, ForeignKey(ExternalParameters.id), nullable=False) + + #: A one-to-one relationship with external_parameters. + external_parameters: Mapped["ExternalParameters"] = relationship(back_populates="workflow") + + #: Workflow reference. + ref: Mapped[str] = mapped_column(String, nullable=False) + + #: Workflow repository. + repository: Mapped[str] = mapped_column(String, nullable=False) + + #: Workflow path. + path: Mapped[str] = mapped_column(String, nullable=False) + + +class InternalParameters(ORMBase): + """The ORM class for provenance predicate build definition internal parameters.""" + + __tablename__ = "_internal_parameters" + + #: The primary key. + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003 + + #: The foreign key to the software component. + build_definition_id: Mapped[int] = mapped_column(Integer, ForeignKey(BuildDefinition.id), nullable=False) + + #: A one-to-one relationship with build definition. + build_definition: Mapped["BuildDefinition"] = relationship(back_populates="internal_parameters") + + #: The GitHub event that triggered the publish. + github_event_name: Mapped[str] = mapped_column(String, nullable=False) + + #: The GitHub repository ID that triggered the publish. + github_repository_id: Mapped[str] = mapped_column(String, nullable=False) + + #: The GitHub repository owner ID that triggered the publish. + github_repository_owner_id: Mapped[str] = mapped_column(String, nullable=False) + + class ReleaseArtifact(ORMBase): """The ORM class for release artifacts.""" @@ -509,10 +686,10 @@ class ReleaseArtifact(ORMBase): slsa_verified: Mapped[bool] = mapped_column(Boolean, nullable=True) #: The foreign key to the SLSA provenance. - provenance_id: Mapped[int] = mapped_column(Integer, ForeignKey(Provenance.id), nullable=True) + provenance_id: Mapped[int] = mapped_column(Integer, ForeignKey(ProvenanceFacts.id), nullable=True) #: A many-to-one relationship with the SLSA provenance. - provenance: Mapped["Provenance"] = relationship(back_populates="artifact") + provenance: Mapped["ProvenanceFacts"] = relationship(back_populates="artifact") #: The one-to-many relationship with the hash digests for this artifact. digests: Mapped[list["HashDigest"]] = relationship(back_populates="artifact") diff --git a/src/macaron/policy_engine/prelude/intoto_policies.dl b/src/macaron/policy_engine/prelude/intoto_policies.dl new file mode 100644 index 000000000..0b4864d3a --- /dev/null +++ b/src/macaron/policy_engine/prelude/intoto_policies.dl @@ -0,0 +1,90 @@ +/* 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/. */ + +/* Souffle datalog rules to assist in authoring in-toto policies.*/ + +/** + * This relation provides the external parameters of a SLSA v1 provenance generated by npm. + The external parameters include details of the triggering hosted build service workflow. + + Here is the related section of an example predicate we process in this relation: + "externalParameters": { + "workflow": { + "ref": "refs/heads/main", + "repository": "https://github.com/npm/node-semver", + "path": ".github/workflows/release.yml" + } + }, + + Parameters: + component_id: number + The target software component id. + purl: symbol + The Package URL identifier for the provenance subject. + ref: symbol + The Git reference. + repository: symbol + The repository URL. + path: symbol + The GitHub Actions workflow path. + + */ +.decl slsa_v1_npm_external_parameters(component_id: number, purl: symbol, ref: symbol, repository: symbol, path: symbol) + +slsa_v1_npm_external_parameters(component_id, purl, ref, repository, path):- + provenance(prov_id, component_id, _, _, _, _), + statement(stmt_id, prov_id, "https://in-toto.io/Statement/v1", "https://slsa.dev/provenance/v1"), + subject(sub_id, stmt_id, purl), + predicate(pred_id, stmt_id), + build_definition(build_id, pred_id, _), + external_parameters(external_params_id, build_id), + workflow(_, external_params_id, ref, repository, path). + +/** + * This relation provides the external parameters of a SLSA v1 provenance generated by npm. + The external parameters include details of the triggering hosted build service workflow. + + Here is the related section of an example predicate we process in this relation: + "internalParameters": { + "github": { + "event_name": "push", + "repository_id": "1357199", + "repository_owner_id": "6078720" + } + }, + + + Parameters: + component_id: number + The target software component id. + purl: symbol + The Package URL identifier for the provenance subject. + github_event_name: symbol + TODO + github_repository_id: symbol + TODO + github_repository_owner_id: symbol + TODO + + */ +.decl slsa_v1_npm_internal_parameters( + component_id: number, + purl: symbol, + github_event_name: symbol, + github_repository_id: symbol, + github_repository_owner_id: symbol +) + +slsa_v1_npm_internal_parameters( + component_id, + purl, + github_event_name, + github_repository_id, + github_repository_owner_id +):- + provenance(prov_id, component_id, _, _, _, _), + statement(stmt_id, prov_id, "https://in-toto.io/Statement/v1", "https://slsa.dev/provenance/v1"), + subject(sub_id, stmt_id, purl), + predicate(pred_id, stmt_id), + build_definition(build_id, pred_id, _), + internal_parameters(_, build_id, github_event_name, github_repository_id, github_repository_owner_id). diff --git a/src/macaron/policy_engine/prelude/prelude.dl b/src/macaron/policy_engine/prelude/prelude.dl index aa5e0d464..7f71057d6 100644 --- a/src/macaron/policy_engine/prelude/prelude.dl +++ b/src/macaron/policy_engine/prelude/prelude.dl @@ -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/. */ /** @@ -13,6 +13,7 @@ #include "helper_rules.dl" #include "policy.dl" #include "aggregate_rules.dl" +#include "intoto_policies.dl" /* The fact import statements generated by the policy engine */ #include "import_data.dl" diff --git a/src/macaron/resources/policies/generic/npm_attestation.dl b/src/macaron/resources/policies/generic/npm_attestation.dl new file mode 100644 index 000000000..fb54fba30 --- /dev/null +++ b/src/macaron/resources/policies/generic/npm_attestation.dl @@ -0,0 +1,53 @@ +/* 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/. */ + +#include "prelude.dl" + +Policy("test_policy", component_id, "") :- + // Checks if the npm attestation has been successfully processed. + check_passed(component_id, "mcn_npm_attestation_validation_1"), + // This relation provides the external parameters of a SLSA v1 provenance generated by npm. + slsa_v1_npm_external_parameters(component_id, purl, ref, repository, path), + // This relation provides the internal parameters of a SLSA v1 provenance generated by npm. + slsa_v1_npm_internal_parameters(component_id, purl, event_name, repository_id, repository_owner_id), + // This match constraint makes sure the subjects we are interested in exist in the provenance. + match("pkg:npm/semver@.*", purl), + // Here we can add constraints that we are interested in. + approved_refs(ref), + approved_repository_owner_ids(repository_owner_id), + repository = "https://github.com/npm/node-semver", + path = ".github/workflows/release.yml". + +Policy("test_policy", component_id, "") :- + // Checks if the npm attestation has been successfully processed. + check_passed(component_id, "mcn_npm_attestation_validation_1"), + // Checks if the repository URL in the provenance matches the repository metadata on deps.dev. + check_passed(component_id, "mcn_provenance_derived_repo_1"), + // Checks if the commit hash in the provenance matches the release tag. + check_passed(component_id, "mcn_provenance_derived_commit_1"), + // This relation provides the external parameters of a SLSA v1 provenance generated by npm. + slsa_v1_npm_external_parameters(component_id, purl, ref, repository, path), + // This relation provides the internal parameters of a SLSA v1 provenance generated by npm. + slsa_v1_npm_internal_parameters(component_id, purl, event_name, repository_id, repository_owner_id), + // This match constraint makes sure the subjects we are interested in exist in the provenance. + match("pkg:npm/semver@.*", purl), + // Here we can add constraints that we are interested in. + approved_refs(ref), + approved_repository_owner_ids(repository_owner_id), + path = ".github/workflows/release.yml". + +// Create a relation containing the approved Git branches for publishing the artifact. +.decl approved_refs(name: symbol) + approved_refs("refs/heads/main"). + approved_refs("refs/heads/master"). + approved_refs("refs/heads/release"). + +// Create a relation containing the approved repository owner IDs for publishing the artifact. +.decl approved_repository_owner_ids(name: symbol) + approved_repository_owner_ids("6078720"). + approved_repository_owner_ids("71096353"). + +// Apply the policy to the desired software components. +apply_policy_to("test_policy", component_id) :- + is_component(component_id, purl), + match("pkg:npm/semver@.*", purl). diff --git a/src/macaron/slsa_analyzer/checks/analyze_npm_attestation_check.py b/src/macaron/slsa_analyzer/checks/analyze_npm_attestation_check.py new file mode 100644 index 000000000..114c320da --- /dev/null +++ b/src/macaron/slsa_analyzer/checks/analyze_npm_attestation_check.py @@ -0,0 +1,156 @@ +# 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 VCS check.""" + + +import logging + +from sqlalchemy import ForeignKey +from sqlalchemy.orm import Mapped, mapped_column + +from macaron.database.table_definitions import ( + BuildDefinition, + CheckFacts, + ExternalParameters, + InternalParameters, + Predicate, + ProvenanceFacts, + ProvenanceSubjectRaw, + Statement, + SubjectDigest, + Workflow, +) +from macaron.json_tools import json_extract +from macaron.slsa_analyzer.analyze_context import AnalyzeContext +from macaron.slsa_analyzer.checks.base_check import BaseCheck, CheckResultType +from macaron.slsa_analyzer.checks.check_result import CheckResultData, Confidence +from macaron.slsa_analyzer.registry import registry +from macaron.slsa_analyzer.slsa_req import ReqName + +logger: logging.Logger = logging.getLogger(__name__) + + +class NPMAttestationFacts(CheckFacts): + """The ORM mapping for justifications in the npm attestation analysis check.""" + + __tablename__ = "_npm_attestation_check" + + #: The primary key. + id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003 + + __mapper_args__ = { + "polymorphic_identity": "_npm_attestation_check", + } + + +class NPMAttestationCheck(BaseCheck): + """This Check extracts attestation fields to be used by the policy engine.""" + + def __init__(self) -> None: + """Initialize instance.""" + check_id = "mcn_npm_attestation_validation_1" + description = "Extract attestation fields to be used by the policy engine." + depends_on: list[tuple[str, CheckResultType]] = [] + eval_reqs = [ReqName.PROV_AVAILABLE] + super().__init__(check_id=check_id, description=description, depends_on=depends_on, eval_reqs=eval_reqs) + + def run_check(self, ctx: AnalyzeContext) -> CheckResultData: + """Implement the check in this method. + + Parameters + ---------- + ctx : AnalyzeContext + The object containing processed data for the target repo. + + Returns + ------- + CheckResultData + The result of the check. + """ + payload = ctx.dynamic_data["provenance"] + if not payload or ctx.dynamic_data["is_inferred_prov"]: + logger.debug("Unable to find a provenance for %s.", ctx.component.purl) + return CheckResultData(result_tables=[], result_type=CheckResultType.FAILED) + + # Extract facts from the attestation to store in the database. + prov_facts = ProvenanceFacts() + stmt = payload.statement + if stmt["predicate"] is None: + logger.debug("Unable to validate provenance content for %s.", ctx.component.purl) + return CheckResultData(result_tables=[], result_type=CheckResultType.FAILED) + + workflow_section = json_extract(stmt["predicate"], ["buildDefinition", "externalParameters", "workflow"], dict) + + if workflow_section is None: + logger.debug("Unable to validate provenance content for %s.", ctx.component.purl) + return CheckResultData(result_tables=[], result_type=CheckResultType.FAILED) + + ref = json_extract(workflow_section, ["ref"], str) + repository = json_extract(workflow_section, ["repository"], str) + path = json_extract(workflow_section, ["path"], str) + + if any(param is None for param in (ref, repository, path)): + logger.debug("Unable to validate provenance content for %s.", ctx.component.purl) + return CheckResultData(result_tables=[], result_type=CheckResultType.FAILED) + + workflow = Workflow(ref=ref, repository=repository, path=path) + + external_parameters = ExternalParameters(workflow=workflow) + + internal_params_gh = json_extract(stmt["predicate"], ["buildDefinition", "internalParameters", "github"], dict) + + if internal_params_gh is None: + logger.debug("Unable to validate provenance content for %s.", ctx.component.purl) + return CheckResultData(result_tables=[], result_type=CheckResultType.FAILED) + + event = json_extract(internal_params_gh, ["event_name"], str) + repo_id = json_extract(internal_params_gh, ["repository_id"], str) + repo_owner_id = json_extract(internal_params_gh, ["repository_owner_id"], str) + + if any(param is None for param in (event, repo_id, repo_owner_id)): + logger.debug("Unable to validate provenance content for %s.", ctx.component.purl) + return CheckResultData(result_tables=[], result_type=CheckResultType.FAILED) + + internal_parameters = InternalParameters( + github_event_name=event, github_repository_id=repo_id, github_repository_owner_id=repo_owner_id + ) + + build_type = json_extract(stmt["predicate"], ["buildDefinition", "buildType"], str) + if build_type != "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1": + logger.debug("Unable to validate provenance content for %s.", ctx.component.purl) + return CheckResultData(result_tables=[], result_type=CheckResultType.FAILED) + + predicate = Predicate( + build_definition=BuildDefinition( + build_type=build_type, + external_parameters=external_parameters, + internal_parameters=internal_parameters, + ) + ) + + subjects = [] + for sub in stmt["subject"]: + if (name := sub["name"]) and (sha512 := json_extract(dict(sub), ["digest", "sha512"], str)): + subjects.append(ProvenanceSubjectRaw(name=name, digest=SubjectDigest(sha512=sha512))) + + if not subjects: + logger.debug("Unable to validate provenance content for %s.", ctx.component.purl) + return CheckResultData(result_tables=[], result_type=CheckResultType.FAILED) + + prov_facts.statement = Statement( + _type=stmt["_type"], predicate_type=stmt["predicateType"], subject=subjects, predicate=predicate + ) + + prov_facts.provenance_json = payload.statement["predicate"] or {} + + # Add the provenance facts to the software component provenance to persist the data in the database. + prov_facts.component = ctx.component + + return CheckResultData( + result_tables=[NPMAttestationFacts(confidence=Confidence.HIGH)], + result_type=CheckResultType.PASSED, + ) + + +registry.register(NPMAttestationCheck()) diff --git a/src/macaron/slsa_analyzer/checks/provenance_l3_check.py b/src/macaron/slsa_analyzer/checks/provenance_l3_check.py index e34a4ce0b..7b659e04e 100644 --- a/src/macaron/slsa_analyzer/checks/provenance_l3_check.py +++ b/src/macaron/slsa_analyzer/checks/provenance_l3_check.py @@ -5,7 +5,6 @@ import glob import hashlib -import json import logging import os import subprocess # nosec B404 @@ -22,7 +21,7 @@ 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.database.table_definitions import CheckFacts, HashDigest, ProvenanceFacts, ReleaseArtifact from macaron.slsa_analyzer.analyze_context import AnalyzeContext from macaron.slsa_analyzer.asset import AssetLocator from macaron.slsa_analyzer.checks.base_check import BaseCheck @@ -350,12 +349,12 @@ class Feedback(NamedTuple): downloaded_provs.append(provenance_payload.statement) # Output provenance - prov = Provenance() + prov = ProvenanceFacts() # TODO: fix commit reference for provenance when release/artifact as an analysis entrypoint is # implemented ensure the provenance commit matches the actual release analyzed prov.version = "0.2" prov.release_commit_sha = "" - prov.provenance_json = json.dumps(provenance_payload.statement) + prov.provenance_json = provenance_payload.statement["predicate"] or {} prov.release_tag = ci_info["release"]["tag_name"] prov.component = ctx.component diff --git a/tests/policy_engine/resources/facts/macaron.db.gz b/tests/policy_engine/resources/facts/macaron.db.gz index 0da56da72..276e24574 100644 Binary files a/tests/policy_engine/resources/facts/macaron.db.gz and b/tests/policy_engine/resources/facts/macaron.db.gz differ diff --git a/tests/policy_engine/test_policy.py b/tests/policy_engine/test_policy.py index b38346c22..507bd5af8 100644 --- a/tests/policy_engine/test_policy.py +++ b/tests/policy_engine/test_policy.py @@ -40,7 +40,7 @@ def test_eval_policy(database_setup) -> None: # type: ignore # pylint: disable= "component_satisfies_policy": [ [ "1", - "pkg:github.com/slsa-framework/slsa-verifier@fc50b662fcfeeeb0e97243554b47d9b20b14efac", + "pkg:github.com/slsa-framework/slsa-verifier@v2.6.0", "trusted_builder", ] ], @@ -48,12 +48,12 @@ def test_eval_policy(database_setup) -> None: # type: ignore # pylint: disable= "component_violates_policy": [ [ "1", - "pkg:github.com/slsa-framework/slsa-verifier@fc50b662fcfeeeb0e97243554b47d9b20b14efac", + "pkg:github.com/slsa-framework/slsa-verifier@v2.6.0", "aggregate_l4", ], [ "1", - "pkg:github.com/slsa-framework/slsa-verifier@fc50b662fcfeeeb0e97243554b47d9b20b14efac", + "pkg:github.com/slsa-framework/slsa-verifier@v2.6.0", "aggregate_l2", ], ],