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

terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 9bd71ec6a51 Fix MCP clarification sensitivity handling (#39169)
9bd71ec6a51 is described below

commit 9bd71ec6a51bfb857047d2a952389e80d6458dcb
Author: Liang Zhang <[email protected]>
AuthorDate: Fri Jul 17 19:35:09 2026 +0800

    Fix MCP clarification sensitivity handling (#39169)
    
    - replace field-name heuristics with explicit secret metadata
    - fail closed for unknown algorithm property sensitivity
    - prevent STDIO transport tests from retaining input threads
    - remove the unused rule artifact serialization path
---
 .../tool/MCPToolClarificationPolicy.java           | 28 ++--------------------
 .../AbstractMCPToolSpecificationFactoryTest.java   |  5 ++++
 .../tool/MCPToolClarificationPolicyTest.java       |  2 +-
 ...ToolElicitationFallbackResponseFactoryTest.java |  2 +-
 .../tool/MCPToolElicitationFlowTest.java           | 26 ++++++++++++++------
 .../SessionManagedStdioTransportProviderTest.java  | 23 +++++++++++++-----
 .../mcp/support/workflow/model/RuleArtifact.java   | 15 ------------
 .../service/WorkflowGuidancePayloadBuilder.java    | 11 +++++----
 .../service/WorkflowPlanPayloadBuilderTest.java    | 24 +++++++++++++++++--
 9 files changed, 73 insertions(+), 63 deletions(-)

diff --git 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicy.java
 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicy.java
index 0cfed9778bf..903b58c4745 100644
--- 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicy.java
+++ 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicy.java
@@ -45,13 +45,6 @@ final class MCPToolClarificationPolicy {
     
     private static final String FORM_PROPERTY_PREFIX = "field_";
     
-    private static final String CAMEL_CASE_SEPARATOR_PATTERN = 
"([a-z])([A-Z])";
-    
-    private static final String NON_ALPHANUMERIC_PATTERN = "[^a-z0-9]+";
-    
-    private static final List<String> SENSITIVE_FIELD_NAME_MARKERS = List.of(
-            "password", "passwd", "passphrase", "secret", "token", 
"accesstoken", "apikey", "privatekey", "credential", "card", "cvv", "payment", 
"key");
-    
     boolean requiresPlanningClarification(final MCPToolDescriptor descriptor, 
final Map<String, Object> payload) {
         Object clarificationQuestions = 
payload.get(MCPPayloadFieldNames.CLARIFICATION_QUESTIONS);
         return 
MCPDescriptorCatalogIndex.findToolRuntimeDescriptor(descriptor.getName())
@@ -112,31 +105,14 @@ final class MCPToolClarificationPolicy {
     }
     
     private boolean isSensitiveClarificationQuestion(final Map<?, ?> question) 
{
-        return Boolean.TRUE.equals(question.get(MCPPayloadFieldNames.SECRET)) 
|| isSecretInputType(question) || isSensitiveFieldName(question) || 
isUnknownAlgorithmPropertySensitivity(question);
+        Object secret = question.get(MCPPayloadFieldNames.SECRET);
+        return !(secret instanceof Boolean) || Boolean.TRUE.equals(secret) || 
isSecretInputType(question);
     }
     
     private boolean isSecretInputType(final Map<?, ?> question) {
         return "secret".equals(normalizeInputType(question));
     }
     
-    private boolean isSensitiveFieldName(final Map<?, ?> question) {
-        String fieldName = normalizeSensitiveName(getField(question));
-        for (String each : SENSITIVE_FIELD_NAME_MARKERS) {
-            if (fieldName.contains(each)) {
-                return true;
-            }
-        }
-        return false;
-    }
-    
-    private boolean isUnknownAlgorithmPropertySensitivity(final Map<?, ?> 
question) {
-        return 
normalizeSensitiveName(getField(question)).contains("algorithmproperties") && 
!question.containsKey(MCPPayloadFieldNames.SECRET);
-    }
-    
-    private String normalizeSensitiveName(final String value) {
-        return value.replaceAll(CAMEL_CASE_SEPARATOR_PATTERN, "$1 
$2").toLowerCase(Locale.ENGLISH).replaceAll(NON_ALPHANUMERIC_PATTERN, "");
-    }
-    
     private String getPlanId(final Map<String, Object> payload) {
         return Objects.toString(payload.get(WorkflowFieldNames.PLAN_ID), "");
     }
diff --git 
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/AbstractMCPToolSpecificationFactoryTest.java
 
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/AbstractMCPToolSpecificationFactoryTest.java
index 70d707e52ab..a7661f5b5c3 100644
--- 
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/AbstractMCPToolSpecificationFactoryTest.java
+++ 
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/AbstractMCPToolSpecificationFactoryTest.java
@@ -270,10 +270,15 @@ abstract class AbstractMCPToolSpecificationFactoryTest {
     }
     
     protected MCPToolDescriptor createPlanningToolDescriptor(final String 
toolName) {
+        return createPlanningToolDescriptor(toolName, Collections.emptyMap());
+    }
+    
+    protected MCPToolDescriptor createPlanningToolDescriptor(final String 
toolName, final Map<String, Object> additionalProperties) {
         Map<String, Object> properties = new LinkedHashMap<>(2, 1F);
         properties.put("custom_properties", Map.of("type", "object", 
"description", "Custom properties.", "additionalProperties", true));
         properties.put("intent", Map.of("type", "object", "description", 
"Intent.", "properties",
                 Map.of("requires_review", Map.of("type", "boolean", 
"description", "Requires review.")), "required", List.of(), 
"additionalProperties", false));
+        properties.putAll(additionalProperties);
         return new MCPToolDescriptor(toolName, "Plan Custom Rule", "Plan a 
custom rule.", createInputSchema(properties, List.of()),
                 Map.of("type", "object"), MCPToolAnnotations.builder()
                         .title("Plan Custom 
Rule").readOnlyHint(false).destructiveHint(false).idempotentHint(true).openWorldHint(true).build(),
diff --git 
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicyTest.java
 
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicyTest.java
index 9821d95aef3..ece7507707c 100644
--- 
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicyTest.java
+++ 
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicyTest.java
@@ -81,7 +81,7 @@ class MCPToolClarificationPolicyTest extends 
AbstractMCPToolSpecificationFactory
     
     @Test
     void assertCreateClarificationFormWithSensitiveQuestion() {
-        Map<String, Object> payload = 
createClarifyingPayload(createClarifyingQuestion("custom_properties.access-token",
 "string", false, "Provide access token."));
+        Map<String, Object> payload = 
createClarifyingPayload(createClarifyingQuestion("custom_properties.access-token",
 "string", true, "Provide access token."));
         Optional<MCPToolClarificationPolicy.ClarificationForm> actual = 
policy.createClarificationForm(payload,
                 
createPlanningToolDescriptor("database_gateway_plan_encrypt_rule"));
         assertTrue(actual.isEmpty());
diff --git 
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFallbackResponseFactoryTest.java
 
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFallbackResponseFactoryTest.java
index 9335f511849..dbdc03f9bf9 100644
--- 
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFallbackResponseFactoryTest.java
+++ 
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFallbackResponseFactoryTest.java
@@ -53,7 +53,7 @@ class MCPToolElicitationFallbackResponseFactoryTest extends 
AbstractMCPToolSpeci
     
     @Test
     void assertCreateSensitiveFallback() {
-        MCPSuccessPayload actual = 
factory.create(createClarifyingPayload(createClarifyingQuestion("primary_algorithm_properties.access-token",
 "string", false, "Provide access token.")),
+        MCPSuccessPayload actual = 
factory.create(createClarifyingPayload(createClarifyingQuestion("primary_algorithm_properties.access-token",
 "string", true, "Provide access token.")),
                 MCPToolElicitationFallbackReason.SENSITIVE_FORM_BLOCKED, 
createClientCapabilities(McpSchema.ClientCapabilities.builder().elicitation().build()));
         Map<String, Object> actualPayload = actual.toPayload();
         assertThat(actualPayload.get("fallback_reason"), 
is("sensitive_form_blocked"));
diff --git 
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFlowTest.java
 
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFlowTest.java
index fa6f5b02748..b9ed4866e2c 100644
--- 
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFlowTest.java
+++ 
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFlowTest.java
@@ -83,6 +83,23 @@ class MCPToolElicitationFlowTest extends 
AbstractMCPToolSpecificationFactoryTest
         }
     }
     
+    @Test
+    void assertCreateToolSpecificationsElicitKeyGeneratorField() {
+        try (MockedStatic<ToolDefinitionRegistry> mockedToolDefinitionRegistry 
= mockStatic(ToolDefinitionRegistry.class)) {
+            String toolName = "database_gateway_plan_encrypt_rule";
+            MCPToolDefinition toolDefinition = 
mockSupportedTool(mockedToolDefinitionRegistry, 
createPlanningToolDescriptor(toolName,
+                    Map.of("key_generator", Map.of("type", "string", 
"description", "Key generator name."))));
+            mockedToolDefinitionRegistry.when(() -> 
ToolDefinitionRegistry.dispatch(any(MCPFeatureRuntimeRequestContext.class), 
eq(toolDefinition), any()))
+                    .thenReturn(new 
MCPMapPayload(createClarifyingPayload(createClarifyingQuestion("key_generator", 
"string", false, "Provide key generator name."))),
+                            new MCPMapPayload(Map.of("status", "planned")));
+            McpSyncServerExchange exchange = createElicitationExchange(new 
McpSchema.ElicitResult(McpSchema.ElicitResult.Action.ACCEPT, Map.of("field_1", 
"snowflake_generator")));
+            CallToolResult actual = callTool(createToolSpecification("stdio"), 
exchange, toolName, Map.of());
+            assertThat(actual.structuredContent(), is(Map.of("status", 
"planned")));
+            mockedToolDefinitionRegistry.verify(() -> 
ToolDefinitionRegistry.dispatch(any(MCPFeatureRuntimeRequestContext.class), 
eq(toolDefinition),
+                    eq(Map.of("plan_id", "plan-1", "key_generator", 
"snowflake_generator"))));
+        }
+    }
+    
     private void assertInteractiveElicitation(final 
McpSchema.ClientCapabilities clientCapabilities) {
         try (MockedStatic<ToolDefinitionRegistry> mockedToolDefinitionRegistry 
= mockStatic(ToolDefinitionRegistry.class)) {
             String toolName = "database_gateway_plan_encrypt_rule";
@@ -115,17 +132,12 @@ class MCPToolElicitationFlowTest extends 
AbstractMCPToolSpecificationFactoryTest
         
assertCreateToolSpecificationsSkipUnsafeElicitation(createClarifyingQuestion("custom_properties.display-name",
 "secret", false, "Provide display name."));
     }
     
-    @Test
-    void assertCreateToolSpecificationsSkipElicitationWithSensitiveFieldName() 
{
-        
assertCreateToolSpecificationsSkipUnsafeElicitation(createClarifyingQuestion("primary_algorithm_properties.access-token",
 "string", false, "Provide access token."));
-    }
-    
     @Test
     void 
assertCreateToolSpecificationsFallbackWithUrlModeForSensitiveQuestion() {
         try (MockedStatic<ToolDefinitionRegistry> mockedToolDefinitionRegistry 
= mockStatic(ToolDefinitionRegistry.class)) {
             String toolName = "database_gateway_plan_encrypt_rule";
             MCPSuccessPayload response = new 
MCPMapPayload(createClarifyingPayload(
-                    
createClarifyingQuestion("primary_algorithm_properties.access-token", "string", 
false, "Provide access token.")));
+                    
createClarifyingQuestion("primary_algorithm_properties.access-token", "string", 
true, "Provide access token.")));
             MCPToolDefinition toolDefinition = 
mockSupportedTool(mockedToolDefinitionRegistry, 
createPlanningToolDescriptor(toolName));
             mockToolDispatch(mockedToolDefinitionRegistry, toolDefinition, 
Map.of(), response);
             McpSyncServerExchange exchange = createElicitationExchange(new 
McpSchema.ElicitResult(McpSchema.ElicitResult.Action.ACCEPT, Map.of()), 
createFormAndUrlClientCapabilities());
@@ -142,7 +154,7 @@ class MCPToolElicitationFlowTest extends 
AbstractMCPToolSpecificationFactoryTest
     }
     
     @Test
-    void 
assertCreateToolSpecificationsSkipElicitationWithUnknownAlgorithmSecretFlag() {
+    void assertCreateToolSpecificationsSkipElicitationWithoutSecretMetadata() {
         assertCreateToolSpecificationsSkipUnsafeElicitationWithPayload(Map.of(
                 "plan_id", "plan-1",
                 "status", "clarifying",
diff --git 
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/stdio/SessionManagedStdioTransportProviderTest.java
 
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/stdio/SessionManagedStdioTransportProviderTest.java
index e05196254dd..896f40110f6 100644
--- 
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/stdio/SessionManagedStdioTransportProviderTest.java
+++ 
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/stdio/SessionManagedStdioTransportProviderTest.java
@@ -24,6 +24,7 @@ import 
org.apache.shardingsphere.mcp.bootstrap.transport.MCPTransportJsonMapperF
 import org.apache.shardingsphere.mcp.core.session.MCPSessionManager;
 import org.junit.jupiter.api.Test;
 
+import java.io.InputStream;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -43,7 +44,7 @@ class SessionManagedStdioTransportProviderTest {
     
     @Test
     void assertProtocolVersions() {
-        SessionManagedStdioTransportProvider provider = new 
SessionManagedStdioTransportProvider(new 
MCPSessionManager(Collections.emptyMap()), 
MCPTransportJsonMapperFactory.create());
+        SessionManagedStdioTransportProvider provider = createProvider(new 
MCPSessionManager(Collections.emptyMap()));
         List<String> actual = provider.protocolVersions();
         assertThat(actual, 
is(MCPTransportConstants.SUPPORTED_PROTOCOL_VERSIONS));
     }
@@ -55,7 +56,7 @@ class SessionManagedStdioTransportProviderTest {
         McpServerSession session = mock(McpServerSession.class);
         
when(sessionFactory.create(any(McpServerTransport.class))).thenReturn(session);
         when(session.getId()).thenReturn("session-id");
-        SessionManagedStdioTransportProvider provider = new 
SessionManagedStdioTransportProvider(sessionManager, 
MCPTransportJsonMapperFactory.create());
+        SessionManagedStdioTransportProvider provider = 
createProvider(sessionManager);
         provider.setSessionFactory(sessionFactory);
         assertTrue(sessionManager.hasSession("session-id"));
     }
@@ -73,7 +74,7 @@ class SessionManagedStdioTransportProviderTest {
             return session;
         });
         when(session.getId()).thenReturn("session-id");
-        SessionManagedStdioTransportProvider provider = new 
SessionManagedStdioTransportProvider(sessionManager, 
MCPTransportJsonMapperFactory.create());
+        SessionManagedStdioTransportProvider provider = 
createProvider(sessionManager);
         provider.setSessionFactory(sessionFactory);
         transport.get().closeGracefully().block();
         assertThat(actualClosedSessionIds, is(List.of("session-id")));
@@ -102,7 +103,7 @@ class SessionManagedStdioTransportProviderTest {
         });
         when(firstSession.getId()).thenReturn("session-id-1");
         when(secondSession.getId()).thenReturn("session-id-2");
-        SessionManagedStdioTransportProvider provider = new 
SessionManagedStdioTransportProvider(sessionManager, 
MCPTransportJsonMapperFactory.create());
+        SessionManagedStdioTransportProvider provider = 
createProvider(sessionManager);
         provider.setSessionFactory(sessionFactory);
         firstTransport.get().close();
         provider.setSessionFactory(sessionFactory);
@@ -125,7 +126,7 @@ class SessionManagedStdioTransportProviderTest {
             return session;
         });
         when(session.getId()).thenReturn("session-id");
-        SessionManagedStdioTransportProvider provider = new 
SessionManagedStdioTransportProvider(sessionManager, 
MCPTransportJsonMapperFactory.create());
+        SessionManagedStdioTransportProvider provider = 
createProvider(sessionManager);
         provider.setSessionFactory(sessionFactory);
         transport.get().close();
         assertThat(actualClosedSessionIds, is(List.of("session-id")));
@@ -145,11 +146,21 @@ class SessionManagedStdioTransportProviderTest {
             return session;
         });
         when(session.getId()).thenReturn("session-id");
-        SessionManagedStdioTransportProvider provider = new 
SessionManagedStdioTransportProvider(sessionManager, 
MCPTransportJsonMapperFactory.create());
+        SessionManagedStdioTransportProvider provider = 
createProvider(sessionManager);
         provider.setSessionFactory(sessionFactory);
         transport.get().close();
         transport.get().closeGracefully().block();
         assertThat(actualClosedSessionIds, is(List.of("session-id")));
         assertFalse(sessionManager.hasSession("session-id"));
     }
+    
+    private SessionManagedStdioTransportProvider createProvider(final 
MCPSessionManager sessionManager) {
+        InputStream originalInput = System.in;
+        try {
+            System.setIn(InputStream.nullInputStream());
+            return new SessionManagedStdioTransportProvider(sessionManager, 
MCPTransportJsonMapperFactory.create());
+        } finally {
+            System.setIn(originalInput);
+        }
+    }
 }
diff --git 
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/RuleArtifact.java
 
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/RuleArtifact.java
index 2d9c2724358..b23d3d20353 100644
--- 
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/RuleArtifact.java
+++ 
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/RuleArtifact.java
@@ -20,9 +20,6 @@ package org.apache.shardingsphere.mcp.support.workflow.model;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
-
 /**
  * Rule artifact.
  */
@@ -33,16 +30,4 @@ public final class RuleArtifact {
     private final String operationType;
     
     private final String sql;
-    
-    /**
-     * Convert to map.
-     *
-     * @return map representation
-     */
-    public Map<String, Object> toMap() {
-        Map<String, Object> result = new LinkedHashMap<>(3, 1F);
-        result.put(WorkflowFieldNames.OPERATION_TYPE, operationType);
-        result.put("sql", sql);
-        return result;
-    }
 }
diff --git 
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowGuidancePayloadBuilder.java
 
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowGuidancePayloadBuilder.java
index 71731c2c33b..c797f71ff0a 100644
--- 
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowGuidancePayloadBuilder.java
+++ 
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowGuidancePayloadBuilder.java
@@ -166,20 +166,21 @@ public final class WorkflowGuidancePayloadBuilder {
     
     private static Map<String, Object> createClarificationQuestion(final 
WorkflowContextSnapshot snapshot, final String fieldName, final String 
clarificationMessage) {
         Map<String, Object> result = new LinkedHashMap<>(6, 1F);
-        String inputType = resolveClarificationInputType(snapshot, fieldName);
+        boolean secret = isSecretClarificationField(snapshot, fieldName);
+        String inputType = resolveClarificationInputType(fieldName, secret);
         result.put(MCPPayloadFieldNames.FIELD, fieldName);
         result.put("question_key", fieldName.replace('.', '_'));
         result.put(MCPPayloadFieldNames.INPUT_TYPE, inputType);
         if ("boolean".equals(inputType)) {
             result.put(MCPPayloadFieldNames.ALLOWED_VALUES, List.of(true, 
false));
         }
-        result.put(MCPPayloadFieldNames.SECRET, 
isSecretClarificationField(snapshot, fieldName));
+        result.put(MCPPayloadFieldNames.SECRET, secret);
         result.put(MCPPayloadFieldNames.DISPLAY_MESSAGE, 
clarificationMessage.isBlank() ? String.format("Please provide `%s`.", 
fieldName) : clarificationMessage);
         return result;
     }
     
-    private static String resolveClarificationInputType(final 
WorkflowContextSnapshot snapshot, final String fieldName) {
-        if (isSecretClarificationField(snapshot, fieldName)) {
+    private static String resolveClarificationInputType(final String 
fieldName, final boolean secret) {
+        if (secret) {
             return "secret";
         }
         return fieldName.startsWith("requires_") ? "boolean" : "string";
@@ -195,7 +196,7 @@ public final class WorkflowGuidancePayloadBuilder {
                 return each.isSecret();
             }
         }
-        return false;
+        return true;
     }
     
     private static void addMissingInputsFromIssue(final Collection<String> 
missingInputs, final WorkflowContextSnapshot snapshot, final WorkflowIssue 
issue) {
diff --git 
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilderTest.java
 
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilderTest.java
index 3cd715a8f87..f3d333884f6 100644
--- 
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilderTest.java
+++ 
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilderTest.java
@@ -112,16 +112,36 @@ class WorkflowPlanPayloadBuilderTest {
         snapshot.getPropertyRequirements().add(new 
AlgorithmPropertyRequirement("primary", "aes-key-value", true, true, "primary 
key", ""));
         snapshot.getPropertyRequirements().add(new 
AlgorithmPropertyRequirement("assisted_query", "salt", true, true, "assist 
key", ""));
         snapshot.getPropertyRequirements().add(new 
AlgorithmPropertyRequirement("like_query", "token", true, true, "like key", 
""));
+        snapshot.getPropertyRequirements().add(new 
AlgorithmPropertyRequirement("primary", "mode", true, false, "mode", ""));
         snapshot.getIssues().add(new WorkflowIssue("code", "warning", 
"clarifying", "message", "action", true,
-                Map.of("missing_properties", List.of("aes-key-value", "salt", 
"token"))));
+                Map.of("missing_properties", List.of("aes-key-value", "salt", 
"token", "mode"))));
         Map<String, Object> actual = 
WorkflowPlanPayloadBuilder.build(snapshot);
         assertThat(actual.get("missing_required_inputs"), 
is(List.of("primary_algorithm_properties.aes-key-value", 
"assisted_query_algorithm_properties.salt",
-                "like_query_algorithm_properties.token")));
+                "like_query_algorithm_properties.token", 
"primary_algorithm_properties.mode")));
         List<?> actualClarificationQuestions = (List<?>) 
actual.get("clarification_questions");
         assertThat(((Map<?, ?>) 
actualClarificationQuestions.getFirst()).get("field"), 
is("primary_algorithm_properties.aes-key-value"));
         assertThat(((Map<?, ?>) 
actualClarificationQuestions.get(1)).get("field"), 
is("assisted_query_algorithm_properties.salt"));
         assertThat(((Map<?, ?>) 
actualClarificationQuestions.get(2)).get("field"), 
is("like_query_algorithm_properties.token"));
         assertTrue((Boolean) ((Map<?, ?>) 
actualClarificationQuestions.getFirst()).get("secret"));
+        assertThat(((Map<?, ?>) 
actualClarificationQuestions.get(3)).get("input_type"), is("string"));
+        assertFalse((Boolean) ((Map<?, ?>) 
actualClarificationQuestions.get(3)).get("secret"));
+    }
+    
+    @Test
+    void assertBuildTreatsUnknownAlgorithmPropertyAsSecret() {
+        WorkflowContextSnapshot snapshot = new WorkflowContextSnapshot();
+        snapshot.setPlanId("plan-1");
+        snapshot.setWorkflowKind(WorkflowKind.valueOf("encrypt.rule"));
+        snapshot.setStatus(WorkflowLifecycle.STATUS_CLARIFYING);
+        WorkflowRequest request = new WorkflowRequest();
+        snapshot.setRequest(request);
+        snapshot.setClarifiedIntent(new ClarifiedIntent());
+        snapshot.setInteractionPlan(InteractionPlan.create("plan-1", request, 
"Encrypt workflow plan.", List.of("review"), List.of("rules")));
+        snapshot.getIssues().add(new WorkflowIssue("code", "warning", 
"clarifying", "message", "action", true, Map.of("missing_properties", 
List.of("unknown-property"))));
+        Map<String, Object> actual = 
WorkflowPlanPayloadBuilder.build(snapshot);
+        Map<?, ?> actualQuestion = (Map<?, ?>) ((List<?>) 
actual.get("clarification_questions")).getFirst();
+        assertThat(actualQuestion.get("input_type"), is("secret"));
+        assertTrue((Boolean) actualQuestion.get("secret"));
     }
     
     @Test

Reply via email to