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 4cbc209  Store data posted from GitHub during upload
4cbc209 is described below

commit 4cbc2093cffa900e3400c55280b0435e05cd9edc
Author: Sean B. Palmer <[email protected]>
AuthorDate: Tue Feb 3 19:59:35 2026 +0000

    Store data posted from GitHub during upload
---
 .gitignore                                      |  1 +
 atr/api/__init__.py                             |  2 ++
 atr/attestable.py                               | 13 +++++++++++-
 atr/models/sql.py                               |  3 +++
 atr/ssh.py                                      | 16 ++++++++++++++-
 atr/storage/writers/ssh.py                      |  6 +++++-
 migrations/versions/0047_2026.02.03_525fe161.py | 27 +++++++++++++++++++++++++
 7 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/.gitignore b/.gitignore
index 7518006..4ab21d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ __pycache__/
 .venv-uv/
 .vscode/
 *.pyc
+*.tmp.py
 apptoken.txt
 atr/_version.py
 bootstrap/build/
diff --git a/atr/api/__init__.py b/atr/api/__init__.py
index b1041e6..e7705a2 100644
--- a/atr/api/__init__.py
+++ b/atr/api/__init__.py
@@ -273,6 +273,7 @@ async def distribute_ssh_register(data: 
models.api.DistributeSshRegisterArgs) ->
             payload["actor_id"],
             release.project_name,
             data.ssh_key,
+            payload,
         )
 
     return models.api.DistributeSshRegisterResults(
@@ -797,6 +798,7 @@ async def publisher_ssh_register(data: 
models.api.PublisherSshRegisterArgs) -> D
             payload["actor_id"],
             project.name,
             data.ssh_key,
+            payload,
         )
 
     return models.api.PublisherSshRegisterResults(
diff --git a/atr/attestable.py b/atr/attestable.py
index 01ed8ed..d576236 100644
--- a/atr/attestable.py
+++ b/atr/attestable.py
@@ -18,7 +18,7 @@
 from __future__ import annotations
 
 import json
-from typing import TYPE_CHECKING, Final
+from typing import TYPE_CHECKING, Any, Final
 
 import aiofiles
 import aiofiles.os
@@ -47,6 +47,17 @@ async def compute_file_hash(path: pathlib.Path) -> str:
     return f"blake3:{hasher.hexdigest()}"
 
 
+def github_tp_payload_path(project_name: str, version_name: str, 
revision_number: str) -> pathlib.Path:
+    return util.get_attestable_dir() / project_name / version_name / 
f"{revision_number}.github-tp.json"
+
+
+async def github_tp_payload_write(
+    project_name: str, version_name: str, revision_number: str, 
github_payload: dict[str, Any]
+) -> None:
+    payload_path = github_tp_payload_path(project_name, version_name, 
revision_number)
+    await util.atomic_write_file(payload_path, json.dumps(github_payload, 
indent=2))
+
+
 async def load(
     project_name: str,
     version_name: str,
diff --git a/atr/models/sql.py b/atr/models/sql.py
index 0dc7780..61a5c62 100644
--- a/atr/models/sql.py
+++ b/atr/models/sql.py
@@ -442,6 +442,9 @@ class WorkflowSSHKey(sqlmodel.SQLModel, table=True):
     asf_uid: str = sqlmodel.Field(index=True)
     github_uid: str = sqlmodel.Field(index=True)
     github_nid: int = sqlmodel.Field(index=True)
+    github_payload: dict[str, Any] = sqlmodel.Field(
+        default_factory=dict, sa_column=sqlalchemy.Column(sqlalchemy.JSON, 
nullable=False)
+    )
     expires: int = sqlmodel.Field()
 
 
diff --git a/atr/ssh.py b/atr/ssh.py
index 074ed37..b04031a 100644
--- a/atr/ssh.py
+++ b/atr/ssh.py
@@ -25,12 +25,13 @@ import os
 import stat
 import string
 import time
-from typing import Final
+from typing import Any, Final
 
 import aiofiles
 import aiofiles.os
 import asyncssh
 
+import atr.attestable as attestable
 import atr.config as config
 import atr.db as db
 import atr.log as log
@@ -57,6 +58,7 @@ class SSHServer(asyncssh.SSHServer):
         # Store connection for use in begin_auth
         self._conn = conn
         self._github_asf_uid: str | None = None
+        self._github_payload: dict[str, Any] | None = None
         peer_addr = conn.get_extra_info("peername")[0]
         log.info(f"SSH connection received from {peer_addr}")
 
@@ -130,6 +132,7 @@ class SSHServer(asyncssh.SSHServer):
                 return False
 
             self._github_asf_uid = workflow_key.asf_uid
+            self._github_payload = workflow_key.github_payload
             return True
 
     def _get_asf_uid(self, process: asyncssh.SSHServerProcess) -> str:
@@ -140,6 +143,12 @@ class SSHServer(asyncssh.SSHServer):
             return self._github_asf_uid
         return username
 
+    def _get_github_payload(self, process: asyncssh.SSHServerProcess) -> 
dict[str, Any] | None:
+        username = process.get_extra_info("username")
+        if username != "github":
+            return None
+        return self._github_payload
+
 
 async def server_start() -> asyncssh.SSHAcceptor:
     """Start the SSH server."""
@@ -580,6 +589,11 @@ async def _step_07b_process_validated_rsync_write(
                 raise types.FailedError(f"rsync upload failed with exit status 
{exit_status} for {for_revision}")
 
         if creating.new is not None:
+            github_payload = server._get_github_payload(process)
+            if github_payload is not None:
+                await attestable.github_tp_payload_write(
+                    project_name, version_name, creating.new.number, 
github_payload
+                )
             log.info(f"rsync upload successful for revision 
{creating.new.number}")
             host = config.get().APP_HOST
             message = f"\nATR: Created revision {creating.new.number} of 
{project_name} {version_name}\n"
diff --git a/atr/storage/writers/ssh.py b/atr/storage/writers/ssh.py
index 932d867..555a173 100644
--- a/atr/storage/writers/ssh.py
+++ b/atr/storage/writers/ssh.py
@@ -19,6 +19,7 @@
 from __future__ import annotations
 
 import time
+from typing import Any
 
 import atr.db as db
 import atr.models.sql as sql
@@ -83,7 +84,9 @@ class CommitteeParticipant(FoundationCommitter):
         self.__asf_uid = asf_uid
         self.__committee_name = committee_name
 
-    async def add_workflow_key(self, github_uid: str, github_nid: int, 
project_name: str, key: str) -> tuple[str, int]:
+    async def add_workflow_key(
+        self, github_uid: str, github_nid: int, project_name: str, key: str, 
github_payload: dict[str, Any]
+    ) -> tuple[str, int]:
         now = int(time.time())
         # Twenty minutes to upload all files
         ttl = 20 * 60
@@ -96,6 +99,7 @@ class CommitteeParticipant(FoundationCommitter):
             asf_uid=self.__asf_uid,
             github_uid=github_uid,
             github_nid=github_nid,
+            github_payload=github_payload,
             expires=expires,
         )
         self.__data.add(wsk)
diff --git a/migrations/versions/0047_2026.02.03_525fe161.py 
b/migrations/versions/0047_2026.02.03_525fe161.py
new file mode 100644
index 0000000..a8b9ac4
--- /dev/null
+++ b/migrations/versions/0047_2026.02.03_525fe161.py
@@ -0,0 +1,27 @@
+"""Add a payload property to GitHub SSH keys
+
+Revision ID: 0047_2026.02.03_525fe161
+Revises: 0046_2026.01.30_72330898
+Create Date: 2026-02-03 19:49:11.922836+00:00
+"""
+
+from collections.abc import Sequence
+
+import sqlalchemy as sa
+from alembic import op
+
+# Revision identifiers, used by Alembic
+revision: str = "0047_2026.02.03_525fe161"
+down_revision: str | None = "0046_2026.01.30_72330898"
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
+
+
+def upgrade() -> None:
+    with op.batch_alter_table("workflowsshkey", schema=None) as batch_op:
+        batch_op.add_column(sa.Column("github_payload", sa.JSON(), 
nullable=False, server_default="{}"))
+
+
+def downgrade() -> None:
+    with op.batch_alter_table("workflowsshkey", schema=None) as batch_op:
+        batch_op.drop_column("github_payload")


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

Reply via email to