|
1 | 1 | package mcp
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "github.com/manusa/kubernetes-mcp-server/pkg/config" |
4 | 5 | "github.com/manusa/kubernetes-mcp-server/pkg/output"
|
5 | 6 | "regexp"
|
6 | 7 | "strings"
|
@@ -176,6 +177,37 @@ func TestPodsListInNamespace(t *testing.T) {
|
176 | 177 | })
|
177 | 178 | }
|
178 | 179 |
|
| 180 | +func TestPodsListDenied(t *testing.T) { |
| 181 | + deniedResourcesServer := &config.StaticConfig{DeniedResources: []config.GroupVersionKind{{Version: "v1", Kind: "Pod"}}} |
| 182 | + testCaseWithContext(t, &mcpContext{staticConfig: deniedResourcesServer}, func(c *mcpContext) { |
| 183 | + c.withEnvTest() |
| 184 | + podsList, _ := c.callTool("pods_list", map[string]interface{}{}) |
| 185 | + t.Run("pods_list has error", func(t *testing.T) { |
| 186 | + if !podsList.IsError { |
| 187 | + t.Fatalf("call tool should fail") |
| 188 | + } |
| 189 | + }) |
| 190 | + t.Run("pods_list describes denial", func(t *testing.T) { |
| 191 | + expectedMessage := "failed to list pods in all namespaces: resource not allowed: /v1, Kind=Pod" |
| 192 | + if podsList.Content[0].(mcp.TextContent).Text != expectedMessage { |
| 193 | + t.Fatalf("expected desciptive error '%s', got %v", expectedMessage, podsList.Content[0].(mcp.TextContent).Text) |
| 194 | + } |
| 195 | + }) |
| 196 | + podsListInNamespace, _ := c.callTool("pods_list_in_namespace", map[string]interface{}{"namespace": "ns-1"}) |
| 197 | + t.Run("pods_list_in_namespace has error", func(t *testing.T) { |
| 198 | + if !podsListInNamespace.IsError { |
| 199 | + t.Fatalf("call tool should fail") |
| 200 | + } |
| 201 | + }) |
| 202 | + t.Run("pods_list_in_namespace describes denial", func(t *testing.T) { |
| 203 | + expectedMessage := "failed to list pods in namespace ns-1: resource not allowed: /v1, Kind=Pod" |
| 204 | + if podsListInNamespace.Content[0].(mcp.TextContent).Text != expectedMessage { |
| 205 | + t.Fatalf("expected desciptive error '%s', got %v", expectedMessage, podsListInNamespace.Content[0].(mcp.TextContent).Text) |
| 206 | + } |
| 207 | + }) |
| 208 | + }) |
| 209 | +} |
| 210 | + |
179 | 211 | func TestPodsListAsTable(t *testing.T) {
|
180 | 212 | testCaseWithContext(t, &mcpContext{listOutput: output.Table}, func(c *mcpContext) {
|
181 | 213 | c.withEnvTest()
|
@@ -380,6 +412,25 @@ func TestPodsGet(t *testing.T) {
|
380 | 412 | })
|
381 | 413 | }
|
382 | 414 |
|
| 415 | +func TestPodsGetDenied(t *testing.T) { |
| 416 | + deniedResourcesServer := &config.StaticConfig{DeniedResources: []config.GroupVersionKind{{Version: "v1", Kind: "Pod"}}} |
| 417 | + testCaseWithContext(t, &mcpContext{staticConfig: deniedResourcesServer}, func(c *mcpContext) { |
| 418 | + c.withEnvTest() |
| 419 | + podsGet, _ := c.callTool("pods_get", map[string]interface{}{"name": "a-pod-in-default"}) |
| 420 | + t.Run("pods_get has error", func(t *testing.T) { |
| 421 | + if !podsGet.IsError { |
| 422 | + t.Fatalf("call tool should fail") |
| 423 | + } |
| 424 | + }) |
| 425 | + t.Run("pods_get describes denial", func(t *testing.T) { |
| 426 | + expectedMessage := "failed to get pod a-pod-in-default in namespace : resource not allowed: /v1, Kind=Pod" |
| 427 | + if podsGet.Content[0].(mcp.TextContent).Text != expectedMessage { |
| 428 | + t.Fatalf("expected desciptive error '%s', got %v", expectedMessage, podsGet.Content[0].(mcp.TextContent).Text) |
| 429 | + } |
| 430 | + }) |
| 431 | + }) |
| 432 | +} |
| 433 | + |
383 | 434 | func TestPodsDelete(t *testing.T) {
|
384 | 435 | testCase(t, func(c *mcpContext) {
|
385 | 436 | c.withEnvTest()
|
@@ -511,6 +562,26 @@ func TestPodsDelete(t *testing.T) {
|
511 | 562 | })
|
512 | 563 | }
|
513 | 564 |
|
| 565 | +func TestPodsDeleteDenied(t *testing.T) { |
| 566 | + t.Skip("To be implemented") // TODO: delete is not checking for denied resources |
| 567 | + deniedResourcesServer := &config.StaticConfig{DeniedResources: []config.GroupVersionKind{{Version: "v1", Kind: "Pod"}}} |
| 568 | + testCaseWithContext(t, &mcpContext{staticConfig: deniedResourcesServer}, func(c *mcpContext) { |
| 569 | + c.withEnvTest() |
| 570 | + podsDelete, _ := c.callTool("pods_delete", map[string]interface{}{"name": "a-pod-in-default"}) |
| 571 | + t.Run("pods_delete has error", func(t *testing.T) { |
| 572 | + if !podsDelete.IsError { |
| 573 | + t.Fatalf("call tool should fail") |
| 574 | + } |
| 575 | + }) |
| 576 | + t.Run("pods_delete describes denial", func(t *testing.T) { |
| 577 | + expectedMessage := "failed to delete pod a-pod-in-default in namespace : resource not allowed: /v1, Kind=Pod" |
| 578 | + if podsDelete.Content[0].(mcp.TextContent).Text != expectedMessage { |
| 579 | + t.Fatalf("expected desciptive error '%s', got %v", expectedMessage, podsDelete.Content[0].(mcp.TextContent).Text) |
| 580 | + } |
| 581 | + }) |
| 582 | + }) |
| 583 | +} |
| 584 | + |
514 | 585 | func TestPodsDeleteInOpenShift(t *testing.T) {
|
515 | 586 | testCaseWithContext(t, &mcpContext{before: inOpenShift, after: inOpenShiftClear}, func(c *mcpContext) {
|
516 | 587 | managedLabels := map[string]string{
|
@@ -651,6 +722,26 @@ func TestPodsLog(t *testing.T) {
|
651 | 722 | })
|
652 | 723 | }
|
653 | 724 |
|
| 725 | +func TestPodsLogDenied(t *testing.T) { |
| 726 | + t.Skip("To be implemented") // TODO: log is not checking for denied resources |
| 727 | + deniedResourcesServer := &config.StaticConfig{DeniedResources: []config.GroupVersionKind{{Version: "v1", Kind: "Pod"}}} |
| 728 | + testCaseWithContext(t, &mcpContext{staticConfig: deniedResourcesServer}, func(c *mcpContext) { |
| 729 | + c.withEnvTest() |
| 730 | + podsLog, _ := c.callTool("pods_log", map[string]interface{}{"name": "a-pod-in-default"}) |
| 731 | + t.Run("pods_log has error", func(t *testing.T) { |
| 732 | + if !podsLog.IsError { |
| 733 | + t.Fatalf("call tool should fail") |
| 734 | + } |
| 735 | + }) |
| 736 | + t.Run("pods_log describes denial", func(t *testing.T) { |
| 737 | + expectedMessage := "failed to log pod a-pod-in-default in namespace : resource not allowed: /v1, Kind=Pod" |
| 738 | + if podsLog.Content[0].(mcp.TextContent).Text != expectedMessage { |
| 739 | + t.Fatalf("expected desciptive error '%s', got %v", expectedMessage, podsLog.Content[0].(mcp.TextContent).Text) |
| 740 | + } |
| 741 | + }) |
| 742 | + }) |
| 743 | +} |
| 744 | + |
654 | 745 | func TestPodsRun(t *testing.T) {
|
655 | 746 | testCase(t, func(c *mcpContext) {
|
656 | 747 | c.withEnvTest()
|
@@ -801,6 +892,25 @@ func TestPodsRun(t *testing.T) {
|
801 | 892 | })
|
802 | 893 | }
|
803 | 894 |
|
| 895 | +func TestPodsRunDenied(t *testing.T) { |
| 896 | + deniedResourcesServer := &config.StaticConfig{DeniedResources: []config.GroupVersionKind{{Version: "v1", Kind: "Pod"}}} |
| 897 | + testCaseWithContext(t, &mcpContext{staticConfig: deniedResourcesServer}, func(c *mcpContext) { |
| 898 | + c.withEnvTest() |
| 899 | + podsRun, _ := c.callTool("pods_run", map[string]interface{}{"image": "nginx"}) |
| 900 | + t.Run("pods_run has error", func(t *testing.T) { |
| 901 | + if !podsRun.IsError { |
| 902 | + t.Fatalf("call tool should fail") |
| 903 | + } |
| 904 | + }) |
| 905 | + t.Run("pods_run describes denial", func(t *testing.T) { |
| 906 | + expectedMessage := "failed to run pod in namespace : resource not allowed: /v1, Kind=Pod" |
| 907 | + if podsRun.Content[0].(mcp.TextContent).Text != expectedMessage { |
| 908 | + t.Fatalf("expected desciptive error '%s', got %v", expectedMessage, podsRun.Content[0].(mcp.TextContent).Text) |
| 909 | + } |
| 910 | + }) |
| 911 | + }) |
| 912 | +} |
| 913 | + |
804 | 914 | func TestPodsRunInOpenShift(t *testing.T) {
|
805 | 915 | testCaseWithContext(t, &mcpContext{before: inOpenShift, after: inOpenShiftClear}, func(c *mcpContext) {
|
806 | 916 | t.Run("pods_run with image, namespace, and port returns route with port", func(t *testing.T) {
|
|
0 commit comments