From b0695dbe0fbd1a681ef9d6e36a94aed2a19d9a8d Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 18 Nov 2024 15:16:43 -0500 Subject: [PATCH 1/6] attestations: remove double states, simplify tests Signed-off-by: William Woodruff --- tests/unit/attestations/test_models.py | 9 +-- tests/unit/attestations/test_services.py | 97 +++++++----------------- tests/unit/oidc/models/test_core.py | 4 +- warehouse/attestations/services.py | 58 ++------------ warehouse/oidc/models/_core.py | 10 ++- warehouse/oidc/models/github.py | 9 ++- 6 files changed, 55 insertions(+), 132 deletions(-) diff --git a/tests/unit/attestations/test_models.py b/tests/unit/attestations/test_models.py index 0a1392ff0c57..6d810643297b 100644 --- a/tests/unit/attestations/test_models.py +++ b/tests/unit/attestations/test_models.py @@ -10,19 +10,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -import pretend import pypi_attestations +from tests.common.db.oidc import GitHubPublisherFactory from tests.common.db.packaging import FileFactory def test_provenance_as_model(db_request, integrity_service, dummy_attestation): - db_request.oidc_publisher = pretend.stub( - publisher_name="GitHub", - repository="fake/fake", - workflow_filename="fake.yml", - environment="fake", - ) + db_request.oidc_publisher = GitHubPublisherFactory.create() file = FileFactory.create() provenance = integrity_service.build_provenance( db_request, file, [dummy_attestation] diff --git a/tests/unit/attestations/test_services.py b/tests/unit/attestations/test_services.py index c955aa360a4c..b052b19867c5 100644 --- a/tests/unit/attestations/test_services.py +++ b/tests/unit/attestations/test_services.py @@ -18,15 +18,18 @@ from pypi_attestations import ( Attestation, AttestationType, - GitHubPublisher, - GitLabPublisher, Provenance, VerificationError, ) from sigstore.verify import Verifier from zope.interface.verify import verifyClass -from tests.common.db.oidc import GitHubPublisherFactory, GitLabPublisherFactory +from tests.common.db.oidc import ( + ActiveStatePublisherFactory, + GitHubPublisherFactory, + GitLabPublisherFactory, + GooglePublisherFactory, +) from tests.common.db.packaging import FileFactory from warehouse.attestations import IIntegrityService, services from warehouse.attestations.errors import AttestationUploadError @@ -38,12 +41,7 @@ def test_interface_matches(self): assert verifyClass(IIntegrityService, services.NullIntegrityService) def test_build_provenance(self, db_request, dummy_attestation): - db_request.oidc_publisher = pretend.stub( - publisher_name="GitHub", - repository="fake/fake", - workflow_filename="fake.yml", - environment="fake", - ) + db_request.oidc_publisher = GitHubPublisherFactory.create() file = FileFactory.create() service = services.NullIntegrityService.create_service(None, db_request) @@ -88,16 +86,27 @@ def test_parse_attestations_fails_no_publisher(self, db_request): ): integrity_service.parse_attestations(db_request, pretend.stub()) - def test_parse_attestations_fails_unsupported_publisher(self, db_request): + @pytest.mark.parametrize( + "publisher_factory", + [ + GitLabPublisherFactory, + GooglePublisherFactory, + ActiveStatePublisherFactory, + ], + ) + def test_parse_attestations_fails_unsupported_publisher( + self, db_request, publisher_factory + ): integrity_service = services.IntegrityService( metrics=pretend.stub(), session=db_request.db ) - db_request.oidc_publisher = pretend.stub( - supports_attestations=False, publisher_name="fake" - ) + db_request.oidc_publisher = publisher_factory.create() with pytest.raises( AttestationUploadError, - match="Attestations are not currently supported with fake publishers", + match=( + "Attestations are not currently supported with " + f"{db_request.oidc_publisher.publisher_name} publishers" + ), ): integrity_service.parse_attestations(db_request, pretend.stub()) @@ -107,7 +116,7 @@ def test_parse_attestations_fails_malformed_attestation(self, metrics, db_reques session=db_request.db, ) - db_request.oidc_publisher = pretend.stub(supports_attestations=True) + db_request.oidc_publisher = pretend.stub(attestation_identity=pretend.stub()) db_request.POST["attestations"] = "{'malformed-attestation'}" with pytest.raises( AttestationUploadError, @@ -128,7 +137,7 @@ def test_parse_attestations_fails_multiple_attestations( session=db_request.db, ) - db_request.oidc_publisher = pretend.stub(supports_attestations=True) + db_request.oidc_publisher = pretend.stub(attestation_identity=pretend.stub()) db_request.POST["attestations"] = TypeAdapter(list[Attestation]).dump_json( [dummy_attestation, dummy_attestation] ) @@ -173,7 +182,7 @@ def test_parse_attestations_fails_verification( ) db_request.oidc_publisher = pretend.stub( - supports_attestations=True, + attestation_identity=pretend.stub(), publisher_verification_policy=pretend.call_recorder(lambda c: None), ) db_request.oidc_claims = {"sha": "somesha"} @@ -204,7 +213,7 @@ def test_parse_attestations_fails_wrong_predicate( session=db_request.db, ) db_request.oidc_publisher = pretend.stub( - supports_attestations=True, + attestation_identity=pretend.stub(), publisher_verification_policy=pretend.call_recorder(lambda c: None), ) db_request.oidc_claims = {"sha": "somesha"} @@ -240,7 +249,7 @@ def test_parse_attestations_succeeds( session=db_request.db, ) db_request.oidc_publisher = pretend.stub( - supports_attestations=True, + attestation_identity=pretend.stub(), publisher_verification_policy=pretend.call_recorder(lambda c: None), ) db_request.oidc_claims = {"sha": "somesha"} @@ -259,31 +268,9 @@ def test_parse_attestations_succeeds( ) assert attestations == [dummy_attestation] - def test_build_provenance_fails_unsupported_publisher( - self, metrics, db_request, dummy_attestation - ): - integrity_service = services.IntegrityService( - metrics=metrics, - session=db_request.db, - ) - - db_request.oidc_publisher = pretend.stub(publisher_name="not-existing") - - file = FileFactory.create() - with pytest.raises(AttestationUploadError, match="Unsupported publisher"): - integrity_service.build_provenance(db_request, file, [dummy_attestation]) - - # If building provenance fails, nothing is stored or associated with the file - assert not file.provenance - - assert metrics.increment.calls == [] - @pytest.mark.parametrize( "publisher_factory", - [ - GitHubPublisherFactory, - GitLabPublisherFactory, - ], + [GitHubPublisherFactory], ) def test_build_provenance_succeeds( self, metrics, db_request, publisher_factory, dummy_attestation @@ -311,32 +298,6 @@ def test_build_provenance_succeeds( ] -def test_publisher_from_oidc_publisher_succeeds_github(db_request): - publisher = GitHubPublisherFactory.create() - - attestation_publisher = services._publisher_from_oidc_publisher(publisher) - assert isinstance(attestation_publisher, GitHubPublisher) - assert attestation_publisher.repository == publisher.repository - assert attestation_publisher.workflow == publisher.workflow_filename - assert attestation_publisher.environment == publisher.environment - - -def test_publisher_from_oidc_publisher_succeeds_gitlab(db_request): - publisher = GitLabPublisherFactory.create() - - attestation_publisher = services._publisher_from_oidc_publisher(publisher) - assert isinstance(attestation_publisher, GitLabPublisher) - assert attestation_publisher.repository == publisher.project_path - assert attestation_publisher.environment == publisher.environment - - -def test_publisher_from_oidc_publisher_fails_unsupported(): - publisher = pretend.stub(publisher_name="not-existing") - - with pytest.raises(AttestationUploadError): - services._publisher_from_oidc_publisher(publisher) - - def test_extract_attestations_from_request_empty_list(db_request): db_request.oidc_publisher = GitHubPublisherFactory.create() db_request.POST = {"attestations": json.dumps([])} diff --git a/tests/unit/oidc/models/test_core.py b/tests/unit/oidc/models/test_core.py index 482f2b40a8a4..0832e4dddd9c 100644 --- a/tests/unit/oidc/models/test_core.py +++ b/tests/unit/oidc/models/test_core.py @@ -54,9 +54,9 @@ def test_oidc_publisher_not_default_verifiable(self): publisher.check_claims_existence(signed_claims={}) assert str(e.value) == "No required verifiable claims" - def test_supports_attestations(self): + def test_attestation_identity(self): publisher = _core.OIDCPublisher(projects=[]) - assert not publisher.supports_attestations + assert not publisher.attestation_identity @pytest.mark.parametrize( ("url", "publisher_url", "expected"), diff --git a/warehouse/attestations/services.py b/warehouse/attestations/services.py index b4b10bb9d6a3..721b992b9026 100644 --- a/warehouse/attestations/services.py +++ b/warehouse/attestations/services.py @@ -23,10 +23,7 @@ AttestationBundle, AttestationType, Distribution, - GitHubPublisher, - GitLabPublisher, Provenance, - Publisher, VerificationError, ) from pyramid.request import Request @@ -36,53 +33,17 @@ from warehouse.attestations.interfaces import IIntegrityService from warehouse.attestations.models import Provenance as DatabaseProvenance from warehouse.metrics.interfaces import IMetricsService -from warehouse.oidc.models import ( - GitHubPublisher as GitHubOIDCPublisher, - GitLabPublisher as GitLabOIDCPublisher, - OIDCPublisher, -) from warehouse.utils.exceptions import InsecureIntegrityServiceWarning if typing.TYPE_CHECKING: from warehouse.packaging.models import File -def _publisher_from_oidc_publisher(publisher: OIDCPublisher) -> Publisher: - """ - Convert an OIDCPublisher object in a pypi-attestations Publisher. - """ - match publisher.publisher_name: - case "GitLab": - publisher = typing.cast(GitLabOIDCPublisher, publisher) - return GitLabPublisher( - repository=publisher.project_path, environment=publisher.environment - ) - case "GitHub": - publisher = typing.cast(GitHubOIDCPublisher, publisher) - return GitHubPublisher( - repository=publisher.repository, - workflow=publisher.workflow_filename, - environment=publisher.environment, - ) - case _: - raise AttestationUploadError( - f"Unsupported publisher: {publisher.publisher_name}" - ) - - def _build_provenance( request: Request, file: File, attestations: list[Attestation] ) -> DatabaseProvenance: - try: - publisher: Publisher = _publisher_from_oidc_publisher(request.oidc_publisher) - except AttestationUploadError as exc: - sentry_sdk.capture_message( - f"Unsupported OIDCPublisher found {request.oidc_publisher.publisher_name}" - ) - raise exc - attestation_bundle = AttestationBundle( - publisher=publisher, + publisher=request.oidc_publisher.attestation_identity, attestations=attestations, ) @@ -100,15 +61,15 @@ def _extract_attestations_from_request(request: Request) -> list[Attestation]: Extract well-formed attestation objects from the given request's payload. """ - publisher: OIDCPublisher | None = request.oidc_publisher - if not publisher: + if not request.oidc_publisher: raise AttestationUploadError( "Attestations are only supported when using Trusted Publishing" ) - if not publisher.supports_attestations: + + if not request.oidc_publisher.attestation_identity: raise AttestationUploadError( "Attestations are not currently supported with " - f"{publisher.publisher_name} publishers" + f"{request.oidc_publisher.publisher_name} publishers" ) metrics = request.find_service(IMetricsService, context=None) @@ -197,16 +158,13 @@ def parse_attestations( attestations = _extract_attestations_from_request(request) - # The above attestation extraction guarantees that we have a publisher. - publisher: OIDCPublisher = request.oidc_publisher + # Sanity-checked above. + expected_identity = request.oidc_publisher.attestation_identity - verification_policy = publisher.publisher_verification_policy( - request.oidc_claims - ) for attestation_model in attestations: try: predicate_type, _ = attestation_model.verify( - verification_policy, + expected_identity, distribution, ) except VerificationError as e: diff --git a/warehouse/oidc/models/_core.py b/warehouse/oidc/models/_core.py index 3fe450f61527..71b54880a037 100644 --- a/warehouse/oidc/models/_core.py +++ b/warehouse/oidc/models/_core.py @@ -29,11 +29,14 @@ from warehouse.oidc.urls import verify_url_from_reference if TYPE_CHECKING: + from pypi_attestations import Publisher + from warehouse.accounts.models import User from warehouse.macaroons.models import Macaroon from warehouse.oidc.services import OIDCPublisherService from warehouse.packaging.models import Project + C = TypeVar("C") @@ -310,13 +313,14 @@ def publisher_url( raise NotImplementedError @property - def supports_attestations(self) -> bool: + def attestation_identity(self) -> Publisher | None: """ - Returns whether or not this kind of publisher supports attestations. + Returns an appropriate attestation verification identity, if this + kind of publisher supports attestations. Concrete subclasses should override this upon adding attestation support. """ - return False + return None def publisher_verification_policy( self, claims: SignedClaims diff --git a/warehouse/oidc/models/github.py b/warehouse/oidc/models/github.py index d1ecab8c5793..4b84d30778a0 100644 --- a/warehouse/oidc/models/github.py +++ b/warehouse/oidc/models/github.py @@ -14,6 +14,7 @@ from typing import Any +from pypi_attestations import GitHubPublisher as GitHubIdentity, Publisher from sigstore.verify.policy import ( AllOf, AnyOf, @@ -280,8 +281,12 @@ def publisher_url(self, claims=None): return base @property - def supports_attestations(self) -> bool: - return True + def attestation_identity(self) -> Publisher | None: + return GitHubIdentity( + repository=self.repository, + workflow=self.workflow_filename, + environment=self.environment if self.environment else None, + ) def publisher_verification_policy(self, claims): """ From 53f26289cc90f73a50b57e6ffd22944f3920c19a Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 18 Nov 2024 15:24:41 -0500 Subject: [PATCH 2/6] remove publisher_verification_policy Handled latently via the Publisher identity. Signed-off-by: William Woodruff --- tests/unit/attestations/test_services.py | 3 -- tests/unit/oidc/models/test_github.py | 25 ----------------- warehouse/oidc/models/_core.py | 11 -------- warehouse/oidc/models/github.py | 35 ------------------------ 4 files changed, 74 deletions(-) diff --git a/tests/unit/attestations/test_services.py b/tests/unit/attestations/test_services.py index b052b19867c5..793e6a16ea02 100644 --- a/tests/unit/attestations/test_services.py +++ b/tests/unit/attestations/test_services.py @@ -183,7 +183,6 @@ def test_parse_attestations_fails_verification( db_request.oidc_publisher = pretend.stub( attestation_identity=pretend.stub(), - publisher_verification_policy=pretend.call_recorder(lambda c: None), ) db_request.oidc_claims = {"sha": "somesha"} db_request.POST["attestations"] = TypeAdapter(list[Attestation]).dump_json( @@ -214,7 +213,6 @@ def test_parse_attestations_fails_wrong_predicate( ) db_request.oidc_publisher = pretend.stub( attestation_identity=pretend.stub(), - publisher_verification_policy=pretend.call_recorder(lambda c: None), ) db_request.oidc_claims = {"sha": "somesha"} db_request.POST["attestations"] = TypeAdapter(list[Attestation]).dump_json( @@ -250,7 +248,6 @@ def test_parse_attestations_succeeds( ) db_request.oidc_publisher = pretend.stub( attestation_identity=pretend.stub(), - publisher_verification_policy=pretend.call_recorder(lambda c: None), ) db_request.oidc_claims = {"sha": "somesha"} db_request.POST["attestations"] = TypeAdapter(list[Attestation]).dump_json( diff --git a/tests/unit/oidc/models/test_github.py b/tests/unit/oidc/models/test_github.py index 04a52952d393..67b8d205c958 100644 --- a/tests/unit/oidc/models/test_github.py +++ b/tests/unit/oidc/models/test_github.py @@ -602,31 +602,6 @@ def test_github_publisher_environment_claim(self, truth, claim, valid): check = github.GitHubPublisher.__optional_verifiable_claims__["environment"] assert check(truth, claim, pretend.stub()) is valid - @pytest.mark.parametrize( - ("ref", "sha", "raises"), - [ - ("ref", "sha", False), - (None, "sha", False), - ("ref", None, False), - (None, None, True), - ], - ) - def test_github_publisher_verification_policy(self, ref, sha, raises): - publisher = github.GitHubPublisher( - repository_name="fakerepo", - repository_owner="fakeowner", - repository_owner_id="fakeid", - workflow_filename="fakeworkflow.yml", - environment="", - ) - claims = {"ref": ref, "sha": sha} - - if not raises: - publisher.publisher_verification_policy(claims) - else: - with pytest.raises(InvalidPublisherError): - publisher.publisher_verification_policy(claims) - def test_github_publisher_duplicates_cant_be_created(self, db_request): publisher1 = github.GitHubPublisher( repository_name="repository_name", diff --git a/warehouse/oidc/models/_core.py b/warehouse/oidc/models/_core.py index 71b54880a037..77244b29d468 100644 --- a/warehouse/oidc/models/_core.py +++ b/warehouse/oidc/models/_core.py @@ -322,17 +322,6 @@ def attestation_identity(self) -> Publisher | None: """ return None - def publisher_verification_policy( - self, claims: SignedClaims - ) -> VerificationPolicy: # pragma: no cover - """ - Get the policy used to verify attestations signed with this publisher. - NOTE: This is **NOT** a `@property` because we pass `claims` to it. - When calling, make sure to use `publisher_verification_policy()` - """ - # Only concrete subclasses are constructed. - raise NotImplementedError - def stored_claims( self, claims: SignedClaims | None = None ) -> dict: # pragma: no cover diff --git a/warehouse/oidc/models/github.py b/warehouse/oidc/models/github.py index 4b84d30778a0..9c3447df09d5 100644 --- a/warehouse/oidc/models/github.py +++ b/warehouse/oidc/models/github.py @@ -288,41 +288,6 @@ def attestation_identity(self) -> Publisher | None: environment=self.environment if self.environment else None, ) - def publisher_verification_policy(self, claims): - """ - Get the policy used to verify attestations signed with GitHub Actions. - - This policy checks the certificate in an attestation against the following - claims: - - OIDCBuildConfigURI (e.g: - https://github.com/org/repo/.github/workflows/workflow.yml@REF}) - - OIDCIssuerV2 (should always be https://token.actions.githubusercontent.com/) - - OIDCSourceRepositoryDigest (the commit SHA corresponding to the version of - the repo used) - - Note: the Build Config URI might end with either a ref (i.e: refs/heads/main) - or with a commit SHA, so we allow either by using the `AnyOf` policy and - grouping both possibilities together. - """ - sha = claims.get("sha") if claims else None - ref = claims.get("ref") if claims else None - if not (ref or sha): - raise InvalidPublisherError("The ref and sha claims are empty") - - expected_build_configs = [ - OIDCBuildConfigURI(f"https://github.com/{self.job_workflow_ref}@{claim}") - for claim in [ref, sha] - if claim is not None - ] - - return AllOf( - [ - OIDCIssuerV2(GITHUB_OIDC_ISSUER_URL), - OIDCSourceRepositoryDigest(sha), - AnyOf(expected_build_configs), - ], - ) - def stored_claims(self, claims=None): claims = claims if claims else {} return {"ref": claims.get("ref"), "sha": claims.get("sha")} From 9f035d70924b5caf8ae77ee80d6d2a6cd064cd01 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 18 Nov 2024 15:30:25 -0500 Subject: [PATCH 3/6] oidc/models: test_github_publisher_attestation_identity Signed-off-by: William Woodruff --- tests/unit/oidc/models/test_github.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/unit/oidc/models/test_github.py b/tests/unit/oidc/models/test_github.py index 67b8d205c958..6ada634046b1 100644 --- a/tests/unit/oidc/models/test_github.py +++ b/tests/unit/oidc/models/test_github.py @@ -651,6 +651,25 @@ def test_github_publisher_verify_url(self, url, expected): ) assert publisher.verify_url(url) == expected + @pytest.mark.parametrize("environment", ("", "some-env")) + def test_github_publisher_attestation_identity(self, environment): + publisher = github.GitHubPublisher( + repository_name="repository_name", + repository_owner="repository_owner", + repository_owner_id="666", + workflow_filename="workflow_filename.yml", + environment=environment, + ) + + identity = publisher.attestation_identity + assert identity.repository == publisher.repository + assert identity.workflow == publisher.workflow_filename + + if not environment: + assert identity.environment is None + else: + assert identity.environment == publisher.environment + class TestPendingGitHubPublisher: def test_reify_does_not_exist_yet(self, db_request): From e57f4d0e5114a74f9a0ac691649666152dd95d02 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 18 Nov 2024 15:36:06 -0500 Subject: [PATCH 4/6] cleanup, remove old imports Signed-off-by: William Woodruff --- tests/unit/oidc/models/test_github.py | 3 +-- warehouse/oidc/models/_core.py | 1 - warehouse/oidc/models/github.py | 7 ------- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/unit/oidc/models/test_github.py b/tests/unit/oidc/models/test_github.py index 6ada634046b1..fa08b4da70d8 100644 --- a/tests/unit/oidc/models/test_github.py +++ b/tests/unit/oidc/models/test_github.py @@ -16,7 +16,6 @@ from tests.common.db.oidc import GitHubPublisherFactory, PendingGitHubPublisherFactory from warehouse.oidc import errors -from warehouse.oidc.errors import InvalidPublisherError from warehouse.oidc.models import _core, github @@ -651,7 +650,7 @@ def test_github_publisher_verify_url(self, url, expected): ) assert publisher.verify_url(url) == expected - @pytest.mark.parametrize("environment", ("", "some-env")) + @pytest.mark.parametrize("environment", ["", "some-env"]) def test_github_publisher_attestation_identity(self, environment): publisher = github.GitHubPublisher( repository_name="repository_name", diff --git a/warehouse/oidc/models/_core.py b/warehouse/oidc/models/_core.py index 77244b29d468..11e872faa8d4 100644 --- a/warehouse/oidc/models/_core.py +++ b/warehouse/oidc/models/_core.py @@ -18,7 +18,6 @@ import rfc3986 import sentry_sdk -from sigstore.verify.policy import VerificationPolicy from sqlalchemy import ForeignKey, String, orm from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column diff --git a/warehouse/oidc/models/github.py b/warehouse/oidc/models/github.py index 9c3447df09d5..51436d9c517a 100644 --- a/warehouse/oidc/models/github.py +++ b/warehouse/oidc/models/github.py @@ -15,13 +15,6 @@ from typing import Any from pypi_attestations import GitHubPublisher as GitHubIdentity, Publisher -from sigstore.verify.policy import ( - AllOf, - AnyOf, - OIDCBuildConfigURI, - OIDCIssuerV2, - OIDCSourceRepositoryDigest, -) from sqlalchemy import ForeignKey, String, UniqueConstraint from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Query, mapped_column From 70a73e157b7839cbd6163533f1787f51704957bf Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 18 Nov 2024 15:52:15 -0500 Subject: [PATCH 5/6] requirements: remove top-level sigstore dep Signed-off-by: William Woodruff --- requirements/main.in | 1 - requirements/main.txt | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/requirements/main.in b/requirements/main.in index cd85094dc919..3205193e5662 100644 --- a/requirements/main.in +++ b/requirements/main.in @@ -64,7 +64,6 @@ redis>=2.8.0,<6.0.0 rfc3986 sentry-sdk setuptools -sigstore~=3.5.1 pypi-attestations==0.0.16 sqlalchemy[asyncio]>=2.0,<3.0 stdlib-list diff --git a/requirements/main.txt b/requirements/main.txt index 998cb839e778..ee38aab06ec8 100644 --- a/requirements/main.txt +++ b/requirements/main.txt @@ -2084,9 +2084,7 @@ sentry-sdk==2.18.0 \ sigstore==3.5.1 \ --hash=sha256:88f73c8edf1662ff9b86ef6fe0870bb6af4ac99ff808b84995e6a41957b7b3d2 \ --hash=sha256:e7023aef4e574120712c16c6bb151f4caee55791c4677fe30c92ef4e50800204 - # via - # -r requirements/main.in - # pypi-attestations + # via pypi-attestations sigstore-protobuf-specs==0.3.2 \ --hash=sha256:50c99fa6747a3a9c5c562a43602cf76df0b199af28f0e9d4319b6775630425ea \ --hash=sha256:cae041b40502600b8a633f43c257695d0222a94efa1e5110a7ec7ada78c39d99 From 7ca30cd066197783b2182ba8cd35f0750674f6c0 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 18 Nov 2024 16:02:10 -0500 Subject: [PATCH 6/6] remove _build_provenance helper Signed-off-by: William Woodruff --- warehouse/attestations/services.py | 41 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/warehouse/attestations/services.py b/warehouse/attestations/services.py index 721b992b9026..18ee9f789899 100644 --- a/warehouse/attestations/services.py +++ b/warehouse/attestations/services.py @@ -39,23 +39,6 @@ from warehouse.packaging.models import File -def _build_provenance( - request: Request, file: File, attestations: list[Attestation] -) -> DatabaseProvenance: - attestation_bundle = AttestationBundle( - publisher=request.oidc_publisher.attestation_identity, - attestations=attestations, - ) - - provenance = Provenance(attestation_bundles=[attestation_bundle]).model_dump( - mode="json" - ) - - db_provenance = DatabaseProvenance(file=file, provenance=provenance) - - return db_provenance - - def _extract_attestations_from_request(request: Request) -> list[Attestation]: """ Extract well-formed attestation objects from the given request's payload. @@ -127,7 +110,16 @@ def parse_attestations( def build_provenance( self, request: Request, file: File, attestations: list[Attestation] ) -> DatabaseProvenance: - return _build_provenance(request, file, attestations) + attestation_bundle = AttestationBundle( + publisher=request.oidc_publisher.attestation_identity, + attestations=attestations, + ) + + provenance = Provenance(attestation_bundles=[attestation_bundle]).model_dump( + mode="json" + ) + + return DatabaseProvenance(file=file, provenance=provenance) @implementer(IIntegrityService) @@ -198,6 +190,15 @@ def parse_attestations( def build_provenance( self, request: Request, file: File, attestations: list[Attestation] ) -> DatabaseProvenance: - provenance = _build_provenance(request, file, attestations) + attestation_bundle = AttestationBundle( + publisher=request.oidc_publisher.attestation_identity, + attestations=attestations, + ) + + provenance = Provenance(attestation_bundles=[attestation_bundle]).model_dump( + mode="json" + ) + db_provenance = DatabaseProvenance(file=file, provenance=provenance) + self.metrics.increment("warehouse.attestations.build_provenance.ok") - return provenance + return db_provenance