Skip to content

Commit

Permalink
[oidc] Highlight publisher errors (pypi#13421)
Browse files Browse the repository at this point in the history
* Jump to errors if present

* Flash error if publisher could not be registered
  • Loading branch information
di authored Apr 13, 2023
1 parent e4cf31b commit 2bde04f
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 71 deletions.
4 changes: 4 additions & 0 deletions warehouse/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1460,6 +1460,10 @@ def add_pending_github_oidc_publisher(self):
form = response["pending_github_publisher_form"]

if not form.validate():
self.request.session.flash(
self.request._("The trusted publisher could not be registered"),
queue="error",
)
return response

publisher_already_exists = (
Expand Down
24 changes: 14 additions & 10 deletions warehouse/locale/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,11 @@ msgid ""
"again later."
msgstr ""

#: warehouse/accounts/views.py:1479
#: warehouse/accounts/views.py:1464 warehouse/manage/views/__init__.py:1258
msgid "The trusted publisher could not be registered"
msgstr ""

#: warehouse/accounts/views.py:1483
msgid ""
"This trusted publisher has already been registered. Please contact PyPI's"
" admins if this wasn't intentional."
Expand Down Expand Up @@ -368,43 +372,43 @@ msgstr ""
msgid "Generating new recovery codes will invalidate your existing codes."
msgstr ""

#: warehouse/manage/views/__init__.py:2035
#: warehouse/manage/views/__init__.py:2039
msgid "Team '${team_name}' already has ${role_name} role for project"
msgstr ""

#: warehouse/manage/views/__init__.py:2143
#: warehouse/manage/views/__init__.py:2147
msgid "User '${username}' already has ${role_name} role for project"
msgstr ""

#: warehouse/manage/views/__init__.py:2211
#: warehouse/manage/views/__init__.py:2215
msgid "${username} is now ${role} of the '${project_name}' project."
msgstr ""

#: warehouse/manage/views/__init__.py:2243
#: warehouse/manage/views/__init__.py:2247
msgid ""
"User '${username}' does not have a verified primary email address and "
"cannot be added as a ${role_name} for project"
msgstr ""

#: warehouse/manage/views/__init__.py:2256
#: warehouse/manage/views/__init__.py:2260
#: warehouse/manage/views/organizations.py:896
msgid "User '${username}' already has an active invite. Please try again later."
msgstr ""

#: warehouse/manage/views/__init__.py:2322
#: warehouse/manage/views/__init__.py:2326
#: warehouse/manage/views/organizations.py:961
msgid "Invitation sent to '${username}'"
msgstr ""

#: warehouse/manage/views/__init__.py:2355
#: warehouse/manage/views/__init__.py:2359
msgid "Could not find role invitation."
msgstr ""

#: warehouse/manage/views/__init__.py:2366
#: warehouse/manage/views/__init__.py:2370
msgid "Invitation already expired."
msgstr ""

#: warehouse/manage/views/__init__.py:2399
#: warehouse/manage/views/__init__.py:2403
#: warehouse/manage/views/organizations.py:1148
msgid "Invitation revoked from '${username}'."
msgstr ""
Expand Down
122 changes: 63 additions & 59 deletions warehouse/manage/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1253,74 +1253,78 @@ def add_github_oidc_publisher(self):
response = self.default_response
form = response["github_publisher_form"]

if form.validate():
# GitHub OIDC publishers are unique on the tuple of
# (repository_name, repository_owner, workflow_filename, environment),
# so we check for an already registered one before creating.
publisher = (
self.request.db.query(GitHubPublisher)
.filter(
GitHubPublisher.repository_name == form.repository.data,
GitHubPublisher.repository_owner == form.normalized_owner,
GitHubPublisher.workflow_filename == form.workflow_filename.data,
GitHubPublisher.environment == form.normalized_environment,
)
.one_or_none()
)
if publisher is None:
publisher = GitHubPublisher(
repository_name=form.repository.data,
repository_owner=form.normalized_owner,
repository_owner_id=form.owner_id,
workflow_filename=form.workflow_filename.data,
environment=form.normalized_environment,
)

self.request.db.add(publisher)

# Each project has a unique set of OIDC publishers; the same
# publisher can't be registered to the project more than once.
if publisher in self.project.oidc_publishers:
self.request.session.flash(
f"{publisher} is already registered with {self.project.name}",
queue="error",
)
return response

for user in self.project.users:
send_trusted_publisher_added_email(
self.request,
user,
project_name=self.project.name,
publisher=publisher,
)

self.project.oidc_publishers.append(publisher)
if not form.validate():
self.request.session.flash(
self.request._("The trusted publisher could not be registered"),
queue="error",
)
return response

self.project.record_event(
tag=EventTag.Project.OIDCPublisherAdded,
ip_address=self.request.remote_addr,
additional={
"publisher": publisher.publisher_name,
"id": str(publisher.id),
"specifier": str(publisher),
"url": publisher.publisher_url,
"submitted_by": self.request.user.username,
},
# GitHub OIDC publishers are unique on the tuple of
# (repository_name, repository_owner, workflow_filename, environment),
# so we check for an already registered one before creating.
publisher = (
self.request.db.query(GitHubPublisher)
.filter(
GitHubPublisher.repository_name == form.repository.data,
GitHubPublisher.repository_owner == form.normalized_owner,
GitHubPublisher.workflow_filename == form.workflow_filename.data,
GitHubPublisher.environment == form.normalized_environment,
)
.one_or_none()
)
if publisher is None:
publisher = GitHubPublisher(
repository_name=form.repository.data,
repository_owner=form.normalized_owner,
repository_owner_id=form.owner_id,
workflow_filename=form.workflow_filename.data,
environment=form.normalized_environment,
)

self.request.db.add(publisher)

# Each project has a unique set of OIDC publishers; the same
# publisher can't be registered to the project more than once.
if publisher in self.project.oidc_publishers:
self.request.session.flash(
f"Added {publisher} to {self.project.name}",
queue="success",
f"{publisher} is already registered with {self.project.name}",
queue="error",
)
return response

self.metrics.increment(
"warehouse.oidc.add_publisher.ok", tags=["publisher:GitHub"]
for user in self.project.users:
send_trusted_publisher_added_email(
self.request,
user,
project_name=self.project.name,
publisher=publisher,
)

return HTTPSeeOther(self.request.path)
self.project.oidc_publishers.append(publisher)

return response
self.project.record_event(
tag=EventTag.Project.OIDCPublisherAdded,
ip_address=self.request.remote_addr,
additional={
"publisher": publisher.publisher_name,
"id": str(publisher.id),
"specifier": str(publisher),
"url": publisher.publisher_url,
"submitted_by": self.request.user.username,
},
)

self.request.session.flash(
f"Added {publisher} to {self.project.name}",
queue="success",
)

self.metrics.increment(
"warehouse.oidc.add_publisher.ok", tags=["publisher:GitHub"]
)

return HTTPSeeOther(self.request.path)

@view_config(
request_method="POST",
Expand Down
2 changes: 1 addition & 1 deletion warehouse/templates/manage/account/publishing.html
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ <h2>{% trans %}Add a new pending publisher{% endtrans %}</h2>
<h3>GitHub</h3>

{{ form_error_anchor(pending_github_publisher_form) }}
<form method="POST" action="{{ request.route_path('manage.account.publishing') }}">
<form method="POST" action="{{ request.route_path('manage.account.publishing') }}#errors">
<input name="csrf_token" type="hidden" value="{{ request.session.get_csrf_token() }}">
{{ form_errors(pending_github_publisher_form) }}
<div class="form-group">
Expand Down
2 changes: 1 addition & 1 deletion warehouse/templates/manage/project/publishing.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ <h3>GitHub</h3>
</p>

{{ form_error_anchor(github_publisher_form) }}
<form method="POST" action="{{ request.route_path('manage.project.settings.publishing', project_name=project.name) }}">
<form method="POST" action="{{ request.route_path('manage.project.settings.publishing', project_name=project.name) }}#errors">
<input name="csrf_token" type="hidden" value="{{ request.session.get_csrf_token() }}">
{{ form_errors(github_publisher_form) }}
<div class="form-group">
Expand Down

0 comments on commit 2bde04f

Please sign in to comment.