Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,10 @@ def execute_complete(self, context: Context, generated_output: str, event: dict[
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,18 @@ def test_approved_no_modifications_ignores_params_input(self, approval_op):

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"]}

Expand Down
Loading