Skip to content

feat!: helm resource repo bindings#2128

Merged
matthiasbruns merged 47 commits into
open-component-model:mainfrom
matthiasbruns:feat/911_helm_resource_repo_bindings
Apr 16, 2026
Merged

feat!: helm resource repo bindings#2128
matthiasbruns merged 47 commits into
open-component-model:mainfrom
matthiasbruns:feat/911_helm_resource_repo_bindings

Conversation

@matthiasbruns

@matthiasbruns matthiasbruns commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

What this PR does / why we need it

Introduces a Helm-based ResourceRepository implementing repository.ResourceRepository and bindings/go/plugin/manager/registries/resource/contract.go.

Full usage can be seen here: #2130

Which issue(s) this PR fixes

Contributes open-component-model/ocm-project#911

CLI PR

#2094

Testing

Fully tested in #2130

Helm ResourceRepository — Changes compared to legacy OCM

  • CLI & transfer will use the ResourceRepository interface instead of the deprecated HelmAccess struct for
    credential identity resolution and chart downloads
  • Deprecated types removed: helm.ResourceConsumerIdentityProvider interface, helmaccess.HelmAccess struct, and
    their tests — functionality is covered by ResourceRepository
  • Blob format: Downloads return a ChartBlob (tar archive wrapping .tgz + optional .prov), replacing the legacy
    pattern of separate blob accessors for chart and provenance
  • Plugin registration: The helm ResourceRepository is registered as a builtin plugin alongside the existing OCI
    and digest processor plugins in feat: 911 helm resource repo #2130
Intentional differences from legacy
Legacy OCM New
CACert / Keyring on access spec Supported as inline fields Omitted — use credential resolver instead
OCI-hosted helm charts (oci://) Handled by helm access method with separate OCI download path Should use the OCI ResourceRepository (separate access type)
Blob return format (only internally) Raw .tgz blob (ChartLayerMediaType), prov accessed separately ChartBlob tar wrapping both .tgz and .prov
Local charts Not in access method (IsLocal() = false) Not in ResourceRepository — handled by helm input plugin
Test coverage
  • Unit tests for ResourceRepository (credential identity, download, temp folder usage, nil guards)
  • Unit tests for ChartBlob extraction (using real testdata charts)
  • Integration test: add cv with helm access to OCI registry
  • Integration test: download resource with helm access from CTF (byte-level verification)
  • Shell test: end-to-end download of podinfo chart with SHA256 verification

@coderabbitai

coderabbitai Bot commented Mar 31, 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 the Helm access/provider pattern with a repository-backed flow: adds a Helm ResourceRepository and ChartBlob for tar-based chart/provenance extraction, centralizes credential identity logic in helminternal.CredentialConsumerIdentity, updates transformer/digest to use the repository, and adds docs and tests.

Changes

Cohort / File(s) Summary
Identity & credential helper
bindings/go/helm/access/access.go, bindings/go/helm/interface.go, bindings/go/helm/access/access_test.go, bindings/go/helm/internal/credentials.go, bindings/go/helm/internal/credentials_test.go
Removed legacy HelmAccess and temporary ResourceConsumerIdentityProvider; added helminternal.CredentialConsumerIdentity(helmRepository) and tests; centralized identity parsing and OCI-vs-legacy selection.
ResourceRepository implementation
bindings/go/helm/repository/resource/resource_repository.go, bindings/go/helm/repository/resource/resource_repository_test.go, bindings/go/helm/repository/resource/doc.go
Added ResourceRepository implementing download (fetch chart+prov, tar to in-memory blob), identity resolution, and disabled upload; includes tests and package docs.
Chart blob handling
bindings/go/helm/blob/chart_blob.go, bindings/go/helm/blob/chart_blob_test.go, bindings/go/helm/blob/doc.go
Added ChartBlob wrapper around a tar ReadOnlyBlob with lazy, cached extraction of a single .tgz and optional .prov, plus tests and package documentation.
Transformer & digest updates
bindings/go/helm/transformation/get_helm_chart.go, bindings/go/helm/transformation/get_helm_chart_test.go, bindings/go/helm/digest/digest.go
Refactored GetHelmChart to require/use repository.ResourceRepository and consume ChartBlob; digest now delegates identity creation to helminternal.CredentialConsumerIdentity; tests updated for repository-centric inputs.
Docs & schema clarifications
bindings/go/helm/access/spec/v1/helm.go, bindings/go/helm/access/spec/v1/schemas/Helm.schema.json, bindings/go/helm/input/method.go
Clarified Helm access docs/schema to target classic HTTP/HTTPS repositories, note TLS credentials via resolver, and direct OCI charts to the OCI access type; minor doc updates.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ResourceRepo as ResourceRepository
    participant CredResolver as CredentialResolver
    participant HelmServer as Helm HTTP Server
    participant ChartBlob

    Client->>ResourceRepo: GetResourceCredentialConsumerIdentity(resource)
    ResourceRepo->>ResourceRepo: helminternal.CredentialConsumerIdentity(helmRepository)
    ResourceRepo-->>Client: runtime.Identity

    Client->>CredResolver: Resolve(identity)
    CredResolver-->>Client: credentials map

    Client->>ResourceRepo: DownloadResource(resource, credentials)
    ResourceRepo->>HelmServer: HTTP GET chart + prov
    HelmServer-->>ResourceRepo: chart files
    ResourceRepo->>ResourceRepo: write files to temp dir\ncreate in-memory tar
    ResourceRepo->>ChartBlob: NewChartBlob(tarBlob)
    ResourceRepo-->>Client: ChartBlob

    Client->>ChartBlob: ChartArchive()
    ChartBlob->>ChartBlob: extract .tgz (lazy, once)
    ChartBlob-->>Client: chart ReadOnlyBlob

    Client->>ChartBlob: ProvFile()
    ChartBlob->>ChartBlob: extract .prov (lazy, once)
    ChartBlob-->>Client: prov ReadOnlyBlob
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

!BREAKING-CHANGE!

Suggested reviewers

  • fabianburth
  • jakobmoellerdev
  • frewilhelm

Poem

🐰 I hopped through tarballs, snug and neat,
Found one .tgz and sometimes a prov to eat.
I cache the extract, nibble once with care,
Hand charts to repos, tidy and fair.
Hooray — downloads hop in perfect beat! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% 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
Description check ✅ Passed Description clearly explains the PR's purpose (Helm ResourceRepository implementation), references related issues/PRs, documents changes vs. legacy OCM, and covers testing approach.
Linked Issues check ✅ Passed PR addresses all primary objectives from issue #911: creates ResourceRepository implementation with plugin registration, replaces deprecated types, provides ChartBlob wrapper, and includes comprehensive unit/integration testing.
Out of Scope Changes check ✅ Passed All changes are scoped to helm resource repository implementation: removed deprecated types, added ChartBlob, ResourceRepository, updated transformer and digest processor integrations, added tests and documentation. No unrelated changes detected.
Title check ✅ Passed The title 'feat!: helm resource repo bindings' directly describes the main change: introducing Helm ResourceRepository bindings with a breaking change marker.

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

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

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.

@github-actions github-actions Bot added kind/feature new feature, enhancement, improvement, extension size/l Large labels Mar 31, 2026
@matthiasbruns matthiasbruns force-pushed the feat/911_helm_resource_repo_bindings branch from a414233 to 752bf5b Compare March 31, 2026 06:00
@matthiasbruns matthiasbruns changed the title feat(911): helm resource repo bindings feat(911)!: helm resource repo bindings Mar 31, 2026
@matthiasbruns matthiasbruns added the !BREAKING-CHANGE! Breaking change in API or ocm-cli or spec label Mar 31, 2026
@matthiasbruns matthiasbruns changed the title feat(911)!: helm resource repo bindings feat!: helm resource repo bindings Mar 31, 2026
@matthiasbruns matthiasbruns changed the title feat!: helm resource repo bindings feat: helm resource repo bindings Mar 31, 2026
@matthiasbruns matthiasbruns removed the !BREAKING-CHANGE! Breaking change in API or ocm-cli or spec label Mar 31, 2026
@matthiasbruns matthiasbruns force-pushed the feat/911_helm_resource_repo_bindings branch from 1d70fb1 to 7fcba25 Compare March 31, 2026 06:43
@matthiasbruns matthiasbruns mentioned this pull request Mar 31, 2026
1 task
@matthiasbruns matthiasbruns force-pushed the feat/911_helm_resource_repo_bindings branch 5 times, most recently from 4606a24 to 584fead Compare April 1, 2026 09:05
@matthiasbruns

Copy link
Copy Markdown
Contributor Author

@coderabbitai review fully

@coderabbitai

coderabbitai Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

@matthiasbruns Sure! I'll kick off a full review of the PR right away.


🧠 Learnings used
Learnt from: matthiasbruns
Repo: open-component-model/open-component-model PR: 2094
File: bindings/go/helm/repository/resource/resource_repository.go:24-24
Timestamp: 2026-03-30T10:12:38.389Z
Learning: In `bindings/go/helm/repository/resource/resource_repository.go` (open-component-model/open-component-model), `ResourceRepository.DownloadResource()` intentionally does NOT verify the downloaded blob against the resource descriptor's integrity metadata inline. Digest verification is handled at a higher level by `ResourceDigestProcessor.ProcessResourceDigest()`, in the constructor/controller layer (e.g., `constructor/construct.go` and `kubernetes/controller/internal/ocm/resource.go`). The OCI `ResourceRepository` follows the same pattern. This is documented in ADR-0006. Do not flag the absence of inline digest verification in `DownloadResource()` as a bug.

Learnt from: matthiasbruns
Repo: open-component-model/open-component-model PR: 1943
File: kubernetes/controller/internal/cel/functions/oci_test.go:401-409
Timestamp: 2026-03-13T11:28:30.904Z
Learning: In `kubernetes/controller/internal/cel/functions/oci_test.go` (open-component-model/open-component-model), the `helmspec` alias refers to the package `"ocm.software/open-component-model/bindings/go/helm/access/spec/v1"`, which is a valid and existing package in the repository. Do not flag this import or its usage (e.g., `helmspec.Helm`) as non-existent or missing.

Learnt from: matthiasbruns
Repo: open-component-model/open-component-model PR: 1832
File: bindings/go/helm/transformation/convert_helm_chart_to_oci.go:134-146
Timestamp: 2026-03-05T12:49:29.729Z
Learning: In `bindings/go/helm/transformation/convert_helm_chart_to_oci.go` (open-component-model/open-component-model), the `referenceFromHelmAccess` function intentionally omits `lref.Registry` when constructing the OCI image reference. By design, the `ImageReference` field in this context should only contain the artifact path (repository and optional tag), never the registry. Flagging the absence of the registry as a bug is incorrect.

Learnt from: jakobmoellerdev
Repo: open-component-model/open-component-model PR: 2069
File: bindings/go/transfer/internal/helpers.go:110-119
Timestamp: 2026-03-25T18:07:39.188Z
Learning: In `bindings/go/transfer/internal/helpers.go` (open-component-model/open-component-model), `RepositoryEqual` intentionally compares `*oci.Repository` by raw `BaseUrl` and `SubPath` fields. This is safe because all repository specs coming through the normal parsing path are normalized by `compref.ParseRepository`, which consistently splits the URL into `BaseUrl+SubPath`. Manually constructing `*oci.Repository` with a different split for the same logical repo is a caller error, not something `RepositoryEqual` or `AppendUniqueRepositories` should compensate for. Do not flag this comparison approach as a bug.
✅ 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.

Actionable comments posted: 4

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/transformation/get_helm_chart.go (1)

59-67: ⚠️ Potential issue | 🔴 Critical

Nil pointer dereference: ResourceRepository not guarded before download call.

Line 59 guards ResourceRepository only for credential resolution, but line 78 calls t.ResourceRepository.DownloadResource() unconditionally. If ResourceRepository is nil, this will panic.

🐛 Proposed fix: add nil guard or make ResourceRepository required

Option 1 - Add nil guard with explicit error:

+	if t.ResourceRepository == nil {
+		return nil, fmt.Errorf("ResourceRepository is required for helm chart download")
+	}
+
 	// Download the chart content via the ResourceRepository.
 	// The returned blob is a ChartBlob that provides structured access to the chart archive and prov file.
 	downloadedBlob, err := t.ResourceRepository.DownloadResource(ctx, targetResource, creds)

Option 2 - Remove the nil guard on line 59 to make the panic fail-fast during credential resolution (if nil is never expected).

Also applies to: 76-81

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

In `@bindings/go/helm/transformation/get_helm_chart.go` around lines 59 - 67, The
code only nil-checks t.ResourceRepository when resolving credentials but later
calls t.ResourceRepository.DownloadResource unconditionally (risking a
nil-pointer panic); update get_helm_chart.go to guard t.ResourceRepository
before any use — either return a clear error if ResourceRepository is nil (e.g.,
"resource repository required") or move/remove the earlier conditional so
ResourceRepository is validated up-front; specifically adjust the logic around
t.ResourceRepository, GetResourceCredentialConsumerIdentity, Resolve and
DownloadResource so DownloadResource is only invoked when t.ResourceRepository
!= nil (or ensure ResourceRepository is required and checked at function start).
🧹 Nitpick comments (2)
bindings/go/helm/blob/chart_blob_test.go (1)

160-177: This doesn't actually assert one-time extraction.

The test still passes if ChartArchive() re-reads the tar on every call, because it only compares the returned bytes. If the lazy/cache contract matters here, wrap tarBlob in a small spy and assert ReadCloser() is hit once across repeated ChartArchive() / ProvFile() calls.

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

In `@bindings/go/helm/blob/chart_blob_test.go` around lines 160 - 177, The test
TestChartBlob_ExtractionIsLazy only compares returned bytes so it won't detect
repeated reads; replace the raw tarBlob with a small spy/wrapper around the
io.ReadCloser produced by createTarBlobFromTestdata that counts calls to
Read/Close (or ReadCloser() if that's the method on the underlying blob) and
expose that counter; then call cb.ChartArchive() (and cb.ProvFile() if relevant)
multiple times and assert the spy's read count equals 1 to verify the extraction
is performed only once; reference the ChartBlob type and its methods
ChartArchive and ProvFile and wrap the tarBlob used to construct
helmblob.NewChartBlob with the spy wrapper to track reads.
bindings/go/helm/repository/resource/resource_repository.go (1)

26-33: Documentation mismatch: also implements BuiltinResourceRepository.

The comment states this implements repository.ResourceRepository, but GetResourceRepositoryScheme() (lines 46-48) is defined in BuiltinResourceRepository (per bindings/go/plugin/manager/registries/resource/contract.go:30-33). Consider updating the doc to reflect the full interface:

-// ResourceRepository implements [repository.ResourceRepository] for Helm charts.
+// ResourceRepository implements [repository.ResourceRepository] and the plugin
+// [BuiltinResourceRepository] interface for Helm charts.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/helm/repository/resource/resource_repository.go` around lines 26
- 33, The struct comment for ResourceRepository is incomplete: update the doc
comment to state that ResourceRepository implements both
repository.ResourceRepository and BuiltinResourceRepository (which includes
GetResourceRepositoryScheme), so editors can see it satisfies the plugin
registry contract; adjust the top-of-file comment that currently references only
repository.ResourceRepository to include BuiltinResourceRepository and mention
GetResourceRepositoryScheme as the defining method.
🤖 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/blob/chart_blob.go`:
- Around line 54-57: ensureExtracted currently can panic on a nil receiver or a
nil source blob; add guards at the start of ChartBlob.ensureExtracted so it
fails closed: if the receiver is nil, immediately return a descriptive error; if
c.ReadOnlyBlob is nil, set c.err to a descriptive error and return it (so
subsequent callers see the failure) before invoking c.extract.Do; otherwise
proceed to call extractFromTar as before. Reference symbols:
ChartBlob.ensureExtracted, NewChartBlob, c.ReadOnlyBlob, extractFromTar, c.err,
and c.extract.Do.

In `@bindings/go/helm/repository/resource/resource_repository_test.go`:
- Around line 158-162: The subtest "returns error for invalid repository URL"
currently passes an empty helmChart to helmResource(t,
"https://localhost:0/nonexistent", ""), causing the earlier "chart name is
required" validation to trigger instead of exercising the repository
URL/transport error; update the call to helmResource (used by the
repo.DownloadResource test) to pass a non-empty chart name (e.g., "testchart" or
"mychart") so the test reaches the invalid-URL branch and asserts the transport
error from repo.DownloadResource.

In `@bindings/go/helm/repository/resource/resource_repository.go`:
- Around line 131-186: In tarDirectoryRecursive, the tar.Writer (tw) must be
explicitly closed before building the inmemory blob so the tar footer is flushed
and any close error is handled; replace the current deferred tw.Close() with an
explicit close call just after filepath.Walk finishes and before the return that
creates inmemory.New, check and propagate/log any error from tw.Close(), and
only then call inmemory.New(&buf, inmemory.WithMediaType("application/x-tar")).

In `@bindings/go/helm/transformation/get_helm_chart.go`:
- Around line 28-33: Update bindings/go/transfer/internal/builder.go to
initialize the GetHelmChart struct using the new ResourceRepository field
instead of the removed ResourceConsumerIdentityProvider: locate the GetHelmChart
construction (currently assigning to ResourceConsumerIdentityProvider) and
replace that assignment with ResourceRepository: resourceRepo, while keeping
Scheme and CredentialProvider assignments (use transformerScheme and
credentialProvider as before) so the struct fields match the GetHelmChart type.

---

Outside diff comments:
In `@bindings/go/helm/transformation/get_helm_chart.go`:
- Around line 59-67: The code only nil-checks t.ResourceRepository when
resolving credentials but later calls t.ResourceRepository.DownloadResource
unconditionally (risking a nil-pointer panic); update get_helm_chart.go to guard
t.ResourceRepository before any use — either return a clear error if
ResourceRepository is nil (e.g., "resource repository required") or move/remove
the earlier conditional so ResourceRepository is validated up-front;
specifically adjust the logic around t.ResourceRepository,
GetResourceCredentialConsumerIdentity, Resolve and DownloadResource so
DownloadResource is only invoked when t.ResourceRepository != nil (or ensure
ResourceRepository is required and checked at function start).

---

Nitpick comments:
In `@bindings/go/helm/blob/chart_blob_test.go`:
- Around line 160-177: The test TestChartBlob_ExtractionIsLazy only compares
returned bytes so it won't detect repeated reads; replace the raw tarBlob with a
small spy/wrapper around the io.ReadCloser produced by createTarBlobFromTestdata
that counts calls to Read/Close (or ReadCloser() if that's the method on the
underlying blob) and expose that counter; then call cb.ChartArchive() (and
cb.ProvFile() if relevant) multiple times and assert the spy's read count equals
1 to verify the extraction is performed only once; reference the ChartBlob type
and its methods ChartArchive and ProvFile and wrap the tarBlob used to construct
helmblob.NewChartBlob with the spy wrapper to track reads.

In `@bindings/go/helm/repository/resource/resource_repository.go`:
- Around line 26-33: The struct comment for ResourceRepository is incomplete:
update the doc comment to state that ResourceRepository implements both
repository.ResourceRepository and BuiltinResourceRepository (which includes
GetResourceRepositoryScheme), so editors can see it satisfies the plugin
registry contract; adjust the top-of-file comment that currently references only
repository.ResourceRepository to include BuiltinResourceRepository and mention
GetResourceRepositoryScheme as the defining method.
🪄 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: ce7bf3b4-ae3f-412e-b6d2-ac185a4881b7

📥 Commits

Reviewing files that changed from the base of the PR and between 865d043 and 584fead.

📒 Files selected for processing (13)
  • bindings/go/helm/access/access.go
  • bindings/go/helm/access/access_test.go
  • bindings/go/helm/access/spec/v1/helm.go
  • bindings/go/helm/access/spec/v1/schemas/Helm.schema.json
  • bindings/go/helm/blob/chart_blob.go
  • bindings/go/helm/blob/chart_blob_test.go
  • bindings/go/helm/blob/doc.go
  • bindings/go/helm/interface.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/transformation/get_helm_chart.go
  • bindings/go/helm/transformation/get_helm_chart_test.go
💤 Files with no reviewable changes (3)
  • bindings/go/helm/interface.go
  • bindings/go/helm/access/access_test.go
  • bindings/go/helm/access/access.go

Comment thread bindings/go/helm/blob/chart_blob.go Outdated
Comment thread bindings/go/helm/repository/resource/resource_repository_test.go
Comment thread bindings/go/helm/repository/resource/resource_repository.go Outdated
Comment thread bindings/go/helm/transformation/get_helm_chart.go
@matthiasbruns

Copy link
Copy Markdown
Contributor Author

@coderabbitai review again

@coderabbitai

coderabbitai Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

@matthiasbruns Sure! Triggering another full review of the PR now.


🧠 Learnings used
Learnt from: matthiasbruns
Repo: open-component-model/open-component-model PR: 2094
File: bindings/go/helm/repository/resource/resource_repository.go:24-24
Timestamp: 2026-03-30T10:12:38.389Z
Learning: In `bindings/go/helm/repository/resource/resource_repository.go` (open-component-model/open-component-model), `ResourceRepository.DownloadResource()` intentionally does NOT verify the downloaded blob against the resource descriptor's integrity metadata inline. Digest verification is handled at a higher level by `ResourceDigestProcessor.ProcessResourceDigest()`, in the constructor/controller layer (e.g., `constructor/construct.go` and `kubernetes/controller/internal/ocm/resource.go`). The OCI `ResourceRepository` follows the same pattern. This is documented in ADR-0006. Do not flag the absence of inline digest verification in `DownloadResource()` as a bug.

Learnt from: matthiasbruns
Repo: open-component-model/open-component-model PR: 2128
File: bindings/go/helm/transformation/get_helm_chart.go:28-33
Timestamp: 2026-04-01T09:22:00.056Z
Learning: In open-component-model/open-component-model, cross-binding updates (e.g., updating `bindings/go/transfer/internal/builder.go` to reference a new field introduced in `bindings/go/helm/`) cannot be done in the same PR as the upstream binding change. The CI workflow checks out bindings from `main` and tests against them, so the dependent binding update must be done in a follow-up PR after the upstream binding change is merged. Do not flag missing cross-binding updates as bugs in PRs that introduce the upstream change.

Learnt from: jakobmoellerdev
Repo: open-component-model/open-component-model PR: 2069
File: bindings/go/transfer/internal/helpers.go:110-119
Timestamp: 2026-03-25T18:07:39.188Z
Learning: In `bindings/go/transfer/internal/helpers.go` (open-component-model/open-component-model), `RepositoryEqual` intentionally compares `*oci.Repository` by raw `BaseUrl` and `SubPath` fields. This is safe because all repository specs coming through the normal parsing path are normalized by `compref.ParseRepository`, which consistently splits the URL into `BaseUrl+SubPath`. Manually constructing `*oci.Repository` with a different split for the same logical repo is a caller error, not something `RepositoryEqual` or `AppendUniqueRepositories` should compensate for. Do not flag this comparison approach as a bug.
✅ 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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
bindings/go/helm/blob/chart_blob.go (1)

87-100: Consider warning or erroring when multiple .tgz files are found.

If a tar archive contains multiple .tgz entries, the current implementation silently uses the last one. While the ResourceRepository should only produce single-chart tars, adding a check could help catch malformed archives early.

💡 Optional enhancement
 		switch {
 		case strings.HasSuffix(header.Name, ".tgz"):
+			if chartBlob != nil {
+				return nil, nil, fmt.Errorf("multiple chart (.tgz) files found in tar archive")
+			}
 			chartBlob = inmemory.New(
 				bytes.NewReader(data),
 				inmemory.WithMediaType(compression.MediaTypeGzip),
 				inmemory.WithSize(int64(len(data))),
 			)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/helm/blob/chart_blob.go` around lines 87 - 100, The loop that
processes tar headers currently overwrites chartBlob when multiple entries match
".tgz"; add a guard so when you encounter a ".tgz" and chartBlob is already
non-nil you surface the problem instead of silently using the last one — e.g.,
detect chartBlob != nil inside the case for strings.HasSuffix(header.Name,
".tgz") and either return an explicit error (preferred) like "multiple .tgz
entries in chart tar" or emit a clear warning via the package logger; update the
containing function's error handling/return signature accordingly and ensure
callers handle the new error path (refer to symbols chartBlob, header.Name, and
the switch/case block around inmemory.New).
bindings/go/helm/repository/resource/resource_repository.go (1)

141-149: Close each archived file immediately instead of deferring inside the walk.

defer f.Close() in the callback keeps every descriptor open until the full walk completes. That is small today, but this helper is generic enough that it is worth closing on each iteration.

One way to tighten the callback
 		f, err := root.Open(path)
 		if err != nil {
 			return fmt.Errorf("error opening file %s: %w", path, err)
 		}
-		defer func() { _ = f.Close() }()
-
 		if _, err := io.Copy(tw, f); err != nil {
+			_ = f.Close()
 			return fmt.Errorf("error writing file %s to tar: %w", path, err)
 		}
+		if err := f.Close(); err != nil {
+			return fmt.Errorf("error closing file %s: %w", path, err)
+		}
 
 		return nil
 	})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/helm/repository/resource/resource_repository.go` around lines 141
- 149, The callback that opens files using root.Open(path) currently defers
f.Close(), keeping descriptors open for the whole walk; change it to close each
file immediately after use by removing the defer and calling f.Close() right
after the io.Copy(tw, f) call (handle and return any Close error appropriately,
e.g., wrap it with fmt.Errorf), so the sequence in the callback is: open file
via root.Open(path), io.Copy to tw, call f.Close(), and propagate any errors
from Copy or Close; update error messages to reference path and use the same
wrapping style used elsewhere in this file.
🤖 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/repository/resource/doc.go`:
- Around line 32-36: The comment incorrectly states that the Helm repository is
registered in the CLI; update the doc text to present the registration snippet
as an example or optional follow-up step rather than asserting current behavior.
Edit the block that references
manager.ResourcePluginRegistry.RegisterInternalResourcePlugin and
resource.NewResourceRepository to say something like "For example, you can
register the repository in the CLI with:" or "As a follow-up you may register
the repository:" so it no longer claims it is already wired by default.

In `@bindings/go/helm/transformation/get_helm_chart.go`:
- Around line 30-32: The code calls t.ResourceRepository.DownloadResource(...)
(and other uses of t.ResourceRepository around the GetHelmChart flow) without
checking for nil, causing a panic when the repository isn't wired; update the
code in the GetHelmChart logic to validate t.ResourceRepository at the start (or
before each use) and return a regular error (not a panic) if it's nil, e.g.,
return fmt.Errorf("missing ResourceRepository: ...") so callers receive a
configuration error instead of a nil-pointer panic; apply the same
nil-check/early-error pattern to all sites where t.ResourceRepository is used
(references around lines where DownloadResource is invoked).

---

Nitpick comments:
In `@bindings/go/helm/blob/chart_blob.go`:
- Around line 87-100: The loop that processes tar headers currently overwrites
chartBlob when multiple entries match ".tgz"; add a guard so when you encounter
a ".tgz" and chartBlob is already non-nil you surface the problem instead of
silently using the last one — e.g., detect chartBlob != nil inside the case for
strings.HasSuffix(header.Name, ".tgz") and either return an explicit error
(preferred) like "multiple .tgz entries in chart tar" or emit a clear warning
via the package logger; update the containing function's error handling/return
signature accordingly and ensure callers handle the new error path (refer to
symbols chartBlob, header.Name, and the switch/case block around inmemory.New).

In `@bindings/go/helm/repository/resource/resource_repository.go`:
- Around line 141-149: The callback that opens files using root.Open(path)
currently defers f.Close(), keeping descriptors open for the whole walk; change
it to close each file immediately after use by removing the defer and calling
f.Close() right after the io.Copy(tw, f) call (handle and return any Close error
appropriately, e.g., wrap it with fmt.Errorf), so the sequence in the callback
is: open file via root.Open(path), io.Copy to tw, call f.Close(), and propagate
any errors from Copy or Close; update error messages to reference path and use
the same wrapping style used elsewhere in this file.
🪄 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: d3f33907-2dbb-4f20-901e-d56a20bc4ca9

📥 Commits

Reviewing files that changed from the base of the PR and between 865d043 and 8bd1f23.

📒 Files selected for processing (15)
  • bindings/go/helm/access/access.go
  • bindings/go/helm/access/access_test.go
  • bindings/go/helm/access/spec/v1/helm.go
  • bindings/go/helm/access/spec/v1/schemas/Helm.schema.json
  • bindings/go/helm/blob/chart_blob.go
  • bindings/go/helm/blob/chart_blob_test.go
  • bindings/go/helm/blob/doc.go
  • bindings/go/helm/digest/digest.go
  • bindings/go/helm/input/method.go
  • bindings/go/helm/interface.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/transformation/get_helm_chart.go
  • bindings/go/helm/transformation/get_helm_chart_test.go
💤 Files with no reviewable changes (2)
  • bindings/go/helm/interface.go
  • bindings/go/helm/access/access_test.go

Comment thread bindings/go/helm/repository/resource/doc.go
Comment thread bindings/go/helm/transformation/get_helm_chart.go
@matthiasbruns matthiasbruns force-pushed the feat/911_helm_resource_repo_bindings branch 2 times, most recently from e6fab60 to 7271f02 Compare April 1, 2026 12:56
@matthiasbruns matthiasbruns marked this pull request as ready for review April 1, 2026 12:58
@matthiasbruns matthiasbruns requested a review from a team as a code owner April 1, 2026 12:58

@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 (1)
bindings/go/helm/transformation/get_helm_chart.go (1)

62-62: Minor: Redundant nil check for ResourceRepository.

The t.ResourceRepository != nil check at line 62 is redundant since line 43 already returns an error if ResourceRepository is nil. This is harmless but could be simplified.

♻️ Optional simplification
-	if t.CredentialProvider != nil && t.ResourceRepository != nil {
+	if t.CredentialProvider != nil {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/helm/transformation/get_helm_chart.go` at line 62, The
conditional `if t.CredentialProvider != nil && t.ResourceRepository != nil`
contains a redundant `t.ResourceRepository != nil` check because earlier in the
function `t.ResourceRepository` is already validated and an error returned if
nil; simplify the condition to only check `t.CredentialProvider != nil` (e.g.,
replace the combined conditional with `if t.CredentialProvider != nil`) so the
branch logic remains the same but the redundant nil check is removed; ensure you
update any nearby comments or logic that assumed the combined check to avoid
changing behavior.
🤖 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/transformation/get_helm_chart.go`:
- Line 62: The conditional `if t.CredentialProvider != nil &&
t.ResourceRepository != nil` contains a redundant `t.ResourceRepository != nil`
check because earlier in the function `t.ResourceRepository` is already
validated and an error returned if nil; simplify the condition to only check
`t.CredentialProvider != nil` (e.g., replace the combined conditional with `if
t.CredentialProvider != nil`) so the branch logic remains the same but the
redundant nil check is removed; ensure you update any nearby comments or logic
that assumed the combined check to avoid changing behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e648b494-c8ff-42df-a966-431dfcb5965b

📥 Commits

Reviewing files that changed from the base of the PR and between 8bd1f23 and 7271f02.

📒 Files selected for processing (7)
  • bindings/go/helm/access/access.go
  • bindings/go/helm/blob/chart_blob_test.go
  • bindings/go/helm/digest/digest.go
  • bindings/go/helm/internal/credentials.go
  • bindings/go/helm/internal/credentials_test.go
  • bindings/go/helm/repository/resource/resource_repository.go
  • bindings/go/helm/transformation/get_helm_chart.go
💤 Files with no reviewable changes (1)
  • bindings/go/helm/access/access.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • bindings/go/helm/digest/digest.go
  • bindings/go/helm/blob/chart_blob_test.go

@jakobmoellerdev jakobmoellerdev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a really cool change 🚀 First pass didnt make me flag anything but need to read through the repo changes more in detail

Comment thread bindings/go/helm/blob/chart_blob.go Outdated
Comment thread bindings/go/helm/repository/resource/resource_repository.go
Comment thread bindings/go/helm/repository/resource/resource_repository.go
Comment thread bindings/go/helm/repository/resource/resource_repository.go Outdated
Comment thread bindings/go/helm/repository/resource/resource_repository.go
Comment thread bindings/go/helm/repository/resource/resource_repository.go Outdated
Comment thread bindings/go/helm/transformation/get_helm_chart.go Outdated
@matthiasbruns

Copy link
Copy Markdown
Contributor Author

why is that? if the header is invalid the archive is corrupt now? (i actually think code is correct, just unsure regarding the conversation here)
@jakobmoellerdev since we rely on the header to determine what kind we are working with (chart or prov), I think failing if we cannot read the header is the correct way to go and we should error out.

matthiasbruns and others added 2 commits April 16, 2026 09:28
On-behalf-of: SAP <matthias.bruns@sap.com>
Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
@matthiasbruns matthiasbruns force-pushed the feat/911_helm_resource_repo_bindings branch from 913520d to ba06438 Compare April 16, 2026 07:30
On-behalf-of: SAP <matthias.bruns@sap.com>
Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
matthiasbruns and others added 2 commits April 16, 2026 09:49
Use the existing filesystem.GetBlobFromPath to create tar archives from
the helm download directory instead of a hand-rolled tarDirectoryRecursive
implementation. The streaming blob is eagerly materialized into an
inmemory blob before the temp directory cleanup runs.

Resolves the TODO at resource_repository.go:118 and closes
open-component-model/ocm-project#1014.

Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
matthiasbruns and others added 2 commits April 16, 2026 14:09
…tion

Replace manual ReadCloser+New+Load+Close sequence with cache.Cache()
which does the same thing and also preserves size/digest/mediaType
metadata from the streaming blob.

Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
@matthiasbruns matthiasbruns enabled auto-merge (squash) April 16, 2026 12:24
matthiasbruns and others added 3 commits April 16, 2026 14:43
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 force-pushed the feat/911_helm_resource_repo_bindings branch from 195e8b8 to 2be84d3 Compare April 16, 2026 12:51
@matthiasbruns matthiasbruns merged commit 2207446 into open-component-model:main Apr 16, 2026
29 checks passed
@matthiasbruns matthiasbruns deleted the feat/911_helm_resource_repo_bindings branch April 16, 2026 13:12
ocmbot Bot pushed a commit that referenced this pull request Apr 16, 2026
#### What this PR does / why we need it

Introduces a Helm-based `ResourceRepository` implementing
`repository.ResourceRepository` and
`bindings/go/plugin/manager/registries/resource/contract.go`.

Full usage can be seen here:
#2130

#### Which issue(s) this PR fixes

Contributes open-component-model/ocm-project#911

#### CLI PR
#2094

#### Testing
Fully tested in
#2130

#### Helm ResourceRepository — Changes compared to legacy OCM

- **CLI & transfer** will use the `ResourceRepository` interface instead
of the deprecated `HelmAccess` struct for
  credential identity resolution and chart downloads
- **Deprecated types removed**: `helm.ResourceConsumerIdentityProvider`
interface, `helmaccess.HelmAccess` struct, and
  their tests — functionality is covered by `ResourceRepository`
- **Blob format**: Downloads return a `ChartBlob` (tar archive wrapping
`.tgz` + optional `.prov`), replacing the legacy
  pattern of separate blob accessors for chart and provenance
- **Plugin registration**: The helm `ResourceRepository` is registered
as a builtin plugin alongside the existing OCI
and digest processor plugins in
#2130

##### Intentional differences from legacy

| | Legacy OCM | New |

|--------------------------------------|-------------------------------------------------------------------|--------------------------------------------------------------|
| `CACert` / `Keyring` on access spec | Supported as inline fields |
Omitted — use credential resolver instead |
| OCI-hosted helm charts (`oci://`) | Handled by helm access method with
separate OCI download path | Should use the OCI ResourceRepository
(separate access type) |
| Blob return format (only internally) | Raw `.tgz` blob
(`ChartLayerMediaType`), prov accessed separately | `ChartBlob` tar
wrapping both `.tgz` and `.prov` |
| Local charts | Not in access method (`IsLocal() = false`) | Not in
ResourceRepository — handled by helm input plugin |

##### Test coverage

- Unit tests for `ResourceRepository` (credential identity, download,
temp folder usage, nil guards)
- Unit tests for `ChartBlob` extraction (using real testdata charts)
- Integration test: `add cv` with helm access to OCI registry
- Integration test: `download resource` with helm access from CTF
(byte-level verification)
- Shell test: end-to-end download of podinfo chart with SHA256
verification

---------

Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
Co-authored-by: Jakob Möller <contact@jakob-moeller.com> 2207446
@matthiasbruns matthiasbruns mentioned this pull request Apr 16, 2026
1 task
matthiasbruns added a commit that referenced this pull request Apr 16, 2026
<!-- markdownlint-disable MD041 -->
#### What this PR does / why we need it
Follow up of
#2128
`transfer` are refactored to use the new Helm ResourceRepository. 

#### Which issue(s) this PR fixes
Contributes
open-component-model/ocm-project#911

#### Testing

##### How to test the changes

Check comment:
#2130 (comment)

##### Verification

- [x] I have tested the changes locally by running `ocm`

---------

Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
@matthiasbruns matthiasbruns linked an issue Apr 16, 2026 that may be closed by this pull request
14 tasks
jakobmoellerdev pushed a commit that referenced this pull request Apr 17, 2026
<!-- markdownlint-disable MD041 -->
#### What this PR does / why we need it
This PR tied the helm ResourceRepository changes together and updates
the spec location changes.

Follow up of
#2128
`cli` and `transfer` are refactored to use the new Helm
ResourceRepository.
Also removes the deprecated `Access` and
`ResourceConsumerIdentityProvider`

#### Which issue(s) this PR fixes
Contributes
open-component-model/ocm-project#911

#### Testing

##### How to test the changes

Check comment:
#2130 (comment)

##### Verification

- [x] I have tested the changes locally by running `ocm`

---------

Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

!BREAKING-CHANGE! Breaking change in API or ocm-cli or spec kind/feature new feature, enhancement, improvement, extension size/l Large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Helm ResourceRepository

6 participants