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

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new beae721a9 fix(ai): validate message properties before confirming a 
send preview (#4470)
beae721a9 is described below

commit beae721a931e8475ae8f95d77b5291bfdb3594c0
Author: 0 <[email protected]>
AuthorDate: Mon Sep 21 20:59:42 2026 +0800

    fix(ai): validate message properties before confirming a send preview 
(#4470)
    
    `MessageSendToolHandler.preview` resolved the topic type and validated the 
send against it, but never parsed `input.properties()`. `execute` does parse 
it, and `parseProperties` throws `ToolError.MESSAGE_PROPERTIES_INVALID` for 
anything that is not a flat JSON object of strings. A caller passing 
`properties: "{"` therefore received a clean confirmation plan and only failed 
once the send was actually attempted — after the operator had approved the 
mutation on the strength of that plan. [...]
    
    `preview` now calls `parseProperties(input.properties())` before 
`validateForTopicType`, with a comment recording that the parsed value is 
deliberately discarded because `execute` rebuilds it. The parameterized test 
asserts that preview and execute both throw `ToolExecutionException` for an 
unterminated object, a JSON array and a nested object, and that `sendMessage` 
is never reached.
---
 .../ai/tool/handler/message/MessageSendToolHandler.java |  2 ++
 .../handler/message/MessageSendToolHandlerTest.java     | 17 +++++++++++++++++
 2 files changed, 19 insertions(+)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/tool/handler/message/MessageSendToolHandler.java
 
b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/tool/handler/message/MessageSendToolHandler.java
index d943ab19c..f93e043fe 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/tool/handler/message/MessageSendToolHandler.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/tool/handler/message/MessageSendToolHandler.java
@@ -66,6 +66,8 @@ public class MessageSendToolHandler extends 
MutationToolHandler<MessageSendInput
 
     @Override
     public ToolPlan preview(MessageSendInput input, ToolExecutionContext 
context) {
+        // Validates only: the parsed value is rebuilt by execute(), so the 
return value is dropped here.
+        parseProperties(input.properties());
         validateForTopicType(resolveTopicType(context.instanceId(), 
input.topicName()), input);
         Map<String, Object> after = new LinkedHashMap<>();
         after.put("topic", input.topicName());
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/tool/handler/message/MessageSendToolHandlerTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/tool/handler/message/MessageSendToolHandlerTest.java
index ac9e8c63d..e75361506 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/tool/handler/message/MessageSendToolHandlerTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/tool/handler/message/MessageSendToolHandlerTest.java
@@ -25,7 +25,10 @@ import org.apache.rocketmq.studio.instance.topic.TopicVO;
 import 
org.apache.rocketmq.studio.ops.ai.tool.contract.message.MessageSendInput;
 import 
org.apache.rocketmq.studio.ops.ai.tool.contract.message.MessageSendOutput;
 import org.apache.rocketmq.studio.ops.ai.tool.contract.plan.ToolPlan;
+import org.apache.rocketmq.studio.ops.ai.tool.core.ToolExecutionException;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.ArgumentCaptor;
 
 import java.util.Map;
@@ -45,6 +48,20 @@ class MessageSendToolHandlerTest {
     private final MetadataService metadata = mock(MetadataService.class);
     private final MessageSendToolHandler handler = new 
MessageSendToolHandler(metadata);
 
+    @ParameterizedTest
+    @ValueSource(strings = {"{", "[]", "{\"nested\":{\"key\":\"value\"}}"})
+    void malformedPropertiesFailDuringPreviewAndExecutionTest(String 
properties) {
+        givenTopicType(TopicType.NORMAL);
+        MessageSendInput request = new MessageSendInput("instance-a", 
"TopicA", "hello", null, null,
+                null, null, properties);
+
+        assertThatThrownBy(() -> handler.preview(request, 
context("instance-a")))
+                .isInstanceOf(ToolExecutionException.class);
+        assertThatThrownBy(() -> handler.execute(request, 
context("instance-a")))
+                .isInstanceOf(ToolExecutionException.class);
+        verify(metadata, never()).sendMessage(any(SendMessageDTO.class));
+    }
+
     private void givenTopicType(TopicType type) {
         TopicVO topic = new TopicVO();
         topic.setName("TopicA");

Reply via email to