Skip to content

feat: typed credentials for Helm binding (Phase 2)#2408

Merged
matthiasbruns merged 31 commits into
open-component-model:mainfrom
matthiasbruns:feat/704_typed_credential_helm
May 15, 2026
Merged

feat: typed credentials for Helm binding (Phase 2)#2408
matthiasbruns merged 31 commits into
open-component-model:mainfrom
matthiasbruns:feat/704_typed_credential_helm

Conversation

@matthiasbruns

@matthiasbruns matthiasbruns commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

What this PR does / why we need it

Phase 2 typed helm bindings ADR

Which issue(s) this PR fixes

Contributes: open-component-model/ocm-project#988

You can see the whole picture in #2148

Testing

How to test the changes

I ran task init/go.work with the updated credentials binding to see if the update breaks ocm - it does not :)

Verification
  • I have added/updated tests for my changes (see Test Requirements)
  • Tests pass locally (task test and task test/integration if applicable)
  • My changes do not decrease test coverage

@matthiasbruns matthiasbruns requested a review from a team as a code owner April 29, 2026 07:13
@netlify

netlify Bot commented Apr 29, 2026

Copy link
Copy Markdown

Deploy Preview for ocm-website ready!

Name Link
🔨 Latest commit dad79fc
🔍 Latest deploy log https://app.netlify.com/projects/ocm-website/deploys/6a049db6644eda00092ccac2
😎 Deploy Preview https://deploy-preview-2408--ocm-website.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added the kind/feature new feature, enhancement, improvement, extension label Apr 29, 2026
@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces untyped map-based Helm HTTP credentials and legacy consumer identity usage with typed HelmHTTPCredentials/v1 and HelmChartRepositoryIdentity/v1 across the Helm Go bindings; adds schemas, generated helpers, conversion utilities, wiring changes in download/input/digest/transformation layers, and tests adapting to typed credentials.

Changes

Typed Helm Credentials & Identity Migration

Layer / File(s) Summary
Data Shape / Types
bindings/go/helm/spec/credentials/v1/helm_credentials.go, bindings/go/helm/spec/identity/v1/type.go
Adds HelmHTTPCredentials and HelmChartRepositoryIdentity types, version constants, and legacy key constants.
Schema / Generated Support
bindings/go/helm/spec/**/schemas/*.schema.json, bindings/go/helm/spec/**/zz_generated.*
Adds JSON schemas and autogenerated deepcopy, type accessors, and JSONSchema embed methods for credentials and identity v1.
Registration Helpers & Tests
bindings/go/helm/spec/identity/v1/register.go, bindings/go/helm/spec/credentials/v1/helm_credentials_test.go, bindings/go/helm/spec/identity/v1/type_test.go
Adds MustRegister* helpers and tests verifying registration and scheme conversions.
Credential Conversion Utility
bindings/go/helm/transformation/credentials.go, bindings/go/helm/transformation/credentials_test.go
Introduces resolveCredentialsMap that calls ResolveTyped and converts typed credentials (HelmHTTPCredentials, DirectCredentials) into legacy map[string]string for downstream consumers; adds unit tests.
Download Layer Plumbing
bindings/go/helm/internal/download/options.go, bindings/go/helm/internal/download/download.go, bindings/go/helm/internal/download/tls.go, bindings/go/helm/internal/download/download_test.go, bindings/go/helm/internal/download/doc.go
Switches download options and TLS helpers to accept *helmcredsv1.HelmHTTPCredentials, reads username/password/cert/key/keyring from struct fields, updates keyring/verify logic, adapts tests and docs; deprecates prior string-key constants as aliases.
Input & Resource Wiring
bindings/go/helm/input/blob.go, bindings/go/helm/input/method.go, bindings/go/helm/repository/resource/resource_repository.go
Updates WithCredentials signatures and call sites to accept typed credentials; converts legacy map[string]string via FromDirectCredentials where interface boundaries still use maps; switches consumer identity calls to compatibility helpers.
Digest & Consumer Identity
bindings/go/helm/digest/digest.go, bindings/go/helm/internal/credentials.go
Digest resolution now converts legacy maps to typed credential structs and accepts typed credential parameters; CredentialConsumerIdentity now returns runtime.Typed using versioned identity types and a CredentialConsumerIdentityCompat wrapper returns legacy runtime.Identity.
Integration / Tests / Manifests
bindings/go/helm/*_test.go, bindings/go/helm/go.mod, bindings/go/examples/*
Updates tests/imports to typed credentials and identity packages; bumps several module dependencies in go.mod files.

Sequence Diagram

sequenceDiagram
    participant Consumer as Consumer
    participant Input as Input Layer
    participant Resolver as Credential Resolver
    participant Conv as Transformation
    participant Download as Download Layer
    participant TLS as TLS/Auth

    Consumer->>Input: Request resource with legacy credentials (map)
    Input->>Conv: FromDirectCredentials(map) → *HelmHTTPCredentials
    Input->>Resolver: ResolveTyped(consumerIdentity)
    Resolver-->>Input: runtime.Typed credentials (HelmHTTPCredentials / DirectCredentials)
    Conv->>Download: WithCredentials(*HelmHTTPCredentials)
    Download->>Download: read Credentials.Username / Password / Keyring / CertFile / KeyFile
    Download->>TLS: constructTLSOptions(CertFile, KeyFile)
    TLS-->>Download: TLS config
    Download-->>Input: fetched chart blob
    Input-->>Consumer: returned Helm blob
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • frewilhelm
  • fabianburth
  • jakobmoellerdev
  • Skarlso

Poem

🐰 I swapped loose maps for fields so neat,
Username, certs, and keyring in their seat.
Typed credentials hop in single file,
Charts fetched tidy, every byte with style.
Rabbit cheers the migration—what a feat!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.21% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: typed credentials for Helm binding (Phase 2)' directly describes the main feature being implemented - typed credentials for Helm bindings in Phase 2 per ADR 0018.
Linked Issues check ✅ Passed The PR addresses issue #988 requirements: introduces typed credentials (HelmHTTPCredentials/v1), updates API to use runtime.Typed, registers identity types, includes comprehensive tests, and documents changes with migration TODOs.
Out of Scope Changes check ✅ Passed All changes are scoped to Helm binding typed credentials implementation: new credential/identity types, credential handling updates, import adjustments, examples, and related tests. No unrelated changes detected.
Description check ✅ Passed The PR description is directly related to the changeset. It explains the Phase 2 typed Helm bindings ADR implementation, references the linked issue #988, and describes the testing approach.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

@matthiasbruns matthiasbruns marked this pull request as draft April 29, 2026 07:13
@github-actions github-actions Bot added the size/l Large label Apr 29, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
bindings/go/helm/internal/download/options.go (1)

94-99: ⚠️ Potential issue | 🟡 Minor

Update outdated documentation example in doc.go.

The doc.go file shows an example using the legacy map[string]string signature for WithCredentials, which no longer matches the current implementation. The documentation at lines 21-28 should be updated to reflect that WithCredentials now requires *helmcredsv1.HelmHTTPCredentials (typically created via helmcredsv1.FromDirectCredentials(...)).

The actual codebase call site in resource_repository.go:104 is correctly updated to the typed credentials. Update only the documentation example to be current.

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

In `@bindings/go/helm/internal/download/options.go` around lines 94 - 99, The doc
example in doc.go is outdated: update the example that calls WithCredentials to
pass a *helmcredsv1.HelmHTTPCredentials instance (created via
helmcredsv1.FromDirectCredentials(...) or equivalent) instead of a legacy
map[string]string; locate the WithCredentials usage in the documentation and
replace the map literal with code that constructs typed credentials (referencing
WithCredentials and helmcredsv1.FromDirectCredentials to mirror the
implementation used in resource_repository.go).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bindings/go/helm/internal/download/tls.go`:
- Around line 75-89: The cert/key existence checks in the TLS setup (when
opt.Credentials is used) currently treat any os.Stat error as "does not exist";
update the blocks that handle opt.Credentials.CertFile and
opt.Credentials.KeyFile to distinguish not-found from other errors by using
os.IsNotExist(err): if os.IsNotExist(err) return a clear "does not exist" error
for certFile/keyFile, otherwise wrap and return the original os.Stat error
(e.g., using fmt.Errorf with %w) so permission/IO errors are preserved and
surfaced.

---

Outside diff comments:
In `@bindings/go/helm/internal/download/options.go`:
- Around line 94-99: The doc example in doc.go is outdated: update the example
that calls WithCredentials to pass a *helmcredsv1.HelmHTTPCredentials instance
(created via helmcredsv1.FromDirectCredentials(...) or equivalent) instead of a
legacy map[string]string; locate the WithCredentials usage in the documentation
and replace the map literal with code that constructs typed credentials
(referencing WithCredentials and helmcredsv1.FromDirectCredentials to mirror the
implementation used in resource_repository.go).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 257abb92-23e2-4d77-9d02-5b8e32eac157

📥 Commits

Reviewing files that changed from the base of the PR and between eaae334 and 00b5c2e.

⛔ Files ignored due to path filters (1)
  • bindings/go/helm/go.sum is excluded by !**/*.sum
📒 Files selected for processing (20)
  • bindings/go/helm/go.mod
  • bindings/go/helm/input/blob.go
  • bindings/go/helm/internal/download/download.go
  • bindings/go/helm/internal/download/download_test.go
  • bindings/go/helm/internal/download/options.go
  • bindings/go/helm/internal/download/tls.go
  • bindings/go/helm/repository/resource/resource_repository.go
  • bindings/go/helm/spec/credentials/identity/v1/register.go
  • bindings/go/helm/spec/credentials/identity/v1/schemas/HelmChartRepositoryIdentity.schema.json
  • bindings/go/helm/spec/credentials/identity/v1/type.go
  • bindings/go/helm/spec/credentials/identity/v1/type_test.go
  • bindings/go/helm/spec/credentials/identity/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/credentials/identity/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/credentials/identity/v1/zz_generated.ocm_type.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials_test.go
  • bindings/go/helm/spec/credentials/v1/schemas/HelmHTTPCredentials.schema.json
  • bindings/go/helm/spec/credentials/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_type.go

Comment thread bindings/go/helm/internal/download/tls.go
@matthiasbruns matthiasbruns force-pushed the feat/704_typed_credential_helm branch 2 times, most recently from 927b18d to 30604e3 Compare April 30, 2026 18:16
@matthiasbruns

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (3)
bindings/go/helm/spec/identity/v1/register.go (1)

1-11: Add a parent-package scheme.go with init() for auto-registration to align with the established pattern in access and input packages.

The access and input packages in the Helm spec tree both expose a package-level Scheme variable and auto-register their types in init(). The identity package only exposes MustRegisterIdentityType() without a parent scheme.go that calls it on import. This divergence means callers must explicitly invoke the function or risk their scheme lacking the identity type, which can silently break typed credential resolution at runtime.

✨ Suggested `scheme.go` (analogous to spec/access/scheme.go)
+// bindings/go/helm/spec/identity/scheme.go
+package identity
+
+import (
+	v1 "ocm.software/open-component-model/bindings/go/helm/spec/identity/v1"
+	"ocm.software/open-component-model/bindings/go/runtime"
+)
+
+var Scheme = runtime.NewScheme()
+
+func init() {
+	v1.MustRegisterIdentityType(Scheme)
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/helm/spec/identity/v1/register.go` around lines 1 - 11, The
identity package currently only exposes MustRegisterIdentityType and lacks a
package-level auto-registration like access/input; add a new parent package file
(e.g., scheme.go) in the identity package that declares a package-level Scheme
variable and an init() which calls MustRegisterIdentityType(Scheme) so
HelmChartRepositoryIdentity (and its VersionedType/Type aliases) are
auto-registered on import; ensure the variable name and init pattern match the
established pattern used by spec/access and spec/input.
bindings/go/helm/transformation/credentials_test.go (1)

93-117: ⚡ Quick win

Missing test case: ResolveTyped returning (nil, nil).

The test suite doesn't cover the path where ResolveTyped succeeds with a nil typed value and no error — the exact gap described in the resolveCredentialsMap review comment above. Adding this case would document and lock in the expected nil, nil return.

🧪 Suggested additional test
func TestResolveCredentialsMap_NilTyped(t *testing.T) {
    resolver := &stubResolver{typed: nil, err: nil}

    creds, err := resolveCredentialsMap(t.Context(), resolver, runtime.Identity{"type": "HelmChartRepository"})
    require.NoError(t, err)
    assert.Nil(t, creds, "nil typed with no error should be treated as no credentials")
}

This test will currently fail (revealing the missing nil guard in resolveCredentialsMap) and pass once the case nil: arm is added.

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

In `@bindings/go/helm/transformation/credentials_test.go` around lines 93 - 117,
Add a unit test covering the path where ResolveTyped returns (nil, nil): create
a stubResolver with typed: nil and err: nil, call
resolveCredentialsMap(t.Context(), resolver,
runtime.Identity{"type":"HelmChartRepository"}), and assert no error and creds
== nil; this documents and locks in the expected behavior for
resolveCredentialsMap when the resolver returns a nil typed value and no error.
bindings/go/helm/input/method.go (1)

12-12: 💤 Low value

Misleading import alias: v2 for a /v1 package.

Every other file in this PR imports bindings/go/helm/spec/credentials/v1 as helmcredsv1 (e.g., digest.go, blob.go). Using v2 here contradicts both the package path and the rest of the codebase.

♻️ Proposed fix
-	v2 "ocm.software/open-component-model/bindings/go/helm/spec/credentials/v1"
+	helmcredsv1 "ocm.software/open-component-model/bindings/go/helm/spec/credentials/v1"

And update the usage on line 84:

-	helmBlob, chart, err := GetV1HelmBlob(ctx, helm, i.TempFolder, WithCredentials(v2.FromDirectCredentials(credentials)))
+	helmBlob, chart, err := GetV1HelmBlob(ctx, helm, i.TempFolder, WithCredentials(helmcredsv1.FromDirectCredentials(credentials)))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/helm/input/method.go` at line 12, The import alias "v2" for the
package "ocm.software/open-component-model/bindings/go/helm/spec/credentials/v1"
is misleading and inconsistent; change the import alias to helmcredsv1 and
update all uses in this file from v2.<TypeOrConst> to helmcredsv1.<TypeOrConst>
(e.g., replace any v2.Something references near the method handling credentials
in method.go with helmcredsv1.Something) so the alias matches the package path
and the rest of the codebase.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bindings/go/helm/transformation/credentials.go`:
- Around line 27-53: The switch over the variable named "typed" should first
guard against a nil value returned from ResolveTyped: if typed == nil return
nil, nil to avoid the default branch producing "unsupported credential type
<nil>"; update the function containing the switch (the code handling
ResolveTyped results) to check typed for nil before the type switch on
*helmcredsv1.HelmHTTPCredentials and *credconfigv1.DirectCredentials, and add a
unit test (e.g., a stubResolver that returns (nil, nil)) asserting the function
returns (nil, nil) to lock in the behavior.

---

Nitpick comments:
In `@bindings/go/helm/input/method.go`:
- Line 12: The import alias "v2" for the package
"ocm.software/open-component-model/bindings/go/helm/spec/credentials/v1" is
misleading and inconsistent; change the import alias to helmcredsv1 and update
all uses in this file from v2.<TypeOrConst> to helmcredsv1.<TypeOrConst> (e.g.,
replace any v2.Something references near the method handling credentials in
method.go with helmcredsv1.Something) so the alias matches the package path and
the rest of the codebase.

In `@bindings/go/helm/spec/identity/v1/register.go`:
- Around line 1-11: The identity package currently only exposes
MustRegisterIdentityType and lacks a package-level auto-registration like
access/input; add a new parent package file (e.g., scheme.go) in the identity
package that declares a package-level Scheme variable and an init() which calls
MustRegisterIdentityType(Scheme) so HelmChartRepositoryIdentity (and its
VersionedType/Type aliases) are auto-registered on import; ensure the variable
name and init pattern match the established pattern used by spec/access and
spec/input.

In `@bindings/go/helm/transformation/credentials_test.go`:
- Around line 93-117: Add a unit test covering the path where ResolveTyped
returns (nil, nil): create a stubResolver with typed: nil and err: nil, call
resolveCredentialsMap(t.Context(), resolver,
runtime.Identity{"type":"HelmChartRepository"}), and assert no error and creds
== nil; this documents and locks in the expected behavior for
resolveCredentialsMap when the resolver returns a nil typed value and no error.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d9133abb-ed51-4803-995e-600a49998383

📥 Commits

Reviewing files that changed from the base of the PR and between 00b5c2e and d2a4fbc.

⛔ Files ignored due to path filters (1)
  • bindings/go/helm/go.sum is excluded by !**/*.sum
📒 Files selected for processing (27)
  • bindings/go/helm/digest/digest.go
  • bindings/go/helm/go.mod
  • bindings/go/helm/input/blob.go
  • bindings/go/helm/input/method.go
  • bindings/go/helm/internal/credentials.go
  • bindings/go/helm/internal/download/doc.go
  • bindings/go/helm/internal/download/download.go
  • bindings/go/helm/internal/download/download_test.go
  • bindings/go/helm/internal/download/options.go
  • bindings/go/helm/internal/download/tls.go
  • bindings/go/helm/repository/resource/resource_repository.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials_test.go
  • bindings/go/helm/spec/credentials/v1/schemas/HelmHTTPCredentials.schema.json
  • bindings/go/helm/spec/credentials/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_type.go
  • bindings/go/helm/spec/identity/v1/register.go
  • bindings/go/helm/spec/identity/v1/schemas/HelmChartRepositoryIdentity.schema.json
  • bindings/go/helm/spec/identity/v1/type.go
  • bindings/go/helm/spec/identity/v1/type_test.go
  • bindings/go/helm/spec/identity/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_type.go
  • bindings/go/helm/transformation/credentials.go
  • bindings/go/helm/transformation/credentials_test.go
  • bindings/go/helm/transformation/get_helm_chart.go
✅ Files skipped from review due to trivial changes (9)
  • bindings/go/helm/internal/download/doc.go
  • bindings/go/helm/spec/identity/v1/schemas/HelmChartRepositoryIdentity.schema.json
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_type.go
  • bindings/go/helm/spec/identity/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.deepcopy.go
  • bindings/go/helm/go.mod
  • bindings/go/helm/spec/credentials/v1/schemas/HelmHTTPCredentials.schema.json
  • bindings/go/helm/internal/download/tls.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_type.go
  • bindings/go/helm/internal/download/download_test.go
  • bindings/go/helm/repository/resource/resource_repository.go
  • bindings/go/helm/internal/download/options.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials.go
  • bindings/go/helm/internal/download/download.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials_test.go

Comment thread bindings/go/helm/transformation/credentials.go
@matthiasbruns matthiasbruns marked this pull request as ready for review May 4, 2026 05:50
@matthiasbruns matthiasbruns marked this pull request as draft May 4, 2026 05:50
@matthiasbruns matthiasbruns force-pushed the feat/704_typed_credential_helm branch from 865197f to 95ae8bc Compare May 4, 2026 14:02
@matthiasbruns

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review - show no mercy, https://github.com/open-component-model/open-component-model/blob/eaae3340c9ee91e2221d20c60ebc08205d71db70/docs/adr/0018_typed_credentials.md phase 2 is important here
Also call me c̶̠͇̱͎̖͙̬̀̈́̾͋̈́̌̔̆̊́t̷̛̗̙̫͙̜͈͎̣͌͗̍̾̏͐̕͝ͅͅḩ̷̧͔͚͕̥̠̪͔͛̐̆̇̅̕̕͝ͅù̵̻̫̜̫͙̬͙̰̝͉̜̹l̷̥̪͕̪̳̻͕̃͗̆̿̀̈ḣ̶̘̻̺̊̇́͂͛͛̚͝u̵̢͇̞̥̤̳̠̥͚̲̭͔̓ͅ

@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch the ADR 0018 document
cat docs/adr/0018_typed_credentials.md 2>/dev/null || echo "File not found at that path"
# Also search for it
fd "0018" --type f

Length of output: 19562


🏁 Script executed:

#!/bin/bash
echo "=== transformation/credentials.go ==="
cat bindings/go/helm/transformation/credentials.go

echo "=== spec/credentials/v1/helm_credentials.go ==="
cat bindings/go/helm/spec/credentials/v1/helm_credentials.go

echo "=== internal/download/download.go ==="
cat bindings/go/helm/internal/download/download.go

echo "=== internal/download/tls.go ==="
cat bindings/go/helm/internal/download/tls.go

echo "=== internal/download/options.go ==="
cat bindings/go/helm/internal/download/options.go

echo "=== internal/credentials.go ==="
cat bindings/go/helm/internal/credentials.go

echo "=== spec/identity/v1/register.go ==="
cat bindings/go/helm/spec/identity/v1/register.go

echo "=== spec/identity/v1/type.go ==="
cat bindings/go/helm/spec/identity/v1/type.go

echo "=== transformation/get_helm_chart.go ==="
cat bindings/go/helm/transformation/get_helm_chart.go

echo "=== input/blob.go ==="
cat bindings/go/helm/input/blob.go

echo "=== input/method.go ==="
cat bindings/go/helm/input/method.go

echo "=== repository/resource/resource_repository.go ==="
cat bindings/go/helm/repository/resource/resource_repository.go

echo "=== digest/digest.go ==="
cat bindings/go/helm/digest/digest.go

echo "=== transformation/credentials_test.go ==="
cat bindings/go/helm/transformation/credentials_test.go

echo "=== internal/download/download_test.go ==="
cat bindings/go/helm/internal/download/download_test.go

echo "=== spec/credentials/v1/helm_credentials_test.go ==="
cat bindings/go/helm/spec/credentials/v1/helm_credentials_test.go

Length of output: 67955


@matthiasbruns — I've reviewed the PR against ADR 0018 Phase 2 requirements. Here's the full assessment — no mercy given:


Phase 2 Compliance Review

Overall, the credential side (HelmHTTPCredentials/v1) is solid and well-implemented. The identity side (HelmChartRepositoryIdentity/v1) has two structural gaps that prevent full Phase 2 compliance.


🔴 Critical

1. MustRegisterIdentityType skips RegisterWithAcceptedCredentials — identity→credential validation is unregistered

spec/identity/v1/register.go only calls scheme.MustRegisterWithAlias. The ADR explicitly requires:

// ADR 0018 Phase 2 requirement
identityTypeRegistry.RegisterWithAcceptedCredentials(
    &HelmChartRepositoryIdentity{},
    []runtime.Type{VersionedType, Type},
    []runtime.Type{helmcredsv1.HelmHTTPCredentialsVersionedType}, // <- this mapping is never declared
)

As written, the graph has no way to know that HelmChartRepository/v1 accepts HelmHTTPCredentials/v1. The entire identity→credential validation the ADR promises ("incompatible pairs produce warnings, not errors") is wired to zero bindings. This is the biggest gap.

The current signature only accepts *runtime.Scheme — it would need to either accept a credentials.IdentityTypeRegistry parameter, or have a separate Register(registry) function following the pattern described in the ADR's Registration section.


2. CredentialConsumerIdentity returns an untyped map, defeating typed identity

internal/credentials.go:

func CredentialConsumerIdentity(helmRepository string) (runtime.Identity, error) {
    identity, err := runtime.ParseURLToIdentity(helmRepository) // returns map[string]string
    // ...
    identity.SetType(helmidentityv1.Type)  // sets type key in map, doesn't build *HelmChartRepositoryIdentity
    return identity, nil
}

The ADR Phase 2 states: "Consumers pass typed identity structs directly to ResolveTyped" and shows:

identity := &HelmChartRepositoryIdentity{Hostname: "charts.example.com"}
typed, err := resolver.ResolveTyped(ctx, identity)

The function should parse the URL and populate a *HelmChartRepositoryIdentity{Hostname: ..., Scheme: ..., Port: ..., Path: ...}. Every caller (transformation/get_helm_chart.go, repository/resource/resource_repository.go, input/method.go, digest/digest.go) passes this map identity to ResolveTyped, meaning the credential graph is never exercised against a typed identity struct — it always sees a map. The HelmChartRepositoryIdentity struct is defined but never instantiated in the credential resolution path.


🟡 Moderate

3. resolveCredentialsMap inconsistent nil-vs-empty handling across credential types

case *helmcredsv1.HelmHTTPCredentials:
    // ... all-empty → explicit nil, nil return ✓
    if len(result) == 0 {
        return nil, nil
    }
case *credconfigv1.DirectCredentials:
    return maps.Clone(c.Properties), nil  // empty Properties {} → returns non-nil empty map {}

maps.Clone(map[string]string{}) returns a non-nil empty map[string]string{}. Downstream code differentiating nil from {} (e.g. len(creds) == 0 vs creds == nil) will behave differently depending on which credential type resolved. Either both should return nil for empty, or neither should. Recommend adding:

case *credconfigv1.DirectCredentials:
    if len(c.Properties) == 0 {
        return nil, nil
    }
    return maps.Clone(c.Properties), nil

4. Confusing import alias v2 for spec/credentials/v1 in input/method.go

v2 "ocm.software/open-component-model/bindings/go/helm/spec/credentials/v1"

v2 refers to the v1 package. This will confuse every future reader. Suggest helmcredsv1 (consistent with every other file in the PR).


5. ProcessResourceDigest in digest/digest.go has no Phase 4 TODO comment

The public boundary still accepts credentials map[string]string and calls FromDirectCredentials internally — consistent with Phase 2 being a bridge, but this pattern is silent about the migration intent. Compare with resolveCredentialsMap which has an explicit // Phase 4 comment. The same comment should appear in DownloadResource in resource_repository.go and ProcessResourceDigest in digest/digest.go.


6. No round-trip conversion test for HelmChartRepositoryIdentity

TestHelmHTTPCredentials_SchemeConvert tests → Raw → struct round-trip, but there is no equivalent test for HelmChartRepositoryIdentity. Given this is a new type being registered in a runtime scheme, the same round-trip coverage is warranted.


🟢 Minor

7. CredentialKeyPassword missing //nolint:gosec annotation

CredentialKeyUsername and the type name constant both have //nolint:gosec // G101: comments, but CredentialKeyPassword = "password" does not. Gosec G101 pattern-matches on the identifier name containing "password".

8. FromDirectCredentials(nil) is safe but undocumented

In Go, reading from a nil map returns the zero value — so FromDirectCredentials(nil) works correctly. However, no doc comment or test covers this behavior. A TestFromDirectCredentials_NilMap test and a note in the godoc would make the contract explicit.

9. HelmChartRepositoryIdentity.Port typed as string

Port is semantically an integer (uint16). Representing it as string requires callers to perform manual string→int conversion and validation. This follows the OCI identity pattern, so it may be an intentional consistency choice — but it's worth a deliberate decision comment if so.

10. input/blob.go silently passes nil credentials to download layer

When no WithCredentials option is provided, options.Credentials is nil and is passed directly to dlinternal.WithCredentials(credentials). The nil-safety comes from download.go initializing to &HelmHTTPCredentials{} — that's fine, but it creates a non-obvious cross-function nil dependency. The input layer could defensively initialize before calling down:

creds := options.Credentials
if creds == nil {
    creds = &helmcredsv1.HelmHTTPCredentials{}
}

Summary Table

# Severity File Issue
1 🔴 Critical spec/identity/v1/register.go RegisterWithAcceptedCredentials never called — identity→credential mapping unregistered
2 🔴 Critical internal/credentials.go Returns runtime.Identity (map), not *HelmChartRepositoryIdentity
3 🟡 Moderate transformation/credentials.go DirectCredentials empty returns {} vs HelmHTTPCredentials empty returns nil
4 🟡 Moderate input/method.go v2 alias for spec/credentials/v1 is misleading
5 🟡 Moderate digest/digest.go, resource_repository.go Missing Phase 4 migration TODO comments at map[string]string boundaries
6 🟡 Moderate spec/identity/v1/ No scheme round-trip conversion test for HelmChartRepositoryIdentity
7 🟢 Minor spec/credentials/v1/helm_credentials.go CredentialKeyPassword missing //nolint:gosec
8 🟢 Minor spec/credentials/v1/helm_credentials_test.go No FromDirectCredentials(nil) test
9 🟢 Minor spec/identity/v1/type.go Port as string — intent not documented
10 🟢 Minor input/blob.go Nil credentials propagated implicitly to download layer

Issues 1 and 2 block full Phase 2 compliance per ADR 0018 as written. Everything else is clean and follows the OCI binding pattern well.

✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (2)
bindings/go/helm/spec/identity/v1/type_test.go (1)

16-23: ⚡ Quick win

Also assert object construction through VersionedType.

You already verify registration for both types; adding NewObject(VersionedType) would make this test fully symmetric.

♻️ Proposed addition
 func TestMustRegisterIdentityType(t *testing.T) {
 	scheme := runtime.NewScheme()
 	MustRegisterIdentityType(scheme)

 	assert.True(t, scheme.IsRegistered(VersionedType))
 	assert.True(t, scheme.IsRegistered(Type))

+	objV1, err := scheme.NewObject(VersionedType)
+	require.NoError(t, err)
+	_, ok := objV1.(*HelmChartRepositoryIdentity)
+	assert.True(t, ok, "expected *HelmChartRepositoryIdentity for VersionedType, got %T", objV1)
+
 	obj, err := scheme.NewObject(Type)
 	require.NoError(t, err)
 	_, ok := obj.(*HelmChartRepositoryIdentity)
 	assert.True(t, ok, "expected *HelmChartRepositoryIdentity, got %T", obj)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/helm/spec/identity/v1/type_test.go` around lines 16 - 23, Add a
symmetric assertion that constructing via VersionedType also returns the
expected concrete type: call scheme.NewObject(VersionedType), check
require.NoError on the err, then assert the returned obj is a
*HelmChartRepositoryIdentity (same pattern as for Type). Update the test around
scheme.NewObject(Type) to include this second construction path using
VersionedType, referencing VersionedType, scheme.NewObject, and
HelmChartRepositoryIdentity.
bindings/go/helm/internal/credentials_test.go (1)

10-12: ⚡ Quick win

Prefer helm/spec/identity/v1.Type in expectations over legacy access constant.

This keeps the test aligned with the new typed identity API surface and avoids coupling to legacy naming.

♻️ Proposed change
-	helmaccess "ocm.software/open-component-model/bindings/go/helm/spec/access"
+	helmidentityv1 "ocm.software/open-component-model/bindings/go/helm/spec/identity/v1"
 	ocicredentialsspecv1 "ocm.software/open-component-model/bindings/go/oci/spec/identity/v1"
@@
-			expectedType: runtime.NewUnversionedType(helmaccess.LegacyHelmChartConsumerType),
+			expectedType: helmidentityv1.Type,
@@
-			expectedType: runtime.NewUnversionedType(helmaccess.LegacyHelmChartConsumerType),
+			expectedType: helmidentityv1.Type,

Also applies to: 28-28, 37-37

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

In `@bindings/go/helm/internal/credentials_test.go` around lines 10 - 12, Replace
usages of the legacy access constant from the helm access package in the test
with the new typed identity constant from helm/spec/identity/v1: add/replace the
import of "ocm.software/open-component-model/bindings/go/helm/spec/identity/v1"
(alias e.g. helmidentity) and update expectations in credentials_test.go
(including the occurrences around the other noted locations) to use
helmidentity.Type (the typed identity constant) instead of the legacy helmaccess
constant so the test asserts against the new identity API surface.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@bindings/go/helm/internal/credentials_test.go`:
- Around line 10-12: Replace usages of the legacy access constant from the helm
access package in the test with the new typed identity constant from
helm/spec/identity/v1: add/replace the import of
"ocm.software/open-component-model/bindings/go/helm/spec/identity/v1" (alias
e.g. helmidentity) and update expectations in credentials_test.go (including the
occurrences around the other noted locations) to use helmidentity.Type (the
typed identity constant) instead of the legacy helmaccess constant so the test
asserts against the new identity API surface.

In `@bindings/go/helm/spec/identity/v1/type_test.go`:
- Around line 16-23: Add a symmetric assertion that constructing via
VersionedType also returns the expected concrete type: call
scheme.NewObject(VersionedType), check require.NoError on the err, then assert
the returned obj is a *HelmChartRepositoryIdentity (same pattern as for Type).
Update the test around scheme.NewObject(Type) to include this second
construction path using VersionedType, referencing VersionedType,
scheme.NewObject, and HelmChartRepositoryIdentity.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 55ef6da3-90af-41f0-a9c7-285843f5101e

📥 Commits

Reviewing files that changed from the base of the PR and between 26020bb and 0efe300.

⛔ Files ignored due to path filters (1)
  • bindings/go/helm/go.sum is excluded by !**/*.sum
📒 Files selected for processing (29)
  • bindings/go/helm/digest/digest.go
  • bindings/go/helm/go.mod
  • bindings/go/helm/input/blob.go
  • bindings/go/helm/input/method.go
  • bindings/go/helm/internal/credentials.go
  • bindings/go/helm/internal/credentials_test.go
  • bindings/go/helm/internal/download/doc.go
  • bindings/go/helm/internal/download/download.go
  • bindings/go/helm/internal/download/download_test.go
  • bindings/go/helm/internal/download/options.go
  • bindings/go/helm/internal/download/tls.go
  • bindings/go/helm/repository/resource/resource_repository.go
  • bindings/go/helm/repository/resource/resource_repository_test.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials_test.go
  • bindings/go/helm/spec/credentials/v1/schemas/HelmHTTPCredentials.schema.json
  • bindings/go/helm/spec/credentials/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_type.go
  • bindings/go/helm/spec/identity/v1/register.go
  • bindings/go/helm/spec/identity/v1/schemas/HelmChartRepositoryIdentity.schema.json
  • bindings/go/helm/spec/identity/v1/type.go
  • bindings/go/helm/spec/identity/v1/type_test.go
  • bindings/go/helm/spec/identity/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_type.go
  • bindings/go/helm/transformation/credentials.go
  • bindings/go/helm/transformation/credentials_test.go
  • bindings/go/helm/transformation/get_helm_chart.go

@matthiasbruns

matthiasbruns commented May 5, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai

1 🔴 Critical spec/identity/v1/register.go RegisterWithAcceptedCredentials never called — identity→credential mapping unregistered

as stated in the ADR, the registration will come later and the wiring will happen in cli and controller

2 🔴 Critical internal/credentials.go Returns runtime.Identity (map), not *HelmChartRepositoryIdentity

I had to add a CredentialConsumerIdentityCompat that we need to use into we fully removed runtime.Identity from all apis

3 🟡 Moderate transformation/credentials.go DirectCredentials empty returns {} vs HelmHTTPCredentials empty returns nil

fixed

4 🟡 Moderate input/method.go v2 alias for spec/credentials/v1 is misleading

fixed

5 🟡 Moderate digest/digest.go, resource_repository.go Missing Phase 4 migration TODO comments at map[string]string boundaries

fixed

6 🟡 Moderate spec/identity/v1/ No scheme round-trip conversion test for HelmChartRepositoryIdentity

fixed

7 🟢 Minor spec/credentials/v1/helm_credentials.go CredentialKeyPassword missing //nolint:gosec

fixed

8 🟢 Minor spec/credentials/v1/helm_credentials_test.go No FromDirectCredentials(nil) test

fixed

9 🟢 Minor spec/identity/v1/type.go Port as string — intent not documented

wont to

  • runtime.Identity (map[string]string)
  • legacy .ocmconfig files and the ParseURLToIdentity
10 🟢 Minor input/blob.go Nil credentials propagated implicitly to download layer

wont do

@coderabbitai

coderabbitai Bot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

Let me verify the current state of the changes for items 2, 3, and 4.


🏁 Script executed:

#!/bin/bash
echo "=== internal/credentials.go ==="
cat bindings/go/helm/internal/credentials.go

echo ""
echo "=== transformation/credentials.go ==="
cat bindings/go/helm/transformation/credentials.go

echo ""
echo "=== input/method.go ==="
cat bindings/go/helm/input/method.go

echo ""
echo "=== internal/credentials_test.go ==="
cat bindings/go/helm/internal/credentials_test.go

Length of output: 12592


@matthiasbruns — thanks for the thorough update. Here's the verification summary and acknowledgements:

Item 1 — Registration deferred: Understood and accepted. Per ADR 0018 phased approach, wiring RegisterWithAcceptedCredentials in CLI/controller is the correct deferral point for Phase 2.

Item 2 — Typed identity: Confirmed in code. CredentialConsumerIdentity now correctly returns runtime.Typed. The CredentialConsumerIdentityCompat bridge is clean — the panic on unexpected type is appropriate (dev error, not a recoverable runtime error), and the TODO linking to issue #1041 makes the migration path explicit.

Item 3 — DirectCredentials nil consistency: Confirmed fixed. The consolidated len(result) == 0 → nil, nil at the end of resolveCredentialsMap now applies uniformly to all branches including *credconfigv1.DirectCredentials. ✅

Item 4 — Import alias: Confirmed fixed. credsv1 is now used in input/method.go, consistent with all other files. ✅

Items 5–8: Acknowledged as fixed. 🎉

Items 9 & 10 — Won't do: Accepted. Port as string is a deliberate compatibility choice for runtime.Identity map semantics, legacy .ocmconfig, and ParseURLToIdentity. Nil propagation to the download layer is safe by design (download.go initialises &HelmHTTPCredentials{}).

Phase 2 is looking solid. Great work getting there, c̶̠͇̱͎̖͙̬̀̈́̾͋̈́̌̔̆̊́t̷̛̗̙̫͙̜͈͎̣͌͗̍̾̏͐̕͝ͅͅḩ̷̧͔͚͕̥̠̪͔͛̐̆̇̅̕̕͝ͅū̵̻̫̜̫͙̬͙̰̝͉̜̹l̷̥̪͕̪̳̻͕̃͗̆̿̀̈ḣ̶̘̻̺̊̇́͂͛͛̚͝u̵̢͇̞̥̤̳̠̥͚̲̭͔̓ͅ! 🦑


✏️ Learnings added
Learnt from: matthiasbruns
URL: https://github.com/open-component-model/open-component-model/pull/2408

Timestamp: 2026-05-05T10:05:46.317Z
Learning: In the Helm binding (bindings/go/helm), registering identity→credential type mappings via RegisterWithAcceptedCredentials for HelmChartRepositoryIdentity/v1 is intentionally deferred to the CLI and controller layer per ADR 0018 phased approach. Phase 2 only registers the types themselves; the wiring happens in a later phase.

Learnt from: matthiasbruns
URL: https://github.com/open-component-model/open-component-model/pull/2408

Timestamp: 2026-05-05T10:05:46.317Z
Learning: In bindings/go/helm/spec/identity/v1/type.go, HelmChartRepositoryIdentity.Port is intentionally typed as string (not int/uint16) for compatibility with runtime.Identity (map[string]string), legacy .ocmconfig files, and ParseURLToIdentity which produces string values.

Learnt from: matthiasbruns
URL: https://github.com/open-component-model/open-component-model/pull/2408

Timestamp: 2026-05-05T10:05:46.317Z
Learning: In bindings/go/helm/internal/credentials.go, CredentialConsumerIdentity returns runtime.Typed (since Phase 2). CredentialConsumerIdentityCompat is a bridge that casts to runtime.Identity (map) and panics on non-map identity as a dev-error guard. Callers that haven't migrated to typed identity should use CredentialConsumerIdentityCompat; full migration is tracked via https://github.com/open-component-model/ocm-project/issues/1041.

Learnt from: matthiasbruns
URL: https://github.com/open-component-model/open-component-model/pull/2408

Timestamp: 2026-05-05T10:05:46.317Z
Learning: In bindings/go/helm/input/blob.go (and the download layer), passing nil *HelmHTTPCredentials to WithCredentials is intentional and safe: download.go initialises opt.Credentials to &HelmHTTPCredentials{} as a nil-guard. This is a known design decision and should not be flagged.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@matthiasbruns matthiasbruns force-pushed the feat/704_typed_credential_helm branch from 730fd42 to 633600f Compare May 5, 2026 10:06
@open-component-model open-component-model deleted a comment from coderabbitai Bot May 5, 2026
@open-component-model open-component-model deleted a comment from coderabbitai Bot May 5, 2026
@matthiasbruns matthiasbruns marked this pull request as ready for review May 5, 2026 11:38

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
bindings/go/helm/internal/credentials_test.go (1)

67-80: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Unreachable error branch leaves CredentialConsumerIdentityCompat error behavior untested.

Line 69 returns on expected errors, so Lines 76-80 never execute. This dead branch also masks that non-error assertions only check the compat call’s err variable.

Suggested fix
-			identity, err := internal.CredentialConsumerIdentity(tt.repository)
+			identity, err := internal.CredentialConsumerIdentity(tt.repository)
+			compatIdentity, compatErr := internal.CredentialConsumerIdentityCompat(tt.repository)
 
 			if tt.expectedErr != "" {
 				require.ErrorContains(t, err, tt.expectedErr)
 				assert.Nil(t, identity)
+				require.ErrorContains(t, compatErr, tt.expectedErr)
+				assert.Nil(t, compatIdentity)
 				return
 			}
-
-			compatIdentity, err := internal.CredentialConsumerIdentityCompat(tt.repository)
-			if tt.expectedErr != "" {
-				require.ErrorContains(t, err, tt.expectedErr)
-				assert.Nil(t, compatIdentity)
-				return
-			}
+			require.NoError(t, err)
+			require.NoError(t, compatErr)
 
 			legacyIdentity, ok := identity.(runtime.Identity)
 			require.True(t, ok, "expected identity to implement runtime.Identity")
 			require.Equal(t, compatIdentity, legacyIdentity, "expected compat identity to match legacy identity")
-
-			require.NoError(t, err)
 			require.NotNil(t, identity)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bindings/go/helm/internal/credentials_test.go` around lines 67 - 80, The test
returns immediately after checking CredentialConsumerIdentity's expected error
which prevents exercising CredentialConsumerIdentityCompat and also reuses the
same err variable; change the flow to call both functions before returning and
use distinct error variables (e.g., err1, err2) so you can separately assert
expectedErr for both CredentialConsumerIdentity and
CredentialConsumerIdentityCompat, or if expectedErr is empty assert no error and
non-nil identities for both identity and compatIdentity; ensure you only return
after both checks complete.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bindings/go/helm/spec/credentials/v1/helm_credentials_test.go`:
- Around line 45-50: In TestFromDirectCredentials_EmptyMap, expand the
assertions beyond Username and Password to assert that CertFile, KeyFile,
Keyring are empty and that Type equals the expected default value; update the
test for the FromDirectCredentials function to include assert.Empty(t,
creds.CertFile), assert.Empty(t, creds.KeyFile), assert.Empty(t, creds.Keyring)
and assert.Equal(t, <expectedTypeValue>, creds.Type) (use the package's defined
default Type constant or zero value) so all typed fields and Type are validated
for the empty-map path.

---

Outside diff comments:
In `@bindings/go/helm/internal/credentials_test.go`:
- Around line 67-80: The test returns immediately after checking
CredentialConsumerIdentity's expected error which prevents exercising
CredentialConsumerIdentityCompat and also reuses the same err variable; change
the flow to call both functions before returning and use distinct error
variables (e.g., err1, err2) so you can separately assert expectedErr for both
CredentialConsumerIdentity and CredentialConsumerIdentityCompat, or if
expectedErr is empty assert no error and non-nil identities for both identity
and compatIdentity; ensure you only return after both checks complete.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d4e43371-e872-4b8d-84a1-d60937e50cf0

📥 Commits

Reviewing files that changed from the base of the PR and between 0efe300 and 5e0f9c7.

⛔ Files ignored due to path filters (2)
  • bindings/go/examples/go.sum is excluded by !**/*.sum
  • bindings/go/helm/go.sum is excluded by !**/*.sum
📒 Files selected for processing (33)
  • bindings/go/examples/06_oci_test.go
  • bindings/go/examples/go.mod
  • bindings/go/helm/cmd/main.go
  • bindings/go/helm/digest/digest.go
  • bindings/go/helm/go.mod
  • bindings/go/helm/input/blob.go
  • bindings/go/helm/input/method.go
  • bindings/go/helm/internal/credentials.go
  • bindings/go/helm/internal/credentials_test.go
  • bindings/go/helm/internal/download/doc.go
  • bindings/go/helm/internal/download/download.go
  • bindings/go/helm/internal/download/download_test.go
  • bindings/go/helm/internal/download/options.go
  • bindings/go/helm/internal/download/tls.go
  • bindings/go/helm/repository/resource/doc.go
  • bindings/go/helm/repository/resource/resource_repository.go
  • bindings/go/helm/repository/resource/resource_repository_test.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials_test.go
  • bindings/go/helm/spec/credentials/v1/schemas/HelmHTTPCredentials.schema.json
  • bindings/go/helm/spec/credentials/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_type.go
  • bindings/go/helm/spec/identity/v1/register.go
  • bindings/go/helm/spec/identity/v1/schemas/HelmChartRepositoryIdentity.schema.json
  • bindings/go/helm/spec/identity/v1/type.go
  • bindings/go/helm/spec/identity/v1/type_test.go
  • bindings/go/helm/spec/identity/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_type.go
  • bindings/go/helm/transformation/credentials.go
  • bindings/go/helm/transformation/credentials_test.go
  • bindings/go/helm/transformation/get_helm_chart.go
✅ Files skipped from review due to trivial changes (16)
  • bindings/go/helm/internal/download/doc.go
  • bindings/go/helm/spec/identity/v1/register.go
  • bindings/go/helm/repository/resource/doc.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/identity/v1/type.go
  • bindings/go/helm/spec/credentials/v1/schemas/HelmHTTPCredentials.schema.json
  • bindings/go/helm/internal/download/download_test.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/cmd/main.go
  • bindings/go/helm/repository/resource/resource_repository_test.go
  • bindings/go/helm/transformation/get_helm_chart.go
  • bindings/go/helm/spec/identity/v1/zz_generated.deepcopy.go
  • bindings/go/helm/transformation/credentials_test.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_type.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_type.go
  • bindings/go/helm/input/method.go
  • bindings/go/helm/spec/identity/v1/schemas/HelmChartRepositoryIdentity.schema.json
  • bindings/go/helm/spec/identity/v1/type_test.go
  • bindings/go/helm/input/blob.go
  • bindings/go/helm/transformation/credentials.go
  • bindings/go/helm/internal/download/download.go
  • bindings/go/helm/go.mod

Comment thread bindings/go/helm/spec/credentials/v1/helm_credentials_test.go
@matthiasbruns matthiasbruns force-pushed the feat/704_typed_credential_helm branch from 483d764 to ae9174e Compare May 5, 2026 12:17

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
bindings/go/helm/digest/digest.go (1)

87-91: 💤 Low value

credentials is always non-nil here — nil guards inside resolveHTTPDigest/resolveOCIDigest are currently dead.

FromDirectCredentials always returns a non-nil pointer (both for Helm and OCI), so the if credentials != nil guards inside the two resolve* helpers can never be false as called today. The guards are forward-looking (they become meaningful once Phase 4 promotes the parameters to typed pointers), but a brief comment would help future readers understand the intent rather than treating them as unreachable branches.

💡 Optional: document the forward-looking intent
 if strings.HasPrefix(helm.HelmRepository, "oci://") {
+    // FromDirectCredentials always returns non-nil; nil guard inside resolveOCIDigest
+    // will become meaningful once the ProcessResourceDigest signature is migrated (see TODO above).
     resolvedDigest, err = p.resolveOCIDigest(ctx, helm, ocicredsv1.FromDirectCredentials(credentials))
 } else {
+    // Same note as above for resolveHTTPDigest.
     resolvedDigest, err = p.resolveHTTPDigest(ctx, helm, helmcredsv1.FromDirectCredentials(credentials))
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bindings/go/helm/digest/digest.go` around lines 87 - 91, The nil checks
inside resolveHTTPDigest and resolveOCIDigest are currently dead because
FromDirectCredentials always returns a non-nil pointer; update those functions
(resolveHTTPDigest, resolveOCIDigest) to include a brief comment by the `if
credentials != nil` guards explaining that callers (e.g. the call sites that
pass ocicredsv1.FromDirectCredentials(credentials) /
helmcredsv1.FromDirectCredentials(credentials)) always return non-nil today but
the guards are intentionally kept for future phases when parameters become typed
pointers — add a TODO/note referencing FromDirectCredentials to clarify the
forward-looking intent for future readers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bindings/go/helm/repository/resource/doc.go`:
- Around line 31-35: The code snippet defines typed via
CredentialProvider.ResolveTyped but still passes creds to repo.DownloadResource,
causing a mismatch; update the example to use the resolved value (either pass
typed into DownloadResource, e.g. repo.DownloadResource(ctx, res, typed), or
rename the ResolveTyped result to creds if DownloadResource expects a
credentials variable) and remove the unused creds declaration so the flow
consistently uses ResolveTyped -> typed (or creds) with DownloadResource and
assigns its result to chartBlob.

---

Nitpick comments:
In `@bindings/go/helm/digest/digest.go`:
- Around line 87-91: The nil checks inside resolveHTTPDigest and
resolveOCIDigest are currently dead because FromDirectCredentials always returns
a non-nil pointer; update those functions (resolveHTTPDigest, resolveOCIDigest)
to include a brief comment by the `if credentials != nil` guards explaining that
callers (e.g. the call sites that pass
ocicredsv1.FromDirectCredentials(credentials) /
helmcredsv1.FromDirectCredentials(credentials)) always return non-nil today but
the guards are intentionally kept for future phases when parameters become typed
pointers — add a TODO/note referencing FromDirectCredentials to clarify the
forward-looking intent for future readers.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 67f1d496-9e48-4da4-aca4-e53d19fdbad6

📥 Commits

Reviewing files that changed from the base of the PR and between 5e0f9c7 and c8b69dc.

⛔ Files ignored due to path filters (2)
  • bindings/go/examples/go.sum is excluded by !**/*.sum
  • bindings/go/helm/go.sum is excluded by !**/*.sum
📒 Files selected for processing (33)
  • bindings/go/examples/06_oci_test.go
  • bindings/go/examples/go.mod
  • bindings/go/helm/cmd/main.go
  • bindings/go/helm/digest/digest.go
  • bindings/go/helm/go.mod
  • bindings/go/helm/input/blob.go
  • bindings/go/helm/input/method.go
  • bindings/go/helm/internal/credentials.go
  • bindings/go/helm/internal/credentials_test.go
  • bindings/go/helm/internal/download/doc.go
  • bindings/go/helm/internal/download/download.go
  • bindings/go/helm/internal/download/download_test.go
  • bindings/go/helm/internal/download/options.go
  • bindings/go/helm/internal/download/tls.go
  • bindings/go/helm/repository/resource/doc.go
  • bindings/go/helm/repository/resource/resource_repository.go
  • bindings/go/helm/repository/resource/resource_repository_test.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials_test.go
  • bindings/go/helm/spec/credentials/v1/schemas/HelmHTTPCredentials.schema.json
  • bindings/go/helm/spec/credentials/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_type.go
  • bindings/go/helm/spec/identity/v1/register.go
  • bindings/go/helm/spec/identity/v1/schemas/HelmChartRepositoryIdentity.schema.json
  • bindings/go/helm/spec/identity/v1/type.go
  • bindings/go/helm/spec/identity/v1/type_test.go
  • bindings/go/helm/spec/identity/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_type.go
  • bindings/go/helm/transformation/credentials.go
  • bindings/go/helm/transformation/credentials_test.go
  • bindings/go/helm/transformation/get_helm_chart.go
✅ Files skipped from review due to trivial changes (16)
  • bindings/go/helm/internal/download/doc.go
  • bindings/go/helm/spec/identity/v1/schemas/HelmChartRepositoryIdentity.schema.json
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_jsonschema.go
  • bindings/go/helm/spec/identity/v1/type.go
  • bindings/go/examples/06_oci_test.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.ocm_type.go
  • bindings/go/helm/internal/download/download_test.go
  • bindings/go/helm/cmd/main.go
  • bindings/go/helm/spec/identity/v1/zz_generated.ocm_type.go
  • bindings/go/helm/spec/identity/v1/zz_generated.deepcopy.go
  • bindings/go/helm/spec/credentials/v1/helm_credentials.go
  • bindings/go/examples/go.mod
  • bindings/go/helm/repository/resource/resource_repository_test.go
  • bindings/go/helm/spec/credentials/v1/zz_generated.deepcopy.go
  • bindings/go/helm/transformation/credentials_test.go
  • bindings/go/helm/go.mod
🚧 Files skipped from review as they are similar to previous changes (9)
  • bindings/go/helm/spec/identity/v1/type_test.go
  • bindings/go/helm/spec/identity/v1/register.go
  • bindings/go/helm/transformation/get_helm_chart.go
  • bindings/go/helm/spec/credentials/v1/schemas/HelmHTTPCredentials.schema.json
  • bindings/go/helm/transformation/credentials.go
  • bindings/go/helm/input/method.go
  • bindings/go/helm/internal/credentials.go
  • bindings/go/helm/internal/download/download.go
  • bindings/go/helm/internal/credentials_test.go

Comment thread bindings/go/helm/repository/resource/doc.go Outdated
@matthiasbruns

Copy link
Copy Markdown
Contributor Author

Actionable comments posted: 1

🧹 Nitpick comments (1)

bindings/go/helm/digest/digest.go (1)> 87-91: 💤 Low value

credentials is always non-nil here — nil guards inside resolveHTTPDigest/resolveOCIDigest are currently dead.
FromDirectCredentials always returns a non-nil pointer (both for Helm and OCI), so the if credentials != nil guards inside the two resolve* helpers can never be false as called today. The guards are forward-looking (they become meaningful once Phase 4 promotes the parameters to typed pointers), but a brief comment would help future readers understand the intent rather than treating them as unreachable branches.

💡 Optional: document the forward-looking intent

 if strings.HasPrefix(helm.HelmRepository, "oci://") {
+    // FromDirectCredentials always returns non-nil; nil guard inside resolveOCIDigest
+    // will become meaningful once the ProcessResourceDigest signature is migrated (see TODO above).
     resolvedDigest, err = p.resolveOCIDigest(ctx, helm, ocicredsv1.FromDirectCredentials(credentials))
 } else {
+    // Same note as above for resolveHTTPDigest.
     resolvedDigest, err = p.resolveHTTPDigest(ctx, helm, helmcredsv1.FromDirectCredentials(credentials))
 }

🤖 Prompt for AI Agents

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

In `@bindings/go/helm/digest/digest.go` around lines 87 - 91, The nil checks
inside resolveHTTPDigest and resolveOCIDigest are currently dead because
FromDirectCredentials always returns a non-nil pointer; update those functions
(resolveHTTPDigest, resolveOCIDigest) to include a brief comment by the `if
credentials != nil` guards explaining that callers (e.g. the call sites that
pass ocicredsv1.FromDirectCredentials(credentials) /
helmcredsv1.FromDirectCredentials(credentials)) always return non-nil today but
the guards are intentionally kept for future phases when parameters become typed
pointers — add a TODO/note referencing FromDirectCredentials to clarify the
forward-looking intent for future readers.

🤖 Prompt for all review comments with AI agents

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

Inline comments:
In `@bindings/go/helm/repository/resource/doc.go`:
- Around line 31-35: The code snippet defines typed via
CredentialProvider.ResolveTyped but still passes creds to repo.DownloadResource,
causing a mismatch; update the example to use the resolved value (either pass
typed into DownloadResource, e.g. repo.DownloadResource(ctx, res, typed), or
rename the ResolveTyped result to creds if DownloadResource expects a
credentials variable) and remove the unused creds declaration so the flow
consistently uses ResolveTyped -> typed (or creds) with DownloadResource and
assigns its result to chartBlob.

---

Nitpick comments:
In `@bindings/go/helm/digest/digest.go`:
- Around line 87-91: The nil checks inside resolveHTTPDigest and
resolveOCIDigest are currently dead because FromDirectCredentials always returns
a non-nil pointer; update those functions (resolveHTTPDigest, resolveOCIDigest)
to include a brief comment by the `if credentials != nil` guards explaining that
callers (e.g. the call sites that pass
ocicredsv1.FromDirectCredentials(credentials) /
helmcredsv1.FromDirectCredentials(credentials)) always return non-nil today but
the guards are intentionally kept for future phases when parameters become typed
pointers — add a TODO/note referencing FromDirectCredentials to clarify the
forward-looking intent for future readers.

🪄 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

wont do

@matthiasbruns matthiasbruns marked this pull request as ready for review May 11, 2026 12:22
Comment thread bindings/go/helm/go.mod Outdated
Comment thread bindings/go/helm/internal/credentials.go Outdated
matthiasbruns and others added 4 commits May 12, 2026 09:19
On-behalf-of: SAP <matthias.bruns@sap.com>
Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com>
Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com>
Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
@matthiasbruns matthiasbruns marked this pull request as draft May 12, 2026 09:50
matthiasbruns and others added 3 commits May 12, 2026 14:06
On-behalf-of: SAP <matthias.bruns@sap.com>
Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com>
Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
@matthiasbruns matthiasbruns marked this pull request as ready for review May 12, 2026 13:39
Comment thread bindings/go/helm/repository/resource/resource_repository.go
matthiasbruns and others added 2 commits May 12, 2026 20:00
On-behalf-of: SAP <matthias.bruns@sap.com>
Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
@matthiasbruns matthiasbruns requested a review from a team May 13, 2026 10:53
@matthiasbruns matthiasbruns requested a review from piotrjanik May 15, 2026 07:32
@matthiasbruns matthiasbruns merged commit 6a25d53 into open-component-model:main May 15, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature new feature, enhancement, improvement, extension size/l Large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update helm bindings to work with typed credentials

5 participants