From 97bb89740785ca4825dc7ae0477ffe32849b00a9 Mon Sep 17 00:00:00 2001 From: slhafzjw Date: Fri, 13 Mar 2026 14:45:50 +0800 Subject: [PATCH] feat(runner): add execution policy abstract for local running --- .../runner/mcp/McpTransportFactory.java | 4 +- .../runner/policy/DirectPolicyProvider.kt | 20 +++ .../action/runner/policy/ExecutionPolicy.kt | 115 ++++++++++++++++++ .../runner/policy/RunnerExecutionPolicy.java | 4 - 4 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/DirectPolicyProvider.kt create mode 100644 Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/ExecutionPolicy.kt delete mode 100644 Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/RunnerExecutionPolicy.java diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/McpTransportFactory.java b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/McpTransportFactory.java index 034999bb..8fa9a387 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/McpTransportFactory.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/McpTransportFactory.java @@ -7,14 +7,14 @@ import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequ import io.modelcontextprotocol.common.McpTransportContext; import io.modelcontextprotocol.json.McpJsonMapper; import io.modelcontextprotocol.spec.McpClientTransport; -import work.slhaf.partner.core.action.runner.policy.RunnerExecutionPolicy; +import work.slhaf.partner.core.action.runner.policy.ExecutionPolicyRegistry; import java.net.URI; import java.net.http.HttpRequest; public class McpTransportFactory { - public McpClientTransport create(McpTransportConfig config, RunnerExecutionPolicy policy) { + public McpClientTransport create(McpTransportConfig config, ExecutionPolicyRegistry policy) { return switch (config) { case McpTransportConfig.Stdio stdio -> { ServerParameters serverParameters = ServerParameters.builder(stdio.command()) diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/DirectPolicyProvider.kt b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/DirectPolicyProvider.kt new file mode 100644 index 00000000..0876fa29 --- /dev/null +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/DirectPolicyProvider.kt @@ -0,0 +1,20 @@ +package work.slhaf.partner.core.action.runner.policy + +object DirectPolicyProvider : PolicyProvider( + policyName = "direct" +) { + + override fun prepare( + policy: ExecutionPolicy, + commands: List + ): WrappedLaunchSpec { + val (command, args) = splitCommands(commands) + return WrappedLaunchSpec( + command = command, + args = args, + workingDirectory = policy.workingDirectory, + environment = resolveEnvironment(policy) + ) + } + +} \ No newline at end of file diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/ExecutionPolicy.kt b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/ExecutionPolicy.kt new file mode 100644 index 00000000..1425c332 --- /dev/null +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/ExecutionPolicy.kt @@ -0,0 +1,115 @@ +package work.slhaf.partner.core.action.runner.policy + +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.CopyOnWriteArraySet + +object ExecutionPolicyRegistry { + + private const val DEFAULT_PROVIDER = "direct" + + private val policyProviders = ConcurrentHashMap().apply { + put(DEFAULT_PROVIDER, DirectPolicyProvider) + } + + private val listeners = CopyOnWriteArraySet() + + @Volatile + private var currentPolicy = ExecutionPolicy( + provider = "direct", + mode = ExecutionPolicy.Mode.DIRECT, + net = ExecutionPolicy.Network.ENABLE, + inheritEnv = true, + env = emptyMap(), + workingDirectory = null, + readOnlyPaths = emptySet(), + writablePaths = emptySet(), + ) + + fun prepare(commands: List): WrappedLaunchSpec { + val policy = currentPolicy + val provider = policyProviders[policy.provider] + ?: policyProviders[DEFAULT_PROVIDER] + ?: error("Default provider '${DEFAULT_PROVIDER}' is not registered") + return provider.prepare(policy, commands) + } + + fun updatePolicy(policy: ExecutionPolicy) { + currentPolicy = policy + listeners.forEach { it.onPolicyChanged(policy) } + } + + fun addListener(listener: RunnerExecutionPolicyListener) { + listeners += listener + } + + fun removeListener(listener: RunnerExecutionPolicyListener) { + listeners -= listener + } + + fun registerPolicyProvider(policyProvider: PolicyProvider) { + val name = policyProvider.policyName + if (policyProviders.containsKey(name)) { + return + } + policyProviders[name] = policyProvider + } +} + +data class ExecutionPolicy( + val mode: Mode, + val provider: String, + val net: Network, + val inheritEnv: Boolean, + val env: Map, + val workingDirectory: String?, + val readOnlyPaths: Set, + val writablePaths: Set, +) { + + enum class Mode { + DIRECT, + SANDBOX + } + + enum class Network { + DISABLE, + ENABLE + } + +} + +data class WrappedLaunchSpec( + val command: String, + val args: List, + val workingDirectory: String? = null, + val environment: Map = emptyMap() +) + +abstract class PolicyProvider( + val policyName: String +) { + + abstract fun prepare( + policy: ExecutionPolicy, + commands: List + ): WrappedLaunchSpec + + protected fun resolveEnvironment(policy: ExecutionPolicy): Map { + val result = LinkedHashMap() + if (policy.inheritEnv) { + result.putAll(System.getenv()) + } + result.putAll(policy.env) + return result + } + + protected fun splitCommands(commands: List): Pair> { + require(commands.isNotEmpty()) { "commands must not be empty" } + return commands.first() to commands.drop(1) + } + +} + +interface RunnerExecutionPolicyListener { + fun onPolicyChanged(policy: ExecutionPolicy) +} diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/RunnerExecutionPolicy.java b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/RunnerExecutionPolicy.java deleted file mode 100644 index f2b63ec5..00000000 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/policy/RunnerExecutionPolicy.java +++ /dev/null @@ -1,4 +0,0 @@ -package work.slhaf.partner.core.action.runner.policy; - -public interface RunnerExecutionPolicy { -}