Skip to content

Commit

Permalink
attestations: add support for upload from GitLab CI/CD
Browse files Browse the repository at this point in the history
Signed-off-by: Facundo Tuesca <facundo.tuesca@trailofbits.com>
  • Loading branch information
facutuesca committed Nov 19, 2024
1 parent dd6a647 commit 42462d5
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 7 deletions.
19 changes: 13 additions & 6 deletions tests/unit/attestations/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -89,7 +93,6 @@ def test_parse_attestations_fails_no_publisher(self, db_request):
@pytest.mark.parametrize(
"publisher_factory",
[
GitLabPublisherFactory,
GooglePublisherFactory,
ActiveStatePublisherFactory,
],
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
19 changes: 19 additions & 0 deletions tests/unit/oidc/models/test_gitlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
1 change: 0 additions & 1 deletion warehouse/attestations/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 9 additions & 0 deletions warehouse/oidc/models/gitlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from typing import Any

from pypi_attestations import GitLabPublisher as GitLabIdentity, Publisher
from sqlalchemy import ForeignKey, String, UniqueConstraint
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Query, mapped_column
Expand Down Expand Up @@ -258,6 +259,14 @@ def publisher_url(self, claims=None):
base = self.publisher_base_url
return f"{base}/commit/{claims['sha']}" if claims else base

@property
def attestation_identity(self) -> 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")}
Expand Down

0 comments on commit 42462d5

Please sign in to comment.