Pulse/internal/ai/tools/kubernetes_control_test.go
2026-03-18 16:06:30 +00:00

679 lines
23 KiB
Go

package tools
import (
"context"
"testing"
"github.com/rcourtman/pulse-go-rewrite/internal/agentexec"
"github.com/rcourtman/pulse-go-rewrite/internal/ai/approval"
"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 newConfiguredKubernetesExecutor(snapshot models.StateSnapshot, mutate func(*ExecutorConfig)) *PulseToolExecutor {
adapter := unifiedresources.NewMonitorAdapter(nil)
adapter.PopulateFromSnapshot(snapshot)
cfg := ExecutorConfig{UnifiedResourceProvider: adapter}
if mutate != nil {
mutate(&cfg)
}
return NewPulseToolExecutor(cfg)
}
func TestValidateKubernetesResourceID(t *testing.T) {
tests := []struct {
name string
value string
wantErr bool
}{
{"valid simple", "nginx", false},
{"valid with dash", "my-app", false},
{"valid with dot", "my.app", false},
{"valid with numbers", "app123", false},
{"valid complex", "my-app-v1.2.3", false},
{"empty", "", true},
{"uppercase", "MyApp", true},
{"underscore", "my_app", true},
{"space", "my app", true},
{"special char", "my@app", true},
{"too long", string(make([]byte, 254)), true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validateKubernetesResourceID(tt.value)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestFindAgentForKubernetesCluster(t *testing.T) {
t.Run("NoStateProvider", func(t *testing.T) {
exec := NewPulseToolExecutor(ExecutorConfig{})
agentID, cluster, err := exec.findAgentForKubernetesCluster("test")
assert.Error(t, err)
assert.Empty(t, agentID)
assert.Nil(t, cluster)
assert.Contains(t, err.Error(), "state not available")
})
t.Run("ClusterNotFound", func(t *testing.T) {
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, nil)
agentID, cluster, err := exec.findAgentForKubernetesCluster("nonexistent")
assert.Error(t, err)
assert.Empty(t, agentID)
assert.Nil(t, cluster)
assert.Contains(t, err.Error(), "not found")
})
t.Run("ClusterNoAgent", func(t *testing.T) {
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: ""},
},
}
exec := newConfiguredKubernetesExecutor(state, nil)
agentID, cluster, err := exec.findAgentForKubernetesCluster("cluster-1")
assert.Error(t, err)
assert.Empty(t, agentID)
assert.Nil(t, cluster)
assert.Contains(t, err.Error(), "no agent configured")
})
t.Run("FoundByID", func(t *testing.T) {
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, nil)
agentID, cluster, err := exec.findAgentForKubernetesCluster("c1")
assert.NoError(t, err)
assert.Equal(t, "agent-1", agentID)
assert.NotNil(t, cluster)
assert.Equal(t, "cluster-1", cluster.Name)
})
t.Run("FoundByDisplayName", func(t *testing.T) {
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", DisplayName: "Production", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, nil)
agentID, _, err := exec.findAgentForKubernetesCluster("Production")
assert.NoError(t, err)
assert.Equal(t, "agent-1", agentID)
})
t.Run("FoundByCustomDisplayName", func(t *testing.T) {
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", CustomDisplayName: "My Cluster", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, nil)
agentID, _, err := exec.findAgentForKubernetesCluster("My Cluster")
assert.NoError(t, err)
assert.Equal(t, "agent-1", agentID)
})
t.Run("FoundWithUnifiedReadStateOnly", func(t *testing.T) {
snapshot := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", CustomDisplayName: "My Cluster", AgentID: "agent-1", Server: "https://k8s.example", Context: "prod"},
},
}
exec := newConfiguredKubernetesExecutor(snapshot, nil)
agentID, cluster, err := exec.findAgentForKubernetesCluster("My Cluster")
assert.NoError(t, err)
assert.Equal(t, "agent-1", agentID)
require.NotNil(t, cluster)
assert.NotEmpty(t, cluster.ID)
assert.Equal(t, "cluster-1", cluster.Name)
assert.Equal(t, "My Cluster", cluster.DisplayName)
assert.Equal(t, "https://k8s.example", cluster.Server)
assert.Equal(t, "prod", cluster.Context)
})
}
func TestExecuteKubernetesScale(t *testing.T) {
ctx := context.Background()
t.Run("MissingCluster", func(t *testing.T) {
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
result, err := exec.executeKubernetesScale(ctx, map[string]interface{}{})
require.NoError(t, err)
assert.True(t, result.IsError)
assert.Contains(t, result.Content[0].Text, "cluster is required")
})
t.Run("MissingDeployment", func(t *testing.T) {
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
result, err := exec.executeKubernetesScale(ctx, map[string]interface{}{
"cluster": "test",
})
require.NoError(t, err)
assert.True(t, result.IsError)
assert.Contains(t, result.Content[0].Text, "deployment is required")
})
t.Run("MissingReplicas", func(t *testing.T) {
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
result, err := exec.executeKubernetesScale(ctx, map[string]interface{}{
"cluster": "test",
"deployment": "nginx",
})
require.NoError(t, err)
assert.True(t, result.IsError)
assert.Contains(t, result.Content[0].Text, "replicas is required")
})
t.Run("InvalidNamespace", func(t *testing.T) {
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
result, err := exec.executeKubernetesScale(ctx, map[string]interface{}{
"cluster": "test",
"deployment": "nginx",
"replicas": 3,
"namespace": "Invalid_NS",
})
require.NoError(t, err)
assert.True(t, result.IsError)
assert.Contains(t, result.Content[0].Text, "invalid namespace")
})
t.Run("ReadOnlyMode", func(t *testing.T) {
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.ControlLevel = ControlLevelReadOnly
})
result, err := exec.executeKubernetesScale(ctx, map[string]interface{}{
"cluster": "cluster-1",
"deployment": "nginx",
"replicas": 3,
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "not available in read-only mode")
})
t.Run("ControlledRequiresApproval", func(t *testing.T) {
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1", DisplayName: "Cluster One"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.ControlLevel = ControlLevelControlled
})
result, err := exec.executeKubernetesScale(ctx, map[string]interface{}{
"cluster": "cluster-1",
"deployment": "nginx",
"replicas": 3,
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "APPROVAL_REQUIRED")
assert.Contains(t, result.Content[0].Text, "scale")
})
t.Run("ExecuteSuccess", func(t *testing.T) {
mockAgent := &mockAgentServer{
agents: []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "k8s-host"}},
}
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.Command == "kubectl -n 'default' scale deployment 'nginx' --replicas=3" &&
cmd.TargetType == "agent"
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "deployment.apps/nginx scaled",
}, nil)
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.AgentServer = mockAgent
cfg.ControlLevel = ControlLevelAutonomous
})
result, err := exec.executeKubernetesScale(ctx, map[string]interface{}{
"cluster": "cluster-1",
"deployment": "nginx",
"replicas": 3,
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "Successfully scaled")
assert.Contains(t, result.Content[0].Text, "nginx")
mockAgent.AssertExpectations(t)
})
}
func TestExecuteKubernetesRestart(t *testing.T) {
ctx := context.Background()
t.Run("MissingDeployment", func(t *testing.T) {
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
result, err := exec.executeKubernetesRestart(ctx, map[string]interface{}{
"cluster": "test",
})
require.NoError(t, err)
assert.True(t, result.IsError)
assert.Contains(t, result.Content[0].Text, "deployment is required")
})
t.Run("ExecuteSuccess", func(t *testing.T) {
mockAgent := &mockAgentServer{
agents: []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "k8s-host"}},
}
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.Command == "kubectl -n 'default' rollout restart deployment/'nginx'"
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "deployment.apps/nginx restarted",
}, nil)
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.AgentServer = mockAgent
cfg.ControlLevel = ControlLevelAutonomous
})
result, err := exec.executeKubernetesRestart(ctx, map[string]interface{}{
"cluster": "cluster-1",
"deployment": "nginx",
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "Successfully initiated rollout restart")
mockAgent.AssertExpectations(t)
})
}
func TestExecuteKubernetesDeletePod(t *testing.T) {
ctx := context.Background()
t.Run("MissingPod", func(t *testing.T) {
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
result, err := exec.executeKubernetesDeletePod(ctx, map[string]interface{}{
"cluster": "test",
})
require.NoError(t, err)
assert.True(t, result.IsError)
assert.Contains(t, result.Content[0].Text, "pod is required")
})
t.Run("ExecuteSuccess", func(t *testing.T) {
mockAgent := &mockAgentServer{
agents: []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "k8s-host"}},
}
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.Command == "kubectl -n 'default' delete pod 'nginx-abc123'"
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "pod \"nginx-abc123\" deleted",
}, nil)
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.AgentServer = mockAgent
cfg.ControlLevel = ControlLevelAutonomous
})
result, err := exec.executeKubernetesDeletePod(ctx, map[string]interface{}{
"cluster": "cluster-1",
"pod": "nginx-abc123",
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "Successfully deleted pod")
mockAgent.AssertExpectations(t)
})
}
func TestExecuteKubernetesExec(t *testing.T) {
ctx := context.Background()
t.Run("MissingCommand", func(t *testing.T) {
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
result, err := exec.executeKubernetesExec(ctx, map[string]interface{}{
"cluster": "test",
"pod": "nginx",
})
require.NoError(t, err)
assert.True(t, result.IsError)
assert.Contains(t, result.Content[0].Text, "command is required")
})
t.Run("ExecuteWithoutContainer", func(t *testing.T) {
mockAgent := &mockAgentServer{
agents: []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "k8s-host"}},
}
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.Command == "kubectl -n 'default' exec 'nginx-pod' -- sh -c 'cat /etc/nginx/nginx.conf'"
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "server { listen 80; }",
}, nil)
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.AgentServer = mockAgent
cfg.ControlLevel = ControlLevelAutonomous
})
result, err := exec.executeKubernetesExec(ctx, map[string]interface{}{
"cluster": "cluster-1",
"pod": "nginx-pod",
"command": "cat /etc/nginx/nginx.conf",
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "Command executed")
assert.Contains(t, result.Content[0].Text, "server { listen 80; }")
mockAgent.AssertExpectations(t)
})
t.Run("ExecuteWithContainer", func(t *testing.T) {
mockAgent := &mockAgentServer{
agents: []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "k8s-host"}},
}
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.Command == "kubectl -n 'kube-system' exec 'coredns-pod' -c 'coredns' -- sh -c 'cat /etc/coredns/Corefile'"
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: ".:53 { forward . /etc/resolv.conf }",
}, nil)
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.AgentServer = mockAgent
cfg.ControlLevel = ControlLevelAutonomous
})
result, err := exec.executeKubernetesExec(ctx, map[string]interface{}{
"cluster": "cluster-1",
"namespace": "kube-system",
"pod": "coredns-pod",
"container": "coredns",
"command": "cat /etc/coredns/Corefile",
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "Command executed")
mockAgent.AssertExpectations(t)
})
t.Run("ExecEscapesMetacharacters", func(t *testing.T) {
mockAgent := &mockAgentServer{
agents: []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "k8s-host"}},
}
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.Command == "kubectl -n 'default' exec 'nginx-pod' -- sh -c 'cat /etc/nginx/nginx.conf; id'"
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "ok",
}, nil)
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.AgentServer = mockAgent
cfg.ControlLevel = ControlLevelAutonomous
})
result, err := exec.executeKubernetesExec(ctx, map[string]interface{}{
"cluster": "cluster-1",
"pod": "nginx-pod",
"command": "cat /etc/nginx/nginx.conf; id",
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "Command executed")
mockAgent.AssertExpectations(t)
})
t.Run("MismatchedApprovedIDDoesNotBypass", func(t *testing.T) {
store, err := approval.NewStore(approval.StoreConfig{
DataDir: t.TempDir(),
DisablePersistence: true,
})
require.NoError(t, err)
approval.SetStore(store)
defer approval.SetStore(nil)
req := &approval.ApprovalRequest{
ID: "approval-1",
Command: "kubectl -n default exec nginx-pod -- whoami",
TargetType: "kubernetes",
TargetID: "nginx-pod",
}
require.NoError(t, store.CreateApproval(req))
_, err = store.Approve("approval-1", "tester")
require.NoError(t, err)
mockAgent := &mockAgentServer{
agents: []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "k8s-host"}},
}
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.AgentServer = mockAgent
cfg.ControlLevel = ControlLevelControlled
})
result, err := exec.executeKubernetesExec(ctx, map[string]interface{}{
"cluster": "cluster-1",
"pod": "nginx-pod",
"command": "cat /etc/nginx/nginx.conf",
"_approval_id": "approval-1",
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "APPROVAL_REQUIRED")
mockAgent.AssertNotCalled(t, "ExecuteCommand", mock.Anything, mock.Anything, mock.Anything)
})
t.Run("MatchingApprovedIDBypassesAndConsumes", func(t *testing.T) {
store, err := approval.NewStore(approval.StoreConfig{
DataDir: t.TempDir(),
DisablePersistence: true,
})
require.NoError(t, err)
approval.SetStore(store)
defer approval.SetStore(nil)
kubeCmd := buildKubectlExecCommand("default", "nginx-pod", "", "cat /etc/nginx/nginx.conf")
req := &approval.ApprovalRequest{
ID: "approval-2",
Command: kubeCmd,
TargetType: "kubernetes",
TargetID: "c1:default:pod:nginx-pod",
}
require.NoError(t, store.CreateApproval(req))
_, err = store.Approve("approval-2", "tester")
require.NoError(t, err)
mockAgent := &mockAgentServer{
agents: []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "k8s-host"}},
}
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.Command == kubeCmd
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "ok",
}, nil)
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.AgentServer = mockAgent
cfg.ControlLevel = ControlLevelControlled
})
result, err := exec.executeKubernetesExec(ctx, map[string]interface{}{
"cluster": "cluster-1",
"pod": "nginx-pod",
"command": "cat /etc/nginx/nginx.conf",
"_approval_id": "approval-2",
})
require.NoError(t, err)
assert.NotContains(t, result.Content[0].Text, "APPROVAL_REQUIRED")
mockAgent.AssertExpectations(t)
// Approval is single-use; second attempt should not bypass.
result, err = exec.executeKubernetesExec(ctx, map[string]interface{}{
"cluster": "cluster-1",
"pod": "nginx-pod",
"command": "cat /etc/nginx/nginx.conf",
"_approval_id": "approval-2",
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "APPROVAL_REQUIRED")
})
}
func TestExecuteKubernetesLogs(t *testing.T) {
ctx := context.Background()
t.Run("MissingPod", func(t *testing.T) {
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
result, err := exec.executeKubernetesLogs(ctx, map[string]interface{}{
"cluster": "test",
})
require.NoError(t, err)
assert.True(t, result.IsError)
assert.Contains(t, result.Content[0].Text, "pod is required")
})
t.Run("LogsNoApprovalNeeded", func(t *testing.T) {
// Logs should work even in controlled mode without approval
mockAgent := &mockAgentServer{
agents: []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "k8s-host"}},
}
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.Command == "kubectl -n 'default' logs 'nginx-pod' --tail=50"
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "2024-01-01 10:00:00 Request received\n2024-01-01 10:00:01 Response sent",
}, nil)
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.AgentServer = mockAgent
cfg.ControlLevel = ControlLevelControlled
})
result, err := exec.executeKubernetesLogs(ctx, map[string]interface{}{
"cluster": "cluster-1",
"pod": "nginx-pod",
"lines": 50,
})
require.NoError(t, err)
// Should NOT require approval since logs is read-only
assert.NotContains(t, result.Content[0].Text, "APPROVAL_REQUIRED")
assert.Contains(t, result.Content[0].Text, "Logs from pod")
mockAgent.AssertExpectations(t)
})
t.Run("LogsWithContainer", func(t *testing.T) {
mockAgent := &mockAgentServer{
agents: []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "k8s-host"}},
}
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.MatchedBy(func(cmd agentexec.ExecuteCommandPayload) bool {
return cmd.Command == "kubectl -n 'default' logs 'nginx-pod' -c 'sidecar' --tail=100"
})).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "Sidecar logs here",
}, nil)
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.AgentServer = mockAgent
cfg.ControlLevel = ControlLevelAutonomous
})
result, err := exec.executeKubernetesLogs(ctx, map[string]interface{}{
"cluster": "cluster-1",
"pod": "nginx-pod",
"container": "sidecar",
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "Logs from pod")
mockAgent.AssertExpectations(t)
})
t.Run("EmptyLogs", func(t *testing.T) {
mockAgent := &mockAgentServer{
agents: []agentexec.ConnectedAgent{{AgentID: "agent-1", Hostname: "k8s-host"}},
}
mockAgent.On("ExecuteCommand", mock.Anything, "agent-1", mock.Anything).Return(&agentexec.CommandResultPayload{
ExitCode: 0,
Stdout: "",
}, nil)
state := models.StateSnapshot{
KubernetesClusters: []models.KubernetesCluster{
{ID: "c1", Name: "cluster-1", AgentID: "agent-1"},
},
}
exec := newConfiguredKubernetesExecutor(state, func(cfg *ExecutorConfig) {
cfg.AgentServer = mockAgent
cfg.ControlLevel = ControlLevelAutonomous
})
result, err := exec.executeKubernetesLogs(ctx, map[string]interface{}{
"cluster": "cluster-1",
"pod": "nginx-pod",
})
require.NoError(t, err)
assert.Contains(t, result.Content[0].Text, "No logs found")
mockAgent.AssertExpectations(t)
})
}
func TestFormatKubernetesApprovalNeeded(t *testing.T) {
result := formatKubernetesApprovalNeeded("scale", "nginx", "default", "production", "kubectl scale...", "approval-123")
assert.Contains(t, result, "APPROVAL_REQUIRED")
assert.Contains(t, result, "scale")
assert.Contains(t, result, "nginx")
assert.Contains(t, result, "default")
assert.Contains(t, result, "production")
assert.Contains(t, result, "approval-123")
}