fix(DynamicActionMcp): apply execution policy to tool handler

This commit is contained in:
2026-04-19 17:21:37 +08:00
parent 657023694c
commit 15d7eb6850
2 changed files with 101 additions and 1 deletions

View File

@@ -15,6 +15,7 @@ import work.slhaf.partner.common.mcp.InProcessMcpTransport;
import work.slhaf.partner.core.action.entity.MetaActionInfo; import work.slhaf.partner.core.action.entity.MetaActionInfo;
import work.slhaf.partner.core.action.exception.ActionInfrastructureStartupException; import work.slhaf.partner.core.action.exception.ActionInfrastructureStartupException;
import work.slhaf.partner.core.action.runner.execution.CommandExecutionService; import work.slhaf.partner.core.action.runner.execution.CommandExecutionService;
import work.slhaf.partner.core.action.runner.policy.ExecutionPolicyRegistry;
import work.slhaf.partner.framework.agent.support.DirectoryWatchSupport; import work.slhaf.partner.framework.agent.support.DirectoryWatchSupport;
import java.io.File; import java.io.File;
@@ -331,7 +332,9 @@ public class DynamicActionMcpManager implements AutoCloseable {
.build()); .build());
} }
return Mono.fromCallable(() -> { return Mono.fromCallable(() -> {
CommandExecutionService.Result execResult = commandExecutionService.exec(commands); CommandExecutionService.Result execResult = commandExecutionService.exec(
ExecutionPolicyRegistry.INSTANCE.prepare(List.of(commands))
);
McpSchema.CallToolResult.Builder builder = McpSchema.CallToolResult.builder() McpSchema.CallToolResult.Builder builder = McpSchema.CallToolResult.builder()
.isError(!execResult.isOk()); .isError(!execResult.isOk());
List<String> resultList = execResult.getResultList(); List<String> resultList = execResult.getResultList();

View File

@@ -0,0 +1,97 @@
package work.slhaf.partner.core.action.runner.mcp;
import io.modelcontextprotocol.spec.McpSchema;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import reactor.core.publisher.Mono;
import work.slhaf.partner.core.action.entity.MetaActionInfo;
import work.slhaf.partner.core.action.runner.policy.ExecutionPolicy;
import work.slhaf.partner.core.action.runner.policy.ExecutionPolicyRegistry;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiFunction;
class DynamicActionMcpManagerPolicyTest {
private static String originalUserHome;
@BeforeAll
static void prepareTestHome() throws IOException {
originalUserHome = System.getProperty("user.home");
Path tempHome = Files.createTempDirectory("partner-test-home");
System.setProperty("user.home", tempHome.toString());
}
@AfterAll
static void restoreUserHome() {
if (originalUserHome != null) {
System.setProperty("user.home", originalUserHome);
}
}
@Test
@SuppressWarnings("unchecked")
void testDynamicActionHandlerAppliesExecutionPolicyEnvironment(@TempDir Path tempDir) throws Exception {
ConcurrentHashMap<String, MetaActionInfo> existedMetaActions = new ConcurrentHashMap<>();
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
DynamicActionMcpManager manager = new DynamicActionMcpManager(tempDir, existedMetaActions, executor)) {
Path script = tempDir.resolve("run.py");
Files.writeString(script, "import os\nprint(os.getenv('PARTNER_DYNAMIC_TEST', ''), end='')\n");
ExecutionPolicy originalPolicy = new ExecutionPolicy(
ExecutionPolicy.Mode.DIRECT,
"direct",
ExecutionPolicy.Network.ENABLE,
true,
Map.of(),
null,
Set.of(),
Set.of()
);
ExecutionPolicyRegistry.INSTANCE.updatePolicy(new ExecutionPolicy(
ExecutionPolicy.Mode.DIRECT,
"direct",
ExecutionPolicy.Network.ENABLE,
false,
Map.of("PARTNER_DYNAMIC_TEST", "dynamic-applied"),
null,
Set.of(),
Set.of()
));
try {
Method method = DynamicActionMcpManager.class.getDeclaredMethod("buildToolHandler", File.class, String.class);
method.setAccessible(true);
BiFunction<?, McpSchema.CallToolRequest, Mono<McpSchema.CallToolResult>> handler =
(BiFunction<?, McpSchema.CallToolRequest, Mono<McpSchema.CallToolResult>>) method.invoke(
manager,
script.toFile(),
"python3"
);
McpSchema.CallToolResult result = handler.apply(
null,
McpSchema.CallToolRequest.builder().name("demo").arguments(Map.of()).build()
).block();
Assertions.assertNotNull(result);
Assertions.assertFalse(Boolean.TRUE.equals(result.isError()));
Assertions.assertEquals("[dynamic-applied]", String.valueOf(result.structuredContent()));
} finally {
ExecutionPolicyRegistry.INSTANCE.updatePolicy(originalPolicy);
}
}
}
}