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 b0920a2  Move functions to add and delete SSH keys to the storage 
interface
b0920a2 is described below

commit b0920a2fac0117a9d54fe2c4f535fae7522301fb
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Sep 4 20:01:56 2025 +0100

    Move functions to add and delete SSH keys to the storage interface
---
 atr/blueprints/api/api.py  |  9 ++++++---
 atr/routes/keys.py         | 29 ++++-------------------------
 atr/storage/writers/ssh.py | 14 ++++++++++++++
 atr/util.py                | 11 +++++++++++
 4 files changed, 35 insertions(+), 28 deletions(-)

diff --git a/atr/blueprints/api/api.py b/atr/blueprints/api/api.py
index 73e89dd..8a239f3 100644
--- a/atr/blueprints/api/api.py
+++ b/atr/blueprints/api/api.py
@@ -41,7 +41,6 @@ import atr.models.sql as sql
 import atr.revision as revision
 import atr.routes as routes
 import atr.routes.announce as announce
-import atr.routes.keys as keys
 import atr.routes.resolve as resolve
 import atr.routes.start as start
 import atr.routes.vote as vote
@@ -974,7 +973,9 @@ async def ssh_key_add(data: models.api.SshKeyAddArgs) -> 
DictResponse:
     An SSH key is associated with a single user.
     """
     asf_uid = _jwt_asf_uid()
-    fingerprint = await keys.ssh_key_add(data.text, asf_uid)
+    async with storage.write(asf_uid) as write:
+        wafc = write.as_foundation_committer()
+        fingerprint = await wafc.ssh.add_key(data.text, asf_uid)
     return models.api.SshKeyAddResults(
         endpoint="/ssh-key/add",
         fingerprint=fingerprint,
@@ -993,7 +994,9 @@ async def ssh_key_delete(data: models.api.SshKeyDeleteArgs) 
-> DictResponse:
     An SSH key can only be deleted by the user who owns it.
     """
     asf_uid = _jwt_asf_uid()
-    await keys.ssh_key_delete(data.fingerprint, asf_uid)
+    async with storage.write(asf_uid) as write:
+        wafc = write.as_foundation_committer()
+        await wafc.ssh.delete_key(data.fingerprint)
     return models.api.SshKeyDeleteResults(
         endpoint="/ssh-key/delete",
         success=True,
diff --git a/atr/routes/keys.py b/atr/routes/keys.py
index 5ec0c13..3c033f9 100644
--- a/atr/routes/keys.py
+++ b/atr/routes/keys.py
@@ -26,7 +26,6 @@ import asfquart as asfquart
 import asfquart.base as base
 import quart
 import werkzeug.datastructures as datastructures
-import werkzeug.exceptions as exceptions
 import werkzeug.wrappers.response as response
 import wtforms
 
@@ -75,10 +74,6 @@ class DeleteKeyForm(forms.Typed):
     submit = forms.submit("Delete key")
 
 
-class SshFingerprintError(ValueError):
-    pass
-
-
 class UpdateCommitteeKeysForm(forms.Typed):
     submit = forms.submit("Regenerate KEYS file")
 
@@ -366,8 +361,10 @@ async def ssh_add(session: routes.CommitterSession) -> 
response.Response | str:
     if await form.validate_on_submit():
         key: str = util.unwrap(form.key.data)
         try:
-            fingerprint = await ssh_key_add(key, session.uid)
-        except SshFingerprintError as e:
+            async with storage.write(session.uid) as write:
+                wafc = write.as_foundation_committer()
+                fingerprint = await wafc.ssh.add_key(key, session.uid)
+        except util.SshFingerprintError as e:
             if isinstance(form.key.errors, list):
                 form.key.errors.append(str(e))
             else:
@@ -384,24 +381,6 @@ async def ssh_add(session: routes.CommitterSession) -> 
response.Response | str:
     )
 
 
-async def ssh_key_add(key: str, asf_uid: str) -> str:
-    try:
-        fingerprint = util.key_ssh_fingerprint(key)
-    except Exception as e:
-        raise SshFingerprintError(str(e)) from e
-    async with db.session() as data:
-        data.add(sql.SSHKey(fingerprint=fingerprint, key=key, asf_uid=asf_uid))
-        await data.commit()
-    return fingerprint
-
-
-async def ssh_key_delete(fingerprint: str, asf_uid: str) -> None:
-    async with db.session() as data:
-        ssh_key = await data.ssh_key(fingerprint=fingerprint, 
asf_uid=asf_uid).demand(exceptions.NotFound())
-        await data.delete(ssh_key)
-        await data.commit()
-
-
 @routes.committer("/keys/update-committee-keys/<committee_name>", 
methods=["POST"])
 async def update_committee_keys(session: routes.CommitterSession, 
committee_name: str) -> response.Response:
     """Generate and save the KEYS file for a specific committee."""
diff --git a/atr/storage/writers/ssh.py b/atr/storage/writers/ssh.py
index 8a65d5e..af8e717 100644
--- a/atr/storage/writers/ssh.py
+++ b/atr/storage/writers/ssh.py
@@ -50,6 +50,20 @@ class FoundationCommitter(GeneralPublic):
             raise storage.AccessError("No ASF UID")
         self.__asf_uid = asf_uid
 
+    async def add_key(self, key: str, asf_uid: str) -> str:
+        fingerprint = util.key_ssh_fingerprint(key)
+        self.__data.add(sql.SSHKey(fingerprint=fingerprint, key=key, 
asf_uid=asf_uid))
+        await self.__data.commit()
+        return fingerprint
+
+    async def delete_key(self, fingerprint: str) -> None:
+        ssh_key = await self.__data.ssh_key(
+            fingerprint=fingerprint,
+            asf_uid=self.__asf_uid,
+        ).demand(storage.AccessError(f"Key not found: {fingerprint}"))
+        await self.__data.delete(ssh_key)
+        await self.__data.commit()
+
 
 class CommitteeParticipant(FoundationCommitter):
     def __init__(
diff --git a/atr/util.py b/atr/util.py
index ba707d6..4afa1d3 100644
--- a/atr/util.py
+++ b/atr/util.py
@@ -59,6 +59,10 @@ T = TypeVar("T")
 USER_TESTS_ADDRESS: Final[str] = "[email protected]"
 
 
+class SshFingerprintError(ValueError):
+    pass
+
+
 @dataclasses.dataclass
 class FileStat:
     path: str
@@ -525,6 +529,13 @@ def is_user_viewing_as_admin(uid: str | None) -> bool:
 
 
 def key_ssh_fingerprint(ssh_key_string: str) -> str:
+    try:
+        return key_ssh_fingerprint_core(ssh_key_string)
+    except ValueError as e:
+        raise SshFingerprintError(str(e)) from e
+
+
+def key_ssh_fingerprint_core(ssh_key_string: str) -> str:
     # The format should be as in *.pub or authorized_keys files
     # I.e. TYPE DATA COMMENT
     ssh_key_parts = ssh_key_string.strip().split()


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to