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 42ef019 Improve the display of public signing keys
42ef019 is described below
commit 42ef019d7639ffa53caa126123dd394e29823425
Author: Sean B. Palmer <[email protected]>
AuthorDate: Wed Jun 18 14:53:24 2025 +0100
Improve the display of public signing keys
---
atr/routes/keys.py | 73 ++++++++++++++++++++-------------------
atr/templates/committee-view.html | 2 +-
atr/templates/keys-review.html | 4 +--
atr/templates/keys-show-gpg.html | 28 +++++++++++++--
4 files changed, 65 insertions(+), 42 deletions(-)
diff --git a/atr/routes/keys.py b/atr/routes/keys.py
index 451bca8..baa5de8 100644
--- a/atr/routes/keys.py
+++ b/atr/routes/keys.py
@@ -34,7 +34,6 @@ import asfquart as asfquart
import asfquart.base as base
import httpx
import quart
-import sqlmodel
import werkzeug.datastructures as datastructures
import werkzeug.wrappers.response as response
import wtforms
@@ -256,8 +255,44 @@ async def delete(session: routes.CommitterSession) ->
response.Response:
return await session.redirect(keys, error="Key not found or not
owned by you")
[email protected]("/keys/details/<fingerprint>", methods=["GET"])
+async def details(session: routes.CommitterSession, fingerprint: str) -> str:
+ """Display details for a specific GPG key."""
+ async with db.session() as data:
+ key = await data.public_signing_key(fingerprint=fingerprint,
_committees=True).get()
+
+ if not key:
+ quart.abort(404, description="GPG key not found")
+ key.committees.sort(key=lambda c: c.name)
+
+ authorised = False
+ if key.apache_uid == session.uid:
+ authorised = True
+ else:
+ user_affiliations = set(session.committees + session.projects)
+ # async with db.session() as data:
+ # key_committees = await data.execute(
+ #
sqlmodel.select(models.KeyLink.committee_name).where(models.KeyLink.key_fingerprint
== fingerprint)
+ # )
+ # key_committee_names = {row[0] for row in key_committees.all()}
+ key_committee_names = {c.name for c in key.committees}
+ if user_affiliations.intersection(key_committee_names):
+ authorised = True
+
+ if not authorised:
+ quart.abort(403, description="You are not authorised to view this key")
+
+ return await template.render(
+ "keys-show-gpg.html",
+ key=key,
+ algorithms=routes.algorithms,
+ now=datetime.datetime.now(datetime.UTC),
+ asf_id=session.uid,
+ )
+
+
@routes.committer("/keys/export/<committee_name>")
-async def exports(session: routes.CommitterSession, committee_name: str) ->
quart.Response:
+async def export(session: routes.CommitterSession, committee_name: str) ->
quart.Response:
"""Generate a KEYS file for a specific committee."""
if committee_name not in (session.committees + session.projects):
quart.abort(403, description=f"You are not authorised to update the
KEYS file for {committee_name}")
@@ -365,40 +400,6 @@ async def keys(session: routes.CommitterSession) -> str:
)
[email protected]("/keys/show-gpg/<fingerprint>", methods=["GET"])
-async def show_gpg_key(session: routes.CommitterSession, fingerprint: str) ->
str:
- """Display details for a specific GPG key."""
- async with db.session() as data:
- key = await data.public_signing_key(fingerprint=fingerprint).get()
-
- if not key:
- quart.abort(404, description="GPG key not found")
-
- authorised = False
- if key.apache_uid == session.uid:
- authorised = True
- else:
- user_affiliations = set(session.committees + session.projects)
- async with db.session() as data:
- key_committees = await data.execute(
-
sqlmodel.select(models.KeyLink.committee_name).where(models.KeyLink.key_fingerprint
== fingerprint)
- )
- key_committee_names = {row[0] for row in key_committees.all()}
- if user_affiliations.intersection(key_committee_names):
- authorised = True
-
- if not authorised:
- quart.abort(403, description="You are not authorised to view this key")
-
- return await template.render(
- "keys-show-gpg.html",
- key=key,
- algorithms=routes.algorithms,
- now=datetime.datetime.now(datetime.UTC),
- asf_id=session.uid,
- )
-
-
@routes.committer("/keys/ssh/add", methods=["GET", "POST"])
async def ssh_add(session: routes.CommitterSession) -> response.Response | str:
"""Add a new SSH key to the user's account."""
diff --git a/atr/templates/committee-view.html
b/atr/templates/committee-view.html
index bc8c133..53c7c61 100644
--- a/atr/templates/committee-view.html
+++ b/atr/templates/committee-view.html
@@ -63,7 +63,7 @@
{% for key in committee.public_signing_keys %}
<tr>
<td class="text-break font-monospace px-2">
- <a href="{{ as_url(routes.keys.show_gpg_key,
fingerprint=key.fingerprint) }}">{{ key.fingerprint[:16]|upper }}</a>
+ <a href="{{ as_url(routes.keys.details,
fingerprint=key.fingerprint) }}">{{ key.fingerprint[:16]|upper }}</a>
</td>
<td class="text-break px-2">{{
email_from_key(key.primary_declared_uid) or 'Not specified' }}</td>
<td class="text-break px-2">{{ key.apache_uid or "-" }}</td>
diff --git a/atr/templates/keys-review.html b/atr/templates/keys-review.html
index 825b2cc..0edbd38 100644
--- a/atr/templates/keys-review.html
+++ b/atr/templates/keys-review.html
@@ -77,7 +77,7 @@
</tr>
<tr>
<th class="p-2 text-dark">User ID</th>
- <td class="text-break">{{ key.declared_uid or 'Not
specified' }}</td>
+ <td class="text-break">{{ key.apache_uid or 'Not specified'
}}</td>
</tr>
<tr>
<th class="p-2 text-dark">Associated PMCs</th>
@@ -182,7 +182,7 @@
{% for key in committee.public_signing_keys %}
<tr>
<td class="text-break font-monospace px-2">
- <a href="{{ as_url(routes.keys.show_gpg_key,
fingerprint=key.fingerprint) }}">{{ key.fingerprint[:16]|upper }}</a>
+ <a href="{{ as_url(routes.keys.details,
fingerprint=key.fingerprint) }}">{{ key.fingerprint[:16]|upper }}</a>
</td>
<td class="text-break px-2">{{
email_from_key(key.primary_declared_uid) or 'Not specified' }}</td>
<td class="text-break px-2">{{ key.apache_uid or "-" }}</td>
diff --git a/atr/templates/keys-show-gpg.html b/atr/templates/keys-show-gpg.html
index 5b5ecb9..94cff5d 100644
--- a/atr/templates/keys-show-gpg.html
+++ b/atr/templates/keys-show-gpg.html
@@ -30,6 +30,12 @@
<th class="p-2 text-dark">Created</th>
<td class="text-break">{{ key.created.strftime("%Y-%m-%d %H:%M:%S")
}}</td>
</tr>
+ <tr>
+ <th class="p-2 text-dark">Latest self signature</th>
+ <td class="text-break">
+ {{ key.latest_self_signature.strftime("%Y-%m-%d %H:%M:%S") if
key.latest_self_signature else 'Never' }}
+ </td>
+ </tr>
<tr>
<th class="p-2 text-dark">Expires</th>
<td class="text-break">
@@ -53,19 +59,35 @@
{% endif %}
</td>
</tr>
+ <tr>
+ <th class="p-2 text-dark">Primary UID</th>
+ <td class="text-break">{{ key.primary_declared_uid or 'Not
specified' }}</td>
+ </tr>
+ <tr>
+ <th class="p-2 text-dark">Secondary UIDs</th>
+ <td class="text-break">
+ {{ key.secondary_declared_uids | join(", ") if
key.secondary_declared_uids else 'Not specified' }}
+ </td>
+ </tr>
<tr>
<th class="p-2 text-dark">Apache UID</th>
<td class="text-break">{{ key.apache_uid }}</td>
</tr>
<tr>
- <th class="p-2 text-dark">Declared UID</th>
- <td class="text-break">{{ key.declared_uid or 'Not specified' }}</td>
+ <th class="p-2 text-dark">Associated PMCs</th>
+ <td class="text-break">
+ {% if key.committees %}
+ {{ key.committees|map(attribute='name') |join(', ') }}
+ {% else %}
+ No PMCs associated
+ {% endif %}
+ </td>
</tr>
</tbody>
</table>
<details class="mt-3 p-3 bg-light rounded">
- <summary class="fw-bold">View ASCII Armored Key</summary>
+ <summary class="fw-bold">View ASCII armored key</summary>
<pre class="mt-3">{{ key.ascii_armored_key }}</pre>
</details>
</div>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]