Skip to content

Commit da6892f

Browse files
authored
fix: allow mixed case GitLab Trusted Publishers (#18824)
In the event a user has configured a Publisher with non-lowercase characters, lowercase them at query time, as the provided JWT claims will have lowercased them. Resolves #18797 Closes #18805 Signed-off-by: Mike Fiedler <[email protected]>
1 parent d870628 commit da6892f

File tree

2 files changed

+29
-5
lines changed

2 files changed

+29
-5
lines changed

tests/unit/oidc/models/test_gitlab.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,29 @@ def test_lookup_fails_invalid_ci_config_ref_uri(self, environment):
7373
):
7474
gitlab.GitLabPublisher.lookup_by_claims(pretend.stub(), signed_claims)
7575

76+
def test_lookup_succeeds_with_mixed_case_project_path(self, db_request):
77+
# Test that we find a matching publisher when the project_path claims match
78+
# even if the case is different.
79+
stored_publisher = GitLabPublisherFactory(
80+
namespace="Foo",
81+
project="Bar",
82+
workflow_filepath=".gitlab-ci.yml",
83+
environment="",
84+
)
85+
86+
signed_claims = {
87+
"project_path": "foo/bar", # different case than stored publisher
88+
"ci_config_ref_uri": ("gitlab.com/foo/bar//.gitlab-ci.yml@refs/heads/main"),
89+
"environment": "some_environment",
90+
}
91+
92+
publisher = gitlab.GitLabPublisher.lookup_by_claims(
93+
db_request.db, signed_claims
94+
)
95+
96+
assert publisher.id == stored_publisher.id
97+
assert publisher.environment == stored_publisher.environment
98+
7699
@pytest.mark.parametrize("environment", ["SomeEnvironment", "SOME_ENVIRONMENT"])
77100
def test_lookup_succeeds_with_non_lowercase_environment(
78101
self, db_request, environment

warehouse/oidc/models/gitlab.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from more_itertools import first_true
1212
from pypi_attestations import GitLabPublisher as GitLabIdentity, Publisher
13-
from sqlalchemy import ForeignKey, String, UniqueConstraint, and_, exists
13+
from sqlalchemy import ForeignKey, String, UniqueConstraint, and_, exists, func
1414
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
1515
from sqlalchemy.orm import Mapped, Query, mapped_column
1616

@@ -244,10 +244,11 @@ def lookup_by_claims(cls, session: Session, signed_claims: SignedClaims) -> Self
244244
"Could not extract workflow filename from OIDC claims"
245245
)
246246

247-
query: Query = Query(cls).filter_by(
248-
namespace=namespace,
249-
project=project,
250-
workflow_filepath=workflow_filepath,
247+
query: Query = Query(cls).filter(
248+
# claims `project_path` is case-insensitive
249+
func.lower(cls.namespace) == namespace,
250+
func.lower(cls.project) == project,
251+
cls.workflow_filepath == workflow_filepath,
251252
)
252253
publishers = query.with_session(session).all()
253254
if publisher := cls._get_publisher_for_environment(publishers, environment):

0 commit comments

Comments
 (0)