feat: plane-2 tool-call intent validation (path containment slice)
Implements the full vertical slice for invariant #9 tool-call assessment: - core:toolintent — new module with ToolCallRule seam, ToolCallAssessor, WorldProbe/FileSystemWorldProbe, WorkspacePolicy, PathContainmentRule, and RiskMapping (assessment → RiskSummary / AssessedIssue) - core:tools — ToolCallAssessmentRecord + ToolInvocationRecord.assessment field; DefaultToolReducer handles ToolCallAssessedEvent (replay proof) - core:config — ToolsConfig gains workspaceRoot + privilegedLocations; ConfigLoader parses both; DEFAULT_PRIVILEGED_LOCATIONS built-in - core:kernel — OrchestratorEngines gains toolCallAssessor/workspacePolicy/ worldProbe fields; SessionOrchestrator.dispatchToolCalls runs runPlane2Assessment before the tier gate: BLOCK → hard-reject without executing; PROMPT_USER → elevates tier into approval path with plane2Risk in the ApprovalRequestedEvent - apps/server — constructs PathContainmentRule + ToolCallAssessor + WorkspacePolicy from config and wires them into OrchestratorEngines Assessment is recorded as ToolCallAssessedEvent (environment observed once, facts stored, replay reads events — invariant #9). Assessor and WorldProbe are only invoked on the live orchestrator path, never in replay.
This commit is contained in:
@@ -299,6 +299,9 @@ object ConfigLoader {
|
||||
fileReadEnabled = fileReadEnabled,
|
||||
fileWriteEnabled = fileWriteEnabled,
|
||||
fileEditEnabled = fileEditEnabled,
|
||||
workspaceRoot = asString(toolsSection["workspace_root"], ""),
|
||||
privilegedLocations = asStringList(toolsSection["privileged_locations"])
|
||||
.ifEmpty { ToolsConfig.DEFAULT_PRIVILEGED_LOCATIONS },
|
||||
)
|
||||
|
||||
val providers = providersList.mapNotNull { providerMap ->
|
||||
|
||||
@@ -39,7 +39,16 @@ data class ToolsConfig(
|
||||
val fileReadEnabled: Boolean = true,
|
||||
val fileWriteEnabled: Boolean = true,
|
||||
val fileEditEnabled: Boolean = true,
|
||||
)
|
||||
val workspaceRoot: String = "",
|
||||
val privilegedLocations: List<String> = DEFAULT_PRIVILEGED_LOCATIONS,
|
||||
) {
|
||||
companion object {
|
||||
val DEFAULT_PRIVILEGED_LOCATIONS: List<String> = listOf(
|
||||
"/etc", "/usr", "/bin", "/sbin", "/boot", "/lib", "/lib64",
|
||||
"/sys", "/proc", "/dev", "/root",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ProviderConfig(
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.correx.core.config
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class WorkspaceConfigTest {
|
||||
|
||||
@Test
|
||||
fun `defaults when keys absent`() {
|
||||
val tools = ToolsConfig()
|
||||
assertEquals("", tools.workspaceRoot)
|
||||
assertTrue(tools.privilegedLocations.contains("/etc"))
|
||||
assertTrue(tools.privilegedLocations.contains("/usr"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `default privileged locations includes system paths`() {
|
||||
val defaults = ToolsConfig.DEFAULT_PRIVILEGED_LOCATIONS
|
||||
assertTrue(defaults.contains("/etc"))
|
||||
assertTrue(defaults.contains("/usr"))
|
||||
assertTrue(defaults.contains("/bin"))
|
||||
assertTrue(defaults.contains("/root"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parseToml parses workspace_root from tools section`() {
|
||||
val toml = """
|
||||
[tools]
|
||||
workspace_root = "/my/workspace"
|
||||
privileged_locations = ["/etc", "/usr", "/custom"]
|
||||
""".trimIndent()
|
||||
|
||||
val parseTomlMethod = ConfigLoader::class.java.getDeclaredMethod("parseToml", String::class.java)
|
||||
parseTomlMethod.isAccessible = true
|
||||
val result = parseTomlMethod.invoke(ConfigLoader, toml) as CorrexConfig
|
||||
|
||||
assertEquals("/my/workspace", result.tools.workspaceRoot)
|
||||
assertEquals(listOf("/etc", "/usr", "/custom"), result.tools.privilegedLocations)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parseToml uses default privileged locations when key absent`() {
|
||||
val toml = """
|
||||
[tools]
|
||||
workspace_root = "/x"
|
||||
""".trimIndent()
|
||||
|
||||
val parseTomlMethod = ConfigLoader::class.java.getDeclaredMethod("parseToml", String::class.java)
|
||||
parseTomlMethod.isAccessible = true
|
||||
val result = parseTomlMethod.invoke(ConfigLoader, toml) as CorrexConfig
|
||||
|
||||
assertEquals(ToolsConfig.DEFAULT_PRIVILEGED_LOCATIONS, result.tools.privilegedLocations)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user