Skip to content

Commit e33b52f

Browse files
authored
feat: allow user to choose custom issuer for project (#18916)
* feat: allow user to choose custom issuer for project If the project is owned by an organization and there is a custom issuer configured, populate the form with the choices available. --------- Signed-off-by: Mike Fiedler <miketheman@gmail.com>
1 parent 315845f commit e33b52f

File tree

9 files changed

+244
-85
lines changed

9 files changed

+244
-85
lines changed

tests/unit/accounts/test_views.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4448,6 +4448,7 @@ def test_add_pending_oidc_publisher_invalid_form(
44484448
"workflow_filepath": "subfolder/some-workflow-filename.yml",
44494449
"environment": "some-environment",
44504450
"project_name": "some-project-name",
4451+
"issuer_url": "https://gitlab.com",
44514452
}
44524453
),
44534454
),
@@ -4638,6 +4639,7 @@ def test_add_pending_oidc_publisher_uniqueviolation(self, monkeypatch, db_reques
46384639
"workflow_filepath": "subfolder/some-workflow-filename.yml",
46394640
"environment": "some-environment",
46404641
"project_name": "some-project-name",
4642+
"issuer_url": "https://gitlab.com",
46414643
}
46424644
),
46434645
PendingGitLabPublisher,

tests/unit/manage/views/test_oidc_publishers.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
class TestManageOIDCPublisherViews:
2929
def test_initializes(self, metrics):
30-
project = pretend.stub()
30+
project = pretend.stub(organization=None)
3131
request = pretend.stub(
3232
find_service=pretend.call_recorder(lambda *a, **kw: metrics),
3333
registry=pretend.stub(
@@ -56,7 +56,7 @@ def test_initializes(self, metrics):
5656
],
5757
)
5858
def test_ratelimiting(self, metrics, ip_exceeded, user_exceeded):
59-
project = pretend.stub()
59+
project = pretend.stub(organization=None)
6060
user_rate_limiter = pretend.stub(
6161
hit=pretend.call_recorder(lambda *a, **kw: None),
6262
test=pretend.call_recorder(lambda uid: not user_exceeded),
@@ -115,7 +115,7 @@ def find_service(iface, name=None, context=None):
115115
view._check_ratelimits()
116116

117117
def test_manage_project_oidc_publishers(self, monkeypatch):
118-
project = pretend.stub(oidc_publishers=[])
118+
project = pretend.stub(oidc_publishers=[], organization=None)
119119
request = pretend.stub(
120120
user=pretend.stub(),
121121
registry=pretend.stub(
@@ -157,7 +157,7 @@ def test_manage_project_oidc_publishers(self, monkeypatch):
157157
def test_manage_project_oidc_publishers_admin_disabled(
158158
self, monkeypatch, pyramid_request
159159
):
160-
project = pretend.stub(oidc_publishers=[])
160+
project = pretend.stub(oidc_publishers=[], organization=None)
161161
pyramid_request.user = pretend.stub()
162162
pyramid_request.registry = pretend.stub(
163163
settings={
@@ -230,6 +230,7 @@ def test_manage_project_oidc_publishers_admin_disabled(
230230
"project": "repo",
231231
"workflow_filepath": "file.yml",
232232
"environment": "my_env",
233+
"issuer_url": "https://gitlab.com",
233234
},
234235
),
235236
# All fields of Google provider
@@ -267,7 +268,7 @@ def test_manage_project_oidc_publishers_admin_disabled(
267268
def test_manage_project_oidc_publishers_prefill(
268269
self, monkeypatch, form_name, prefilled_data
269270
):
270-
project = pretend.stub(oidc_publishers=[])
271+
project = pretend.stub(oidc_publishers=[], organization=None)
271272
request = pretend.stub(
272273
user=pretend.stub(),
273274
registry=pretend.stub(
@@ -350,7 +351,7 @@ def test_manage_project_oidc_publishers_prefill(
350351
def test_manage_project_oidc_publishers_prefill_partial(
351352
self, monkeypatch, missing_fields, prefilled_data, extra_fields
352353
):
353-
project = pretend.stub(oidc_publishers=[])
354+
project = pretend.stub(oidc_publishers=[], organization=None)
354355
request = pretend.stub(
355356
user=pretend.stub(),
356357
registry=pretend.stub(
@@ -396,7 +397,7 @@ def test_manage_project_oidc_publishers_prefill_partial(
396397
assert view.github_publisher_form.data == expected_data
397398

398399
def test_manage_project_oidc_publishers_prefill_unknown_provider(self, monkeypatch):
399-
project = pretend.stub(oidc_publishers=[])
400+
project = pretend.stub(oidc_publishers=[], organization=None)
400401
prefilled_data = {
401402
"provider": "github2",
402403
"owner": "owner",
@@ -649,7 +650,7 @@ def test_manage_project_oidc_publishers_constrain_environment_shared_publisher(
649650
]
650651

651652
def test_constrain_oidc_publisher_admin_disabled(self, monkeypatch):
652-
project = pretend.stub()
653+
project = pretend.stub(organization=None)
653654
request = pretend.stub(
654655
method="POST",
655656
params=MultiDict(),
@@ -687,7 +688,7 @@ def test_constrain_oidc_publisher_admin_disabled(self, monkeypatch):
687688
]
688689

689690
def test_constrain_oidc_publisher_invalid_params(self, monkeypatch, metrics):
690-
project = pretend.stub()
691+
project = pretend.stub(organization=None)
691692
request = pretend.stub(
692693
method="POST",
693694
params=MultiDict(),
@@ -727,7 +728,7 @@ def test_constrain_oidc_publisher_invalid_params(self, monkeypatch, metrics):
727728
def test_constrain_non_extant_oidc_publisher(
728729
self, monkeypatch, metrics, db_request
729730
):
730-
project = pretend.stub()
731+
project = pretend.stub(organization=None)
731732
db_request.method = "POST"
732733
db_request.POST = MultiDict(
733734
{
@@ -1051,6 +1052,7 @@ def test_constrain_environment_publisher_already_exists(
10511052
namespace=pretend.stub(data=publisher.namespace),
10521053
workflow_filepath=pretend.stub(data=publisher.workflow_filepath),
10531054
normalized_environment=publisher.environment,
1055+
issuer_url=pretend.stub(data="https://gitlab.com"),
10541056
),
10551057
),
10561058
(
@@ -1100,6 +1102,7 @@ def test_add_oidc_publisher_preexisting(
11001102
project = pretend.stub(
11011103
name="fakeproject",
11021104
oidc_publishers=[],
1105+
organization=None,
11031106
record_event=pretend.call_recorder(lambda *a, **kw: None),
11041107
users=[],
11051108
)
@@ -1210,6 +1213,7 @@ def test_add_oidc_publisher_preexisting(
12101213
namespace=pretend.stub(data="fakeowner"),
12111214
workflow_filepath=pretend.stub(data="subfolder/fakeworkflow.yml"),
12121215
normalized_environment="some-environment",
1216+
issuer_url=pretend.stub(data="https://gitlab.com"),
12131217
),
12141218
pretend.stub(publisher_name="GitLab"),
12151219
),
@@ -1245,6 +1249,7 @@ def test_add_oidc_publisher_created(
12451249
project = pretend.stub(
12461250
name="fakeproject",
12471251
oidc_publishers=[],
1252+
organization=None,
12481253
record_event=pretend.call_recorder(lambda *a, **kw: None),
12491254
users=[fakeuser],
12501255
)
@@ -1385,6 +1390,7 @@ def test_add_oidc_publisher_created(
13851390
"project": "some-repository",
13861391
"workflow_filepath": "subfolder/some-workflow-filename.yml",
13871392
"environment": "some-environment",
1393+
"issuer_url": "https://gitlab.com",
13881394
}
13891395
),
13901396
),
@@ -1432,6 +1438,7 @@ def test_add_oidc_publisher_already_registered_with_project(
14321438
project = pretend.stub(
14331439
name="fakeproject",
14341440
oidc_publishers=[publisher],
1441+
organization=None,
14351442
record_event=pretend.call_recorder(lambda *a, **kw: None),
14361443
)
14371444

@@ -1528,6 +1535,7 @@ def test_add_oidc_publisher_already_registered_after_normalization(
15281535
project = pretend.stub(
15291536
name="fakeproject",
15301537
oidc_publishers=[publisher],
1538+
organization=None,
15311539
record_event=pretend.call_recorder(lambda *a, **kw: None),
15321540
)
15331541

@@ -1598,7 +1606,7 @@ def test_add_oidc_publisher_already_registered_after_normalization(
15981606
def test_add_oidc_publisher_ratelimited(
15991607
self, metrics, monkeypatch, view_name, publisher_name
16001608
):
1601-
project = pretend.stub()
1609+
project = pretend.stub(organization=None)
16021610

16031611
request = pretend.stub(
16041612
user=pretend.stub(),
@@ -1648,7 +1656,7 @@ def test_add_oidc_publisher_ratelimited(
16481656
def test_add_oidc_publisher_admin_disabled(
16491657
self, monkeypatch, view_name, publisher_name
16501658
):
1651-
project = pretend.stub()
1659+
project = pretend.stub(organization=None)
16521660
request = pretend.stub(
16531661
user=pretend.stub(),
16541662
find_service=lambda *a, **kw: None,
@@ -1691,7 +1699,7 @@ def test_add_oidc_publisher_admin_disabled(
16911699
def test_add_oidc_publisher_invalid_form(
16921700
self, metrics, monkeypatch, view_name, publisher_name
16931701
):
1694-
project = pretend.stub()
1702+
project = pretend.stub(organization=None)
16951703
request = pretend.stub(
16961704
user=pretend.stub(),
16971705
find_service=lambda *a, **kw: metrics,
@@ -1966,7 +1974,7 @@ def test_delete_oidc_publisher_entirely(self, monkeypatch, db_request, publisher
19661974

19671975
def test_delete_oidc_publisher_invalid_form(self, metrics, monkeypatch):
19681976
publisher = pretend.stub()
1969-
project = pretend.stub(oidc_publishers=[publisher])
1977+
project = pretend.stub(oidc_publishers=[publisher], organization=None)
19701978
request = pretend.stub(
19711979
user=pretend.stub(),
19721980
find_service=lambda *a, **kw: metrics,
@@ -2020,6 +2028,7 @@ def test_delete_oidc_publisher_not_found(
20202028

20212029
project = pretend.stub(
20222030
oidc_publishers=[publisher],
2031+
organization=None,
20232032
name="fakeproject",
20242033
record_event=pretend.call_recorder(lambda *a, **kw: None),
20252034
)
@@ -2074,7 +2083,7 @@ def test_delete_oidc_publisher_not_found(
20742083
assert delete_publisher_form_obj.validate.calls == [pretend.call()]
20752084

20762085
def test_delete_oidc_publisher_admin_disabled(self, monkeypatch):
2077-
project = pretend.stub()
2086+
project = pretend.stub(organization=None)
20782087
request = pretend.stub(
20792088
user=pretend.stub(),
20802089
find_service=lambda *a, **kw: None,

tests/unit/oidc/forms/test_gitlab.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ def test_validate(self, project_service):
2626
"project": "some-repo",
2727
"workflow_filepath": "subfolder/some-workflow.yml",
2828
"project_name": "some-project",
29+
"issuer_url": "https://gitlab.com",
2930
}
3031
)
3132
form = gitlab.PendingGitLabPublisherForm(
3233
MultiDict(data),
3334
route_url=route_url,
3435
check_project_name=project_service.check_project_name,
3536
user=user,
37+
issuer_url_choices=["https://gitlab.com"],
3638
)
3739

3840
assert form._route_url == route_url
@@ -54,6 +56,7 @@ def test_validate_project_name_already_in_use_owner(
5456
route_url=route_url,
5557
check_project_name=project_service.check_project_name,
5658
user=user,
59+
issuer_url_choices=["https://gitlab.com"],
5760
)
5861

5962
field = pretend.stub(data="some-project")
@@ -66,7 +69,7 @@ def test_validate_project_name_already_in_use_owner(
6669
pretend.call(
6770
"manage.project.settings.publishing",
6871
project_name="some-project",
69-
_query={"provider": {"gitlab"}},
72+
_query={"issuer_url": "https://gitlab.com", "provider": {"gitlab"}},
7073
)
7174
]
7275

@@ -99,22 +102,27 @@ class TestGitLabPublisherForm:
99102
"namespace": "some-owner",
100103
"project": "some-repo",
101104
"workflow_filepath": "subfolder/some-workflow.yml",
105+
"issuer_url": "https://gitlab.com",
102106
},
103107
{
104108
"namespace": "some-group/some-subgroup",
105109
"project": "some-repo",
106110
"workflow_filepath": "subfolder/some-workflow.yml",
111+
"issuer_url": "https://gitlab.com",
107112
},
108113
# Leading/trailing whitespace is stripped from filepath
109114
{
110115
"namespace": "some-group/some-subgroup",
111116
"project": "some-repo",
112117
"workflow_filepath": " subfolder/some-workflow.yml ",
118+
"issuer_url": "https://gitlab.com",
113119
},
114120
],
115121
)
116122
def test_validate(self, data):
117-
form = gitlab.GitLabPublisherForm(MultiDict(data))
123+
form = gitlab.GitLabPublisherForm(
124+
MultiDict(data), issuer_url_choices=["https://gitlab.com"]
125+
)
118126

119127
# We're testing only the basic validation here.
120128
assert form.validate(), str(form.errors)

tests/unit/oidc/models/test_gitlab.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import pytest
66

77
from tests.common.db.oidc import GitLabPublisherFactory, PendingGitLabPublisherFactory
8+
from tests.common.db.organizations import OrganizationOIDCIssuerFactory
89
from warehouse.oidc import errors
910
from warehouse.oidc.models import _core, gitlab
1011

@@ -897,6 +898,58 @@ def test_exists(self, db_request, exists_in_db):
897898

898899
assert publisher.exists(db_request.db) == exists_in_db
899900

901+
def test_get_available_issuer_urls_default(self):
902+
"""By default, there's a single known GitLab issuer URL."""
903+
issuer_urls = gitlab.GitLabPublisher.get_available_issuer_urls()
904+
assert issuer_urls == ["https://gitlab.com"]
905+
906+
def test_get_available_issuer_urls_custom(self, db_session):
907+
"""If a custom GitLab issuer URL is configured for the org, it is included."""
908+
org_oidc_issuer = OrganizationOIDCIssuerFactory(issuer_type="gitlab")
909+
910+
issuer_urls = gitlab.GitLabPublisher.get_available_issuer_urls(
911+
org_oidc_issuer.organization
912+
)
913+
914+
assert issuer_urls == ["https://gitlab.com", org_oidc_issuer.issuer_url]
915+
916+
def test_get_available_issuer_urls_multiple_custom(self, db_session):
917+
"""
918+
If multiple custom GitLab issuer URLs are configured for the org,
919+
they are all included, and sorted alphabetically after the default.
920+
"""
921+
org_oidc_issuer1 = OrganizationOIDCIssuerFactory(
922+
issuer_type="gitlab", issuer_url="https://zzz.example.com"
923+
)
924+
org_oidc_issuer2 = OrganizationOIDCIssuerFactory(
925+
organization=org_oidc_issuer1.organization,
926+
issuer_type="gitlab",
927+
issuer_url="https://aaa.example.com",
928+
)
929+
930+
issuer_urls = gitlab.GitLabPublisher.get_available_issuer_urls(
931+
org_oidc_issuer1.organization
932+
)
933+
934+
assert issuer_urls == [
935+
"https://gitlab.com",
936+
org_oidc_issuer2.issuer_url,
937+
org_oidc_issuer1.issuer_url,
938+
]
939+
940+
def test_get_available_issuer_urls_custom_non_gitlab(self, db_session):
941+
"""
942+
If a custom OIDC issuer URL of a different type is configured for the org,
943+
it is not included.
944+
"""
945+
org_oidc_issuer = OrganizationOIDCIssuerFactory(issuer_type="github")
946+
947+
issuer_urls = gitlab.GitLabPublisher.get_available_issuer_urls(
948+
org_oidc_issuer.organization
949+
)
950+
951+
assert issuer_urls == ["https://gitlab.com"]
952+
900953

901954
class TestPendingGitLabPublisher:
902955
def test_reify_does_not_exist_yet(self, db_request):

0 commit comments

Comments
 (0)