Skip to content

Commit 9cfbbf9

Browse files
authored
test: add types to oidc.* modules (#18798)
1 parent 7e2d76a commit 9cfbbf9

File tree

18 files changed

+295
-163
lines changed

18 files changed

+295
-163
lines changed

warehouse/locale/messages.pot

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ msgstr ""
393393
msgid "Select project"
394394
msgstr ""
395395

396-
#: warehouse/manage/forms.py:507 warehouse/oidc/forms/_core.py:24
396+
#: warehouse/manage/forms.py:507 warehouse/oidc/forms/_core.py:36
397397
#: warehouse/oidc/forms/gitlab.py:47
398398
msgid "Specify project name"
399399
msgstr ""
@@ -676,45 +676,45 @@ msgstr ""
676676
msgid "Expired invitation for '${username}' deleted."
677677
msgstr ""
678678

679-
#: warehouse/oidc/forms/_core.py:26 warehouse/oidc/forms/_core.py:37
679+
#: warehouse/oidc/forms/_core.py:38 warehouse/oidc/forms/_core.py:49
680680
#: warehouse/oidc/forms/gitlab.py:50 warehouse/oidc/forms/gitlab.py:54
681681
msgid "Invalid project name"
682682
msgstr ""
683683

684-
#: warehouse/oidc/forms/_core.py:55
684+
#: warehouse/oidc/forms/_core.py:68
685685
#, python-brace-format
686686
msgid ""
687687
"This project already exists: use the project's publishing settings <a "
688688
"href='${url}'>here</a> to create a Trusted Publisher for it."
689689
msgstr ""
690690

691-
#: warehouse/oidc/forms/_core.py:64
691+
#: warehouse/oidc/forms/_core.py:77
692692
msgid "This project already exists."
693693
msgstr ""
694694

695-
#: warehouse/oidc/forms/_core.py:69
695+
#: warehouse/oidc/forms/_core.py:82
696696
msgid "This project name isn't allowed"
697697
msgstr ""
698698

699-
#: warehouse/oidc/forms/_core.py:73
699+
#: warehouse/oidc/forms/_core.py:86
700700
msgid "This project name is too similar to an existing project"
701701
msgstr ""
702702

703-
#: warehouse/oidc/forms/_core.py:78
703+
#: warehouse/oidc/forms/_core.py:91
704704
msgid ""
705705
"This project name isn't allowed (conflict with the Python standard "
706706
"library module name)"
707707
msgstr ""
708708

709-
#: warehouse/oidc/forms/_core.py:106 warehouse/oidc/forms/_core.py:117
709+
#: warehouse/oidc/forms/_core.py:119 warehouse/oidc/forms/_core.py:130
710710
msgid "Specify a publisher ID"
711711
msgstr ""
712712

713-
#: warehouse/oidc/forms/_core.py:107 warehouse/oidc/forms/_core.py:118
713+
#: warehouse/oidc/forms/_core.py:120 warehouse/oidc/forms/_core.py:131
714714
msgid "Publisher must be specified by ID"
715715
msgstr ""
716716

717-
#: warehouse/oidc/forms/_core.py:123
717+
#: warehouse/oidc/forms/_core.py:136
718718
msgid "Specify an environment name"
719719
msgstr ""
720720

warehouse/macaroons/services.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,14 @@ def verify(self, raw_macaroon: str, request, context, permission) -> bool:
140140

141141
def create_macaroon(
142142
self,
143-
location,
144-
description,
145-
scopes,
143+
location: str,
144+
description: str,
145+
scopes: list[caveats.Caveat],
146146
*,
147-
user_id=None,
148-
oidc_publisher_id=None,
149-
additional=None,
150-
):
147+
user_id: uuid.UUID | None = None,
148+
oidc_publisher_id: str | None = None,
149+
additional: dict[str, typing.Any] | None = None,
150+
) -> tuple[str, Macaroon]:
151151
"""
152152
Returns a tuple of a new raw (serialized) macaroon and its DB model.
153153
The description provided is not embedded into the macaroon, only stored

warehouse/oidc/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# SPDX-License-Identifier: Apache-2.0
2+
from __future__ import annotations
3+
4+
import typing
25

36
from celery.schedules import crontab
47

@@ -12,8 +15,11 @@
1215
GOOGLE_OIDC_ISSUER_URL,
1316
)
1417

18+
if typing.TYPE_CHECKING:
19+
from pyramid.config import Configurator
20+
1521

16-
def includeme(config):
22+
def includeme(config: Configurator) -> None:
1723
oidc_publisher_service_class = config.maybe_dotted(
1824
config.registry.settings["oidc.backend"]
1925
)

warehouse/oidc/forms/_core.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# SPDX-License-Identifier: Apache-2.0
22

3+
from __future__ import annotations
4+
5+
import typing
6+
37
import markupsafe
48
import structlog
59
import wtforms
@@ -15,10 +19,18 @@
1519
)
1620
from warehouse.utils.project import PROJECT_NAME_RE
1721

22+
if typing.TYPE_CHECKING:
23+
from warehouse.accounts.models import User
24+
1825
log = structlog.get_logger()
1926

2027

2128
class PendingPublisherMixin:
29+
# Attributes that must be provided by subclasses
30+
_user: User
31+
_check_project_name: typing.Callable[[str], None]
32+
_route_url: typing.Callable[..., str]
33+
2234
project_name = wtforms.StringField(
2335
validators=[
2436
wtforms.validators.InputRequired(message=_("Specify project name")),
@@ -28,7 +40,7 @@ class PendingPublisherMixin:
2840
]
2941
)
3042

31-
def validate_project_name(self, field):
43+
def validate_project_name(self, field: wtforms.Field) -> None:
3244
project_name = field.data
3345

3446
try:
@@ -39,7 +51,8 @@ def validate_project_name(self, field):
3951
# If the user owns the existing project, the error message includes a
4052
# link to the project settings that the user can modify.
4153
if self._user in e.existing_project.owners:
42-
url_params = {name: value for name, value in self.data.items() if value}
54+
# Mixin doesn't inherit from wtforms.Form but composed classes do
55+
url_params = {name: value for name, value in self.data.items() if value} # type: ignore[attr-defined] # noqa: E501
4356
url_params["provider"] = {self.provider}
4457
url = self._route_url(
4558
"manage.project.settings.publishing",

warehouse/oidc/forms/activestate.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ class GqlResponse(TypedDict):
3131
errors: list[dict[str, Any]]
3232

3333

34-
def _no_double_dashes(form, field):
34+
def _no_double_dashes(_form: wtforms.Form, field: wtforms.Field) -> None:
3535
if _DOUBLE_DASHES.search(field.data):
3636
raise wtforms.validators.ValidationError(
3737
_("Double dashes are not allowed in the name")
3838
)
3939

4040

41-
def _no_leading_or_trailing_dashes(form, field):
41+
def _no_leading_or_trailing_dashes(_form: wtforms.Form, field: wtforms.Field) -> None:
4242
if field.data.startswith("-") or field.data.endswith("-"):
4343
raise wtforms.validators.ValidationError(
4444
_("Leading or trailing dashes are not allowed in the name")
@@ -150,7 +150,7 @@ def process_org_response(response: GqlResponse) -> None:
150150
_GRAPHQL_GET_ORGANIZATION, {"orgname": org_url_name}, process_org_response
151151
)
152152

153-
def validate_organization(self, field):
153+
def validate_organization(self, field: wtforms.Field) -> None:
154154
self._lookup_organization(field.data)
155155

156156
def _lookup_actor(self, actor: str) -> UserResponse:
@@ -170,7 +170,7 @@ def process_actor_response(response: GqlResponse) -> UserResponse:
170170
_GRAPHQL_GET_ACTOR, {"username": actor}, process_actor_response
171171
)
172172

173-
def validate_actor(self, field):
173+
def validate_actor(self, field: wtforms.Field) -> None:
174174
actor = field.data
175175

176176
actor_info = self._lookup_actor(actor)

warehouse/oidc/forms/github.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,16 @@ class GitHubPublisherBase(wtforms.Form):
4545
# https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment
4646
environment = wtforms.StringField(validators=[wtforms.validators.Optional()])
4747

48-
def __init__(self, *args, api_token, **kwargs):
48+
def __init__(self, *args, api_token: str, **kwargs):
4949
super().__init__(*args, **kwargs)
5050
self._api_token = api_token
5151

52-
def _headers_auth(self):
52+
def _headers_auth(self) -> dict[str, str]:
5353
if not self._api_token:
5454
return {}
5555
return {"Authorization": f"token {self._api_token}"}
5656

57-
def _lookup_owner(self, owner):
57+
def _lookup_owner(self, owner: str) -> dict[str, str | int]:
5858
# To actually validate the owner, we ask GitHub's API about them.
5959
# We can't do this for the repository, since it might be private.
6060
try:
@@ -113,7 +113,7 @@ def _lookup_owner(self, owner):
113113

114114
return response.json()
115115

116-
def validate_owner(self, field):
116+
def validate_owner(self, field: wtforms.Field) -> None:
117117
owner = field.data
118118

119119
# We pre-filter owners with a regex, to avoid loading GitHub's API
@@ -129,7 +129,7 @@ def validate_owner(self, field):
129129
self.normalized_owner = owner_info["login"]
130130
self.owner_id = owner_info["id"]
131131

132-
def validate_workflow_filename(self, field):
132+
def validate_workflow_filename(self, field: wtforms.Field) -> None:
133133
workflow_filename = field.data
134134

135135
if not (
@@ -144,7 +144,7 @@ def validate_workflow_filename(self, field):
144144
_("Workflow filename must be a filename only, without directories")
145145
)
146146

147-
def validate_environment(self, field):
147+
def validate_environment(self, field: wtforms.Field) -> None:
148148
environment = field.data
149149

150150
if not environment:
@@ -174,7 +174,7 @@ def validate_environment(self, field):
174174
)
175175

176176
@property
177-
def normalized_environment(self):
177+
def normalized_environment(self) -> str:
178178
# The only normalization is due to case-insensitivity.
179179
#
180180
# NOTE: We explicitly do not compare `self.environment.data` to None,

warehouse/oidc/forms/gitlab.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class GitLabPublisherBase(wtforms.Form):
7676
def __init__(self, *args, **kwargs):
7777
super().__init__(*args, **kwargs)
7878

79-
def validate_workflow_filepath(self, field):
79+
def validate_workflow_filepath(self, field: wtforms.Field) -> None:
8080
workflow_filepath = field.data
8181

8282
if not (
@@ -91,7 +91,7 @@ def validate_workflow_filepath(self, field):
9191
)
9292

9393
@property
94-
def normalized_environment(self):
94+
def normalized_environment(self) -> str:
9595
# NOTE: We explicitly do not compare `self.environment.data` to None,
9696
# since it might also be falsey via an empty string (or might be
9797
# only whitespace, which we also treat as a None case).

warehouse/oidc/interfaces.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
from warehouse.rate_limiting.interfaces import RateLimiterException
1010

1111
if TYPE_CHECKING:
12-
from warehouse.oidc.models import PendingOIDCPublisher
12+
from warehouse.oidc.models import OIDCPublisher, PendingOIDCPublisher
1313
from warehouse.packaging.models import Project
1414

15-
SignedClaims = NewType("SignedClaims", dict[str, Any])
15+
SignedClaims = NewType("SignedClaims", dict[str, Any]) # TODO: narrow this down
1616

1717

1818
class IOIDCPublisherService(Interface):
19-
def verify_jwt_signature(unverified_token: str):
19+
def verify_jwt_signature(unverified_token: str) -> SignedClaims | None:
2020
"""
2121
Verify the given JWT's signature, returning its signed claims if
2222
valid. If the signature is invalid, `None` is returned.
@@ -26,7 +26,9 @@ def verify_jwt_signature(unverified_token: str):
2626
"""
2727
pass
2828

29-
def find_publisher(signed_claims: SignedClaims, *, pending: bool = False):
29+
def find_publisher(
30+
signed_claims: SignedClaims, *, pending: bool = False
31+
) -> OIDCPublisher | PendingOIDCPublisher | None:
3032
"""
3133
Given a mapping of signed claims produced by `verify_jwt_signature`,
3234
attempt to find and return either a `OIDCPublisher` or `PendingOIDCPublisher`
@@ -38,7 +40,7 @@ def find_publisher(signed_claims: SignedClaims, *, pending: bool = False):
3840

3941
def reify_pending_publisher(
4042
pending_publisher: PendingOIDCPublisher, project: Project
41-
):
43+
) -> OIDCPublisher:
4244
"""
4345
Reify the given pending `PendingOIDCPublisher` into an `OIDCPublisher`,
4446
adding it to the given project (presumed newly created) in the process.

0 commit comments

Comments
 (0)