Skip to content

feat: add operations for helm - #17

Merged
Cali0707 merged 1 commit into
mcpchecker:mainfrom
matzew:Kube_helm_extension
Feb 27, 2026
Merged

feat: add operations for helm#17
Cali0707 merged 1 commit into
mcpchecker:mainfrom
matzew:Kube_helm_extension

Conversation

@matzew

@matzew matzew commented Feb 6, 2026

Copy link
Copy Markdown
Contributor

adding operations for working with helm charts

Summary by CodeRabbit

  • New Features

    • Added three Helm operations: install charts (with optional name, namespace, values), list releases (namespace or all-namespaces), and uninstall charts (treats missing releases as success).
  • Documentation

    • Expanded Kubernetes extension docs with Helm usage examples, YAML snippets, and detailed operation reference.
  • Tests

    • Added tests covering parameter validation and expected behaviors for the Helm operations.
  • Chores

    • CI workflow updated to install Helm before running tests.

@coderabbitai

coderabbitai Bot commented Feb 6, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds Helm support to the Kubernetes extension: three new operations (kubernetes.helmInstall, kubernetes.helmList, kubernetes.helmUninstall), their handler implementations and unit tests, documentation updates, a CI step to install Helm, and a new Extension field to persist kubeconfigPath.

Changes

Cohort / File(s) Summary
Documentation
README.md
Added Helm operations to docs: operations table, usage examples (setup/cleanup), Helm example task, and detailed operation reference with YAML and outputs.
Helm Feature Implementation
pkg/extension/helm.go, pkg/extension/operations.go
New handlers handleHelmInstall, handleHelmList, handleHelmUninstall; operations registered with JSON schemas and linked handlers. Handlers validate args, build/execute helm CLI commands, parse helm list JSON, and return structured OperationResult.
Extension State
pkg/extension/extension.go
Added kubeconfigPath string field to Extension and set it during initialization to persist kubeconfig path.
Helm Tests
pkg/extension/helm_test.go
Unit tests for parameter validation and expected behaviors (install/list/uninstall). Tests conditionally skip when Helm/Kubernetes unavailable.
CI Workflow
.github/workflows/test.yaml
Added "Install Helm" step using azure/setup-helm@v4 (version: latest) before running tests.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Extension
    participant Shell as "Helm CLI (shell)"
    participant Parser as "JSON Parser"

    Client->>Extension: OperationRequest (helmInstall / helmList / helmUninstall)
    Extension->>Extension: validate args, build helm command
    Extension->>Shell: execute helm command
    Shell-->>Extension: stdout/stderr, exit status
    alt helmList (JSON output)
        Extension->>Parser: parse JSON output
        Parser-->>Extension: structured releases
    end
    Extension-->>Client: OperationResult (Success/Failure + output)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • nader-ziada
  • Cali0707

Poem

🐰 I hopped a chart from tree to sea,
Installed, listed, uninstalled with glee.
Namespace paths and values bright,
Shell commands humming through the night.
A little hop — Helm set free! 🐇

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add operations for helm' directly and accurately summarizes the main change in the changeset, which introduces three new Helm-related operations (helmInstall, helmList, helmUninstall) to the Kubernetes extension.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@pkg/extension/helm_test.go`:
- Around line 129-188: The test assumes the helm CLI exists; mirror the
TestHandleHelmList fix by detecting helm with exec.LookPath("helm") at the start
of TestHandleHelmUninstall and, if helm is not found, adjust the expectations
for cases that relied on the "release not found" behavior (e.g., the "valid name
parameter for non-existent release" and "with namespace" cases) or skip those
subtests—modify the tests in TestHandleHelmUninstall (referencing the
TestHandleHelmUninstall function and the ext.handleHelmUninstall call) so they
either set wantSuccess=false when helm is missing or call t.Skipf with a clear
message when the helm binary is absent.
- Around line 65-71: The test in helm_test.go currently skips asserting the
error text: when tt.wantErrMsg != "" it only verifies result.Success is false
but never checks result.Message content; update the test to import "strings"
and, inside the block where tt.wantErrMsg != "" && result.Message != "", assert
that strings.Contains(result.Message, tt.wantErrMsg) (and if not, call t.Errorf
with a helpful message), and also ensure you still fail if result.Success is
true when an error was expected.
- Around line 76-127: Test failures occur because the CI has no helm binary;
update the TestHandleHelmList test to detect helm availability and skip the test
when absent: in pkg/extension/helm_test.go inside TestHandleHelmList (or before
running subtests) call exec.LookPath("helm") (or run a simple
exec.CommandContext check) and if it returns an error call t.Skipf("skipping
helm-dependent tests: %v", err); this keeps handleHelmList and Extension
unchanged and avoids asserting wantSuccess=true when the helm executable is not
present.

In `@pkg/extension/helm.go`:
- Around line 44-47: The loop building cmdArgs with "--set" is vulnerable to
shell/Helm parsing problems and doesn't support nested maps; instead either
serialize complex structures to a temporary YAML file and pass it via "--values"
or implement a recursive flattener (e.g., flattenValues(prefix string, values
map[string]interface{}, result map[string]string)) to produce dot-notated keys
(service.type=LoadBalancer) and then append safe, properly formatted values to
cmdArgs; additionally ensure values are sanitized/quoted (use fmt.Sprintf or
strconv.Quote-like formatting) when constructing the final "--set" arguments to
avoid injection/escaping issues.

In `@README.md`:
- Around line 216-217: The README claim that helmList outputs a `releases` field
is inconsistent with the implementation: update the helmList implementation in
helm.go (the function/method named helmList that currently calls sdk.Success
with a formatted string) to return structured data (e.g., an object/struct with
a `releases` array of {name, namespace, status, chart} entries) via the SDK
success path instead of a formatted string, or alternatively update README.md to
describe the actual string returned by sdk.Success; pick one approach and make
the code/docs consistent by changing either helmList/sdk.Success usage or the
README description accordingly.
🧹 Nitpick comments (3)
pkg/extension/helm.go (3)

55-63: Consider sanitizing or quoting command output in error messages.

The error message includes raw command output which could contain sensitive information (registry credentials, internal paths, etc.) that might be logged or displayed to users.


105-111: JSON unmarshal may fail on valid empty array output.

If helm list returns an empty JSON array [], len(output) > 0 is true, but releases will be an empty slice after unmarshal, which is handled correctly at line 113. However, if the output is whitespace-only or contains just a newline, the unmarshal will fail.

Consider trimming the output before the length check.

Suggested improvement
 	// Parse JSON output
 	var releases []map[string]interface{}
-	if len(output) > 0 {
+	trimmedOutput := strings.TrimSpace(string(output))
+	if len(trimmedOutput) > 0 {
-		if err := json.Unmarshal(output, &releases); err != nil {
+		if err := json.Unmarshal([]byte(trimmedOutput), &releases); err != nil {
 			return sdk.Failure(fmt.Errorf("failed to parse helm list output: %s", err)), nil
 		}
 	}

157-164: Fragile "not found" detection.

The string match strings.Contains(string(output), "not found") is locale-dependent and may break with different Helm versions or localized error messages. Additionally, if the helm binary itself is not found, this check won't match and the error will propagate differently.

Consider checking the exit code or using helm status first to verify release existence.

Comment on lines +65 to +71
if tt.wantErrMsg != "" && result.Message != "" {
// Check if error message contains expected substring
// (we don't check exact match because helm error messages may vary)
if result.Success {
t.Errorf("expected failure with message containing %q, but got success", tt.wantErrMsg)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Error message assertion is ineffective.

The check at lines 65-71 verifies tt.wantErrMsg but only checks if the result succeeded when an error message was expected. It never actually validates that result.Message contains the expected error substring.

Proposed fix
-		if tt.wantErrMsg != "" && result.Message != "" {
-			// Check if error message contains expected substring
-			// (we don't check exact match because helm error messages may vary)
-			if result.Success {
-				t.Errorf("expected failure with message containing %q, but got success", tt.wantErrMsg)
-			}
-		}
+		if tt.wantErrMsg != "" {
+			if result.Success {
+				t.Errorf("expected failure with message containing %q, but got success", tt.wantErrMsg)
+			} else if !strings.Contains(result.Message, tt.wantErrMsg) {
+				t.Errorf("expected message containing %q, got %q", tt.wantErrMsg, result.Message)
+			}
+		}

Note: You'll need to add "strings" to the imports.

🤖 Prompt for AI Agents
In `@pkg/extension/helm_test.go` around lines 65 - 71, The test in helm_test.go
currently skips asserting the error text: when tt.wantErrMsg != "" it only
verifies result.Success is false but never checks result.Message content; update
the test to import "strings" and, inside the block where tt.wantErrMsg != "" &&
result.Message != "", assert that strings.Contains(result.Message,
tt.wantErrMsg) (and if not, call t.Errorf with a helpful message), and also
ensure you still fail if result.Success is true when an error was expected.

Comment thread pkg/extension/helm_test.go
Comment thread pkg/extension/helm_test.go
Comment thread pkg/extension/helm.go
Comment on lines +44 to +47
// Add values as --set flags
for k, v := range values {
cmdArgs = append(cmdArgs, "--set", fmt.Sprintf("%s=%v", k, v))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Command injection risk and limited values support.

Two concerns with the --set flag handling:

  1. Shell metacharacters: If k or v contain special characters (e.g., commas, brackets, quotes), they can break Helm's --set parsing or cause unexpected behavior.

  2. Nested values limitation: The current approach doesn't handle nested values. For example, {"service": {"type": "LoadBalancer"}} would need --set service.type=LoadBalancer, not --set service=map[type:LoadBalancer].

Consider using a temporary values file with --values for complex structures, or recursively flatten nested maps with dot notation.

Sketch: Flatten nested values
func flattenValues(prefix string, values map[string]interface{}, result map[string]string) {
	for k, v := range values {
		key := k
		if prefix != "" {
			key = prefix + "." + k
		}
		switch val := v.(type) {
		case map[string]interface{}:
			flattenValues(key, val, result)
		default:
			result[key] = fmt.Sprintf("%v", val)
		}
	}
}
🤖 Prompt for AI Agents
In `@pkg/extension/helm.go` around lines 44 - 47, The loop building cmdArgs with
"--set" is vulnerable to shell/Helm parsing problems and doesn't support nested
maps; instead either serialize complex structures to a temporary YAML file and
pass it via "--values" or implement a recursive flattener (e.g.,
flattenValues(prefix string, values map[string]interface{}, result
map[string]string)) to produce dot-notated keys (service.type=LoadBalancer) and
then append safe, properly formatted values to cmdArgs; additionally ensure
values are sanitized/quoted (use fmt.Sprintf or strconv.Quote-like formatting)
when constructing the final "--set" arguments to avoid injection/escaping
issues.

Comment thread README.md
Comment on lines +216 to +217
**Outputs:**
- `releases`: Information about found Helm releases (name, namespace, status, chart)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Documentation inconsistency: releases output doesn't match implementation.

The documentation states that helmList outputs a releases field, but the implementation in helm.go returns a formatted string message via sdk.Success(), not structured data with a releases key.

Either update the documentation to reflect the actual string output, or modify the implementation to return structured release data.

🤖 Prompt for AI Agents
In `@README.md` around lines 216 - 217, The README claim that helmList outputs a
`releases` field is inconsistent with the implementation: update the helmList
implementation in helm.go (the function/method named helmList that currently
calls sdk.Success with a formatted string) to return structured data (e.g., an
object/struct with a `releases` array of {name, namespace, status, chart}
entries) via the SDK success path instead of a formatted string, or
alternatively update README.md to describe the actual string returned by
sdk.Success; pick one approach and make the code/docs consistent by changing
either helmList/sdk.Success usage or the README description accordingly.

@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/mcpchecker/kubernetes-extension/issues/comments/3859927137","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> \n> \n> ```ascii\n>  ____________________________________________________________________\n> < Sometimes, I feel like a code reviewer in a world of copy-pasters. >\n>  --------------------------------------------------------------------\n>   \\\n>    \\   \\\n>         \\ /\\\n>         ( )\n>       .( o ).\n> ```\n> \n> <sub>✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.</sub>\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n<!-- usage_tips_start -->\n\n> [!TIP]\n> <details>\n> <summary>CodeRabbit can suggest fixes for GitHub Check annotations.</summary>\n> \n> Configure the `reviews.tools.github-checks` setting to adjust the time to wait for GitHub Checks to complete.\n> \n> </details>\n\n<!-- usage_tips_end -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nThis change adds Helm support to the Kubernetes extension by introducing three new operations (helmInstall, helmList, helmUninstall) with corresponding handler implementations, comprehensive unit tests, and documentation updates. No modifications to existing code or public APIs.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Documentation** <br> `README.md`|Added Helm operations to the Kubernetes extension documentation with usage examples, setup/cleanup blocks, and detailed operation reference sections for each new Helm command.|\n|**Helm Feature Implementation** <br> `pkg/extension/helm.go`, `pkg/extension/helm_test.go`|Implemented three Helm handlers (install, list, uninstall) with validation, command execution, and error handling; included comprehensive unit tests covering parameter validation and success scenarios.|\n|**Operations Registration** <br> `pkg/extension/operations.go`|Registered three new Helm operations with JSON schemas specifying input properties, required fields, and descriptive parameter metadata.|\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Suggested reviewers\n\n- Cali0707\n\n## Poem\n\n> 🐰 Helmsman hops with glee, charting courses through the sea,\n> Three new commands now take flight—install, list, uninstall bright!\n> Values floating through the air, namespaces with utmost care,\n> The Kubernetes kingdom grows, as our config ships and flows! ⚓\n\n</details>\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 2 | ❌ 1</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning)</summary>\n\n|     Check name     | Status     | Explanation                                                                          | Resolution                                                                         |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n</details>\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                 |\n| :---------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                 |\n|    Title check    | ✅ Passed | The title 'feat: add operations for helm' directly and accurately describes the main change: adding new Helm operations (helmInstall, helmList, helmUninstall) to the Kubernetes extension. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/mcpchecker/kubernetes-extension/issues/comments/3859927137","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:37:44 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-media-type":"github.v3; format=json","x-github-request-id":"28AB:38A9EB:2C2166:BB5FDC:698A0D56","x-ratelimit-limit":"60","x-ratelimit-remaining":"0","x-ratelimit-reset":"1770658413","x-ratelimit-resource":"core","x-ratelimit-used":"1848","x-xss-protection":"0"},"data":""}}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/test.yaml:
- Around line 19-22: The workflow currently sets the Helm installer to use
`version: 'latest'` (in the azure/setup-helm@v4 step), which makes CI
non-deterministic; update the Helm setup step to pin a specific, tested release
(e.g., replace 'latest' with a concrete tag such as 'v4.1.0' for Helm v4 or
'v3.20.0' for Helm v3) so every run installs the exact same Helm version for
reproducible CI builds and local debugging.

Comment on lines +19 to +22
- name: Install Helm
uses: azure/setup-helm@v4
with:
version: 'latest'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

latest stable version of Helm 2025 2026

💡 Result:

As of February 9, 2026, the latest stable Helm releases are:

  • Helm v4 (current major): v4.1.0 — released January 21, 2026. [1]
  • Helm v3 (still maintained): v3.20.0 — released January 21, 2026. [2]

(Helm v4 was officially announced/released on November 12, 2025.) [3]

Sources:
[1] (github.com)
[2] (github.com)
[3] (cncf.io)

Citations:


🏁 Script executed:

# Check the actual workflow file for context
cat -n .github/workflows/test.yaml | sed -n '1,30p'

Repository: mcpchecker/kubernetes-extension

Length of output: 653


🌐 Web query:

azure/setup-helm action latest version v4 v5

💡 Result:

  • Latest azure/setup-helm release/tag: v4.3.1 (github.com)
  • Latest major version: v4 (you can use azure/setup-helm@v4 to track the latest v4.x). (github.com)
  • Is there a v5? Not currently—there’s no v5 release/tag in the upstream repo releases. (github.com)

Citations:


Pin Helm to a specific version for reproducible CI builds.

Using version: 'latest' introduces non-determinism—different workflow runs may install different Helm versions, potentially causing unexpected test failures when a new Helm release ships breaking changes. Pin to a specific version (e.g., v4.1.0 for Helm v4, or v3.20.0 for Helm v3) to ensure reproducibility and easier local debugging.

♻️ Suggested fix
      - name: Install Helm
        uses: azure/setup-helm@v4
        with:
-          version: 'latest'
+          version: 'v4.1.0'
🤖 Prompt for AI Agents
In @.github/workflows/test.yaml around lines 19 - 22, The workflow currently
sets the Helm installer to use `version: 'latest'` (in the azure/setup-helm@v4
step), which makes CI non-deterministic; update the Helm setup step to pin a
specific, tested release (e.g., replace 'latest' with a concrete tag such as
'v4.1.0' for Helm v4 or 'v3.20.0' for Helm v3) so every run installs the exact
same Helm version for reproducible CI builds and local debugging.

Comment thread pkg/extension/helm.go
Comment on lines +32 to +43
if name != "" {
cmdArgs = append(cmdArgs, name)
} else {
cmdArgs = append(cmdArgs, "--generate-name")
}

cmdArgs = append(cmdArgs, chart)

if namespace != "" {
cmdArgs = append(cmdArgs, "--namespace", namespace)
}

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.

here let's also set the --kubeconfig flag - the extension can receive a different kubeconfig path than the default on startup.

We don't currently expose the path to that file through the client, but it should be simple to add something around here:

// ResourceClient abstracts Kubernetes resource operations for testability.
// Implementations can use the real dynamic client or a mock for testing.
type ResourceClient interface {
// Create creates a Kubernetes resource and returns the created object.
Create(ctx context.Context, gvr schema.GroupVersionResource, obj *unstructured.Unstructured, namespace string) (*unstructured.Unstructured, error)
// Get retrieves a Kubernetes resource by name.
Get(ctx context.Context, gvr schema.GroupVersionResource, name, namespace string) (*unstructured.Unstructured, error)
// Delete removes a Kubernetes resource.
Delete(ctx context.Context, gvr schema.GroupVersionResource, name, namespace string, opts metav1.DeleteOptions) error
// CheckAccess checks if a user can perform an action on a resource.
CheckAccess(ctx context.Context, user, verb, resource, apiGroup, namespace, resourceName string) (bool, string, error)
// ListContexts returns all contexts from the kubeconfig sorted by name.
// Each context includes its name, cluster, user, namespace, and whether it's the current context.
ListContexts(ctx context.Context) ([]ContextInfo, error)
// GetCurrentContext returns the current context name from the kubeconfig.
// Returns an error if the kubeconfig cannot be loaded.
GetCurrentContext(ctx context.Context) (string, error)
// ViewConfig returns the kubeconfig as YAML.
// When minify is true, only the current context and its dependencies are included.
ViewConfig(ctx context.Context, minify bool) (string, error)
}
// dynamicClientAdapter adapts the Kubernetes dynamic client to the ResourceClient interface.
type dynamicClientAdapter struct {
client dynamic.Interface
authzClient authorizationv1client.AuthorizationV1Interface
kubeconfigPath string
}

Signed-off-by: Matthias Wessendorf <[email protected]>
@matzew
matzew force-pushed the Kube_helm_extension branch from 4d46898 to ba32a57 Compare February 27, 2026 08:19
@matzew

matzew commented Feb 27, 2026

Copy link
Copy Markdown
Contributor Author

@Cali0707 updated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/extension/helm.go (1)

59-60: Consider checking for helm binary availability.

If the helm binary is not installed or not in PATH, the error message from exec.CommandContext may be cryptic. A pre-check with exec.LookPath("helm") and a clearer error message would improve user experience.

💡 Suggested improvement
// Could add at the start of each handler or as a shared check:
if _, err := exec.LookPath("helm"); err != nil {
    return sdk.Failure(fmt.Errorf("helm CLI not found in PATH: please install helm")), nil
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/extension/helm.go` around lines 59 - 60, Add a pre-check for the helm
binary before calling exec.CommandContext by using exec.LookPath("helm") where
you construct cmd := exec.CommandContext(ctx, "helm", cmdArgs...) and return a
clear sdk.Failure error if not found (e.g., "helm CLI not found in PATH: please
install helm"); this check can be placed at the start of the handler or factored
into a shared helper used by the code that runs CombinedOutput() so callers
receive a human-friendly message instead of a cryptic exec error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/extension/helm_test.go`:
- Around line 18-26: The kubernetesAvailable function has inverted logic: when
cmd.CombinedOutput() returns an error it currently returns true for
non-"unreachable" errors; change it so any error from exec.Command("helm",
"list") causes kubernetesAvailable to return false (i.e., treat failures like
auth/permission errors as Kubernetes not available). Update the error branch in
kubernetesAvailable (which uses cmd.CombinedOutput() and strings.Contains) to
return false on err != nil, only returning true when the command succeeds.

---

Nitpick comments:
In `@pkg/extension/helm.go`:
- Around line 59-60: Add a pre-check for the helm binary before calling
exec.CommandContext by using exec.LookPath("helm") where you construct cmd :=
exec.CommandContext(ctx, "helm", cmdArgs...) and return a clear sdk.Failure
error if not found (e.g., "helm CLI not found in PATH: please install helm");
this check can be placed at the start of the handler or factored into a shared
helper used by the code that runs CombinedOutput() so callers receive a
human-friendly message instead of a cryptic exec error.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff6d526 and ba32a57.

📒 Files selected for processing (6)
  • .github/workflows/test.yaml
  • README.md
  • pkg/extension/extension.go
  • pkg/extension/helm.go
  • pkg/extension/helm_test.go
  • pkg/extension/operations.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/extension/operations.go
  • .github/workflows/test.yaml
  • README.md

Comment on lines +18 to +26
// kubernetesAvailable checks if a Kubernetes cluster is reachable via helm
func kubernetesAvailable() bool {
cmd := exec.Command("helm", "list")
output, err := cmd.CombinedOutput()
if err != nil {
return !strings.Contains(string(output), "unreachable")
}
return true
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inverted logic in kubernetesAvailable check.

The logic at line 23 is inverted. If helm list fails with an error that doesn't contain "unreachable", the function returns true, incorrectly indicating Kubernetes is available. For example, authentication failures or permission errors would cause the function to return true.

🐛 Proposed fix
 func kubernetesAvailable() bool {
 	cmd := exec.Command("helm", "list")
 	output, err := cmd.CombinedOutput()
 	if err != nil {
-		return !strings.Contains(string(output), "unreachable")
+		// If helm list fails for any reason, assume Kubernetes is not available
+		return false
 	}
 	return true
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// kubernetesAvailable checks if a Kubernetes cluster is reachable via helm
func kubernetesAvailable() bool {
cmd := exec.Command("helm", "list")
output, err := cmd.CombinedOutput()
if err != nil {
return !strings.Contains(string(output), "unreachable")
}
return true
}
// kubernetesAvailable checks if a Kubernetes cluster is reachable via helm
func kubernetesAvailable() bool {
cmd := exec.Command("helm", "list")
output, err := cmd.CombinedOutput()
if err != nil {
// If helm list fails for any reason, assume Kubernetes is not available
return false
}
return true
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/extension/helm_test.go` around lines 18 - 26, The kubernetesAvailable
function has inverted logic: when cmd.CombinedOutput() returns an error it
currently returns true for non-"unreachable" errors; change it so any error from
exec.Command("helm", "list") causes kubernetesAvailable to return false (i.e.,
treat failures like auth/permission errors as Kubernetes not available). Update
the error branch in kubernetesAvailable (which uses cmd.CombinedOutput() and
strings.Contains) to return false on err != nil, only returning true when the
command succeeds.

@Cali0707 Cali0707 left a comment

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.

LGTM, thanks @matzew !

@Cali0707
Cali0707 merged commit 8bde856 into mcpchecker:main Feb 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants