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

eladkal 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 efdc08e9869 Fix LLMApprovalMixin to enforce allow_modifications in 
execute_complete (#64244)
efdc08e9869 is described below

commit efdc08e98696623e9601e39fad11e79f46f8e8e0
Author: Elad Kalif <[email protected]>
AuthorDate: Thu Mar 26 21:24:51 2026 +0200

    Fix LLMApprovalMixin to enforce allow_modifications in execute_complete 
(#64244)
    
    * Fix LLMApprovalMixin to enforce allow_modifications in execute_complete
---
 .../ai/src/airflow/providers/common/ai/mixins/approval.py    |  6 ++++--
 .../common/ai/tests/unit/common/ai/mixins/test_approval.py   | 12 ++++++++++++
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git 
a/providers/common/ai/src/airflow/providers/common/ai/mixins/approval.py 
b/providers/common/ai/src/airflow/providers/common/ai/mixins/approval.py
index 22fa641333b..df5929eedc0 100644
--- a/providers/common/ai/src/airflow/providers/common/ai/mixins/approval.py
+++ b/providers/common/ai/src/airflow/providers/common/ai/mixins/approval.py
@@ -168,8 +168,10 @@ class LLMApprovalMixin:
         output = generated_output
         params_input: dict[str, Any] = event.get("params_input") or {}
 
-        # If the reviewer provided modified output, return their version
-        if params_input:
+        # Only accept modified output when the operator explicitly allows 
modifications.
+        # Without this guard a reviewer could craft a request with 
params_input even
+        # when allow_modifications=False, bypassing the read-only approval 
flow.
+        if getattr(self, "allow_modifications", False) and params_input:
             modified = params_input.get("output")
             if modified is not None and modified != generated_output:
                 log.info("output=%s modified by the reviewer=%s ", modified, 
responded_by_user)
diff --git a/providers/common/ai/tests/unit/common/ai/mixins/test_approval.py 
b/providers/common/ai/tests/unit/common/ai/mixins/test_approval.py
index 7b2d2b90f89..08355c3b922 100644
--- a/providers/common/ai/tests/unit/common/ai/mixins/test_approval.py
+++ b/providers/common/ai/tests/unit/common/ai/mixins/test_approval.py
@@ -295,6 +295,18 @@ class TestDeferForApproval:
 
         assert result == "original"
 
+    def test_approved_no_modifications_rejects_tampered_params_input(self, 
approval_op):
+        """When allow_modifications=False, tampered params_input with output 
must be ignored."""
+        event = {
+            "chosen_options": ["Approve"],
+            "responded_by_user": "reviewer",
+            "params_input": {"output": "tampered output"},
+        }
+
+        result = approval_op.execute_complete({}, generated_output="original", 
event=event)
+
+        assert result == "original"
+
     def test_event_missing_responded_by_user(self, approval_op):
         event = {"chosen_options": ["Approve"]}
 

Reply via email to