Files
pulse/internal/ai/tools/file_docker_test.go
T
rcourtman f4c2fd0c38 Fail closed on unknown remediation lock state for autonomous dispatches
The AI action broker treated an unreadable operator lock as unlocked:
isResourceRemediationLocked returned (false, nil) with no audit store
wired, and the caller logged store errors then dispatched anyway. An
operator's NeverAutoRemediate=true could be silently ignored whenever
the policy store was missing or erroring, which is unacceptable while
Patrol and Assistant run at assisted or full autonomy.

Posture change at the dispatch decision point:
- isResourceRemediationLocked now reports unknown state (nil store or
  lookup failure) as an ErrRemediationLockStateUnknown-wrapped error
  instead of silently defaulting to unlocked.
- New checkRemediationLockForDispatch gate: dispatches without an
  approved human decision fail CLOSED on unknown lock state and
  surface "remediation lock state unknown; operator approval
  required". Human-approved dispatches keep the historical fail-open
  behavior with a warning log. A confirmed lock still refuses even
  approved dispatches, as before.
- executeNativeActionWithAudit (TrueNAS app start/stop/restart) now
  enforces the lock too; it previously skipped the check entirely.
- Refusals persist Failed audit records with stable
  remediation_lock_state_unknown: / resource_remediation_locked:
  ErrorMessage prefixes.
- ai-runtime subsystem contract updated to pin the new posture.

Tests cover store-error and nil-store at both autonomy postures on
both dispatch paths; routing/control tests now wire an in-memory
audit store since autonomous dispatch without one is refused.
2026-07-10 00:14:01 +01:00

529 lines
21 KiB
Go

package tools
import (
"context"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"strings"
"testing"
"github.com/rcourtman/pulse-go-rewrite/internal/agentexec"
"github.com/rcourtman/pulse-go-rewrite/internal/models"
"github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
func TestExecuteFileEditDockerContainerValidation(t *testing.T) {
ctx := context.Background()
t.Run("InvalidDockerContainerName", func(t *testing.T) {
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
result, err := exec.executeFileEdit(ctx, map[string]interface{}{
"action": "read",
"path": "/config/test.json",
"target_host": "tower",
"container": "my container", // space is invalid
})
require.NoError(t, err)
assert.True(t, result.IsError)
assert.Contains(t, result.Content[0].Text, "invalid character")
})
t.Run("ValidDockerContainerName", func(t *testing.T) {
// This should pass validation but fail on agent lookup
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
result, err := exec.executeFileEdit(ctx, map[string]interface{}{
"action": "read",
"path": "/config/test.json",
"target_host": "tower",
"container": "my-container_v1.2",
})
require.NoError(t, err)
// Should fail with "no agent" not "invalid character"
assert.NotContains(t, result.Content[0].Text, "invalid character")
})
}
func TestExecuteFileReadDocker(t *testing.T) {
ctx := context.Background()
t.Run("ReadFromDockerContainer", func(t *testing.T) {
agents := []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "tower"}}
mockAgent := &mockAgentServer{}
mockAgent.On("GetConnectedAgents").Return(agents)
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
// Should wrap with docker exec
return strings.Contains(cmd.Command, "docker exec") &&
strings.Contains(cmd.Command, "jellyfin") &&
strings.Contains(cmd.Command, "cat") &&
strings.Contains(cmd.Command, "/config/settings.json")
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: `{"setting": "value"}`,
}, nil)
exec := NewPulseToolExecutor(ExecutorConfig{
StateProvider: &mockStateProvider{state: models.StateSnapshot{}},
AgentServer: mockAgent,
ControlLevel: ControlLevelAutonomous,
ActionAuditStore: unifiedresources.NewMemoryStore(),
})
result, err := exec.executeFileRead(ctx, "/config/settings.json", "tower", "jellyfin")
require.NoError(t, err)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
assert.True(t, resp["success"].(bool))
assert.Equal(t, "/config/settings.json", resp["path"])
assert.Equal(t, "jellyfin", resp["container"])
assert.Equal(t, `{"setting": "value"}`, resp["content"])
mockAgent.AssertExpectations(t)
})
t.Run("ReadFromHostWithoutDocker", func(t *testing.T) {
agents := []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "tower"}}
mockAgent := &mockAgentServer{}
mockAgent.On("GetConnectedAgents").Return(agents)
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
// Should NOT wrap with docker exec
return !strings.Contains(cmd.Command, "docker exec") &&
strings.Contains(cmd.Command, "cat") &&
strings.Contains(cmd.Command, "/etc/hostname")
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "tower",
}, nil)
exec := NewPulseToolExecutor(ExecutorConfig{
StateProvider: &mockStateProvider{state: models.StateSnapshot{}},
AgentServer: mockAgent,
ControlLevel: ControlLevelAutonomous,
ActionAuditStore: unifiedresources.NewMemoryStore(),
})
result, err := exec.executeFileRead(ctx, "/etc/hostname", "tower", "") // empty container
require.NoError(t, err)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
assert.True(t, resp["success"].(bool))
assert.Nil(t, resp["container"]) // should not be in response
mockAgent.AssertExpectations(t)
})
t.Run("DockerContainerNotFound", func(t *testing.T) {
agents := []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "tower"}}
mockAgent := &mockAgentServer{}
mockAgent.On("GetConnectedAgents").Return(agents)
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.Anything).Return(&agentexec.CommandResultPayload{
ExitCode: 1,
Stderr: "Error: No such container: nonexistent",
}, nil)
exec := NewPulseToolExecutor(ExecutorConfig{
StateProvider: &mockStateProvider{state: models.StateSnapshot{}},
AgentServer: mockAgent,
ControlLevel: ControlLevelAutonomous,
ActionAuditStore: unifiedresources.NewMemoryStore(),
})
result, err := exec.executeFileRead(ctx, "/config/test.json", "tower", "nonexistent")
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "Failed to read file from container 'nonexistent'")
assert.Contains(t, result.Content[0].Text, "No such container")
mockAgent.AssertExpectations(t)
})
}
func TestExecuteFileWriteDocker(t *testing.T) {
ctx := context.Background()
t.Run("WriteToDockerContainer", func(t *testing.T) {
content := `{"new": "config"}`
encodedContent := base64.StdEncoding.EncodeToString([]byte(content))
expectedWriteCmd := fmt.Sprintf(
"docker exec %s sh -c %s",
shellEscape("nginx"),
shellEscape(fmt.Sprintf("echo %s | base64 -d > %s", shellEscape(encodedContent), shellEscape("/etc/nginx/nginx.conf"))),
)
expected := sha256.Sum256([]byte(content))
expectedHex := hex.EncodeToString(expected[:])
agents := []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "tower"}}
mockAgent := &mockAgentServer{}
mockAgent.On("GetConnectedAgents").Return(agents)
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.Command == expectedWriteCmd
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "",
}, nil)
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return strings.Contains(cmd.Command, "docker exec") &&
strings.Contains(cmd.Command, "nginx") &&
strings.Contains(cmd.Command, "sha256sum") &&
strings.Contains(cmd.Command, "/etc/nginx/nginx.conf")
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: expectedHex + " /etc/nginx/nginx.conf\n",
}, nil)
exec := NewPulseToolExecutor(ExecutorConfig{
StateProvider: &mockStateProvider{state: models.StateSnapshot{}},
AgentServer: mockAgent,
ControlLevel: ControlLevelAutonomous,
ActionAuditStore: unifiedresources.NewMemoryStore(),
})
result, err := exec.executeFileWrite(ctx, "/etc/nginx/nginx.conf", content, "tower", "nginx", map[string]interface{}{})
require.NoError(t, err)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
assert.True(t, resp["success"].(bool))
assert.Equal(t, "write", resp["action"])
assert.Equal(t, "nginx", resp["container"])
assert.Equal(t, float64(len(content)), resp["bytes_written"])
if v, ok := resp["verification"].(map[string]interface{}); ok {
assert.True(t, v["ok"].(bool))
}
mockAgent.AssertExpectations(t)
})
t.Run("WriteControlledRequiresApproval", func(t *testing.T) {
agents := []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "tower"}}
mockAgent := &mockAgentServer{}
mockAgent.On("GetConnectedAgents").Return(agents)
exec := NewPulseToolExecutor(ExecutorConfig{
StateProvider: &mockStateProvider{state: models.StateSnapshot{}},
AgentServer: mockAgent,
ControlLevel: ControlLevelControlled,
})
result, err := exec.executeFileWrite(ctx, "/config/test.json", "test", "tower", "mycontainer", map[string]interface{}{})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "APPROVAL_REQUIRED")
assert.Contains(t, result.Content[0].Text, "container: mycontainer")
})
}
func TestExecuteFileAppendDocker(t *testing.T) {
ctx := context.Background()
t.Run("AppendToDockerContainer", func(t *testing.T) {
content := "\nnew line"
encodedContent := base64.StdEncoding.EncodeToString([]byte(content))
expectedAppendCmd := fmt.Sprintf(
"docker exec %s sh -c %s",
shellEscape("logcontainer"),
shellEscape(fmt.Sprintf("echo %s | base64 -d >> %s", shellEscape(encodedContent), shellEscape("/var/log/app.log"))),
)
expected := sha256.Sum256([]byte(content))
expectedHex := hex.EncodeToString(expected[:])
agents := []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "tower"}}
mockAgent := &mockAgentServer{}
mockAgent.On("GetConnectedAgents").Return(agents)
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.Command == expectedAppendCmd
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "",
}, nil)
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return strings.Contains(cmd.Command, "docker exec") &&
strings.Contains(cmd.Command, "logcontainer") &&
strings.Contains(cmd.Command, "tail -c") &&
(strings.Contains(cmd.Command, "sha256sum") || strings.Contains(cmd.Command, "shasum"))
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: expectedHex + " -\n",
}, nil)
exec := NewPulseToolExecutor(ExecutorConfig{
StateProvider: &mockStateProvider{state: models.StateSnapshot{}},
AgentServer: mockAgent,
ControlLevel: ControlLevelAutonomous,
ActionAuditStore: unifiedresources.NewMemoryStore(),
})
result, err := exec.executeFileAppend(ctx, "/var/log/app.log", content, "tower", "logcontainer", map[string]interface{}{})
require.NoError(t, err)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
assert.True(t, resp["success"].(bool))
assert.Equal(t, "append", resp["action"])
assert.Equal(t, "logcontainer", resp["container"])
if v, ok := resp["verification"].(map[string]interface{}); ok {
assert.True(t, v["ok"].(bool))
}
mockAgent.AssertExpectations(t)
})
}
func TestExecuteFileWriteLXCVMTargets(t *testing.T) {
ctx := context.Background()
t.Run("WriteToLXCRoutedCorrectly", func(t *testing.T) {
// Test that file writes to LXC are routed with correct target type/ID
// Agent handles sh -c wrapping, so tool sends raw pipeline command
content := "test content"
encodedContent := base64.StdEncoding.EncodeToString([]byte(content))
expected := sha256.Sum256([]byte(content))
expectedHex := hex.EncodeToString(expected[:])
agents := []agentexec.ConnectedAgent{{AgentID: "proxmox-agent", Hostname: "pve-node"}}
mockAgent := &mockAgentServer{}
mockAgent.On("GetConnectedAgents").Return(agents)
mockAgent.On("ExecuteCommand", mock.Anything, "proxmox-agent", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
// Tool sends raw pipeline, agent wraps in sh -c for LXC
return cmd.TargetType == "container" &&
cmd.TargetID == "141" &&
strings.Contains(cmd.Command, encodedContent) &&
strings.Contains(cmd.Command, "| base64 -d >") &&
!strings.Contains(cmd.Command, "docker exec")
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "",
}, nil)
mockAgent.On("ExecuteCommand", mock.Anything, "proxmox-agent", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.TargetType == "container" &&
cmd.TargetID == "141" &&
strings.Contains(cmd.Command, "sha256sum") &&
strings.Contains(cmd.Command, "/opt/test/config.yaml") &&
!strings.Contains(cmd.Command, "docker exec")
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: expectedHex + " /opt/test/config.yaml\n",
}, nil)
state := models.StateSnapshot{
Containers: []models.Container{
{VMID: 141, Name: "homepage-docker", Node: "pve-node"},
},
}
exec := NewPulseToolExecutor(ExecutorConfig{
StateProvider: &mockStateProvider{state: state},
AgentServer: mockAgent,
ControlLevel: ControlLevelAutonomous,
ActionAuditStore: unifiedresources.NewMemoryStore(),
})
result, err := exec.executeFileWrite(ctx, "/opt/test/config.yaml", content, "homepage-docker", "", map[string]interface{}{})
require.NoError(t, err)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
assert.True(t, resp["success"].(bool))
assert.Equal(t, "write", resp["action"])
assert.Nil(t, resp["container"]) // No Docker container
if v, ok := resp["verification"].(map[string]interface{}); ok {
assert.True(t, v["ok"].(bool))
}
mockAgent.AssertExpectations(t)
})
t.Run("WriteToVMRoutedCorrectly", func(t *testing.T) {
// Test that file writes to VMs are routed with correct target type/ID
content := "vm config"
encodedContent := base64.StdEncoding.EncodeToString([]byte(content))
expected := sha256.Sum256([]byte(content))
expectedHex := hex.EncodeToString(expected[:])
agents := []agentexec.ConnectedAgent{{AgentID: "proxmox-agent", Hostname: "pve-node"}}
mockAgent := &mockAgentServer{}
mockAgent.On("GetConnectedAgents").Return(agents)
mockAgent.On("ExecuteCommand", mock.Anything, "proxmox-agent", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.TargetType == "vm" &&
cmd.TargetID == "100" &&
strings.Contains(cmd.Command, encodedContent)
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "",
}, nil)
mockAgent.On("ExecuteCommand", mock.Anything, "proxmox-agent", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.TargetType == "vm" &&
cmd.TargetID == "100" &&
strings.Contains(cmd.Command, "sha256sum") &&
strings.Contains(cmd.Command, "/etc/test.conf") &&
!strings.Contains(cmd.Command, "docker exec")
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: expectedHex + " /etc/test.conf\n",
}, nil)
state := models.StateSnapshot{
VMs: []models.VM{
{VMID: 100, Name: "test-vm", Node: "pve-node"},
},
}
exec := NewPulseToolExecutor(ExecutorConfig{
StateProvider: &mockStateProvider{state: state},
AgentServer: mockAgent,
ControlLevel: ControlLevelAutonomous,
ActionAuditStore: unifiedresources.NewMemoryStore(),
})
result, err := exec.executeFileWrite(ctx, "/etc/test.conf", content, "test-vm", "", map[string]interface{}{})
require.NoError(t, err)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
assert.True(t, resp["success"].(bool))
if v, ok := resp["verification"].(map[string]interface{}); ok {
assert.True(t, v["ok"].(bool))
}
mockAgent.AssertExpectations(t)
})
t.Run("WriteToDirectHost", func(t *testing.T) {
// Direct host writes use raw pipeline command
content := "host config"
encodedContent := base64.StdEncoding.EncodeToString([]byte(content))
expected := sha256.Sum256([]byte(content))
expectedHex := hex.EncodeToString(expected[:])
agents := []agentexec.ConnectedAgent{{AgentID: "agent", Hostname: "tower"}}
mockAgent := &mockAgentServer{}
mockAgent.On("GetConnectedAgents").Return(agents)
mockAgent.On("ExecuteCommand", mock.Anything, "agent", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.TargetType == "agent" &&
strings.Contains(cmd.Command, encodedContent) &&
strings.Contains(cmd.Command, "| base64 -d >")
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "",
}, nil)
mockAgent.On("ExecuteCommand", mock.Anything, "agent", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.TargetType == "agent" &&
strings.Contains(cmd.Command, "sha256sum") &&
strings.Contains(cmd.Command, "/tmp/test.txt") &&
!strings.Contains(cmd.Command, "docker exec")
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: expectedHex + " /tmp/test.txt\n",
}, nil)
exec := NewPulseToolExecutor(ExecutorConfig{
StateProvider: &mockStateProvider{state: models.StateSnapshot{}},
AgentServer: mockAgent,
ControlLevel: ControlLevelAutonomous,
ActionAuditStore: unifiedresources.NewMemoryStore(),
})
result, err := exec.executeFileWrite(ctx, "/tmp/test.txt", content, "tower", "", map[string]interface{}{})
require.NoError(t, err)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
assert.True(t, resp["success"].(bool))
if v, ok := resp["verification"].(map[string]interface{}); ok {
assert.True(t, v["ok"].(bool))
}
mockAgent.AssertExpectations(t)
})
t.Run("AppendToLXCRoutedCorrectly", func(t *testing.T) {
// Append operations to LXC are routed with correct target type/ID
content := "\nnew line"
encodedContent := base64.StdEncoding.EncodeToString([]byte(content))
expected := sha256.Sum256([]byte(content))
expectedHex := hex.EncodeToString(expected[:])
agents := []agentexec.ConnectedAgent{{AgentID: "proxmox-agent", Hostname: "pve-node"}}
mockAgent := &mockAgentServer{}
mockAgent.On("GetConnectedAgents").Return(agents)
mockAgent.On("ExecuteCommand", mock.Anything, "proxmox-agent", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.TargetType == "container" &&
cmd.TargetID == "141" &&
strings.Contains(cmd.Command, encodedContent) &&
strings.Contains(cmd.Command, ">>") // append uses >>
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "",
}, nil)
mockAgent.On("ExecuteCommand", mock.Anything, "proxmox-agent", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.TargetType == "container" &&
cmd.TargetID == "141" &&
strings.Contains(cmd.Command, "tail -c") &&
strings.Contains(cmd.Command, "/var/log/app.log") &&
(strings.Contains(cmd.Command, "sha256sum") || strings.Contains(cmd.Command, "shasum")) &&
!strings.Contains(cmd.Command, "docker exec")
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: expectedHex + " -\n",
}, nil)
state := models.StateSnapshot{
Containers: []models.Container{
{VMID: 141, Name: "homepage-docker", Node: "pve-node"},
},
}
exec := NewPulseToolExecutor(ExecutorConfig{
StateProvider: &mockStateProvider{state: state},
AgentServer: mockAgent,
ControlLevel: ControlLevelAutonomous,
ActionAuditStore: unifiedresources.NewMemoryStore(),
})
result, err := exec.executeFileAppend(ctx, "/var/log/app.log", content, "homepage-docker", "", map[string]interface{}{})
require.NoError(t, err)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
assert.True(t, resp["success"].(bool))
assert.Equal(t, "append", resp["action"])
if v, ok := resp["verification"].(map[string]interface{}); ok {
assert.True(t, v["ok"].(bool))
}
mockAgent.AssertExpectations(t)
})
}
func TestExecuteFileEditDockerNestedRouting(t *testing.T) {
ctx := context.Background()
t.Run("DockerInsideLXC", func(t *testing.T) {
// Test case: Docker running inside an LXC container
// target_host="homepage-docker" (LXC), container="nginx"
// Command should route through Proxmox node agent with LXC target type
agents := []agentexec.ConnectedAgent{{AgentID: "proxmox-agent", Hostname: "pve-node"}}
mockAgent := &mockAgentServer{}
mockAgent.On("GetConnectedAgents").Return(agents)
mockAgent.On("ExecuteCommand", mock.Anything, "proxmox-agent", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
// Should have container target type for LXC routing
// and command should include docker exec
return cmd.TargetType == "container" &&
cmd.TargetID == "141" &&
strings.Contains(cmd.Command, "docker exec") &&
strings.Contains(cmd.Command, "nginx")
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "file content",
}, nil)
state := models.StateSnapshot{
Containers: []models.Container{
{VMID: 141, Name: "homepage-docker", Node: "pve-node"},
},
}
exec := NewPulseToolExecutor(ExecutorConfig{
StateProvider: &mockStateProvider{state: state},
AgentServer: mockAgent,
ControlLevel: ControlLevelAutonomous,
ActionAuditStore: unifiedresources.NewMemoryStore(),
})
result, err := exec.executeFileRead(ctx, "/config/test.json", "homepage-docker", "nginx")
require.NoError(t, err)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
assert.True(t, resp["success"].(bool))
assert.Equal(t, "nginx", resp["container"])
mockAgent.AssertExpectations(t)
})
}