diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java index 3c9e4676..b11e33d1 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java @@ -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.exception.ActionInfrastructureStartupException; 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 java.io.File; @@ -331,7 +332,9 @@ public class DynamicActionMcpManager implements AutoCloseable { .build()); } 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() .isError(!execResult.isOk()); List resultList = execResult.getResultList(); diff --git a/Partner-Core/src/test/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManagerPolicyTest.java b/Partner-Core/src/test/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManagerPolicyTest.java new file mode 100644 index 00000000..010dd38b --- /dev/null +++ b/Partner-Core/src/test/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManagerPolicyTest.java @@ -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 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> handler = + (BiFunction>) 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); + } + } + } +}