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 1fd2843  Keep all key UIDs in the database
1fd2843 is described below

commit 1fd28436ad8271df593598a2c588d099d32c2a88
Author: Sean B. Palmer <[email protected]>
AuthorDate: Wed May 21 17:01:18 2025 +0100

    Keep all key UIDs in the database
---
 atr/db/__init__.py                              |  9 ++++---
 atr/db/interaction.py                           |  7 +++---
 atr/db/models.py                                |  8 +++++--
 atr/routes/keys.py                              |  6 ++---
 migrations/versions/0003_2025.05.21_ebed2397.py | 31 +++++++++++++++++++++++++
 5 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/atr/db/__init__.py b/atr/db/__init__.py
index 942613c..02094ec 100644
--- a/atr/db/__init__.py
+++ b/atr/db/__init__.py
@@ -312,7 +312,8 @@ class Session(sqlalchemy.ext.asyncio.AsyncSession):
         length: Opt[int] = NOT_SET,
         created: Opt[datetime.datetime] = NOT_SET,
         expires: Opt[datetime.datetime | None] = NOT_SET,
-        declared_uid: Opt[str | None] = NOT_SET,
+        primary_declared_uid: Opt[str | None] = NOT_SET,
+        secondary_declared_uids: Opt[list[str]] = NOT_SET,
         apache_uid: Opt[str] = NOT_SET,
         ascii_armored_key: Opt[str] = NOT_SET,
         _committees: bool = False,
@@ -329,8 +330,10 @@ class Session(sqlalchemy.ext.asyncio.AsyncSession):
             query = query.where(models.PublicSigningKey.created == created)
         if is_defined(expires):
             query = query.where(models.PublicSigningKey.expires == expires)
-        if is_defined(declared_uid):
-            query = query.where(models.PublicSigningKey.declared_uid == 
declared_uid)
+        if is_defined(primary_declared_uid):
+            query = query.where(models.PublicSigningKey.primary_declared_uid 
== primary_declared_uid)
+        if is_defined(secondary_declared_uids):
+            query = 
query.where(models.PublicSigningKey.secondary_declared_uids == 
secondary_declared_uids)
         if is_defined(apache_uid):
             query = query.where(models.PublicSigningKey.apache_uid == 
apache_uid)
         if is_defined(ascii_armored_key):
diff --git a/atr/db/interaction.py b/atr/db/interaction.py
index 86476fd..678c024 100644
--- a/atr/db/interaction.py
+++ b/atr/db/interaction.py
@@ -120,7 +120,7 @@ async def key_user_session_add(
     if not isinstance(fingerprint, str):
         raise RuntimeError("Invalid key fingerprint")
     fingerprint = fingerprint.lower()
-    uids = key.get("uids")
+    uids = key.get("uids", [])
     key_record: models.PublicSigningKey | None = None
 
     async with data.begin():
@@ -143,7 +143,8 @@ async def key_user_session_add(
                 length=int(key.get("length", "0")),
                 created=created,
                 expires=expires,
-                declared_uid=uids[0] if uids else None,
+                primary_declared_uid=uids[0] if uids else None,
+                secondary_declared_uids=uids[1:],
                 apache_uid=asf_uid,
                 ascii_armored_key=public_key,
             )
@@ -181,7 +182,7 @@ async def key_user_session_add(
                 continue
 
     # Extract email for sorting
-    user_id_str = key_record.declared_uid or ""
+    user_id_str = key_record.primary_declared_uid or ""
     email_match = re.search(r"<([^>]+)>", user_id_str)
     email = email_match.group(1) if email_match else user_id_str
 
diff --git a/atr/db/models.py b/atr/db/models.py
index fe7ab68..1789475 100644
--- a/atr/db/models.py
+++ b/atr/db/models.py
@@ -102,8 +102,12 @@ class PublicSigningKey(sqlmodel.SQLModel, table=True):
     created: datetime.datetime = 
sqlmodel.Field(sa_column=sqlalchemy.Column(UTCDateTime))
     # Expiration date
     expires: datetime.datetime | None = sqlmodel.Field(default=None, 
sa_column=sqlalchemy.Column(UTCDateTime))
-    # The UID declared in the key
-    declared_uid: str | None
+    # The primary UID declared in the key
+    primary_declared_uid: str | None
+    # The secondary UIDs declared in the key
+    secondary_declared_uids: list[str] = sqlmodel.Field(
+        default_factory=list, sa_column=sqlalchemy.Column(sqlalchemy.JSON)
+    )
     # The UID used by Apache
     apache_uid: str
     # The ASCII armored key
diff --git a/atr/routes/keys.py b/atr/routes/keys.py
index 215ba47..e30678e 100644
--- a/atr/routes/keys.py
+++ b/atr/routes/keys.py
@@ -382,9 +382,9 @@ async def update_committee_keys(session: 
routes.CommitterSession, committee_name
         for key in sorted_keys:
             fingerprint_short = key.fingerprint[:16].upper()
             apache_uid = key.apache_uid
-            declared_uid_str = key.declared_uid or ""
-            email_match = re.search(r"<([^>]+)>", declared_uid_str)
-            email = email_match.group(1) if email_match else declared_uid_str
+            primary_declared_uid_str = key.primary_declared_uid or ""
+            email_match = re.search(r"<([^>]+)>", primary_declared_uid_str)
+            email = email_match.group(1) if email_match else 
primary_declared_uid_str
             if email == f"{apache_uid}@apache.org":
                 comment_line = f"# {fingerprint_short} {email}"
             else:
diff --git a/migrations/versions/0003_2025.05.21_ebed2397.py 
b/migrations/versions/0003_2025.05.21_ebed2397.py
new file mode 100644
index 0000000..06da93b
--- /dev/null
+++ b/migrations/versions/0003_2025.05.21_ebed2397.py
@@ -0,0 +1,31 @@
+"""Add secondary signing key UIDs
+
+Revision ID: 0003_2025.05.21_ebed2397
+Revises: 0002_2025.05.19_93ec427d
+Create Date: 2025-05-21 15:56:45.161982+00:00
+"""
+
+from collections.abc import Sequence
+
+import sqlalchemy as sa
+from alembic import op
+
+# Revision identifiers, used by Alembic
+revision: str = "0003_2025.05.21_ebed2397"
+down_revision: str | None = "0002_2025.05.19_93ec427d"
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
+
+
+def upgrade() -> None:
+    op.add_column("publicsigningkey", sa.Column("primary_declared_uid", 
sa.String(), nullable=True))
+    op.add_column("publicsigningkey", sa.Column("secondary_declared_uids", 
sa.JSON(), nullable=True))
+    op.execute("UPDATE publicsigningkey SET primary_declared_uid = 
declared_uid")
+    op.drop_column("publicsigningkey", "declared_uid")
+
+
+def downgrade() -> None:
+    op.add_column("publicsigningkey", sa.Column("declared_uid", sa.VARCHAR(), 
nullable=True))
+    op.execute("UPDATE publicsigningkey SET declared_uid = 
primary_declared_uid")
+    op.drop_column("publicsigningkey", "secondary_declared_uids")
+    op.drop_column("publicsigningkey", "primary_declared_uid")


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

Reply via email to