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

henry3260 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 51411acb7e5 Fix empty audit log dag_id for DAG.cli() subcommands 
(#73379)
51411acb7e5 is described below

commit 51411acb7e579fbda882503d469128bccfb54783
Author: Y-C <[email protected]>
AuthorDate: Tue Oct 20 10:47:45 2026 +0800

    Fix empty audit log dag_id for DAG.cli() subcommands (#73379)
    
    The Dag file is its own entry point on this path, so the parser behind
    DAG.cli() drops dag_id - there is nothing for the user to type. But
    action_cli snapshots the namespace and writes the Log row before the
    handler runs, so every audit row for python my_dag.py dags pause and its
    five sibling subcommands lands with dag_id NULL: the event cannot be
    filtered by Dag, and in multi-team mode team_name is resolved from
    dag_id, so it also drops out of the owning team's view.
    
    The back-fills already inside set_is_paused, dag_list_dag_runs and
    dag_list_jobs cannot cover this. They run after that insert has been
    committed, and they write to the namespace rather than to the metrics
    dict that was built from it.
    
    Every one of the six subcommands receives the Dag positionally and
    reads args.dag_id only behind a dag or ... short-circuit, so supplying
    it changes no control flow - only what the audit row records.
    
    Co-authored-by: Eason09053360 
<[email protected]>
---
 airflow-core/tests/unit/utils/test_cli_util.py | 16 ++++++++++++++++
 task-sdk/src/airflow/sdk/definitions/dag.py    |  3 +++
 2 files changed, 19 insertions(+)

diff --git a/airflow-core/tests/unit/utils/test_cli_util.py 
b/airflow-core/tests/unit/utils/test_cli_util.py
index 98cbad6fbcf..6c9bb2a2eb2 100644
--- a/airflow-core/tests/unit/utils/test_cli_util.py
+++ b/airflow-core/tests/unit/utils/test_cli_util.py
@@ -1012,6 +1012,22 @@ class TestCliUtil:
 
         assert log.team_name == "payments"
 
+    def test_dag_cli_records_the_dag_id_in_the_audit_log(self):
+        """``DAG.cli()``'s parser drops ``dag_id``, so the Dag has to supply 
it before dispatch."""
+        dag = DAG("dag_cli_audit_log")
+
+        with (
+            mock.patch.object(sys, "argv", ["dag_cli_audit_log.py", "tasks", 
"list"]),
+            mock.patch("airflow.utils.session.create_session") as 
mock_create_session,
+        ):
+            dag.cli()
+
+        audit_session = mock_create_session.return_value.__enter__.return_value
+        model, rows = audit_session.bulk_insert_mappings.call_args.args
+        assert model is Log
+        assert rows[0]["event"] == "cli_task_list"
+        assert rows[0]["dag_id"] == "dag_cli_audit_log"
+
     def test_setup_locations_relative_pid_path(self):
         relative_pid_path = "fake.pid"
         pid_full_path = os.path.join(os.getcwd(), relative_pid_path)
diff --git a/task-sdk/src/airflow/sdk/definitions/dag.py 
b/task-sdk/src/airflow/sdk/definitions/dag.py
index 0594ac80658..b0e227c5c85 100644
--- a/task-sdk/src/airflow/sdk/definitions/dag.py
+++ b/task-sdk/src/airflow/sdk/definitions/dag.py
@@ -1211,6 +1211,9 @@ class DAG:
 
         parser = cli_parser.get_parser(dag_parser=True)
         args = parser.parse_args()
+        # This parser drops ``dag_id``, but the audit log is written from the 
namespace before the
+        # command runs, so a handler back-filling it later is already too late.
+        args.dag_id = self.dag_id
         args.func(args, self)
 
     @classmethod

Reply via email to