From 6f73becfdacc7d2d6de438a78b01374a251c20b5 Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 21 Nov 2024 09:57:26 +0100 Subject: [PATCH 01/12] Initial version --- .../templates/includes/file-details.html | 76 +++++++++++++++++-- 1 file changed, 69 insertions(+), 7 deletions(-) diff --git a/warehouse/templates/includes/file-details.html b/warehouse/templates/includes/file-details.html index 1fdeb30d5215..507c2ff3c93c 100644 --- a/warehouse/templates/includes/file-details.html +++ b/warehouse/templates/includes/file-details.html @@ -12,15 +12,40 @@ # limitations under the License. -#} -{% macro publisher(publ) -%} +{% macro repo_url_with_reference(repo_url, reference) %} + {{ repo_url }}/tree/{{ reference }} +{% endmacro %} + +{% macro workflow_filename(publisher) %} + {% if publisher.kind == "GitHub" %} + {{- publisher.workflow -}} + {% elif publisher.kind == "GitLab" %} + {{- publisher.workflow_filepath -}} + {% endif %} +{% endmacro %} + +{% macro workflow_url(publisher, claims) %} + {%- set repo_url = claims.get('1.3.6.1.4.1.57264.1.12', '') -%} + {%- set build_hash = claims.get('1.3.6.1.4.1.57264.1.19', '') -%} + {%- set workflow_url = claims.get('1.3.6.1.4.1.57264.1.18', '') -%} + {%- set file_path = workflow_url.split('@')[0].replace(repo_url + '/', '') -%} + {{ repo_url + "/blob/" + build_hash + "/" + file_path }} +{% endmacro %} + +{% macro repository_name(publisher) %} + {{ publisher.repository }} +{% endmacro %} + +{% macro publisher(publ, claims) -%} {% if publ.kind == "GitHub" %} + {%- set brand="github" -%} +{% endif %}

- Publisher: - - {{ publ.workflow }} on {{ publ.repository }} + Publisher: + + {{ workflow_filename(publ) }} on {{ repository_name(publ) }}

-{% endif %} {%- endmacro %}
@@ -111,7 +136,7 @@

Provenance

- {{ publisher(bundle.publisher )}} + {{ publisher(bundle.publisher, bundle.attestations[0].certificate_claims )}} Attestations: + Certificate claims: + This information comes from the certificate used to sign the release. + + {% set claims = attestation.certificate_claims %} + {% endfor %} @@ -133,4 +195,4 @@

Provenance

{% endfor %} {% endif %} - + \ No newline at end of file From 3f43bfbd3bdb8e5c7081737802c56778631ada8d Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 21 Nov 2024 10:54:10 +0100 Subject: [PATCH 02/12] Refine UI --- Dockerfile | 3 +- warehouse/static/sass/blocks/_files.scss | 7 ++ .../templates/includes/file-details.html | 94 ++++++++++--------- 3 files changed, 59 insertions(+), 45 deletions(-) diff --git a/Dockerfile b/Dockerfile index 51782549274a..d6ad26e6b4c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -220,7 +220,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ set -x \ && apt-get update \ && apt-get install --no-install-recommends -y \ - libpq5 libxml2 libxslt1.1 libcurl4 \ + libpq5 libxml2 libxslt1.1 libcurl4 git \ $(if [ "$DEVEL" = "yes" ]; then echo 'bash libjpeg62 postgresql-client build-essential libffi-dev libxml2-dev libxslt-dev libpq-dev libcurl4-openssl-dev libssl-dev vim oathtool'; fi) \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* @@ -238,4 +238,5 @@ COPY . /opt/warehouse/src/ RUN tldextract --update # Load our module to pre-compile as much bytecode as we can easily. # Saves time collectively on container boot! +RUN pip install --force pypi-attestations@git+https://github.com/trailofbits/pypi-attestations/@dm/extensions RUN python -m warehouse diff --git a/warehouse/static/sass/blocks/_files.scss b/warehouse/static/sass/blocks/_files.scss index d3470d995f74..8cfdf1b43980 100644 --- a/warehouse/static/sass/blocks/_files.scss +++ b/warehouse/static/sass/blocks/_files.scss @@ -57,5 +57,12 @@ &__card { display: block; margin: $quarter-spacing-unit 0; + + small { + display: block; + margin-top: 4px; + margin-bottom: 6px; + } + } } diff --git a/warehouse/templates/includes/file-details.html b/warehouse/templates/includes/file-details.html index 507c2ff3c93c..97037f10c016 100644 --- a/warehouse/templates/includes/file-details.html +++ b/warehouse/templates/includes/file-details.html @@ -29,21 +29,23 @@ {%- set build_hash = claims.get('1.3.6.1.4.1.57264.1.19', '') -%} {%- set workflow_url = claims.get('1.3.6.1.4.1.57264.1.18', '') -%} {%- set file_path = workflow_url.split('@')[0].replace(repo_url + '/', '') -%} - {{ repo_url + "/blob/" + build_hash + "/" + file_path }} + {{- repo_url + "/blob/" + build_hash + "/" + file_path -}} {% endmacro %} {% macro repository_name(publisher) %} - {{ publisher.repository }} + {{- publisher.repository -}} {% endmacro %} {% macro publisher(publ, claims) -%} {% if publ.kind == "GitHub" %} {%- set brand="github" -%} +{% elif publ.kind == "GitLab" %} + {%- set brand="gitlab" -%} {% endif %}

- Publisher: + Permanent source link: - {{ workflow_filename(publ) }} on {{ repository_name(publ) }} + {{ repository_name(publ) }}#{{ claims.get("1.3.6.1.4.1.57264.1.13") }}

{%- endmacro %} @@ -138,12 +140,16 @@

Provenance

{{ publisher(bundle.publisher, bundle.attestations[0].certificate_claims )}} Attestations: + + Values shown here reflect the state when the release was signed and may no longer be current. +
From baa9e725c4104a37871507c575e1816ea5717747 Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 21 Nov 2024 11:29:14 +0100 Subject: [PATCH 03/12] Update translations --- warehouse/locale/messages.pot | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/warehouse/locale/messages.pot b/warehouse/locale/messages.pot index 4fc56b05440c..5c8e8c072699 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:101 +#: warehouse/templates/includes/file-details.html:121 #: 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:34 +#: warehouse/templates/includes/file-details.html:54 msgid "File details" msgstr "" -#: warehouse/templates/includes/file-details.html:45 +#: warehouse/templates/includes/file-details.html:65 #, python-format msgid "Upload date: %(upload_time)s" msgstr "" -#: warehouse/templates/includes/file-details.html:46 +#: warehouse/templates/includes/file-details.html:66 #, python-format msgid "Size: %(size)s" msgstr "" -#: warehouse/templates/includes/file-details.html:47 +#: warehouse/templates/includes/file-details.html:67 #, python-format msgid "Tags: %(tags)s" msgstr "" -#: warehouse/templates/includes/file-details.html:49 +#: warehouse/templates/includes/file-details.html:69 #, python-format msgid "Uploaded using Trusted Publishing? %(is_tp)s" msgstr "" -#: warehouse/templates/includes/file-details.html:54 +#: warehouse/templates/includes/file-details.html:74 #, python-format msgid "Uploaded via: %(uploaded_via)s" msgstr "" -#: warehouse/templates/includes/file-details.html:62 +#: warehouse/templates/includes/file-details.html:82 #, python-format msgid "Hashes for %(filename)s" msgstr "" -#: warehouse/templates/includes/file-details.html:65 +#: warehouse/templates/includes/file-details.html:85 msgid "Algorithm" msgstr "" -#: warehouse/templates/includes/file-details.html:66 +#: warehouse/templates/includes/file-details.html:86 msgid "Hash digest" msgstr "" -#: warehouse/templates/includes/file-details.html:75 -#: warehouse/templates/includes/file-details.html:84 -#: warehouse/templates/includes/file-details.html:93 +#: warehouse/templates/includes/file-details.html:95 +#: warehouse/templates/includes/file-details.html:104 +#: warehouse/templates/includes/file-details.html:113 #: 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:76 -#: warehouse/templates/includes/file-details.html:85 -#: warehouse/templates/includes/file-details.html:94 +#: warehouse/templates/includes/file-details.html:96 +#: warehouse/templates/includes/file-details.html:105 +#: warehouse/templates/includes/file-details.html:114 #: 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:101 +#: warehouse/templates/includes/file-details.html:121 #, python-format msgid "" " Date: Tue, 26 Nov 2024 17:17:14 +0100 Subject: [PATCH 04/12] Update claims. --- tests/unit/packaging/test_views.py | 130 ++++++++++++++++++ warehouse/packaging/views.py | 62 +++++++++ .../templates/includes/file-details.html | 92 ++++--------- 3 files changed, 221 insertions(+), 63 deletions(-) diff --git a/tests/unit/packaging/test_views.py b/tests/unit/packaging/test_views.py index bf7aea3bcde5..b363d6f76f9a 100644 --- a/tests/unit/packaging/test_views.py +++ b/tests/unit/packaging/test_views.py @@ -232,6 +232,8 @@ def test_detail_rendered(self, db_request): ], "maintainers": sorted(users, key=lambda u: u.username.lower()), "license": None, + "get_publication_details": views.get_publication_details, + "format_url": views.format_url, } def test_detail_renders_files_natural_sort(self, db_request): @@ -323,6 +325,134 @@ def test_long_singleline_license(self, db_request): "characters, it's really so lo..." ) + @pytest.mark.parametrize( + ("base_url", "reference", "expected"), + [ + ( + "https://github.com/pypi/warehouse", + "2ec275dc2a05cd8ed2f0a9a0adadfcff9096d982", + ( + "https://github.com/pypi/warehouse/tree/" + "2ec275dc2a05cd8ed2f0a9a0adadfcff9096d982" + ), + ), + ( + "https://gitlab.com/sample/sample", + "refs/heads/main", + "https://gitlab.com/sample/sample/tree/refs/heads/main", + ), + ], + ) + def test_format_url(self, base_url, reference, expected): + assert views.format_url(base_url, reference) == expected + + @pytest.mark.parametrize( + ("publisher_name", "claims"), + [ + ( + "GitLab", + { + "1.3.6.1.4.1.57264.1.8": "https://gitlab.com", + "1.3.6.1.4.1.57264.1.9": ( + "https://gitlab.com/facutuesca/gitlab-oidc-project//" + ".gitlab-ci.yml@refs/heads/main" + ), + "1.3.6.1.4.1.57264.1.10": ( + "72f7c63b75eb55ea80864962f0e645c93414da34" + ), + "1.3.6.1.4.1.57264.1.11": "gitlab-hosted", + "1.3.6.1.4.1.57264.1.12": ( + "https://gitlab.com/facutuesca/gitlab-oidc-project" + ), + "1.3.6.1.4.1.57264.1.13": ( + "72f7c63b75eb55ea80864962f0e645c93414da34" + ), + "1.3.6.1.4.1.57264.1.14": "refs/heads/main", + "1.3.6.1.4.1.57264.1.15": "55235664", + "1.3.6.1.4.1.57264.1.16": "https://gitlab.com/facutuesca", + "1.3.6.1.4.1.57264.1.17": "12885801", + "1.3.6.1.4.1.57264.1.18": ( + "https://gitlab.com/facutuesca/gitlab-oidc-project//" + ".gitlab-ci.yml@refs/heads/main" + ), + "1.3.6.1.4.1.57264.1.19": ( + "72f7c63b75eb55ea80864962f0e645c93414da34" + ), + "1.3.6.1.4.1.57264.1.20": "push", + "1.3.6.1.4.1.57264.1.21": ( + "https://gitlab.com/facutuesca/gitlab-oidc-project/-/jobs/" + "8415754949" + ), + "1.3.6.1.4.1.57264.1.22": "private", + }, + ), + ( + "GitHub", + { + "1.3.6.1.4.1.57264.1.8": ( + "https://token.actions.githubusercontent.com" + ), + "1.3.6.1.4.1.57264.1.9": ( + "https://github.com/trailofbits/pypi-attestations/" + ".github/workflows/release.yml@refs/tags/v0.0.16" + ), + "1.3.6.1.4.1.57264.1.10": ( + "58c872e67c03c9c031ba71b1654ff542ff290cd7" + ), + "1.3.6.1.4.1.57264.1.11": "github-hosted", + "1.3.6.1.4.1.57264.1.12": ( + "https://github.com/trailofbits/pypi-attestations" + ), + "1.3.6.1.4.1.57264.1.13": ( + "58c872e67c03c9c031ba71b1654ff542ff290cd7" + ), + "1.3.6.1.4.1.57264.1.14": "refs/tags/v0.0.16", + "1.3.6.1.4.1.57264.1.15": "772247423", + "1.3.6.1.4.1.57264.1.16": "https://github.com/trailofbits", + "1.3.6.1.4.1.57264.1.17": "2314423", + "1.3.6.1.4.1.57264.1.18": ( + "https://github.com/trailofbits/pypi-attestations/" + ".github/workflows/release.yml@refs/tags/v0.0.16" + ), + "1.3.6.1.4.1.57264.1.19": ( + "58c872e67c03c9c031ba71b1654ff542ff290cd7" + ), + "1.3.6.1.4.1.57264.1.20": "release", + "1.3.6.1.4.1.57264.1.21": ( + "https://github.com/trailofbits/pypi-attestations/actions/" + "runs/11732568384/attempts/1" + ), + "1.3.6.1.4.1.57264.1.22": "public", + }, + ), + ], + ) + def test_get_publication_details(self, publisher_name, claims): + if publisher_name == "GitLab": + publisher = pretend.stub( + kind="GitLab", + workflow_filepath="subfolder/example.yml", + ) + elif publisher_name == "GitHub": + publisher = pretend.stub( + kind="GitHub", + workflow="example.yml", + ) + + views.get_publication_details( + claims, + publisher, + ) + + def test_get_publication_details_unknown(self): + results = views.get_publication_details( + claims={}, + publisher=pretend.stub(kind="unknown-publisher"), + ) + + assert not results["workflow_filename"] + assert results["workflow_url"] == "/blob//" + class TestReportMalwareButton: def test_report_malware_button(self): diff --git a/warehouse/packaging/views.py b/warehouse/packaging/views.py index 6e083d119608..7d7600179acb 100644 --- a/warehouse/packaging/views.py +++ b/warehouse/packaging/views.py @@ -9,6 +9,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import typing from natsort import natsorted from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound @@ -22,6 +23,9 @@ from warehouse.packaging.forms import SubmitMalwareObservationForm from warehouse.packaging.models import Description, File, Project, Release, Role +if typing.TYPE_CHECKING: + import pypi_attestations + @view_config( route_name="packaging.project", @@ -56,6 +60,61 @@ def project_detail(project, request): return release_detail(release, request) +def format_url(base_url: str, reference: str): + """Format a URL to create a permalink to a repository. + + Works on both GitHub and GitLab. + Reference can either be a hash or a named revision. + """ + return f"{base_url}/tree/{reference}" + + +def get_publication_details( + claims: dict[str, str], publisher: pypi_attestations.Publisher +): + """Helper function for Jinja to format the claims present in the attestation.""" + workflow_filename = "" + if publisher.kind == "GitHub": + workflow_filename = publisher.workflow + elif publisher.kind == "GitLab": + workflow_filename = publisher.workflow_filepath + + # Source Repository URI + repo_url = claims.get("1.3.6.1.4.1.57264.1.12", "") + # Build Config URI + workflow_url = claims.get("1.3.6.1.4.1.57264.1.18", "") + # Build Config Digest + build_hash = claims.get("1.3.6.1.4.1.57264.1.19", "") + + # The claim `workflow_url` does not return a valid link to the repository, + # but we can use it to retrieve the path towards the workflow file. + workflow_file_path = workflow_url.split("@")[0].replace(repo_url + "/", "") + + workflow_permalink = f"{repo_url}/blob/{build_hash}/{workflow_file_path}" + + return { + "workflow_url": workflow_permalink, + "workflow_filename": workflow_filename, + "build_hash": build_hash, + # Issuer + "issuer": claims.get("1.3.6.1.4.1.57264.1.8"), + # Runner Environment + "environment": claims.get("1.3.6.1.4.1.57264.1.11"), + # Source Repository URI + "source": claims.get("1.3.6.1.4.1.57264.1.12"), + # Source Repository Digest + "source_digest": claims.get("1.3.6.1.4.1.57264.1.13"), + # Source Repository Ref + "source_ref": claims.get("1.3.6.1.4.1.57264.1.14"), + # Source Repository Owner URI + "owner": claims.get("1.3.6.1.4.1.57264.1.16"), + # Build Trigger + "trigger": claims.get("1.3.6.1.4.1.57264.1.20"), + # Source Repository Visibility At Signing + "access": claims.get("1.3.6.1.4.1.57264.1.22"), + } + + @view_config( route_name="packaging.release", context=Release, @@ -148,6 +207,9 @@ def release_detail(release, request): "all_versions": project.all_versions, "maintainers": maintainers, "license": license, + # Additional function to format the attestations + "get_publication_details": get_publication_details, + "format_url": format_url, } diff --git a/warehouse/templates/includes/file-details.html b/warehouse/templates/includes/file-details.html index 97037f10c016..e6febcd45ee3 100644 --- a/warehouse/templates/includes/file-details.html +++ b/warehouse/templates/includes/file-details.html @@ -12,42 +12,22 @@ # limitations under the License. -#} -{% macro repo_url_with_reference(repo_url, reference) %} - {{ repo_url }}/tree/{{ reference }} -{% endmacro %} - -{% macro workflow_filename(publisher) %} - {% if publisher.kind == "GitHub" %} - {{- publisher.workflow -}} - {% elif publisher.kind == "GitLab" %} - {{- publisher.workflow_filepath -}} - {% endif %} -{% endmacro %} - -{% macro workflow_url(publisher, claims) %} - {%- set repo_url = claims.get('1.3.6.1.4.1.57264.1.12', '') -%} - {%- set build_hash = claims.get('1.3.6.1.4.1.57264.1.19', '') -%} - {%- set workflow_url = claims.get('1.3.6.1.4.1.57264.1.18', '') -%} - {%- set file_path = workflow_url.split('@')[0].replace(repo_url + '/', '') -%} - {{- repo_url + "/blob/" + build_hash + "/" + file_path -}} -{% endmacro %} - -{% macro repository_name(publisher) %} - {{- publisher.repository -}} -{% endmacro %} - -{% macro publisher(publ, claims) -%} +{% macro publisher(publ) -%} {% if publ.kind == "GitHub" %} - {%- set brand="github" -%} +

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

{% elif publ.kind == "GitLab" %} - {%- set brand="gitlab" -%} -{% endif %}

- Permanent source link: - - {{ repository_name(publ) }}#{{ claims.get("1.3.6.1.4.1.57264.1.13") }} + Publisher: + + {{ publ.workflow_filepath }} on {{ publ.repository }}

+{% endif %} {%- endmacro %}
@@ -138,14 +118,14 @@

Provenance

- {{ publisher(bundle.publisher, bundle.attestations[0].certificate_claims )}} + {{ publisher(bundle.publisher) }} Attestations: Values shown here reflect the state when the release was signed and may no longer be current.
From 611631f97a5c5bcdd237043d3590ba063641efae Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 27 Nov 2024 15:36:23 +0100 Subject: [PATCH 05/12] Fix GitLab URLs --- tests/unit/packaging/test_views.py | 16 ++++++-- warehouse/packaging/views.py | 40 +++++++++++-------- .../templates/includes/file-details.html | 4 +- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/tests/unit/packaging/test_views.py b/tests/unit/packaging/test_views.py index b363d6f76f9a..66a80f5562b0 100644 --- a/tests/unit/packaging/test_views.py +++ b/tests/unit/packaging/test_views.py @@ -326,11 +326,12 @@ def test_long_singleline_license(self, db_request): ) @pytest.mark.parametrize( - ("base_url", "reference", "expected"), + ("base_url", "reference", "publisher", "expected"), [ ( "https://github.com/pypi/warehouse", "2ec275dc2a05cd8ed2f0a9a0adadfcff9096d982", + pretend.stub(kind="GitHub"), ( "https://github.com/pypi/warehouse/tree/" "2ec275dc2a05cd8ed2f0a9a0adadfcff9096d982" @@ -339,12 +340,19 @@ def test_long_singleline_license(self, db_request): ( "https://gitlab.com/sample/sample", "refs/heads/main", - "https://gitlab.com/sample/sample/tree/refs/heads/main", + pretend.stub(kind="GitLab"), + "https://gitlab.com/sample/sample/-/tree/main", + ), + ( + "https://example.com/sample/sample", + "refs/heads/main", + pretend.stub(kind="Unknown"), + "https://example.com/sample/sample/refs/heads/main", ), ], ) - def test_format_url(self, base_url, reference, expected): - assert views.format_url(base_url, reference) == expected + def test_format_url(self, base_url, reference, publisher, expected): + assert views.format_url(base_url, reference, publisher) == expected @pytest.mark.parametrize( ("publisher_name", "claims"), diff --git a/warehouse/packaging/views.py b/warehouse/packaging/views.py index 7d7600179acb..8b359f954dbb 100644 --- a/warehouse/packaging/views.py +++ b/warehouse/packaging/views.py @@ -9,9 +9,11 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import typing + +from typing import cast from natsort import natsorted +from pypi_attestations import GitHubPublisher, GitLabPublisher, Publisher from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound from pyramid.view import view_config from sqlalchemy.exc import NoResultFound @@ -23,9 +25,6 @@ from warehouse.packaging.forms import SubmitMalwareObservationForm from warehouse.packaging.models import Description, File, Project, Release, Role -if typing.TYPE_CHECKING: - import pypi_attestations - @view_config( route_name="packaging.project", @@ -60,24 +59,31 @@ def project_detail(project, request): return release_detail(release, request) -def format_url(base_url: str, reference: str): +def format_url(base_url: str, reference: str, publisher: Publisher): """Format a URL to create a permalink to a repository. - Works on both GitHub and GitLab. Reference can either be a hash or a named revision. """ - return f"{base_url}/tree/{reference}" - - -def get_publication_details( - claims: dict[str, str], publisher: pypi_attestations.Publisher -): + match publisher.kind: + case "GitHub": + return f"{base_url}/tree/{reference}" + case "GitLab": + reference = reference.removeprefix("refs/heads/") + return f"{base_url}/-/tree/{reference}" + case _: + # Best effort here + return f"{base_url}/{reference}" + + +def get_publication_details(claims: dict[str, str], publisher: Publisher): """Helper function for Jinja to format the claims present in the attestation.""" - workflow_filename = "" - if publisher.kind == "GitHub": - workflow_filename = publisher.workflow - elif publisher.kind == "GitLab": - workflow_filename = publisher.workflow_filepath + match publisher.kind: + case "GitHub": + workflow_filename = cast(GitHubPublisher, publisher).workflow + case "GitLab": + workflow_filename = cast(GitLabPublisher, publisher).workflow_filepath + case _: + workflow_filename = "" # Source Repository URI repo_url = claims.get("1.3.6.1.4.1.57264.1.12", "") diff --git a/warehouse/templates/includes/file-details.html b/warehouse/templates/includes/file-details.html index e6febcd45ee3..074e8b7f4f43 100644 --- a/warehouse/templates/includes/file-details.html +++ b/warehouse/templates/includes/file-details.html @@ -140,10 +140,10 @@

Provenance

{% set claims = get_publication_details(attestation.certificate_claims, bundle.publisher) %} Source repository: