Skip to content

HELM-703: Add authentication for Helm chart URLs#16360

Open
sowmya-sl wants to merge 4 commits intoopenshift:mainfrom
sowmya-sl:add-auth-helm
Open

HELM-703: Add authentication for Helm chart URLs#16360
sowmya-sl wants to merge 4 commits intoopenshift:mainfrom
sowmya-sl:add-auth-helm

Conversation

@sowmya-sl
Copy link
Copy Markdown
Contributor

@sowmya-sl sowmya-sl commented Apr 28, 2026

Analysis / Root cause:
The Helm installation using URLs is currently supported without any authentication. This becomes difficult when charts are in registries which require username and password. So add support for the same.

Solution description:
The solution is creating a generic secret having username and password as keys. This secret is read and shared with the Helm registry in the backend.

Screenshots / screen recording:
First tab:
image
image

On clicking Next:
image

Clicking on Install installs the Helm release

If secret is not needed, then this is the flow:
image
On clicking Next
image

Test setup:

  1. Docker Hub for checking OCI charts with authentication
  2. Any HTTP/HTTPS repository which has username and password option.

Reviewers and assignees:

@openshift/team-ux-review

Summary by CodeRabbit

  • New Features

    • Add Basic Auth Secret selection in the Helm URL installer with loading/empty-state UX and a read-only display of the chosen secret; the install flow now includes the selected secret and sends it when needed.
    • New localization strings for the Basic Auth Secret UI and secret structure guidance.
  • Tests

    • Extended test infrastructure and scenarios to cover OCI/basic-auth chart pulls, plus helper scripts and testdata for a basic-auth registry.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Apr 28, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Apr 28, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Apr 28, 2026

@sowmya-sl: This pull request references HELM-703 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Analysis / Root cause:
The Helm installation using URLs is currently supported without any authentication. This becomes difficult when charts are in registries which require username and password. So add support for the same.

Solution description:
The solution is creating a generic secret having username and password as keys. This secret is read and shared with the Helm registry in the backend.

Screenshots / screen recording:

Test setup:

Test cases:

Browser conformance:

  • Chrome
  • Firefox
  • Safari (or Epiphany on Linux)

Additional info:

Reviewers and assignees:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci Bot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. component/backend Related to backend labels Apr 28, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Apr 28, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: sowmya-sl
Once this PR has been reviewed and has the lgtm label, please assign spadgett for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added component/helm Related to helm-plugin kind/i18n Indicates issue or PR relates to internationalization or has content that needs to be translated labels Apr 28, 2026
@sowmya-sl sowmya-sl marked this pull request as ready for review April 28, 2026 09:58
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 28, 2026
@openshift-ci openshift-ci Bot requested review from martinszuc and sg00dwin April 28, 2026 09:59
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Walkthrough

Adds optional OCI/HTTP basic-auth via Kubernetes Secrets across frontend and backend. Frontend: new localization entries, a namespaced Secret typeahead that filters for Secrets with username and password, threads basicAuthSecretName through the URL chart form and install wizard, and surfaces the selected secret on the install page. Backend: API request includes basic_auth_secret_name; handlers and Helm actions accept basicAuthSecretName, load credentials from the Secret, and apply them to Helm commands and registry clients (new RegistryClientWithBasicAuth helper). Tests, Zot basic-auth fixtures, and upload scripts are added/updated to cover basic-auth scenarios.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Ote Binary Stdout Contract ❌ Error PR violates OTE Binary Stdout Contract by adding fmt.Println() calls in TestMain cleanup and bash script echo statements that corrupt JSON output. Redirect stdout writes to stderr using fmt.Fprintln(os.Stderr, ...) and modify ExecuteScript() to redirect bash stdout to os.Stderr or ioutil.Discard.
Docstring Coverage ⚠️ Warning Docstring coverage is 31.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ⚠️ Warning Test spawns async goroutine with fixed 2-second sleep, no timeout or context cancellation, and lacks meaningful assertion failure messages. Violates isolation with suite-level cleanup instead of per-test cleanup. Add context-based timeouts using context.WithTimeout() or t.Deadline(), include meaningful assertion messages, and implement per-test cleanup patterns for proper resource isolation.
✅ Passed checks (9 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding authentication support for Helm chart URLs, which aligns with the comprehensive implementation across frontend and backend components.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed Modified test files use standard Go testing with t.Run() and table-driven tests, not Ginkgo. Test names are static descriptive strings with no dynamic values, so Ginkgo check does not apply.
Microshift Test Compatibility ✅ Passed PR adds unit tests and test infrastructure only; no Ginkgo e2e tests are introduced.
Single Node Openshift (Sno) Test Compatibility ✅ Passed PR modifies frontend components, backend Go handlers, and standard Go unit tests. No Ginkgo e2e tests are introduced, so multi-node assumptions check is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed Pull request modifies only frontend UI components, backend handlers, and test infrastructure for basic auth secret selector—no deployment manifests, operators, or scheduling constraints affected.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PR contains only standard Go unit/integration tests using testing.T, not Ginkgo e2e tests. No Ginkgo patterns (Describe, It, Context, BeforeSuite, etc.) detected. Tests use local registries (localhost:5000/5001/5443) without external registry dependencies. Localhost naturally resolves to both IPv4 and IPv6, making tests compatible with IPv6-only environments.
Description check ✅ Passed PR description covers all required template sections with detailed analysis, solution, screenshots, test setup, and test cases.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@sowmya-sl
Copy link
Copy Markdown
Contributor Author

@CodeRabbit help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
  • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
  • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@sowmya-sl
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pkg/helm/handlers/handlers.go (1)

452-471: ⚠️ Potential issue | 🟠 Major

Inconsistent namespace usage in action configuration.

HandleURLChartGet reads namespace from query params (lines 454-457) but still passes hardcoded "default" to getActionConfigurations on line 465. This is inconsistent with HandleChartGet (line 238) which was fixed in this PR. If basic_auth_secret_name references a Secret in the user-provided namespace, the action config needs the correct namespace to resolve it.

🔧 Proposed fix
-	conf := h.getActionConfigurations(h.ApiServerHost, "default", user.Token, &h.Transport)
+	conf := h.getActionConfigurations(h.ApiServerHost, namespace, user.Token, &h.Transport)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/helm/handlers/handlers.go` around lines 452 - 471, HandleURLChartGet
reads namespace from query params into the local variable namespace but still
calls getActionConfigurations with the hardcoded "default"; update the call to
getActionConfigurations inside HandleURLChartGet to pass the parsed namespace
variable (namespace) instead of the string "default" so action configuration
(used by NewHandlerClients and getChartFromURL) resolves Secrets like
basic_auth_secret_name in the correct namespace.
pkg/helm/actions/install_chart.go (1)

327-335: ⚠️ Potential issue | 🟡 Minor

Preserve original URL for traceability in OCI install path.

In InstallChartFromURL, the chart_url annotation stores the modified URL (version-stripped at line 315) rather than the original user-provided URL. While version trimming is intentional for OCI handling (stored separately in ChartPathOptions.Version), the original URL is lost. For consistency with InstallChart/InstallChartAsync and to maintain full traceability across release upgrades, capture the original URL before trimming and store it in the annotation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/helm/actions/install_chart.go` around lines 327 - 335, In
InstallChartFromURL capture the original user-provided URL before you
trim/version-strip it (e.g., save url to originalURL) and set
ch.Metadata.Annotations["chart_url"] = originalURL while keeping the trimmed url
used for OCI handling and ChartPathOptions.Version; ensure you still set
ch.Metadata.Annotations["installation"] = "url_install" and that trimming logic
(the code that mutates url and populates ChartPathOptions.Version) remains
unchanged so traceability is preserved.
🧹 Nitpick comments (6)
pkg/helm/handlers/handler_test.go (1)

204-205: Assert the new basicAuthSecretName parameter in this mock.

The new argument is accepted but ignored, so forwarding regressions in the handler path would still pass tests.

Suggested test hardening
-func fakeInstallChartFromURL(mockedSecret *kv1.Secret, err error) func(ns string, name string, url string, values map[string]interface{}, conf *action.Configuration, coreClient corev1client.CoreV1Interface, version string, basicAuthSecretName string) (*kv1.Secret, error) {
-	return func(ns string, name string, url string, values map[string]interface{}, conf *action.Configuration, coreClient corev1client.CoreV1Interface, version string, basicAuthSecretName string) (*kv1.Secret, error) {
+func fakeInstallChartFromURL(mockedSecret *kv1.Secret, expectedBasicAuthSecretName string, t *testing.T, err error) func(ns string, name string, url string, values map[string]interface{}, conf *action.Configuration, coreClient corev1client.CoreV1Interface, version string, basicAuthSecretName string) (*kv1.Secret, error) {
+	return func(ns string, name string, url string, values map[string]interface{}, conf *action.Configuration, coreClient corev1client.CoreV1Interface, version string, basicAuthSecretName string) (*kv1.Secret, error) {
+		if basicAuthSecretName != expectedBasicAuthSecretName {
+			t.Errorf("basicAuthSecretName mismatch: expected %q got %q", expectedBasicAuthSecretName, basicAuthSecretName)
+		}
 		return mockedSecret, err
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/helm/handlers/handler_test.go` around lines 204 - 205, The mock factory
fakeInstallChartFromURL currently accepts basicAuthSecretName but ignores it;
modify the factory to take an expectedBasicAuthSecretName (or capture it via
closure) and assert the incoming basicAuthSecretName equals that expected value
inside the returned function (using t.Fatalf/t.Errorf or testify require/assert)
before proceeding to return the fake secret/error; update tests that call
fakeInstallChartFromURL to pass the expected basicAuthSecretName so the mock
will fail if the handler forwards an incorrect value.
pkg/helm/actions/setup_test.go (1)

178-180: Prefer readiness polling over fixed sleep for OCI basic-auth setup.

Line 178 introduces a fixed 5s delay, which is a common source of CI flakes when startup is slower than expected.

Suggested direction
-	time.Sleep(5 * time.Second)
+	if err := waitForTCP("127.0.0.1:5001", 30*time.Second); err != nil {
+		return fmt.Errorf("zot basic-auth registry not ready: %w", err)
+	}
// add helper in this file
func waitForTCP(addr string, timeout time.Duration) error {
	deadline := time.Now().Add(timeout)
	for time.Now().Before(deadline) {
		c, err := net.DialTimeout("tcp", addr, 1*time.Second)
		if err == nil {
			_ = c.Close()
			return nil
		}
		time.Sleep(250 * time.Millisecond)
	}
	return fmt.Errorf("timeout waiting for %s", addr)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/helm/actions/setup_test.go` around lines 178 - 180, Replace the fixed 5s
sleep before calling ExecuteScript with a readiness polling helper (e.g., add
waitForTCP(addr string, timeout time.Duration)) and call it to wait for the
OCI/basic-auth service TCP port to become available; locate the test block
containing time.Sleep(5 * time.Second) and
ExecuteScript("./testdata/uploadOciCharts.sh", ...) and swap the sleep for
waitForTCP("<host:port>", 30*time.Second) (or appropriate timeout) so the test
proceeds only after the service is reachable, returning any error from
waitForTCP instead of relying on a fixed delay.
pkg/helm/actions/install_chart_test.go (1)

450-475: Add a malformed-secret negative case (username/password key missing).

Current additions cover valid and wrong credentials, but not the required secret shape contract. A case where the secret exists but misses one required key would prevent regressions in validation behavior.

Also applies to: 491-502

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/helm/actions/install_chart_test.go` around lines 450 - 475, Add a
negative test case to the install_chart tests that uses the same OCI chart
inputs but supplies a secret name that exists with a malformed shape (missing
the "username" and/or "password" keys) to validate secret shape validation;
update the table of test cases (the struct entries with fields testName,
releaseName, chartPath, chartName, chartVersion, plainHTTP, skipTLSVerify,
basicAuthSecretName, basicAuthUser, basicAuthPass, expectError) by adding an
entry named like "OCI chart with malformed auth secret" that points
basicAuthSecretName at the malformed secret and sets expectError=true so the
test ensures the code path in the install logic (where basic auth secret is
parsed/validated) rejects secrets missing "username"/"password".
frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartInstallPage.tsx (1)

168-179: Prefer reusing shared installChartFromURL helper for request construction.

This block duplicates the API payload contract already captured in frontend/packages/helm-plugin/src/utils/helm-utils.ts (including basic_auth_secret_name). Reusing the helper reduces drift risk.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartInstallPage.tsx`
around lines 168 - 179, The payload construction in HelmURLChartInstallPage.tsx
duplicates the API contract; replace the manual payload object and direct
coFetchJSON.post call with the shared helper installChartFromURL from
frontend/packages/helm-plugin/src/utils/helm-utils.ts: call
installChartFromURL({ namespace, releaseName, fullChartURL, chartVersion,
valuesObj, basicAuthSecretName, noRepo: true }) (map parameter names to the
helper's expected keys, ensuring basic_auth_secret_name and chart_version are
set by the helper) and use its returned promise instead of coFetchJSON.post to
avoid naming-convention eslint disables and drift.
frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartForm.tsx (2)

187-191: Minor: Remove trailing period from form label.

Form labels typically don't end with punctuation. This also differs from the PR screenshots showing "Secret for basic authentication" without a period.

✏️ Proposed fix
               <FormGroup
-                label={t('helm-plugin~Secret for basic authentication.')}
+                label={t('helm-plugin~Secret for basic authentication')}
                 fieldId="basic-auth-secret"
               >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartForm.tsx`
around lines 187 - 191, In HelmURLChartForm.tsx update the FormGroup label prop
(inside the GridItem md={12} block) to remove the trailing period so the label
reads "Secret for basic authentication" instead of "Secret for basic
authentication."; locate the FormGroup component where
label={t('helm-plugin~Secret for basic authentication.')} and remove the final
period within the translation string to match the screenshots and form
conventions.

54-68: Consider handling watch errors and optimizing secret filtering.

The useK8sWatchResource hook returns a third value for errors. Currently, if the watch fails (e.g., RBAC issues), users see no feedback. Additionally, fetching all secrets and filtering client-side may be inefficient in namespaces with many secrets.

♻️ Proposed improvement for error handling
-  const [secrets, secretsLoaded] = useK8sWatchResource<SecretKind[]>({
+  const [secrets, secretsLoaded, secretsError] = useK8sWatchResource<SecretKind[]>({
     kind: SecretModel.kind,
     namespace,
     isList: true,
   });
+
+  // Consider showing secretsError in UI if watch fails

You could display an error state in the SelectList when secretsError is truthy, similar to the loading state pattern already implemented.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartForm.tsx`
around lines 54 - 68, The watch currently ignores the third return value
(errors) from useK8sWatchResource and always fetches all secrets then filters
client-side; update the hook call to capture the error (e.g., const [secrets,
secretsLoaded, secretsError] = useK8sWatchResource(...)) and surface
secretsError to the UI (show an error state/message in the SelectList like you
do for loading). Also limit server-side load by adding a selector/fieldSelector
in the useK8sWatchResource options (or a label selector on SecretModel) so you
only request potential basic-auth secrets instead of fetching all secrets, and
include secretsError and any new selector fields in the basicAuthSecrets
dependencies to avoid stale results (referencing useK8sWatchResource,
secretsLoaded, secrets, secretsError, basicAuthSecrets, SecretModel,
SelectList).
🤖 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/helm/actions/get_chart.go`:
- Around line 78-84: The code currently creates an OCI registry client whenever
basicAuthSecretName is set; change this to only build the OCI client when the
chart source is an OCI URL (e.g., starts with "oci://") to avoid creating the
client for plain HTTP/HTTPS .tgz URLs. In the block referencing
basicAuthSecretName, first obtain the chart source URL used for fetching (the
chart URL value used in this function), check it with a simple guard like
strings.HasPrefix(chartURL, "oci://") (or use an existing helper that detects
OCI charts if available), and only call RegistryClientWithBasicAuth(...) and
cmd.SetRegistryClient(...) when that guard passes; otherwise skip OCI client
creation. Use the symbols basicAuthSecretName, RegistryClientWithBasicAuth, and
cmd.SetRegistryClient to locate and modify the code.

In `@pkg/helm/actions/install_chart.go`:
- Around line 311-316: The current unconditional strings.TrimSuffix(url,
":"+version) can corrupt non-OCI HTTP archive URLs; update the logic in
install_chart.go so the URL trimming is only applied for OCI-style URLs (e.g.,
check strings.HasPrefix(url, "oci://") or an equivalent OCI detection used by
LocateChart/Helm), leaving HTTP/HTTPS archive URLs untouched; keep the existing
behavior of setting cmd.ChartPathOptions.Version = version and continue to use
chartVersionFromURL(url) when version is empty.

In `@pkg/helm/actions/testdata/uploadOciCharts.sh`:
- Line 3: The script currently accepts flags and silently falls back to no-TLS
on unknown input; update the argument parsing (the flag handling around lines
24-38 in pkg/helm/actions/testdata/uploadOciCharts.sh) to explicitly validate
flags and fail fast: detect any unknown flag, print a clear error and usage
hint, and exit non‑zero instead of defaulting to no‑TLS. Ensure the parser only
accepts the advertised modes (--tls, --no-tls, --basic-auth) and refers to the
existing mode variable(s) used in the script so behavior remains unchanged for
valid flags.

In `@pkg/helm/actions/testdata/zot-stop.sh`:
- Around line 5-6: The kill invocation using the unquoted command substitution
kill -TERM $(< zot-basicauth.pid) should be changed to quote the substitution so
the PID string won't be subject to word splitting (i.e., read and use the
contents of zot-basicauth.pid inside quotes when invoking kill -TERM). Locate
the line containing kill -TERM $(< zot-basicauth.pid) and wrap the substitution
in quotes, or equivalently use a quoted cat of zot-basicauth.pid; optionally,
add an existence/readability check for zot-basicauth.pid before attempting to
kill to avoid errors when the file is missing.

In `@pkg/helm/actions/testdata/zotWithBasicAuth.sh`:
- Around line 6-9: The script pkg/helm/actions/testdata/zotWithBasicAuth.sh uses
relative paths for the zot binary, config file
(testdata/zot-config-basicauth.json) and PID file (zot-basicauth.pid), which
break when run from a different CWD; update the script to compute the script
directory at runtime (based on the script's location) and use that absolute path
when referencing ./$GOOS-$GOARCH/zot, ./testdata/zot-config-basicauth.json and
the ./zot-storage-5001 and zot-basicauth.pid locations so all file lookups and
the PID file are created relative to the script location rather than the
caller's working directory.

---

Outside diff comments:
In `@pkg/helm/actions/install_chart.go`:
- Around line 327-335: In InstallChartFromURL capture the original user-provided
URL before you trim/version-strip it (e.g., save url to originalURL) and set
ch.Metadata.Annotations["chart_url"] = originalURL while keeping the trimmed url
used for OCI handling and ChartPathOptions.Version; ensure you still set
ch.Metadata.Annotations["installation"] = "url_install" and that trimming logic
(the code that mutates url and populates ChartPathOptions.Version) remains
unchanged so traceability is preserved.

In `@pkg/helm/handlers/handlers.go`:
- Around line 452-471: HandleURLChartGet reads namespace from query params into
the local variable namespace but still calls getActionConfigurations with the
hardcoded "default"; update the call to getActionConfigurations inside
HandleURLChartGet to pass the parsed namespace variable (namespace) instead of
the string "default" so action configuration (used by NewHandlerClients and
getChartFromURL) resolves Secrets like basic_auth_secret_name in the correct
namespace.

---

Nitpick comments:
In
`@frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartForm.tsx`:
- Around line 187-191: In HelmURLChartForm.tsx update the FormGroup label prop
(inside the GridItem md={12} block) to remove the trailing period so the label
reads "Secret for basic authentication" instead of "Secret for basic
authentication."; locate the FormGroup component where
label={t('helm-plugin~Secret for basic authentication.')} and remove the final
period within the translation string to match the screenshots and form
conventions.
- Around line 54-68: The watch currently ignores the third return value (errors)
from useK8sWatchResource and always fetches all secrets then filters
client-side; update the hook call to capture the error (e.g., const [secrets,
secretsLoaded, secretsError] = useK8sWatchResource(...)) and surface
secretsError to the UI (show an error state/message in the SelectList like you
do for loading). Also limit server-side load by adding a selector/fieldSelector
in the useK8sWatchResource options (or a label selector on SecretModel) so you
only request potential basic-auth secrets instead of fetching all secrets, and
include secretsError and any new selector fields in the basicAuthSecrets
dependencies to avoid stale results (referencing useK8sWatchResource,
secretsLoaded, secrets, secretsError, basicAuthSecrets, SecretModel,
SelectList).

In
`@frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartInstallPage.tsx`:
- Around line 168-179: The payload construction in HelmURLChartInstallPage.tsx
duplicates the API contract; replace the manual payload object and direct
coFetchJSON.post call with the shared helper installChartFromURL from
frontend/packages/helm-plugin/src/utils/helm-utils.ts: call
installChartFromURL({ namespace, releaseName, fullChartURL, chartVersion,
valuesObj, basicAuthSecretName, noRepo: true }) (map parameter names to the
helper's expected keys, ensuring basic_auth_secret_name and chart_version are
set by the helper) and use its returned promise instead of coFetchJSON.post to
avoid naming-convention eslint disables and drift.

In `@pkg/helm/actions/install_chart_test.go`:
- Around line 450-475: Add a negative test case to the install_chart tests that
uses the same OCI chart inputs but supplies a secret name that exists with a
malformed shape (missing the "username" and/or "password" keys) to validate
secret shape validation; update the table of test cases (the struct entries with
fields testName, releaseName, chartPath, chartName, chartVersion, plainHTTP,
skipTLSVerify, basicAuthSecretName, basicAuthUser, basicAuthPass, expectError)
by adding an entry named like "OCI chart with malformed auth secret" that points
basicAuthSecretName at the malformed secret and sets expectError=true so the
test ensures the code path in the install logic (where basic auth secret is
parsed/validated) rejects secrets missing "username"/"password".

In `@pkg/helm/actions/setup_test.go`:
- Around line 178-180: Replace the fixed 5s sleep before calling ExecuteScript
with a readiness polling helper (e.g., add waitForTCP(addr string, timeout
time.Duration)) and call it to wait for the OCI/basic-auth service TCP port to
become available; locate the test block containing time.Sleep(5 * time.Second)
and ExecuteScript("./testdata/uploadOciCharts.sh", ...) and swap the sleep for
waitForTCP("<host:port>", 30*time.Second) (or appropriate timeout) so the test
proceeds only after the service is reachable, returning any error from
waitForTCP instead of relying on a fixed delay.

In `@pkg/helm/handlers/handler_test.go`:
- Around line 204-205: The mock factory fakeInstallChartFromURL currently
accepts basicAuthSecretName but ignores it; modify the factory to take an
expectedBasicAuthSecretName (or capture it via closure) and assert the incoming
basicAuthSecretName equals that expected value inside the returned function
(using t.Fatalf/t.Errorf or testify require/assert) before proceeding to return
the fake secret/error; update tests that call fakeInstallChartFromURL to pass
the expected basicAuthSecretName so the mock will fail if the handler forwards
an incorrect value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 282a7534-9cff-4cf6-8313-2e7e319e10ea

📥 Commits

Reviewing files that changed from the base of the PR and between 1298e98 and 355844a.

📒 Files selected for processing (19)
  • frontend/packages/helm-plugin/locales/en/helm-plugin.json
  • frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartForm.tsx
  • frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartInstallPage.tsx
  • frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLInstallForm.tsx
  • frontend/packages/helm-plugin/src/components/forms/url-chart/types.ts
  • frontend/packages/helm-plugin/src/utils/helm-utils.ts
  • pkg/helm/actions/get_chart.go
  • pkg/helm/actions/get_registry.go
  • pkg/helm/actions/install_chart.go
  • pkg/helm/actions/install_chart_test.go
  • pkg/helm/actions/setup_test.go
  • pkg/helm/actions/testdata/htpasswd
  • pkg/helm/actions/testdata/uploadOciCharts.sh
  • pkg/helm/actions/testdata/zot-config-basicauth.json
  • pkg/helm/actions/testdata/zot-stop.sh
  • pkg/helm/actions/testdata/zotWithBasicAuth.sh
  • pkg/helm/handlers/handler_test.go
  • pkg/helm/handlers/handlers.go
  • pkg/helm/handlers/request.go
📜 Review details
🧰 Additional context used
🪛 Shellcheck (0.11.0)
pkg/helm/actions/testdata/zotWithBasicAuth.sh

[info] 8-8: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 8-8: Double quote to prevent globbing and word splitting.

(SC2086)

pkg/helm/actions/testdata/zot-stop.sh

[warning] 5-5: Quote this to prevent word splitting.

(SC2046)

🔇 Additional comments (16)
pkg/helm/actions/testdata/htpasswd (1)

1-1: Test fixture addition looks good.

This keeps the basic-auth test setup self-contained and reproducible.

pkg/helm/actions/get_registry.go (1)

15-31: Nice refactor and credential wiring.

Centralizing client option construction and reusing it for basic-auth client creation is clean and reduces drift risk.

Also applies to: 33-41, 47-52

frontend/packages/helm-plugin/src/components/forms/url-chart/types.ts (1)

9-9: Type extension is clean and backward-compatible.

Using an optional field here is the right choice for incremental rollout.

pkg/helm/actions/testdata/zot-config-basicauth.json (1)

1-19: Config setup for basic-auth Zot test instance looks good.

Dedicated port, storage root, and htpasswd path keep this fixture isolated from other registry test modes.

pkg/helm/handlers/request.go (1)

12-13: Good request-model extension for optional auth secret.

Line 12 and Line 13 are clear and align with the API payload naming used across handlers.

frontend/packages/helm-plugin/locales/en/helm-plugin.json (1)

127-132: i18n entries for secret selection look good.

These additions are clear and match the new URL install/authentication flow.

Also applies to: 139-139

frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLInstallForm.tsx (1)

149-159: Read-only Basic Auth Secret summary is wired correctly.

Line 149 to Line 159 cleanly exposes the selected secret in the confirm/configure form.

frontend/packages/helm-plugin/src/utils/helm-utils.ts (1)

353-360: Backward-compatible API payload update looks correct.

The optional parameter and conditional basic_auth_secret_name payload mapping are implemented cleanly.

Also applies to: 367-367

pkg/helm/handlers/handlers.go (3)

67-77: LGTM on signature updates.

The function signatures have been correctly extended to accept basicAuthSecretName as the final parameter, maintaining backward compatibility and consistent positioning across both installChartFromURL and getChartFromURL. Clean integration with the existing handler infrastructure.


161-169: Proper threading of basicAuthSecretName in async install flow.

The req.BasicAuthSecretName is correctly passed through to installChartFromURL for the NoRepo path. The HTTP status codes (400 for chart errors, 201 for success) are appropriate.


226-251: Good fix: namespace now used for action configuration.

Line 238 correctly uses the resolved namespace variable instead of a hardcoded "default" when building the action configuration. This ensures the correct namespace context when fetching secrets for basic auth. The basicAuthSecretName query parameter is properly extracted and forwarded.

frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartForm.tsx (2)

192-263: Well-implemented PatternFly 6 typeahead Select with good a11y coverage.

The Select component correctly implements:

  • PatternFly 6 patterns with MenuToggle + TextInputGroup for typeahead
  • Proper ARIA attributes (role="combobox", aria-controls, aria-label, isExpanded)
  • Loading and empty states with disabled options
  • Clear button with accessible label
  • Consistent i18n usage throughout

One minor a11y enhancement: consider adding aria-describedby linking to the helper text for screen readers.


80-94: Good UX: Focus management after selection/clear.

The textInputRef?.current?.focus() calls ensure keyboard users can continue typing after selecting or clearing, maintaining good focus management patterns.

pkg/helm/actions/install_chart.go (3)

262-283: Solid implementation of applyBasicAuthFromSecret.

Good defensive programming:

  • Early return for empty secret name
  • Wrapped errors with %w for proper error chaining
  • Clear, actionable error messages including namespace and secret name
  • Uses the existing username/password constants for key names (consistency with HelmChartRepository convention)

298-309: Correct handling of OCI registry client credentials.

Good catch on Helm's OCI getter behavior—it doesn't merge ChartPathOptions username/password onto an existing RegistryClient. Rebuilding the client with ClientOptBasicAuth is the right approach. The conditional check (basicAuthSecretName != "") correctly gates this to only when credentials are provided.


336-351: Async installation follows established patterns.

The goroutine implementation correctly:

  • Logs success/failure with contextual info
  • Creates error-tracking secret on failure
  • Cleans up error secret after 15-second delay
  • Records metrics on success

This aligns with the existing InstallChartAsync pattern.

Comment thread pkg/helm/actions/get_chart.go
Comment thread pkg/helm/actions/install_chart.go
Comment thread pkg/helm/actions/testdata/uploadOciCharts.sh
Comment thread pkg/helm/actions/testdata/zot-stop.sh Outdated
Comment thread pkg/helm/actions/testdata/zotWithBasicAuth.sh
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (4)
pkg/helm/actions/testdata/zot-stop.sh (1)

5-5: ⚠️ Potential issue | 🟡 Minor

Quote the PID substitution in kill.

Line 5 still uses unquoted command substitution ($(< zot-basicauth.pid)), which triggers ShellCheck SC2046 and can cause word-splitting/globbing surprises.

Suggested fix
-kill -TERM $(< zot-basicauth.pid) || echo "Zot (basic auth) is not currently running."
+kill -TERM "$(<zot-basicauth.pid)" || echo "Zot (basic auth) is not currently running."
#!/bin/bash
set -euo pipefail

# Verify current warning and validate fix result.
if command -v shellcheck >/dev/null 2>&1; then
  shellcheck pkg/helm/actions/testdata/zot-stop.sh
else
  rg -n 'kill -TERM \$\(<\s*zot-basicauth\.pid\)' pkg/helm/actions/testdata/zot-stop.sh
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/helm/actions/testdata/zot-stop.sh` at line 5, The kill invocation in
zot-stop.sh uses unquoted command substitution (kill -TERM $(<
zot-basicauth.pid)) which can trigger word-splitting/globbing; update the kill
call to use a quoted substitution or assign the PID to a variable and pass it
quoted (e.g., read the PID from zot-basicauth.pid into a variable and call kill
-TERM "$PID") while keeping the existing || echo fallback unchanged.
pkg/helm/actions/testdata/uploadOciCharts.sh (1)

24-38: ⚠️ Potential issue | 🟡 Minor

Reject unknown flags instead of silently defaulting to no-TLS mode.

Line 24-Line 38 still allows typoed flags to fall into default behavior, which hides setup mistakes.

Proposed fix
-# Push charts to OCI registry using helm push
-if [[ $1 == "--tls" ]]; then
-  REGISTRY="localhost:5443"
-  echo "Pushing mariadb-7.3.5.tgz to oci://$REGISTRY/helm-charts..."
-  $HELM push $CHARTS_DIR/mariadb-7.3.5.tgz oci://$REGISTRY/helm-charts --ca-file=$CACERT
-elif [[ $1 == "--basic-auth" ]]; then
-  REGISTRY="localhost:5001"
-  echo "Logging in to oci://$REGISTRY with basic auth..."
-  echo "hunter2" | $HELM registry login $REGISTRY --username AzureDiamond --password-stdin --plain-http
-  echo "Pushing mychart-0.1.0.tgz to oci://$REGISTRY/helm-charts..."
-  $HELM push $CHARTS_DIR/mychart-0.1.0.tgz oci://$REGISTRY/helm-charts --plain-http
-else
-  REGISTRY="localhost:5000"
-  echo "Pushing mychart-0.1.0.tgz to oci://$REGISTRY/helm-charts..."
-  $HELM push $CHARTS_DIR/mychart-0.1.0.tgz oci://$REGISTRY/helm-charts --plain-http
-fi
+mode="${1:---no-tls}"
+case "$mode" in
+  --tls)
+    REGISTRY="localhost:5443"
+    echo "Pushing mariadb-7.3.5.tgz to oci://$REGISTRY/helm-charts..."
+    $HELM push $CHARTS_DIR/mariadb-7.3.5.tgz oci://$REGISTRY/helm-charts --ca-file=$CACERT
+    ;;
+  --basic-auth)
+    REGISTRY="localhost:5001"
+    echo "Logging in to oci://$REGISTRY with basic auth..."
+    echo "hunter2" | $HELM registry login $REGISTRY --username AzureDiamond --password-stdin --plain-http
+    echo "Pushing mychart-0.1.0.tgz to oci://$REGISTRY/helm-charts..."
+    $HELM push $CHARTS_DIR/mychart-0.1.0.tgz oci://$REGISTRY/helm-charts --plain-http
+    ;;
+  --no-tls|"")
+    REGISTRY="localhost:5000"
+    echo "Pushing mychart-0.1.0.tgz to oci://$REGISTRY/helm-charts..."
+    $HELM push $CHARTS_DIR/mychart-0.1.0.tgz oci://$REGISTRY/helm-charts --plain-http
+    ;;
+  *)
+    echo "Usage: uploadOciCharts.sh --tls | --no-tls | --basic-auth" >&2
+    exit 2
+    ;;
+esac
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/helm/actions/testdata/uploadOciCharts.sh` around lines 24 - 38, The
script currently treats any unrecognized first argument ($1) as the no-TLS
default; change the conditional to explicitly validate allowed flags ("--tls"
and "--basic-auth") and make the else branch print a clear usage/error message
and exit non-zero instead of proceeding; reference the existing checks for
"--tls" and "--basic-auth" and the variables REGISTRY, $HELM and $CHARTS_DIR so
you update the conditional logic to reject unknown flags (echo "Usage: ... --tls
| --basic-auth" >&2; exit 1) before attempting any pushes.
pkg/helm/actions/testdata/zotWithBasicAuth.sh (1)

6-9: ⚠️ Potential issue | 🟠 Major

Use script-relative paths; current CWD-dependent paths are fragile.

Line 6, Line 8, and Line 9 still depend on caller working directory, so startup/pid placement can break outside repo root.

Proposed fix
 #!/bin/bash -e
 # Start zot OCI registry server with basic auth (htpasswd)
 GOOS=${GOOS:-$(go env GOOS)}
 GOARCH=${GOARCH:-$(go env GOARCH)}
+SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
+ACTIONS_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)"
 
-mkdir -p ./zot-storage-5001
+mkdir -p "$ACTIONS_DIR/zot-storage-5001"
 
-./$GOOS-$GOARCH/zot serve ./testdata/zot-config-basicauth.json &
-echo $! > ./zot-basicauth.pid
+"$ACTIONS_DIR/$GOOS-$GOARCH/zot" serve "$SCRIPT_DIR/zot-config-basicauth.json" &
+echo "$!" > "$ACTIONS_DIR/zot-basicauth.pid"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/helm/actions/testdata/zotWithBasicAuth.sh` around lines 6 - 9, The script
uses relative paths for the storage dir, config, binary and PID file (mkdir -p
./zot-storage-5001, ./$GOOS-$GOARCH/zot serve
./testdata/zot-config-basicauth.json &, echo $! > ./zot-basicauth.pid) which
breaks when run outside the repo root; modify the script to compute the script
directory (e.g. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" or
equivalent) and then replace those relative paths with absolute paths prefixed
by that directory (use "$SCRIPT_DIR"/zot-storage-5001,
"$SCRIPT_DIR"/$GOOS-$GOARCH/zot,
"$SCRIPT_DIR"/testdata/zot-config-basicauth.json, and
"$SCRIPT_DIR"/zot-basicauth.pid) so startup and PID placement are
script-location independent.
pkg/helm/actions/get_chart.go (1)

78-84: ⚠️ Potential issue | 🟠 Major

Only create an OCI registry client for oci:// sources.

Line 78 still builds a Helm registry client for any authenticated URL. For direct http(s) archives, LocateChart can use cmd.Username / cmd.Password directly, so this adds an avoidable failure path unrelated to the requested chart source.

Proposed fix
 import (
 	"fmt"
 	"os"
+	"strings"
@@
-	if basicAuthSecretName != "" {
+	if basicAuthSecretName != "" && strings.HasPrefix(strings.ToLower(url), "oci://") {
 		rc, err := RegistryClientWithBasicAuth(false, false, cmd.Username, cmd.Password)
 		if err != nil {
 			return nil, fmt.Errorf("failed to configure OCI registry client: %w", err)
 		}
 		cmd.SetRegistryClient(rc)
 	}
🧹 Nitpick comments (4)
pkg/helm/handlers/handler_test.go (1)

204-205: Strengthen test helper by asserting basicAuthSecretName propagation.

The new parameter is accepted but not validated, so handler wiring regressions could pass unnoticed. Please assert the expected value in the fake used by the no-repo install tests.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/helm/handlers/handler_test.go` around lines 204 - 205, Update the
fakeInstallChartFromURL test helper to validate the propagated
basicAuthSecretName: change fakeInstallChartFromURL signature to accept an
expectedBasicAuthSecretName string (in addition to mockedSecret and err) and
inside the returned func assert that the incoming basicAuthSecretName equals
expectedBasicAuthSecretName (use the test helper's t/require/fatal to fail if
not). This ensures the returned fake (fakeInstallChartFromURL) checks the
basicAuthSecretName parameter passed into the handler wiring.
pkg/helm/actions/setup_test.go (1)

107-109: Replace fixed sleep with TCP readiness polling to reduce CI flakiness.

The setupTestOCIBasicAuth() function (line 178) uses a hardcoded 5-second delay before uploading OCI charts. Since zotWithBasicAuth.sh starts the registry in the background without readiness signaling, slow startup times in CI can cause intermittent failures. Polling the registry port is more reliable.

Suggested implementation
 import (
 	"fmt"
 	"io/ioutil"
+	"net"
 	"os"
 	"os/exec"
 	"regexp"
 	"runtime/debug"
 	"strings"
 	"testing"
 	"time"
@@
 func setupTestOCIBasicAuth() error {
 	if err := ExecuteScript("./testdata/zotWithBasicAuth.sh", false); err != nil {
 		return err
 	}
-	time.Sleep(5 * time.Second)
+	if err := waitForTCP("127.0.0.1:5001", 30*time.Second); err != nil {
+		return err
+	}
 	if err := ExecuteScript("./testdata/uploadOciCharts.sh", true, "--basic-auth"); err != nil {
 		return err
 	}
 	return nil
 }
+
+func waitForTCP(addr string, timeout time.Duration) error {
+	deadline := time.Now().Add(timeout)
+	for time.Now().Before(deadline) {
+		conn, err := net.DialTimeout("tcp", addr, 1*time.Second)
+		if err == nil {
+			_ = conn.Close()
+			return nil
+		}
+		time.Sleep(250 * time.Millisecond)
+	}
+	return fmt.Errorf("timed out waiting for %s", addr)
+}

Note: Similar patterns exist in setupTestWithTls(), setupTestWithoutTls(), and setupTestBasicAuth() that could benefit from the same treatment.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/helm/actions/setup_test.go` around lines 107 - 109, The test setup uses a
fixed sleep in setupTestOCIBasicAuth (and similarly in setupTestWithTls,
setupTestWithoutTls, setupTestBasicAuth) which causes CI flakiness; replace the
hardcoded time.Sleep with a TCP readiness poll that repeatedly dials the
registry address/port (with a short backoff and an overall timeout) and only
proceeds to upload OCI charts once the TCP connection succeeds, failing the
setup if the timeout elapses; implement this polling logic inside
setupTestOCIBasicAuth (and mirror into the other setup* functions) so the upload
occurs after a successful dial rather than after a fixed delay.
frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartInstallPage.tsx (1)

78-85: Prefer URLSearchParams over manual query-string concatenation.

The current string assembly is brittle and harder to maintain as params grow.

Proposed refactor
-        let authParam = '';
-        if (basicAuthSecretName) {
-          authParam = `&basic_auth_secret_name=${encodeURIComponent(basicAuthSecretName)}`;
-        }
-        const apiUrl = `/api/helm/chart?url=${encodeURIComponent(
-          fullChartURL,
-        )}&noRepo=true&namespace=${namespace}${authParam}`;
+        const params = new URLSearchParams({
+          url: fullChartURL,
+          noRepo: 'true',
+          namespace: namespace ?? '',
+        });
+        if (basicAuthSecretName) {
+          params.set('basic_auth_secret_name', basicAuthSecretName);
+        }
+        const apiUrl = `/api/helm/chart?${params.toString()}`;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartInstallPage.tsx`
around lines 78 - 85, The current apiUrl assembly using string concatenation
(variables authParam, basicAuthSecretName, fullChartURL, namespace, and apiUrl)
is brittle; replace it with URLSearchParams: create a params = new
URLSearchParams(), set url=fullChartURL, noRepo=true, namespace=namespace, and
conditionally set basic_auth_secret_name when basicAuthSecretName is present,
then build apiUrl = `/api/helm/chart?${params.toString()}` so encoding is
handled automatically and the code is easier to extend and maintain.
pkg/helm/actions/install_chart_test.go (1)

450-475: Add one malformed-secret test case to lock key-contract behavior.

You now cover valid creds and wrong creds; consider adding a case where the referenced secret is present but missing username or password, and assert an error.

Also applies to: 491-502

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/helm/actions/install_chart_test.go` around lines 450 - 475, Add a test
case to the table that exercises a malformed basic-auth secret (present but
missing either the username or password key) and expect the install to fail;
e.g. add an entry similar to the existing OCI cases with basicAuthSecretName:
"malformed-auth-secret", set one of basicAuthUser or basicAuthPass empty (or
both) and expectError: true, and ensure the test harness/fixture that creates
secrets for tests creates a secret with the missing key for
"malformed-auth-secret"; repeat the same malformed-secret case in the other test
table referenced around the second block (the section you noted at 491-502) so
both places assert an error when the secret is missing username/password.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartForm.tsx`:
- Around line 54-59: The secret watch currently only destructures two return
values from useK8sWatchResource (const [secrets, secretsLoaded] =
useK8sWatchResource<SecretKind[]>()), which hides watch errors and makes
RBAC/network failures look like “no matching secrets”; update the destructuring
to capture the third return value (e.g., const [secrets, secretsLoaded,
secretsError] = useK8sWatchResource<SecretKind[]>()), then add explicit handling
in HelmURLChartForm to check secretsError and render a clear error state/message
(instead of or alongside the empty-state UI) so users see
permission/network/watch failures; repeat the same change for the other secret
watch instance currently around the later block that uses the same hook.

In `@pkg/helm/actions/install_chart.go`:
- Around line 303-309: The code always creates an OCI registry client when
basicAuthSecretName is set, causing failures for non-OCI (plain http(s) chart
archive) installs; change the logic so RegistryClientWithBasicAuth is only
called for OCI installs by adding a guard that detects OCI installs (e.g., check
the chart reference/URL or an existing isOCI flag for this install) before
invoking RegistryClientWithBasicAuth and before calling cmd.SetRegistryClient;
keep the same error handling but skip creating/setting the registry client when
the install is not OCI (use basicAuthSecretName, RegistryClientWithBasicAuth,
and cmd.SetRegistryClient to locate where to apply the conditional).

---

Duplicate comments:
In `@pkg/helm/actions/testdata/uploadOciCharts.sh`:
- Around line 24-38: The script currently treats any unrecognized first argument
($1) as the no-TLS default; change the conditional to explicitly validate
allowed flags ("--tls" and "--basic-auth") and make the else branch print a
clear usage/error message and exit non-zero instead of proceeding; reference the
existing checks for "--tls" and "--basic-auth" and the variables REGISTRY, $HELM
and $CHARTS_DIR so you update the conditional logic to reject unknown flags
(echo "Usage: ... --tls | --basic-auth" >&2; exit 1) before attempting any
pushes.

In `@pkg/helm/actions/testdata/zot-stop.sh`:
- Line 5: The kill invocation in zot-stop.sh uses unquoted command substitution
(kill -TERM $(< zot-basicauth.pid)) which can trigger word-splitting/globbing;
update the kill call to use a quoted substitution or assign the PID to a
variable and pass it quoted (e.g., read the PID from zot-basicauth.pid into a
variable and call kill -TERM "$PID") while keeping the existing || echo fallback
unchanged.

In `@pkg/helm/actions/testdata/zotWithBasicAuth.sh`:
- Around line 6-9: The script uses relative paths for the storage dir, config,
binary and PID file (mkdir -p ./zot-storage-5001, ./$GOOS-$GOARCH/zot serve
./testdata/zot-config-basicauth.json &, echo $! > ./zot-basicauth.pid) which
breaks when run outside the repo root; modify the script to compute the script
directory (e.g. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" or
equivalent) and then replace those relative paths with absolute paths prefixed
by that directory (use "$SCRIPT_DIR"/zot-storage-5001,
"$SCRIPT_DIR"/$GOOS-$GOARCH/zot,
"$SCRIPT_DIR"/testdata/zot-config-basicauth.json, and
"$SCRIPT_DIR"/zot-basicauth.pid) so startup and PID placement are
script-location independent.

---

Nitpick comments:
In
`@frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartInstallPage.tsx`:
- Around line 78-85: The current apiUrl assembly using string concatenation
(variables authParam, basicAuthSecretName, fullChartURL, namespace, and apiUrl)
is brittle; replace it with URLSearchParams: create a params = new
URLSearchParams(), set url=fullChartURL, noRepo=true, namespace=namespace, and
conditionally set basic_auth_secret_name when basicAuthSecretName is present,
then build apiUrl = `/api/helm/chart?${params.toString()}` so encoding is
handled automatically and the code is easier to extend and maintain.

In `@pkg/helm/actions/install_chart_test.go`:
- Around line 450-475: Add a test case to the table that exercises a malformed
basic-auth secret (present but missing either the username or password key) and
expect the install to fail; e.g. add an entry similar to the existing OCI cases
with basicAuthSecretName: "malformed-auth-secret", set one of basicAuthUser or
basicAuthPass empty (or both) and expectError: true, and ensure the test
harness/fixture that creates secrets for tests creates a secret with the missing
key for "malformed-auth-secret"; repeat the same malformed-secret case in the
other test table referenced around the second block (the section you noted at
491-502) so both places assert an error when the secret is missing
username/password.

In `@pkg/helm/actions/setup_test.go`:
- Around line 107-109: The test setup uses a fixed sleep in
setupTestOCIBasicAuth (and similarly in setupTestWithTls, setupTestWithoutTls,
setupTestBasicAuth) which causes CI flakiness; replace the hardcoded time.Sleep
with a TCP readiness poll that repeatedly dials the registry address/port (with
a short backoff and an overall timeout) and only proceeds to upload OCI charts
once the TCP connection succeeds, failing the setup if the timeout elapses;
implement this polling logic inside setupTestOCIBasicAuth (and mirror into the
other setup* functions) so the upload occurs after a successful dial rather than
after a fixed delay.

In `@pkg/helm/handlers/handler_test.go`:
- Around line 204-205: Update the fakeInstallChartFromURL test helper to
validate the propagated basicAuthSecretName: change fakeInstallChartFromURL
signature to accept an expectedBasicAuthSecretName string (in addition to
mockedSecret and err) and inside the returned func assert that the incoming
basicAuthSecretName equals expectedBasicAuthSecretName (use the test helper's
t/require/fatal to fail if not). This ensures the returned fake
(fakeInstallChartFromURL) checks the basicAuthSecretName parameter passed into
the handler wiring.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: f68dfb6b-c9c5-4f6d-93ed-2b42a181fc57

📥 Commits

Reviewing files that changed from the base of the PR and between 1298e98 and 355844a.

📒 Files selected for processing (19)
  • frontend/packages/helm-plugin/locales/en/helm-plugin.json
  • frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartForm.tsx
  • frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartInstallPage.tsx
  • frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLInstallForm.tsx
  • frontend/packages/helm-plugin/src/components/forms/url-chart/types.ts
  • frontend/packages/helm-plugin/src/utils/helm-utils.ts
  • pkg/helm/actions/get_chart.go
  • pkg/helm/actions/get_registry.go
  • pkg/helm/actions/install_chart.go
  • pkg/helm/actions/install_chart_test.go
  • pkg/helm/actions/setup_test.go
  • pkg/helm/actions/testdata/htpasswd
  • pkg/helm/actions/testdata/uploadOciCharts.sh
  • pkg/helm/actions/testdata/zot-config-basicauth.json
  • pkg/helm/actions/testdata/zot-stop.sh
  • pkg/helm/actions/testdata/zotWithBasicAuth.sh
  • pkg/helm/handlers/handler_test.go
  • pkg/helm/handlers/handlers.go
  • pkg/helm/handlers/request.go
📜 Review details
🧰 Additional context used
🪛 Shellcheck (0.11.0)
pkg/helm/actions/testdata/zotWithBasicAuth.sh

[info] 8-8: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 8-8: Double quote to prevent globbing and word splitting.

(SC2086)

pkg/helm/actions/testdata/zot-stop.sh

[warning] 5-5: Quote this to prevent word splitting.

(SC2046)

🔇 Additional comments (11)
pkg/helm/actions/testdata/htpasswd (1)

1-1: Looks good for test fixture usage.

The added htpasswd entry is appropriate for the new basic-auth test flow.

pkg/helm/actions/testdata/zot-stop.sh (1)

6-6: Good cleanup update.

Including zot-basicauth.pid in the teardown cleanup is the right addition.

frontend/packages/helm-plugin/src/components/forms/url-chart/types.ts (1)

9-9: Type shape change is clean and backward-compatible.

basicAuthSecretName being optional is the right choice for existing URL chart flows.

pkg/helm/actions/testdata/zot-config-basicauth.json (1)

1-19: Config wiring looks consistent for the new basic-auth test registry.

Address, port, auth backend, and storage isolation are aligned with the companion test scripts.

frontend/packages/helm-plugin/locales/en/helm-plugin.json (1)

127-132: i18n additions are complete for the new secret-selection UX.

Nice coverage of label, CTA text, loading/empty states, and install-summary label.

Also applies to: 139-139

pkg/helm/handlers/request.go (1)

12-13: Request model update is clear and API-compatible.

The optional basic_auth_secret_name field and inline doc make the contract explicit for URL-based installs.

frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLInstallForm.tsx (1)

149-159: Good conditional read-only rendering for selected auth secret.

This is a clean way to surface the selected secret in the summary/configure step without allowing accidental edits.

frontend/packages/helm-plugin/src/utils/helm-utils.ts (1)

353-368: Nice backward-compatible extension of install payload.

Optional basic_auth_secret_name is threaded cleanly without affecting existing callers.

pkg/helm/handlers/handlers.go (1)

67-76: No concerns on handler-side secret propagation.

The no-repo flow consistently threads basic_auth_secret_name through request parsing and action invocation.

Also applies to: 162-163, 232-252, 471-471

pkg/helm/actions/get_registry.go (1)

15-57: Nice consolidation of registry client setup.

Centralizing the TLS/plain-HTTP options keeps the default and basic-auth OCI client paths aligned and reduces drift between them.

pkg/helm/actions/install_chart.go (1)

262-283: Good helper extraction for Secret-backed auth.

Pulling the Secret lookup and key validation into one helper keeps the URL install/get flows consistent and gives clear errors when the Secret is malformed.

Comment thread frontend/packages/helm-plugin/src/components/forms/url-chart/HelmURLChartForm.tsx Outdated
Comment thread pkg/helm/actions/install_chart.go
@webbnh
Copy link
Copy Markdown
Contributor

webbnh commented Apr 30, 2026

/retest

- Add basicAuthSecretName parameter to GetChartFromURL and InstallChartFromURL
- Build RegistryClient with basic auth credentials for OCI registry pulls
- Extract shared registryClientOptions from GetOCIRegistry for reuse
- Add applyBasicAuthFromSecret helper to read credentials from K8s Secret
- Strip OCI version tags before LocateChart to prevent duplicate tag errors
- Wire basic_auth_secret_name through HandleChartGet and HandleHelmInstallAsync
- Add OCI basic auth test cases with zot registry and htpasswd auth
@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 1, 2026
    - Add typeahead secret dropdown to HelmURLChartForm
    - Surface errors for invalid secrets with explanatory description
    - Pass basicAuthSecretName through fetchChartData and install API calls
    - Append namespace and basic_auth_secret_name to chart fetch query string
    - Display selected secret as read-only field on the install confirmation step
    - Add basicAuthSecretName to HelmURLChartFormData type and helm-utils
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 1, 2026
@sowmya-sl
Copy link
Copy Markdown
Contributor Author

/retest

…stallForm

- Remove stale useTheme import that caused TS6133 build error
- Drop theme property from useHelmReadmeModalLauncher (not in Props type)
- Pass namespace to HelmURLInstallForm for ResourceDropdownField
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 1, 2026

@sowmya-sl: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Copy link
Copy Markdown
Contributor

@webbnh webbnh left a comment

Choose a reason for hiding this comment

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

Looks generally good. I have a bunch of polishing suggestions for you. Also, you should look at CodeRabbit's nitpick suggestions and see if any are appropriate to fix (it came up with the same test concern that I did).

Also, it would be good to update the description with fresh screenshots, since you've changed the selector.

Comment on lines +78 to +81
let authParam = '';
if (basicAuthSecretName) {
authParam = `&basic_auth_secret_name=${encodeURIComponent(basicAuthSecretName)}`;
}
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.

Alternatively, I believe you can use a ternary,

Suggested change
let authParam = '';
if (basicAuthSecretName) {
authParam = `&basic_auth_secret_name=${encodeURIComponent(basicAuthSecretName)}`;
}
const authParam = basicAuthSecretName ? `&basic_auth_secret_name=${encodeURIComponent(basicAuthSecretName)}` : '';

which avoids the need for using let.

Comment on lines +82 to +84
const apiUrl = `/api/helm/chart?url=${encodeURIComponent(
fullChartURL,
)}&noRepo=true&namespace=${namespace}${authParam}`;
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.

This might be prettier if you went ahead and used one more local variable:

Suggested change
const apiUrl = `/api/helm/chart?url=${encodeURIComponent(
fullChartURL,
)}&noRepo=true&namespace=${namespace}${authParam}`;
const urlParam = encodeURIComponent(fullChartURL)
const apiUrl = `/api/helm/chart?url=${urlParam}&noRepo=true&namespace=${namespace}${authParam}`;

Comment on lines +161 to +162
name="basicAuthSecretName"
label={t('helm-plugin~Secret for basic authentication.')}
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.

The label at HelmURLInstallForm.tsx line 185 doesn't have a trailing period...should we remove the one here?

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.

These changes seem very similar to the ones in HelmURLChartForm.tsx, would it be appropriate to refactor these into common code?

Comment on lines +36 to +37
echo "Logging in to oci://$REGISTRY with basic auth..."
echo "hunter2" | $HELM registry login $REGISTRY --username AzureDiamond --password-stdin --plain-http
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.

Given that you're hard-coding the password into the script, you might as well put it on the command line and save the pipe-gymnastics:

Suggested change
echo "Logging in to oci://$REGISTRY with basic auth..."
echo "hunter2" | $HELM registry login $REGISTRY --username AzureDiamond --password-stdin --plain-http
echo "Logging in to oci://$REGISTRY with basic auth..."
$HELM registry login $REGISTRY --username AzureDiamond --password "hunter2" --plain-http

Comment on lines +262 to +264
// applyBasicAuthFromSecret sets cmd.Username and cmd.Password from a Secret in ns with
// keys "username" and "password" (same convention as HelmChartRepository connectionConfig).
func applyBasicAuthFromSecret(cmd *action.Install, coreClient corev1client.CoreV1Interface, ns, secretName string) error {
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.

This function seems like it should be a method receiving a *action.Install. Is that feasible?

Comment on lines +451 to +452
{
testName: "OCI chart with basic auth",
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.

What about HTTP(S) chart with basic auth? (And, if that is feasible, what about the same with wrong credentials?)

Comment on lines +459 to +461
basicAuthSecretName: "oci-auth-secret",
basicAuthUser: "AzureDiamond",
basicAuthPass: "hunter2",
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.

What about a malformed secrets? (I.e., ones missing the username, password, or both.)

Comment on lines +508 to 510
rel, err := InstallChartFromURL("test-namespace", tt.releaseName, tt.chartPath, nil, actionConfig, coreClient, tt.chartVersion, tt.basicAuthSecretName)
require.Error(t, err)
require.Nil(t, rel)
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.

Simply requiring "an error" is a very weak assertion, one which could result if a false positive if the test fails for the wrong reason (i.e., if there's a bug in the test). Can we do better, here? (E.g., if expectError is a pointer to an error or a string, instead of a boolean, then, if it is non-nil/empty, we can check for the correct error.)

Comment on lines -473 to -474
// For valid URLs: create the release secret in a background goroutine
// to simulate what Helm's cmd.Run would do, unblocking getSecret's Watch.
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.

Was this explanation wrong? If not, it seems like it would be good to have an explanation of why we're using a goroutine instead of doing this synchronously.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/backend Related to backend component/helm Related to helm-plugin jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. kind/i18n Indicates issue or PR relates to internationalization or has content that needs to be translated

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants