This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git
The following commit(s) were added to refs/heads/main by this push:
new a91f1c6 Update and improve the form to add an SSH key
a91f1c6 is described below
commit a91f1c6af09783bbc271a383d06f0f72898f20f3
Author: Sean B. Palmer <[email protected]>
AuthorDate: Tue May 13 18:56:30 2025 +0100
Update and improve the form to add an SSH key
---
atr/routes/keys.py | 27 +++++++++++++++++++++------
atr/tarzip.py | 7 +++++--
atr/templates/keys-ssh-add.html | 24 +++++++-----------------
atr/templates/macros/forms.html | 17 +++++++++++++++++
4 files changed, 50 insertions(+), 25 deletions(-)
diff --git a/atr/routes/keys.py b/atr/routes/keys.py
index 8091929..accd485 100644
--- a/atr/routes/keys.py
+++ b/atr/routes/keys.py
@@ -48,7 +48,15 @@ from atr.routes import compose
class AddSSHKeyForm(util.QuartFormTyped):
- key = wtforms.StringField("SSH key", widget=wtforms.widgets.TextArea())
+ key = wtforms.StringField(
+ "SSH public key",
+ widget=wtforms.widgets.TextArea(),
+ render_kw={"placeholder": "Paste your SSH public key here (in the
format used in authorized_keys files)"},
+ description=(
+ "Your SSH public key should be in the standard format, starting
with a key type"
+ ' (like "ssh-rsa" or "ssh-ed25519") followed by the key data.'
+ ),
+ )
submit = wtforms.SubmitField("Add SSH key")
@@ -321,11 +329,18 @@ async def ssh_add(session: routes.CommitterSession) ->
response.Response | str:
fingerprint = None
if await form.validate_on_submit():
key: str = util.unwrap(form.key.data)
- fingerprint = await asyncio.to_thread(key_ssh_fingerprint, key)
- async with db.session() as data:
- async with data.begin():
- data.add(models.SSHKey(fingerprint=fingerprint, key=key,
asf_uid=session.uid))
- return await session.redirect(keys, success=f"SSH key added
successfully: {fingerprint}")
+ try:
+ fingerprint = await asyncio.to_thread(key_ssh_fingerprint, key)
+ except ValueError as e:
+ if isinstance(form.key.errors, list):
+ form.key.errors.append(str(e))
+ else:
+ form.key.errors = [str(e)]
+ else:
+ async with db.session() as data:
+ async with data.begin():
+ data.add(models.SSHKey(fingerprint=fingerprint, key=key,
asf_uid=session.uid))
+ return await session.redirect(keys, success=f"SSH key added
successfully: {fingerprint}")
return await quart.render_template(
"keys-ssh-add.html",
diff --git a/atr/tarzip.py b/atr/tarzip.py
index 532c0ff..1a9e01e 100644
--- a/atr/tarzip.py
+++ b/atr/tarzip.py
@@ -23,10 +23,13 @@ from typing import IO, Generic, TypeVar
from typing import Protocol as TypingProtocol
ArchiveT = TypeVar("ArchiveT", tarfile.TarFile, zipfile.ZipFile)
-MemberT = TypeVar("MemberT", tarfile.TarInfo, zipfile.ZipInfo)
+# If you set this covariant=True, then mypy says an "invariant one is expected"
+# But pyright warns, "should be covariant" if you don't
+# We'll use the covariant version and ignore the mypy error
+MemberT = TypeVar("MemberT", tarfile.TarInfo, zipfile.ZipInfo, covariant=True)
-class AbstractArchiveMember(TypingProtocol, Generic[MemberT]):
+class AbstractArchiveMember(TypingProtocol, Generic[MemberT]): # type:
ignore[misc]
name: str
_original_info: MemberT
diff --git a/atr/templates/keys-ssh-add.html b/atr/templates/keys-ssh-add.html
index a19e426..eb9d24e 100644
--- a/atr/templates/keys-ssh-add.html
+++ b/atr/templates/keys-ssh-add.html
@@ -22,28 +22,18 @@
</p>
</div>
- {% if form.errors %}
- <h2 class="text-danger">Form errors</h2>
- <div class="mt-3 mb-3">
- {% for field, errors in form.errors.items() %}
- {% for error in errors %}<p class="text-danger mb-1">{{ field }}: {{
error }}</p>{% endfor %}
- {% endfor %}
- </div>
- {% endif %}
+ {{ forms.errors_summary(form) }}
- <form method="post" class="atr-canary">
+ <form method="post" class="atr-canary py-4 px-5" novalidate>
{{ form.hidden_tag() }}
<div class="mb-4">
- <div class="mb-3">
- <label for="key" class="form-label">SSH public key:</label>
- </div>
- {{ form.key(class="form-control mb-2", rows=4, placeholder="Paste your
SSH public key here (in the format used in authorized_keys files)",
aria_describedby="key-help") }}
- <small id="key-help" class="form-text text-muted">
- Your SSH public key should be in the standard format, starting with a
key type (like "ssh-rsa" or "ssh-ed25519") followed by the key data.
- </small>
+ {{ forms.label(form.key) }}
+ {{ forms.widget(form.key, classes="form-control mb-2", rows=4,
id=form.key.id) }}
+ {{ forms.errors(form.key, classes="invalid-feedback d-block") }}
+ {{ forms.description(form.key) }}
</div>
- {{ form.submit(class="btn btn-primary") }}
+ {{ form.submit(class_="btn btn-primary") }}
</form>
{% endblock content %}
diff --git a/atr/templates/macros/forms.html b/atr/templates/macros/forms.html
index 8ef5a33..8fecf77 100644
--- a/atr/templates/macros/forms.html
+++ b/atr/templates/macros/forms.html
@@ -64,3 +64,20 @@
{% macro description(field, classes="form-text text-muted") %}
{% if field.description %}<div id="{{ field.id }}-help" class="{{ classes
}}">{{ field.description }}</div>{% endif %}
{% endmacro %}
+
+{% macro errors_summary(form, alert_classes='alert alert-danger mt-3 mb-3',
heading_text='Please correct the errors below:') %}
+ {% if form.errors and form.errors|length > 0 %}
+ <div class="{{ alert_classes }}" role="alert">
+ <p class="alert-heading">
+ <strong>{{ heading_text }}</strong>
+ </p>
+ <ul class="mb-0">
+ {% for field_name, field_errors in form.errors.items() %}
+ {% for error in field_errors %}
+ <li>{{ form[field_name].label.text if form[field_name] and
form[field_name].label else field_name }}: {{ error }}</li>
+ {% endfor %}
+ {% endfor %}
+ </ul>
+ </div>
+ {% endif %}
+{% endmacro %}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]