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:
2026-05-19 12:48:47 +04:00
parent c0efa0ef03
commit 71a73a4fa2
30 changed files with 253 additions and 94 deletions
@@ -78,6 +78,7 @@ object ConfigLoader {
val tuiSection = sections["tui"] ?: emptyMap()
val cliSection = sections["cli"] ?: emptyMap()
val approvalSection = sections["approval"] ?: emptyMap()
val toolsSection = sections["tools"] ?: emptyMap()
val server = ServerConfig(
host = serverSection["host"] ?: "localhost",
@@ -97,11 +98,22 @@ object ConfigLoader {
timeoutMs = approvalSection["timeout_ms"]?.toLongOrNull() ?: 300_000L,
)
val tools = ToolsConfig(
sandboxRoot = toolsSection["sandbox_root"] ?: "",
workingDir = toolsSection["working_dir"] ?: "",
shellAllowedExecutables = toolsSection["shell_allowed_executables"]
?.split(",")?.map { it.trim() }?.filter { it.isNotEmpty() }
?: emptyList(),
defaultSystemPromptPath = toolsSection["default_system_prompt_path"]
?: "~/.config/correx/prompts/default_system.md",
)
return CorrexConfig(
server = server,
tui = tui,
cli = cli,
approval = approval,
tools = tools,
)
}
}
@@ -8,6 +8,7 @@ data class CorrexConfig(
val tui: TuiConfig = TuiConfig(),
val cli: CliConfig = CliConfig(),
val approval: ApprovalConfig = ApprovalConfig(),
val tools: ToolsConfig = ToolsConfig(),
)
@Serializable
@@ -31,3 +32,11 @@ data class CliConfig(
data class ApprovalConfig(
val timeoutMs: Long = 300_000L,
)
@Serializable
data class ToolsConfig(
val sandboxRoot: String = "",
val workingDir: String = "",
val shellAllowedExecutables: List<String> = emptyList(),
val defaultSystemPromptPath: String = "~/.config/correx/prompts/default_system.md",
)
@@ -1,17 +0,0 @@
package com.correx.core.events.types
object EventTypes {
const val SESSION_STARTED = "session.started"
const val SESSION_PAUSED = "session.paused"
const val SESSION_COMPLETED = "session.completed"
const val TOOL_INVOKED = "tool.invoked"
const val TOOL_COMPLETED = "tool.completed"
const val APPROVAL_REQUESTED = "approval.requested"
const val APPROVAL_DECISION_RESOLVED = "approval.decision_resolved"
const val APPROVAL_GRANT_CREATED = "approval.grant_created"
const val APPROVAL_GRANT_EXPIRED = "approval.grant_expired"
const val ARTIFACT_CREATED = "artifact.created"
}
@@ -96,7 +96,7 @@ class ReplayOrchestrator(
currentStageId = advanceStage(ctx.sessionId, ctx.currentStageId, decision),
),
)
is ReplayStepResult.Terminal -> return result.result
is ReplayStepResult.Terminal -> result.result
}
}