|  | 
| 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