diff --git a/internal/test/mock_server.go b/internal/test/mock_server.go index e256f425..dc199eea 100644 --- a/internal/test/mock_server.go +++ b/internal/test/mock_server.go @@ -186,6 +186,33 @@ WaitForStreams: return ctx, nil } +type DiscoveryClientHandler struct{} + +var _ http.Handler = (*DiscoveryClientHandler)(nil) + +func (h *DiscoveryClientHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + // Request Performed by DiscoveryClient to Kube API (Get API Groups legacy -core-) + if req.URL.Path == "/api" { + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"kind":"APIVersions","versions":["v1"],"serverAddressByClientCIDRs":[{"clientCIDR":"0.0.0.0/0"}]}`)) + return + } + // Request Performed by DiscoveryClient to Kube API (Get API Groups) + if req.URL.Path == "/apis" { + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"kind":"APIGroupList","apiVersion":"v1","groups":[]}`)) + return + } + // Request Performed by DiscoveryClient to Kube API (Get API Resources) + if req.URL.Path == "/api/v1" { + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"kind":"APIResourceList","apiVersion":"v1","resources":[ + {"name":"pods","singularName":"","namespaced":true,"kind":"Pod","verbs":["get","list","watch","create","update","patch","delete"]} + ]}`)) + return + } +} + type InOpenShiftHandler struct { } diff --git a/pkg/mcp/events_test.go b/pkg/mcp/events_test.go index 68ca85a8..06d64954 100644 --- a/pkg/mcp/events_test.go +++ b/pkg/mcp/events_test.go @@ -132,8 +132,10 @@ func (s *EventsSuite) TestEventsListDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to list events in all namespaces: resource not allowed: /v1, Kind=Event" - s.Equalf(expectedMessage, toolResult.Content[0].(mcp.TextContent).Text, + msg := toolResult.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to list events in all namespaces:(.+:)? resource not allowed: /v1, Kind=Event" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, toolResult.Content[0].(mcp.TextContent).Text) }) }) diff --git a/pkg/mcp/helm_test.go b/pkg/mcp/helm_test.go index 5d52c79c..c40342e8 100644 --- a/pkg/mcp/helm_test.go +++ b/pkg/mcp/helm_test.go @@ -86,9 +86,11 @@ func (s *HelmSuite) TestHelmInstallDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - s.Truef(strings.HasPrefix(toolResult.Content[0].(mcp.TextContent).Text, "failed to install helm chart"), "expected descriptive error, got %v", toolResult.Content[0].(mcp.TextContent).Text) + msg := toolResult.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + s.Truef(strings.HasPrefix(msg, "failed to install helm chart"), "expected descriptive error, got %v", toolResult.Content[0].(mcp.TextContent).Text) expectedMessage := ": resource not allowed: /v1, Kind=Secret" - s.Truef(strings.HasSuffix(toolResult.Content[0].(mcp.TextContent).Text, expectedMessage), "expected descriptive error '%s', got %v", expectedMessage, toolResult.Content[0].(mcp.TextContent).Text) + s.Truef(strings.HasSuffix(msg, expectedMessage), "expected descriptive error '%s', got %v", expectedMessage, toolResult.Content[0].(mcp.TextContent).Text) }) }) } @@ -260,8 +262,8 @@ func (s *HelmSuite) TestHelmUninstallDenied() { }) s.Run("describes denial", func() { s.T().Skipf("Helm won't report what underlying resource caused the failure, so we can't assert on it") - expectedMessage := "failed to uninstall release: resource not allowed: /v1, Kind=Secret" - s.Equalf(expectedMessage, toolResult.Content[0].(mcp.TextContent).Text, "expected descriptive error '%s', got %v", expectedMessage, toolResult.Content[0].(mcp.TextContent).Text) + expectedMessage := "failed to uninstall release:(.+:)? resource not allowed: /v1, Kind=Secret" + s.Regexpf(expectedMessage, toolResult.Content[0].(mcp.TextContent).Text, "expected descriptive error '%s', got %v", expectedMessage, toolResult.Content[0].(mcp.TextContent).Text) }) }) } diff --git a/pkg/mcp/mcp_test.go b/pkg/mcp/mcp_test.go index 25e1c651..d2a09438 100644 --- a/pkg/mcp/mcp_test.go +++ b/pkg/mcp/mcp_test.go @@ -22,25 +22,9 @@ func (s *McpHeadersSuite) SetupTest() { s.pathHeaders = make(map[string]http.Header) s.mockServer.Handle(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { s.pathHeaders[req.URL.Path] = req.Header.Clone() - // Request Performed by DiscoveryClient to Kube API (Get API Groups legacy -core-) - if req.URL.Path == "/api" { - w.Header().Set("Content-Type", "application/json") - _, _ = w.Write([]byte(`{"kind":"APIVersions","versions":["v1"],"serverAddressByClientCIDRs":[{"clientCIDR":"0.0.0.0/0"}]}`)) - return - } - // Request Performed by DiscoveryClient to Kube API (Get API Groups) - if req.URL.Path == "/apis" { - w.Header().Set("Content-Type", "application/json") - //w.Write([]byte(`{"kind":"APIGroupList","apiVersion":"v1","groups":[{"name":"apps","versions":[{"groupVersion":"apps/v1","version":"v1"}],"preferredVersion":{"groupVersion":"apps/v1","version":"v1"}}]}`)) - _, _ = w.Write([]byte(`{"kind":"APIGroupList","apiVersion":"v1","groups":[]}`)) - return - } - // Request Performed by DiscoveryClient to Kube API (Get API Resources) - if req.URL.Path == "/api/v1" { - w.Header().Set("Content-Type", "application/json") - _, _ = w.Write([]byte(`{"kind":"APIResourceList","apiVersion":"v1","resources":[{"name":"pods","singularName":"","namespaced":true,"kind":"Pod","verbs":["get","list","watch","create","update","patch","delete"]}]}`)) - return - } + })) + s.mockServer.Handle(&test.DiscoveryClientHandler{}) + s.mockServer.Handle(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { // Request Performed by DynamicClient if req.URL.Path == "/api/v1/namespaces/default/pods" { w.Header().Set("Content-Type", "application/json") diff --git a/pkg/mcp/namespaces_test.go b/pkg/mcp/namespaces_test.go index 25565512..be2c3c8b 100644 --- a/pkg/mcp/namespaces_test.go +++ b/pkg/mcp/namespaces_test.go @@ -56,8 +56,10 @@ func (s *NamespacesSuite) TestNamespacesListDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to list namespaces: resource not allowed: /v1, Kind=Namespace" - s.Equalf(expectedMessage, toolResult.Content[0].(mcp.TextContent).Text, + msg := toolResult.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to list namespaces:(.+:)? resource not allowed: /v1, Kind=Namespace" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, toolResult.Content[0].(mcp.TextContent).Text) }) }) @@ -159,8 +161,10 @@ func (s *NamespacesSuite) TestProjectsListInOpenShiftDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to list projects: resource not allowed: project.openshift.io/v1, Kind=Project" - s.Equalf(expectedMessage, projectsList.Content[0].(mcp.TextContent).Text, + msg := projectsList.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to list projects:(.+:)? resource not allowed: project.openshift.io/v1, Kind=Project" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, projectsList.Content[0].(mcp.TextContent).Text) }) }) diff --git a/pkg/mcp/nodes_test.go b/pkg/mcp/nodes_test.go index 62ac55e9..4bad52db 100644 --- a/pkg/mcp/nodes_test.go +++ b/pkg/mcp/nodes_test.go @@ -93,7 +93,7 @@ func (s *NodesSuite) TestNodesLog() { }) s.Run("describes missing name", func() { expectedMessage := "failed to get node log, missing argument query" - s.Equalf(expectedMessage, toolResult.Content[0].(mcp.TextContent).Text, + s.Regexpf(expectedMessage, toolResult.Content[0].(mcp.TextContent).Text, "expected descriptive error '%s', got %v", expectedMessage, toolResult.Content[0].(mcp.TextContent).Text) }) }) @@ -215,8 +215,10 @@ func (s *NodesSuite) TestNodesLogDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { + msg := toolResult.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") expectedMessage := "failed to get node log for does-not-matter: resource not allowed: /v1, Kind=Node" - s.Equalf(expectedMessage, toolResult.Content[0].(mcp.TextContent).Text, + s.Equalf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, toolResult.Content[0].(mcp.TextContent).Text) }) }) @@ -324,8 +326,10 @@ func (s *NodesSuite) TestNodesStatsSummaryDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to get node stats summary for does-not-matter: resource not allowed: /v1, Kind=Node" - s.Equalf(expectedMessage, toolResult.Content[0].(mcp.TextContent).Text, + msg := toolResult.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to get node stats summary for does-not-matter:(.+:)? resource not allowed: /v1, Kind=Node" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, toolResult.Content[0].(mcp.TextContent).Text) }) }) diff --git a/pkg/mcp/nodes_top_test.go b/pkg/mcp/nodes_top_test.go index 23ae9945..4b81ec01 100644 --- a/pkg/mcp/nodes_top_test.go +++ b/pkg/mcp/nodes_top_test.go @@ -236,8 +236,10 @@ func (s *NodesTopSuite) TestNodesTopDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to get nodes top: resource not allowed: metrics.k8s.io/v1beta1, Kind=NodeMetrics" - s.Equalf(expectedMessage, toolResult.Content[0].(mcp.TextContent).Text, + msg := toolResult.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to get nodes top:(.+:)? resource not allowed: metrics.k8s.io/v1beta1, Kind=NodeMetrics" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, toolResult.Content[0].(mcp.TextContent).Text) }) }) diff --git a/pkg/mcp/pods_exec_test.go b/pkg/mcp/pods_exec_test.go index c39cc8d6..d295464d 100644 --- a/pkg/mcp/pods_exec_test.go +++ b/pkg/mcp/pods_exec_test.go @@ -126,8 +126,10 @@ func (s *PodsExecSuite) TestPodsExecDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to exec in pod pod-to-exec in namespace default: resource not allowed: /v1, Kind=Pod" - s.Equalf(expectedMessage, toolResult.Content[0].(mcp.TextContent).Text, + msg := toolResult.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to exec in pod pod-to-exec in namespace default:(.+:)? resource not allowed: /v1, Kind=Pod" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, toolResult.Content[0].(mcp.TextContent).Text) }) }) diff --git a/pkg/mcp/pods_run_test.go b/pkg/mcp/pods_run_test.go index 4c329f3e..83370045 100644 --- a/pkg/mcp/pods_run_test.go +++ b/pkg/mcp/pods_run_test.go @@ -102,8 +102,10 @@ func (s *PodsRunSuite) TestPodsRunDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to run pod in namespace : resource not allowed: /v1, Kind=Pod" - s.Equalf(expectedMessage, podsRun.Content[0].(mcp.TextContent).Text, + msg := podsRun.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to run pod in namespace :(.+:)? resource not allowed: /v1, Kind=Pod" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, podsRun.Content[0].(mcp.TextContent).Text) }) }) diff --git a/pkg/mcp/pods_test.go b/pkg/mcp/pods_test.go index ddeec3ea..704c3c50 100644 --- a/pkg/mcp/pods_test.go +++ b/pkg/mcp/pods_test.go @@ -162,8 +162,10 @@ func (s *PodsSuite) TestPodsListDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to list pods in all namespaces: resource not allowed: /v1, Kind=Pod" - s.Equalf(expectedMessage, podsList.Content[0].(mcp.TextContent).Text, + msg := podsList.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to list pods in all namespaces:(.+:)? resource not allowed: /v1, Kind=Pod" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, podsList.Content[0].(mcp.TextContent).Text) }) }) @@ -174,8 +176,10 @@ func (s *PodsSuite) TestPodsListDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to list pods in namespace ns-1: resource not allowed: /v1, Kind=Pod" - s.Equalf(expectedMessage, podsListInNamespace.Content[0].(mcp.TextContent).Text, + msg := podsListInNamespace.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to list pods in namespace ns-1:(.+:)? resource not allowed: /v1, Kind=Pod" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, podsListInNamespace.Content[0].(mcp.TextContent).Text) }) }) @@ -346,8 +350,10 @@ func (s *PodsSuite) TestPodsGetDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to get pod a-pod-in-default in namespace : resource not allowed: /v1, Kind=Pod" - s.Equalf(expectedMessage, podsGet.Content[0].(mcp.TextContent).Text, + msg := podsGet.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to get pod a-pod-in-default in namespace :(.+:)? resource not allowed: /v1, Kind=Pod" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, podsGet.Content[0].(mcp.TextContent).Text) }) }) @@ -447,8 +453,10 @@ func (s *PodsSuite) TestPodsDeleteDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to delete pod a-pod-in-default in namespace : resource not allowed: /v1, Kind=Pod" - s.Equalf(expectedMessage, podsDelete.Content[0].(mcp.TextContent).Text, + msg := podsDelete.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to delete pod a-pod-in-default in namespace :(.+:)? resource not allowed: /v1, Kind=Pod" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, podsDelete.Content[0].(mcp.TextContent).Text) }) }) @@ -599,8 +607,10 @@ func (s *PodsSuite) TestPodsLogDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to get pod a-pod-in-default log in namespace : resource not allowed: /v1, Kind=Pod" - s.Equalf(expectedMessage, podsLog.Content[0].(mcp.TextContent).Text, + msg := podsLog.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to get pod a-pod-in-default log in namespace :(.+:)? resource not allowed: /v1, Kind=Pod" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, podsLog.Content[0].(mcp.TextContent).Text) }) }) diff --git a/pkg/mcp/pods_top_test.go b/pkg/mcp/pods_top_test.go index 92f6505a..60186249 100644 --- a/pkg/mcp/pods_top_test.go +++ b/pkg/mcp/pods_top_test.go @@ -30,19 +30,7 @@ func (s *PodsTopSuite) TearDownTest() { } func (s *PodsTopSuite) TestPodsTopMetricsUnavailable() { - s.mockServer.Handle(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - w.Header().Set("Content-Type", "application/json") - // Request Performed by DiscoveryClient to Kube API (Get API Groups legacy -core-) - if req.URL.Path == "/api" { - _, _ = w.Write([]byte(`{"kind":"APIVersions","versions":[],"serverAddressByClientCIDRs":[{"clientCIDR":"0.0.0.0/0"}]}`)) - return - } - // Request Performed by DiscoveryClient to Kube API (Get API Groups) - if req.URL.Path == "/apis" { - _, _ = w.Write([]byte(`{"kind":"APIGroupList","apiVersion":"v1","groups":[]}`)) - return - } - })) + s.mockServer.Handle(&test.DiscoveryClientHandler{}) s.InitMcpClient() s.Run("pods_top with metrics API not available", func() { @@ -238,8 +226,10 @@ func (s *PodsTopSuite) TestPodsTopDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to get pods top: resource not allowed: metrics.k8s.io/v1beta1, Kind=PodMetrics" - s.Equalf(expectedMessage, result.Content[0].(mcp.TextContent).Text, + msg := result.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to get pods top:(.+:)? resource not allowed: metrics.k8s.io/v1beta1, Kind=PodMetrics" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, result.Content[0].(mcp.TextContent).Text) }) }) diff --git a/pkg/mcp/resources_test.go b/pkg/mcp/resources_test.go index 21329d20..a1f176ff 100644 --- a/pkg/mcp/resources_test.go +++ b/pkg/mcp/resources_test.go @@ -116,8 +116,10 @@ func (s *ResourcesSuite) TestResourcesListDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to list resources: resource not allowed: /v1, Kind=Secret" - s.Equalf(expectedMessage, deniedByKind.Content[0].(mcp.TextContent).Text, + msg := deniedByKind.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to list resources:(.+:)? resource not allowed: /v1, Kind=Secret" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, deniedByKind.Content[0].(mcp.TextContent).Text) }) }) @@ -128,8 +130,10 @@ func (s *ResourcesSuite) TestResourcesListDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to list resources: resource not allowed: rbac.authorization.k8s.io/v1, Kind=Role" - s.Equalf(expectedMessage, deniedByGroup.Content[0].(mcp.TextContent).Text, + msg := deniedByGroup.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to list resources:(.+:)? resource not allowed: rbac.authorization.k8s.io/v1, Kind=Role" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, deniedByGroup.Content[0].(mcp.TextContent).Text) }) }) @@ -289,8 +293,10 @@ func (s *ResourcesSuite) TestResourcesGetDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to get resource: resource not allowed: /v1, Kind=Secret" - s.Equalf(expectedMessage, deniedByKind.Content[0].(mcp.TextContent).Text, + msg := deniedByKind.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to get resource:(.+:)? resource not allowed: /v1, Kind=Secret" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, deniedByKind.Content[0].(mcp.TextContent).Text) }) }) @@ -301,8 +307,10 @@ func (s *ResourcesSuite) TestResourcesGetDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to get resource: resource not allowed: rbac.authorization.k8s.io/v1, Kind=Role" - s.Equalf(expectedMessage, deniedByGroup.Content[0].(mcp.TextContent).Text, + msg := deniedByGroup.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to get resource:(.+:)? resource not allowed: rbac.authorization.k8s.io/v1, Kind=Role" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, deniedByGroup.Content[0].(mcp.TextContent).Text) }) }) @@ -450,8 +458,10 @@ func (s *ResourcesSuite) TestResourcesCreateOrUpdateDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to create or update resources: resource not allowed: /v1, Kind=Secret" - s.Equalf(expectedMessage, deniedByKind.Content[0].(mcp.TextContent).Text, + msg := deniedByKind.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to create or update resources:(.+:)? resource not allowed: /v1, Kind=Secret" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, deniedByKind.Content[0].(mcp.TextContent).Text) }) }) @@ -463,8 +473,10 @@ func (s *ResourcesSuite) TestResourcesCreateOrUpdateDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to create or update resources: resource not allowed: rbac.authorization.k8s.io/v1, Kind=Role" - s.Equalf(expectedMessage, deniedByGroup.Content[0].(mcp.TextContent).Text, + msg := deniedByGroup.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to create or update resources:(.+:)? resource not allowed: rbac.authorization.k8s.io/v1, Kind=Role" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, deniedByGroup.Content[0].(mcp.TextContent).Text) }) }) @@ -565,8 +577,10 @@ func (s *ResourcesSuite) TestResourcesDeleteDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to delete resource: resource not allowed: /v1, Kind=Secret" - s.Equalf(expectedMessage, deniedByKind.Content[0].(mcp.TextContent).Text, + msg := deniedByKind.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to delete resource:(.+:)? resource not allowed: /v1, Kind=Secret" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, deniedByKind.Content[0].(mcp.TextContent).Text) }) }) @@ -577,8 +591,10 @@ func (s *ResourcesSuite) TestResourcesDeleteDenied() { s.Nilf(err, "call tool should not return error object") }) s.Run("describes denial", func() { - expectedMessage := "failed to delete resource: resource not allowed: rbac.authorization.k8s.io/v1, Kind=Role" - s.Equalf(expectedMessage, deniedByGroup.Content[0].(mcp.TextContent).Text, + msg := deniedByGroup.Content[0].(mcp.TextContent).Text + s.Contains(msg, "resource not allowed:") + expectedMessage := "failed to delete resource:(.+:)? resource not allowed: rbac.authorization.k8s.io/v1, Kind=Role" + s.Regexpf(expectedMessage, msg, "expected descriptive error '%s', got %v", expectedMessage, deniedByGroup.Content[0].(mcp.TextContent).Text) }) })