This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch sbp
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git


The following commit(s) were added to refs/heads/sbp by this push:
     new 02787d1f Move key association management to the storage interface
02787d1f is described below

commit 02787d1fe2ee9e08696dc0abd383e95a91b89ed1
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Apr 2 19:57:51 2026 +0100

    Move key association management to the storage interface
---
 atr/post/keys.py            | 38 +++++++++----------------------
 atr/storage/writers/keys.py | 54 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+), 28 deletions(-)

diff --git a/atr/post/keys.py b/atr/post/keys.py
index 69b3ece3..16c4c8e3 100644
--- a/atr/post/keys.py
+++ b/atr/post/keys.py
@@ -107,34 +107,16 @@ async def details(
     key_fingerprint = str(fingerprint).lower()
 
     try:
-        async with db.session() as data:
-            key = await data.public_signing_key(fingerprint=key_fingerprint, 
_committees=True).get()
-            if not key:
-                await quart.flash("OpenPGP key not found", "error")
-                return await session.redirect(get.keys.keys)
-
-            if not (key.apache_uid and session.uid and (key.apache_uid.lower() 
== session.uid.lower())):
-                await quart.flash("You are not authorized to modify this key", 
"error")
-                return await session.redirect(get.keys.keys)
-
-            selected_committee_keys = update_form.selected_committees
-            old_committee_keys = {c.key for c in key.committees}
-
-            new_committees = await 
data.committee(name_in=selected_committee_keys).all()
-            key.committees = list(new_committees)
-            data.add(key)
-            await data.commit()
-
-            affected_committee_keys = 
old_committee_keys.union(set(selected_committee_keys))
-            if affected_committee_keys:
-                async with storage.write() as write:
-                    for affected_committee_key in affected_committee_keys:
-                        wacm = 
write.as_committee_member_outcome(affected_committee_key).result_or_none()
-                        if wacm is None:
-                            continue
-                        await wacm.keys.autogenerate_keys_file()
-
-            await quart.flash("Key committee associations updated 
successfully.", "success")
+        async with storage.write() as write:
+            wafc = write.as_foundation_committer()
+            await wafc.keys.update_committee_associations(
+                key_fingerprint,
+                update_form.selected_committees,
+            )
+
+        await quart.flash("Key committee associations updated successfully.", 
"success")
+    except storage.AccessError as e:
+        await quart.flash(str(e), "error")
     except Exception as e:
         log.exception("Error updating key committee associations:")
         await quart.flash(f"An unexpected error occurred: {e!s}", "error")
diff --git a/atr/storage/writers/keys.py b/atr/storage/writers/keys.py
index 3a29ae1a..cebad86c 100644
--- a/atr/storage/writers/keys.py
+++ b/atr/storage/writers/keys.py
@@ -211,6 +211,60 @@ class FoundationCommitter(GeneralPublic):
         except Exception as e:
             return outcome.Error(e)
 
+    async def update_committee_associations(
+        self,
+        fingerprint: str,
+        selected_committee_keys: list[str],
+    ) -> set[str]:
+        via = sql.validate_instrumented_attribute
+
+        key = await self.__data.public_signing_key(
+            fingerprint=fingerprint,
+            apache_uid=self.__asf_uid,
+            _committees=True,
+        ).get()
+        if not key:
+            raise storage.AccessError("Key not found or not owned by you")
+
+        old_committee_keys = {c.key for c in key.committees}
+        new_committee_keys = set(selected_committee_keys)
+        to_add = new_committee_keys - old_committee_keys
+        to_remove = old_committee_keys - new_committee_keys
+        affected = to_add | to_remove
+
+        if not affected:
+            return affected
+
+        for committee_key in sorted(to_add):
+            self.__write.as_committee_participant(committee_key)
+
+        await self.__data.begin_immediate()
+
+        if to_add:
+            link_values = [{"committee_key": ck, "key_fingerprint": 
fingerprint} for ck in to_add]
+            await self.__data.execute(
+                sqlite.insert(sql.KeyLink)
+                .values(link_values)
+                .on_conflict_do_nothing(index_elements=["committee_key", 
"key_fingerprint"])
+            )
+
+        if to_remove:
+            await self.__data.execute(
+                sqlmodel.delete(sql.KeyLink).where(
+                    via(sql.KeyLink.key_fingerprint) == fingerprint,
+                    via(sql.KeyLink.committee_key).in_(to_remove),
+                )
+            )
+
+        await self.__data.commit()
+
+        for committee_key in sorted(affected):
+            wacp = 
self.__write.as_committee_participant_outcome(committee_key).result_or_none()
+            if wacp is not None:
+                await wacp.keys.autogenerate_keys_file()
+
+        return affected
+
     def __block_model(self, key_block: str, ldap_data: dict[str, str]) -> 
types.Key:
         # This cache is only held for the session
         if key_block in self.__key_block_models_cache:


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

Reply via email to