diff --git a/requirements/main.in b/requirements/main.in index 3205193e5662..02c76fa47ff1 100644 --- a/requirements/main.in +++ b/requirements/main.in @@ -64,7 +64,7 @@ redis>=2.8.0,<6.0.0 rfc3986 sentry-sdk setuptools -pypi-attestations==0.0.16 +pypi-attestations==0.0.17 sqlalchemy[asyncio]>=2.0,<3.0 stdlib-list stripe diff --git a/requirements/main.txt b/requirements/main.txt index ee38aab06ec8..970b529d3674 100644 --- a/requirements/main.txt +++ b/requirements/main.txt @@ -1779,9 +1779,9 @@ pyparsing==3.2.0 \ --hash=sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84 \ --hash=sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c # via linehaul -pypi-attestations==0.0.16 \ - --hash=sha256:1d816719b5067ef49ac47c7ae229bd03752c57f957daf95b19b2ba19a66220e4 \ - --hash=sha256:cbd2b946fe160793606dee4516ef58ac5959456e69630a7f03e7de73aa7f2737 +pypi-attestations==0.0.17 \ + --hash=sha256:5936c0c69af4e31d69543d03c9809c53c3f1c12b7eed6d83fe1bc81bf6a58c2e \ + --hash=sha256:5a8a6a89f146d97357284fb6f467ea095273cf385f2f62ce49ad70b0a2057841 # via -r requirements/main.in pyqrcode==1.2.1 \ --hash=sha256:1b2812775fa6ff5c527977c4cd2ccb07051ca7d0bc0aecf937a43864abe5eff6 \ diff --git a/tests/unit/attestations/test_services.py b/tests/unit/attestations/test_services.py index 793e6a16ea02..4457c98b9d8d 100644 --- a/tests/unit/attestations/test_services.py +++ b/tests/unit/attestations/test_services.py @@ -40,8 +40,12 @@ class TestNullIntegrityService: def test_interface_matches(self): assert verifyClass(IIntegrityService, services.NullIntegrityService) - def test_build_provenance(self, db_request, dummy_attestation): - db_request.oidc_publisher = GitHubPublisherFactory.create() + @pytest.mark.parametrize( + "publisher_factory", + [GitHubPublisherFactory, GitLabPublisherFactory], + ) + def test_build_provenance(self, db_request, dummy_attestation, publisher_factory): + db_request.oidc_publisher = publisher_factory.create() file = FileFactory.create() service = services.NullIntegrityService.create_service(None, db_request) @@ -89,7 +93,6 @@ def test_parse_attestations_fails_no_publisher(self, db_request): @pytest.mark.parametrize( "publisher_factory", [ - GitLabPublisherFactory, GooglePublisherFactory, ActiveStatePublisherFactory, ], @@ -267,7 +270,7 @@ def test_parse_attestations_succeeds( @pytest.mark.parametrize( "publisher_factory", - [GitHubPublisherFactory], + [GitHubPublisherFactory, GitLabPublisherFactory], ) def test_build_provenance_succeeds( self, metrics, db_request, publisher_factory, dummy_attestation @@ -295,8 +298,12 @@ def test_build_provenance_succeeds( ] -def test_extract_attestations_from_request_empty_list(db_request): - db_request.oidc_publisher = GitHubPublisherFactory.create() +@pytest.mark.parametrize( + "publisher_factory", + [GitHubPublisherFactory, GitLabPublisherFactory], +) +def test_extract_attestations_from_request_empty_list(db_request, publisher_factory): + db_request.oidc_publisher = publisher_factory.create() db_request.POST = {"attestations": json.dumps([])} with pytest.raises( diff --git a/tests/unit/oidc/models/test_gitlab.py b/tests/unit/oidc/models/test_gitlab.py index 00a247d12bed..ca427789c4e9 100644 --- a/tests/unit/oidc/models/test_gitlab.py +++ b/tests/unit/oidc/models/test_gitlab.py @@ -710,6 +710,25 @@ def test_gitlab_publisher_verify_url( ) assert publisher.verify_url(url) == expected + @pytest.mark.parametrize("environment", ["", "some-env"]) + def test_gitlab_publisher_attestation_identity(self, environment): + publisher = gitlab.GitLabPublisher( + project="project", + namespace="group/subgroup", + workflow_filepath="workflow_filename.yml", + environment=environment, + ) + + identity = publisher.attestation_identity + assert identity is not None + assert identity.repository == publisher.project_path + assert identity.workflow_filepath == publisher.workflow_filepath + + if not environment: + assert identity.environment is None + else: + assert identity.environment == publisher.environment + class TestPendingGitLabPublisher: def test_reify_does_not_exist_yet(self, db_request): diff --git a/warehouse/attestations/services.py b/warehouse/attestations/services.py index ae8b8399a313..10e9f00378dd 100644 --- a/warehouse/attestations/services.py +++ b/warehouse/attestations/services.py @@ -151,7 +151,6 @@ def parse_attestations( artifact. Attestations are only allowed when uploading via a Trusted Publisher, because a Trusted Publisher provides the identity that will be used to verify the attestations. - Only GitHub Actions Trusted Publishers are supported. """ attestations = _extract_attestations_from_request(request) diff --git a/warehouse/locale/messages.pot b/warehouse/locale/messages.pot index 4d8141199bbe..4fc56b05440c 100644 --- a/warehouse/locale/messages.pot +++ b/warehouse/locale/messages.pot @@ -826,7 +826,7 @@ msgstr "" #: warehouse/templates/base.html:321 warehouse/templates/base.html:331 #: warehouse/templates/base.html:344 #: warehouse/templates/includes/accounts/profile-callout.html:18 -#: warehouse/templates/includes/file-details.html:94 +#: warehouse/templates/includes/file-details.html:101 #: warehouse/templates/index.html:100 warehouse/templates/index.html:104 #: warehouse/templates/manage/account.html:228 #: warehouse/templates/manage/account.html:234 @@ -2707,51 +2707,51 @@ msgstr "" msgid "Public profile" msgstr "" -#: warehouse/templates/includes/file-details.html:27 +#: warehouse/templates/includes/file-details.html:34 msgid "File details" msgstr "" -#: warehouse/templates/includes/file-details.html:38 +#: warehouse/templates/includes/file-details.html:45 #, python-format msgid "Upload date: %(upload_time)s" msgstr "" -#: warehouse/templates/includes/file-details.html:39 +#: warehouse/templates/includes/file-details.html:46 #, python-format msgid "Size: %(size)s" msgstr "" -#: warehouse/templates/includes/file-details.html:40 +#: warehouse/templates/includes/file-details.html:47 #, python-format msgid "Tags: %(tags)s" msgstr "" -#: warehouse/templates/includes/file-details.html:42 +#: warehouse/templates/includes/file-details.html:49 #, python-format msgid "Uploaded using Trusted Publishing? %(is_tp)s" msgstr "" -#: warehouse/templates/includes/file-details.html:47 +#: warehouse/templates/includes/file-details.html:54 #, python-format msgid "Uploaded via: %(uploaded_via)s" msgstr "" -#: warehouse/templates/includes/file-details.html:55 +#: warehouse/templates/includes/file-details.html:62 #, python-format msgid "Hashes for %(filename)s" msgstr "" -#: warehouse/templates/includes/file-details.html:58 +#: warehouse/templates/includes/file-details.html:65 msgid "Algorithm" msgstr "" -#: warehouse/templates/includes/file-details.html:59 +#: warehouse/templates/includes/file-details.html:66 msgid "Hash digest" msgstr "" -#: warehouse/templates/includes/file-details.html:68 -#: warehouse/templates/includes/file-details.html:77 -#: warehouse/templates/includes/file-details.html:86 +#: warehouse/templates/includes/file-details.html:75 +#: warehouse/templates/includes/file-details.html:84 +#: warehouse/templates/includes/file-details.html:93 #: warehouse/templates/manage/account.html:206 #: warehouse/templates/manage/account/recovery_codes-provision.html:58 #: warehouse/templates/manage/account/totp-provision.html:57 @@ -2761,9 +2761,9 @@ msgstr "" msgid "Copy to clipboard" msgstr "" -#: warehouse/templates/includes/file-details.html:69 -#: warehouse/templates/includes/file-details.html:78 -#: warehouse/templates/includes/file-details.html:87 +#: warehouse/templates/includes/file-details.html:76 +#: warehouse/templates/includes/file-details.html:85 +#: warehouse/templates/includes/file-details.html:94 #: warehouse/templates/manage/account.html:207 #: warehouse/templates/manage/account/recovery_codes-provision.html:59 #: warehouse/templates/manage/account/totp-provision.html:58 @@ -2772,7 +2772,7 @@ msgstr "" msgid "Copy" msgstr "" -#: warehouse/templates/includes/file-details.html:94 +#: warehouse/templates/includes/file-details.html:101 #, python-format msgid "" " Publisher | None: + return GitLabIdentity( + repository=self.project_path, + workflow_filepath=self.workflow_filepath, + environment=self.environment if self.environment else None, + ) + def stored_claims(self, claims=None): claims = claims if claims else {} return {"ref_path": claims.get("ref_path"), "sha": claims.get("sha")} diff --git a/warehouse/templates/includes/file-details.html b/warehouse/templates/includes/file-details.html index 1fdeb30d5215..cb3fdd4afc4b 100644 --- a/warehouse/templates/includes/file-details.html +++ b/warehouse/templates/includes/file-details.html @@ -20,6 +20,13 @@ {{ publ.workflow }} on {{ publ.repository }}

+{% elif publ.kind == "GitLab" %} +

+ Publisher: + + {{ publ.workflow_filepath }} on {{ publ.repository }} + +

{% endif %} {%- endmacro %}