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

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


The following commit(s) were added to refs/heads/main by this push:
     new f994f84  #283: Add admin ID to session metadata and include in log and 
audit log kwargs
f994f84 is described below

commit f994f843b1e2222f869ebe1fceaf095db5ccd119
Author: Alastair McFarlane <[email protected]>
AuthorDate: Wed Feb 4 13:43:17 2026 +0000

    #283: Add admin ID to session metadata and include in log and audit log 
kwargs
---
 atr/admin/__init__.py   | 14 ++++++--------
 atr/log.py              |  7 ++++++-
 atr/server.py           |  2 ++
 atr/storage/__init__.py |  6 ++++++
 4 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/atr/admin/__init__.py b/atr/admin/__init__.py
index 5811edd..8991711 100644
--- a/atr/admin/__init__.py
+++ b/atr/admin/__init__.py
@@ -154,14 +154,10 @@ async def browse_as_post(session: web.Committer, 
browse_form: BrowseAsUserForm)
         committee_data,
         bind_dn,
         bind_password,
+        {"admin": current_session.uid},
     )
     log_safe_data = _log_safe_session_data(
-        ldap_data,
-        new_uid,
-        ldap_projects_data,
-        committee_data,
-        bind_dn,
-        bind_password,
+        ldap_data, new_uid, ldap_projects_data, committee_data, bind_dn, 
bind_password, {"admin": current_session.uid}
     )
     log.info(f"New Quart cookie (not ASFQuart session) data: {log_safe_data}")
     asfquart.session.clear()
@@ -1108,6 +1104,7 @@ def _log_safe_session_data(
     committee_data: apache.CommitteeData,
     bind_dn: str,
     bind_password: str,
+    metadata: dict[str, Any] | None = None,
 ) -> dict[str, Any]:
     # This version excludes "mfa" which CodeQL treats as sensitive
     # It's just a bool, but we can't suppress the error at source
@@ -1123,7 +1120,7 @@ def _log_safe_session_data(
         "pmcs": common.pmcs,
         "projects": common.projects,
         "isRole": False,
-        "metadata": {},
+        "metadata": metadata if metadata is not None else {},
     }
 
 
@@ -1146,6 +1143,7 @@ def _session_data(
     committee_data: apache.CommitteeData,
     bind_dn: str,
     bind_password: str,
+    metadata: dict[str, Any] | None = None,
 ) -> dict[str, Any]:
     common = _session_data_common(ldap_data, new_uid, ldap_projects, 
committee_data, bind_dn, bind_password)
     return {
@@ -1162,7 +1160,7 @@ def _session_data(
         "projects": common.projects,
         "mfa": current_session.mfa,
         "isRole": False,
-        "metadata": {},
+        "metadata": metadata if metadata is not None else {},
     }
 
 
diff --git a/atr/log.py b/atr/log.py
index c506f6e..eb81d98 100644
--- a/atr/log.py
+++ b/atr/log.py
@@ -21,7 +21,7 @@ import logging
 import logging.handlers
 import queue
 import threading
-from typing import Final
+from typing import Any, Final
 
 import structlog
 
@@ -110,6 +110,11 @@ def exception(msg: str, **kwargs) -> None:
     _event(logging.ERROR, msg, exc_info=True, **kwargs)
 
 
+def get_context(arg) -> Any | None:
+    """Get context from the request log"""
+    return structlog.contextvars.get_contextvars().get(arg, None)
+
+
 def get_recent_logs() -> list[str] | None:
     if _global_recent_logs is None:
         return None
diff --git a/atr/server.py b/atr/server.py
index d889e61..2abff42 100644
--- a/atr/server.py
+++ b/atr/server.py
@@ -886,6 +886,8 @@ async def _reset_request_log_context():
     session = await asfquart.session.read()
     if session is not None:
         log.add_context(user_id=session.uid)
+        if "admin" in session.metadata:
+            log.add_context(admin_id=session.metadata["admin"])
     elif hasattr(quart.g, "jwt_claims"):
         claims = getattr(quart.g, "jwt_claims", {})
         asf_uid = claims.get("sub")
diff --git a/atr/storage/__init__.py b/atr/storage/__init__.py
index 6115791..fcca6c0 100644
--- a/atr/storage/__init__.py
+++ b/atr/storage/__init__.py
@@ -47,7 +47,13 @@ def audit(**kwargs: basic.JSON) -> None:
     now = 
datetime.datetime.now(datetime.UTC).isoformat(timespec="milliseconds")
     now = now.replace("+00:00", "Z")
     action = log.caller_name(depth=2)
+    request_user_id = log.get_context("user_id")
+    admin_user_id = log.get_context("admin_id")
     kwargs = {"datetime": now, "action": action, **kwargs}
+    if request_user_id:
+        kwargs["request_user_id"] = request_user_id
+    if admin_user_id and request_user_id != admin_user_id:
+        kwargs["admin_user_id"] = admin_user_id
     msg = json.dumps(kwargs, allow_nan=False)
     # The atr.log logger should give the same name
     # But to be extra sure, we set it manually


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

Reply via email to