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 }}
+ Publisher:
+
+ {{ publ.workflow_filepath }}
on {{ publ.repository }}
+
+