Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions examples/config-read-only.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,8 @@ tools:
config_manager:
# Enable configuration management tools (optional, default: false)
enabled: true

# Violations management tools
violations:
# Enable violations tools (optional, default: false)
enabled: true
2 changes: 2 additions & 0 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/stackrox/stackrox-mcp/internal/server"
"github.com/stackrox/stackrox-mcp/internal/toolsets"
toolsetConfig "github.com/stackrox/stackrox-mcp/internal/toolsets/config"
toolsetViolations "github.com/stackrox/stackrox-mcp/internal/toolsets/violations"
toolsetVulnerability "github.com/stackrox/stackrox-mcp/internal/toolsets/vulnerability"
)

Expand All @@ -24,6 +25,7 @@ func GetToolsets(cfg *config.Config, c *client.Client) []toolsets.Toolset {
return []toolsets.Toolset{
toolsetConfig.NewToolset(cfg, c),
toolsetVulnerability.NewToolset(cfg, c),
toolsetViolations.NewToolset(cfg, c),
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package vulnerability
// Package cluster provides shared cluster utilities for toolsets.
package cluster

import (
"context"
Expand All @@ -8,9 +9,9 @@ import (
"google.golang.org/grpc"
)

// resolveClusterID resolves a cluster name to its ID.
// ResolveClusterID resolves a cluster name to its ID.
// Returns error if cluster name is not found or if API call fails.
func resolveClusterID(ctx context.Context, conn *grpc.ClientConn,
func ResolveClusterID(ctx context.Context, conn *grpc.ClientConn,
Comment on lines +12 to +14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Convert cluster API failures with client.NewError.

The exported resolver returns the raw GetClusters gRPC error through every consuming MCP handler, potentially exposing backend details and bypassing consistent error mapping.

Proposed fix
 import (
+	"github.com/stackrox/stackrox-mcp/internal/client"
 )

 // ...

 	if err != nil {
-		return "", fmt.Errorf("failed to fetch clusters: %w", err)
+		return "", client.NewError(err, "GetClusters")
 	}

As per path instructions, Go MCP server code requires “Proper error wrapping with client.NewError for user-facing errors.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cluster/resolver.go` around lines 12 - 14, Update ResolveClusterID
to wrap failures from the GetClusters API call with client.NewError before
returning them, while preserving the existing not-found behavior and successful
cluster ID resolution. Ensure every error propagated by this exported resolver
follows the user-facing client error mapping.

Source: Path instructions

clusterID string, clusterName string) (string, error) {
// Cluster ID has priority.
if clusterID != "" {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package vulnerability
package cluster

import (
"context"
Expand Down Expand Up @@ -79,7 +79,7 @@ func TestResolveClusterID_Success(t *testing.T) {

defer func() { _ = conn.Close() }()

clusterID, err := resolveClusterID(
clusterID, err := ResolveClusterID(
context.Background(),
conn,
testCase.clusterID,
Expand Down Expand Up @@ -126,7 +126,7 @@ func TestResolveClusterID_Failure(t *testing.T) {

defer func() { _ = conn.Close() }()

clusterID, err := resolveClusterID(
clusterID, err := ResolveClusterID(
context.Background(),
conn,
"",
Expand Down
9 changes: 8 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ type ServerConfig struct {
type ToolsConfig struct {
Vulnerability ToolsetVulnerabilityConfig `mapstructure:"vulnerability"`
ConfigManager ToolConfigManagerConfig `mapstructure:"config_manager"`
Violations ToolsetViolationsConfig `mapstructure:"violations"`
}

// ToolsetVulnerabilityConfig contains configuration for vulnerability management tools.
Expand All @@ -96,6 +97,11 @@ type ToolConfigManagerConfig struct {
Enabled bool `mapstructure:"enabled"`
}

// ToolsetViolationsConfig contains configuration for violations management tools.
type ToolsetViolationsConfig struct {
Enabled bool `mapstructure:"enabled"`
}

// LoadConfig loads configuration from YAML file and environment variables.
// Environment variables take precedence over YAML configuration.
// Env var naming convention: STACKROX_MCP__SECTION__KEY (double underscore as separator).
Expand Down Expand Up @@ -164,6 +170,7 @@ func setDefaults(viper *viper.Viper) {

viper.SetDefault("tools.vulnerability.enabled", false)
viper.SetDefault("tools.config_manager.enabled", false)
viper.SetDefault("tools.violations.enabled", false)
}

// GetURLHostname returns URL hostname.
Expand Down Expand Up @@ -269,7 +276,7 @@ func (c *Config) Validate() error {
return err
}

if !c.Tools.Vulnerability.Enabled && !c.Tools.ConfigManager.Enabled {
if !c.Tools.Vulnerability.Enabled && !c.Tools.ConfigManager.Enabled && !c.Tools.Violations.Enabled {
return errors.New("at least one tool has to be enabled")
}

Expand Down
Loading