chore(audit): tool path resolution, config file, dead code removal, static analysis cleanup
Tool fixes: - FileWriteTool, FileEditTool: resolve relative paths against workingDir instead of JVM cwd - FileReadTool: remove allowedPaths restriction — reads are unrestricted - ShellTool: add workingDir for ProcessBuilder, remove environment().clear(), fail-open when allowedExecutables empty Config: - Add [tools] section to config.toml: sandbox_root, working_dir, shell_allowed_executables, default_system_prompt_path - Three-level resolution: env var > config file > hardcoded default - OrchestrationConfig sandboxRoot and defaultSystemPromptPath now sourced from CorrexConfig - Single defaultOrchestrationConfig in ServerModule, shared by SessionRoutes and GlobalStreamHandler Dead code: - Delete EventTypes.kt — orphaned string constants duplicating serialization annotations Static analysis: - Remove 10 unused imports across 9 files - Remove redundant return in ReplayOrchestrator - Remove redundant suspend from ApprovalCoordinator.handleResponse - Fix unreachable InputMode.None branch in InputBar - Enable full detekt rule sets in detekt.yml
This commit is contained in:
-1
@@ -1,6 +1,5 @@
|
||||
package com.correx.infrastructure.tools
|
||||
|
||||
import com.correx.core.approvals.Tier
|
||||
import com.correx.core.events.EventDispatcher
|
||||
import com.correx.core.events.events.EventPayload
|
||||
import com.correx.core.events.events.ToolExecutionCompletedEvent
|
||||
|
||||
@@ -23,9 +23,14 @@ data class FileWriteConfig(
|
||||
val artifactStore: ArtifactStore? = null,
|
||||
val materializingWriter: MaterializingArtifactWriter? = null,
|
||||
val sandboxRoot: Path? = null,
|
||||
val workingDir: Path? = null,
|
||||
)
|
||||
data class FileEditConfig(val enabled: Boolean = false, val allowedPaths: Set<Path> = emptySet())
|
||||
data class ShellConfig(val enabled: Boolean = false, val allowedExecutables: Set<String> = emptySet())
|
||||
data class FileEditConfig(
|
||||
val enabled: Boolean = false,
|
||||
val allowedPaths: Set<Path> = emptySet(),
|
||||
val workingDir: Path? = null,
|
||||
)
|
||||
data class ShellConfig(val enabled: Boolean = false, val allowedExecutables: Set<String> = emptySet(), val workingDir: Path? = null)
|
||||
|
||||
/**
|
||||
* Extension function to convert [ToolConfig] into a list of [Tool] implementations.
|
||||
@@ -33,7 +38,8 @@ data class ShellConfig(val enabled: Boolean = false, val allowedExecutables: Set
|
||||
fun ToolConfig.buildTools(): List<Tool> = buildList {
|
||||
if (shell.enabled) {
|
||||
add(ShellTool(
|
||||
allowedExecutables = shell.allowedExecutables
|
||||
allowedExecutables = shell.allowedExecutables,
|
||||
workingDir = shell.workingDir,
|
||||
))
|
||||
}
|
||||
if (fileRead.enabled) {
|
||||
@@ -47,11 +53,13 @@ fun ToolConfig.buildTools(): List<Tool> = buildList {
|
||||
artifactStore = fileWrite.artifactStore,
|
||||
materializingWriter = fileWrite.materializingWriter,
|
||||
sandboxRoot = fileWrite.sandboxRoot,
|
||||
workingDir = fileWrite.workingDir,
|
||||
))
|
||||
}
|
||||
if (fileEdit.enabled) {
|
||||
add(FileEditTool(
|
||||
allowedPaths = fileEdit.allowedPaths
|
||||
allowedPaths = fileEdit.allowedPaths,
|
||||
workingDir = fileEdit.workingDir,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -14,10 +14,12 @@ import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import java.nio.file.Path
|
||||
|
||||
class ShellTool(
|
||||
private val allowedExecutables: Set<String> = emptySet(),
|
||||
private val timeoutMs: Long = 30_000L,
|
||||
private val workingDir: Path? = null,
|
||||
) : Tool, ToolExecutor {
|
||||
override val name: String = "shell"
|
||||
override val description: String = "Execute a shell command"
|
||||
@@ -31,7 +33,7 @@ class ShellTool(
|
||||
return when {
|
||||
argv.isNullOrEmpty() ->
|
||||
ValidationResult.Invalid("Missing or empty 'argv' parameter. Expected List<String>.")
|
||||
argv[0] !in allowedExecutables ->
|
||||
allowedExecutables.isNotEmpty() && argv[0] !in allowedExecutables ->
|
||||
ValidationResult.Invalid("Executable '${argv[0]}' is not in the allowed list.")
|
||||
else -> ValidationResult.Valid
|
||||
}
|
||||
@@ -42,7 +44,7 @@ class ShellTool(
|
||||
takeIf { this is ValidationResult.Valid }?.let {
|
||||
val argv = (request.parameters["argv"] as? List<*>)?.filterIsInstance<String>()
|
||||
val process = ProcessBuilder(argv).apply {
|
||||
environment().clear()
|
||||
workingDir?.let { directory(it.toFile()) }
|
||||
}.start()
|
||||
runCatching {
|
||||
runCmd(request, process)
|
||||
|
||||
Reference in New Issue
Block a user