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