Skip to content

Conversation

@mdbooth
Copy link
Contributor

@mdbooth mdbooth commented Dec 16, 2025

Rewrite manifests-gen to support embedding CAPI installer manifests in the provider image instead of in a transport configmap.

Update the CAPI installer controller to support the new embedded manifests in addition to the existing transport configmaps. This allows us to have a smooth transition period while we update all providers.

Summary by CodeRabbit

  • New Features

    • Provider image metadata support with runtime caching to surface provider manifests used during installation.
  • Infrastructure

    • RBAC Role and RoleBinding added to allow reading the image pull-secret.
    • Operator Deployment updated to mount a provider-image cache and set the cache directory env var.
  • Manifests / Tooling

    • New manifest generator writes manifests.yaml and metadata.yaml and supports kustomize components.
  • Tests

    • Comprehensive tests added for provider image extraction and processing.

✏️ Tip: You can customize this high-level summary in your review settings.

@openshift-ci-robot
Copy link

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Dec 16, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 16, 2025

📝 Walkthrough

Walkthrough

Threads provider image metadata into startup and reconciler wiring, adds a providerimages package to fetch/cache provider manifests from container images, replaces legacy manifest pipeline with a Go-based manifests-generator using typed client.Object, and updates RBAC and deployment to allow reading cached provider manifests.

Changes

Cohort / File(s) Summary
Startup & reconciler wiring
cmd/cluster-capi-operator/main.go
Read provider images from disk (env PROVIDER_IMAGE_DIR), compute providerProfiles early, and propagate providerProfiles/provider images into setupPlatformReconcilers and setupReconcilers
Provider image module & auth
pkg/providerimages/providerimages.go
pkg/providerimages/pullsecret.go
pkg/providerimages/providerimages_test.go
New package to fetch images (go-containerregistry), extract /capi-operator-manifests/{metadata.yaml,manifests.yaml}, cache manifests to disk with content IDs, parse pull-secret into a keychain; extensive tests added
CAPI installer reconciler
pkg/controllers/capiinstaller/capi_installer_controller.go
pkg/controllers/capiinstaller/capi_installer_controller_test.go
Added exported ProviderImages []providerimages.ProviderImageManifests field; reader-based manifest extraction; reconcileProviderImages / applyProviderImage; envsubst and multi-doc handling; tests adjusted
Manifest generator (new)
manifests-gen/*.go (e.g., main.go, generate.go, customizations.go, util.go)
manifests-gen/kustomization.yaml
manifests-gen/go.mod
New Go-based manifests generator using krusty/kustomize; converts kustomize output to client.Object slices, processes/customizes objects, writes manifests.yaml and metadata.yaml, adds CLI options and validation
Removed legacy provider pipeline
manifests-gen/providers.go
manifests-gen/providercustomizations.go
Deleted previous provider-loading, per-provider customization, and manifest-writing orchestration; replaced by manifests-gen tooling and providerimages package
RBAC & deployment changes
manifests/0000_30_cluster-api_03_rbac_roles.yaml
manifests/0000_30_cluster-api_04_rbac_bindings.yaml
manifests/0000_30_cluster-api_11_deployment.yaml
Add Role/RoleBinding to read pull-secret and mount provider-images emptyDir; set env PROVIDER_IMAGE_DIR for the operator pod
Dependency updates
go.mod, e2e/go.mod, hack/tools/go.mod, manifests-gen/go.mod
Added/updated modules (google/go-containerregistry, docker/cli, controller-runtime, x/tools, oauth2, estargz, etc.) and replace directives
Config & util changes
pkg/util/readconfig.go
Removed YAML provider support; ReadImagesFile now reads JSON map of image names→refs; removed ReadProvidersFile and related types
Minor lint cleanups
pkg/controllers/infracluster/azure.go
pkg/conversion/capi2mapi/aws.go
Removed nolint:gosec comments (no logic change)

Sequence Diagram(s)

sequenceDiagram
    participant Operator as Cluster CAPI Operator
    participant K8s as Kubernetes API
    participant Registry as Container Registry
    participant Disk as Local Disk Cache
    participant Reconciler as CAPI Installer Reconciler

    Operator->>K8s: Read pull-secret (openshift-config)
    K8s-->>Operator: Return pull-secret
    Operator->>Registry: Fetch provider image (using keychain)
    Registry-->>Operator: Return image layers
    Operator->>Operator: Extract metadata.yaml & manifests.yaml
    Operator->>Disk: Write manifests to providerImageDir/<sanitized-ref>/
    Operator->>Operator: Compute ContentID (SHA256)
    Operator->>Reconciler: Pass ProviderImages metadata & paths
    Reconciler->>Disk: Read cached manifests
    Reconciler->>K8s: Apply manifests
    K8s-->>Reconciler: Apply results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nibble tarballs, hop through layers,
pull secrets fetched with careful prayers.
Manifests cached and hashed just so,
reconcilers wake and outward go.
Hooray—provider images set to show!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main objective: a rewrite of manifests-gen to support upgrade safety by embedding CAPI manifests in provider images.

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

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 92fb887 and dfdbf0d.

📒 Files selected for processing (3)
  • pkg/controllers/capiinstaller/capi_installer_controller.go
  • pkg/providerimages/providerimages.go
  • pkg/providerimages/providerimages_test.go
🧰 Additional context used
🧬 Code graph analysis (2)
pkg/providerimages/providerimages_test.go (1)
pkg/providerimages/providerimages.go (1)
  • ProviderImageManifests (56-64)
pkg/controllers/capiinstaller/capi_installer_controller.go (1)
pkg/providerimages/providerimages.go (1)
  • ProviderImageManifests (56-64)
🔇 Additional comments (15)
pkg/providerimages/providerimages_test.go (5)

39-60: LGTM on fakeImageFetcher implementation.

The fake properly checks context cancellation before proceeding and handles both error injection and image lookup scenarios correctly for test isolation.


62-123: Test helpers are well-implemented.

The tar layer creation and image construction helpers correctly use go-containerregistry APIs with proper error handling and memory management.


155-163: Metadata YAML field name is now correct.

The helper correctly uses providerImageRef matching the ProviderMetadata struct's JSON tag json:"providerImageRef,omitempty".


489-533: Layer precedence test correctly validates OCI layer semantics.

The test verifies that when multiple layers contain the same files, the higher (later) layer's content takes precedence, which matches standard OCI image behavior.


610-678: Comprehensive test runner with proper resource and context management.

The test runner correctly manages resources via t.TempDir(), handles context setup/cancellation, and validates output directory structure. The common validation at lines 641-672 ensures manifests are written to correct locations with appropriate assertions for directory structure and file existence.

pkg/controllers/capiinstaller/capi_installer_controller.go (4)

188-235: Provider image reconciliation logic is well-structured.

The filtering by OCPPlatform correctly handles empty platform as "match all", and the sorting ensures deterministic application order (core → infrastructure → others, then by name).


237-262: Resource handling is now correct.

The defer pattern works correctly here since applyProviderImage is a separate function called per-iteration. The named return value err allows the deferred close to join any close errors with the function's error.


517-532: Resource leak in configMapReader is now fixed.

The function correctly returns io.ReadCloser, using io.NopCloser for plain data and reader.IOReadCloser() for the zstd decoder, ensuring callers can properly close resources.


358-363: Good defensive check for empty manifests.

Skipping empty/whitespace-only manifests prevents parsing errors from empty YAML documents that can result from splitting multi-document YAML.

pkg/providerimages/providerimages.go (6)

118-132: Pull secret retrieval and keychain setup are correct.

The function properly retrieves the pull secret from the well-known location and creates a keychain for registry authentication before delegating to the internal readProviderImages function.


140-193: Concurrent image processing is well-implemented.

The function correctly uses errgroup with a concurrency limit of 5, collects results via a channel, and aggregates all errors. This allows processing to continue even if some images fail, while still reporting all failures.


354-381: Layer extraction correctly handles OCI layer precedence.

The implementation iterates layers in reverse order (top to bottom) and skips existing files, ensuring higher layers take precedence. This correctly implements standard OCI image semantics.


267-305: Profile discovery with validation is well-designed.

The implementation correctly:

  • Scans only subdirectories (not files at the root level)
  • Validates that profiles contain both required files
  • Returns early errors for incomplete profiles
  • Returns errNoCapiManifests when no valid profiles are found

469-497: Manifest writing with hash calculation is efficiently implemented.

The function uses io.MultiWriter to simultaneously write to the file and compute the SHA256 hash in a single pass, avoiding the need to read the content twice.


458-467: Image reference sanitization handles common characters.

The function correctly replaces /, :, and @ characters that appear in image references and aren't valid in directory names. Note that theoretical collisions are possible (e.g., a/b:v1 and a_b_v1 would map to the same directory) but unlikely in practice with real image references.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Dec 16, 2025

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

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Dec 16, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

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

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

@mdbooth mdbooth changed the title Rewrite manifests-gen to support upgrade safety OCPCLOUD-3327: Rewrite manifests-gen to support upgrade safety Dec 16, 2025
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Dec 16, 2025
@openshift-ci-robot
Copy link

openshift-ci-robot commented Dec 16, 2025

@mdbooth: This pull request references OCPCLOUD-3327 which is a valid jira issue.

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

Details

In response to this:

  • Remove provider customisation for PowerVS
  • manifests-gen: Rewrite to support Update Safety
  • capiinstaller: Compatibility with new manifests-gen

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

@mdbooth
Copy link
Contributor Author

mdbooth commented Dec 16, 2025

/test e2e-aws-ovn-techpreview

@mdbooth
Copy link
Contributor Author

mdbooth commented Dec 16, 2025

/testwith openshift/cluster-capi-operator/main/e2e-aws-ovn-techpreview openshift/cluster-api-provider-aws#584

@mdbooth
Copy link
Contributor Author

mdbooth commented Dec 17, 2025

/testwith openshift/cluster-capi-operator/main/e2e-aws-ovn-techpreview openshift/cluster-api-provider-aws#584

@mdbooth
Copy link
Contributor Author

mdbooth commented Dec 17, 2025

/test e2e-aws-ovn-techpreview

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 18, 2025
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 18, 2025
@mdbooth mdbooth force-pushed the manifests-gen branch 3 times, most recently from f3ba06c to a8a93e3 Compare December 18, 2025 16:54
@mdbooth
Copy link
Contributor Author

mdbooth commented Dec 19, 2025

/test e2e-aws-ovn-techpreview
/testwith openshift/cluster-capi-operator/main/e2e-aws-ovn-techpreview openshift/cluster-api-provider-aws#584

@mdbooth
Copy link
Contributor Author

mdbooth commented Dec 19, 2025

/test e2e-aws-ovn-techpreview

@mdbooth
Copy link
Contributor Author

mdbooth commented Dec 19, 2025

/testwith openshift/cluster-capi-operator/main/e2e-aws-ovn-techpreview openshift/cluster-api-provider-aws#584 openshift/cluster-api#259

2 similar comments
@mdbooth
Copy link
Contributor Author

mdbooth commented Dec 19, 2025

/testwith openshift/cluster-capi-operator/main/e2e-aws-ovn-techpreview openshift/cluster-api-provider-aws#584 openshift/cluster-api#259

@mdbooth
Copy link
Contributor Author

mdbooth commented Dec 19, 2025

/testwith openshift/cluster-capi-operator/main/e2e-aws-ovn-techpreview openshift/cluster-api-provider-aws#584 openshift/cluster-api#259

@mdbooth
Copy link
Contributor Author

mdbooth commented Dec 21, 2025

The e2e-aws-ovn-techpreview pass shows the modifications to the capiinstaller controller are backwards compatible with current transport configmaps.

openshift/cluster-api-provider-aws#584 and openshift/cluster-api#259 update CAPA and core CAPI to publish manifests only in the provider images. They do not publish transport configmaps.

The multi-pr test pass with these 2 PRs shows that pulling manifests from images is working.

@mdbooth mdbooth marked this pull request as ready for review January 5, 2026 13:09
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jan 5, 2026
@openshift-ci openshift-ci bot requested review from nrb and theobarberbany January 5, 2026 13:09
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 5, 2026

@mdbooth: Overrode contexts on behalf of mdbooth: ci/prow/okd-scos-images

Details

In response to this:

/override ci/prow/okd-scos-images

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

@mdbooth
Copy link
Contributor Author

mdbooth commented Jan 5, 2026

The existing tests will demonstrate that the PR continues to work with existing transport configmaps.

The following test will demonstrate that the PR works with updated providers which use image-based manifests.

/testwith openshift/cluster-capi-operator/main/e2e-aws-ovn-techpreview openshift/cluster-api-provider-aws#584 openshift/cluster-api#259

@mdbooth
Copy link
Contributor Author

mdbooth commented Jan 5, 2026

/testwith openshift/cluster-capi-operator/main/e2e-aws-ovn-techpreview openshift/cluster-api-provider-aws#584 openshift/cluster-api#259

@mdbooth
Copy link
Contributor Author

mdbooth commented Jan 5, 2026

/pipeline required

@openshift-ci-robot
Copy link

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@mdbooth
Copy link
Contributor Author

mdbooth commented Jan 5, 2026

/retest-required

1 similar comment
@mdbooth
Copy link
Contributor Author

mdbooth commented Jan 6, 2026

/retest-required

@mdbooth
Copy link
Contributor Author

mdbooth commented Jan 6, 2026

/test e2e-azure-ovn-techpreview
/test e2e-metal3-capi-techpreview

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 6, 2026

@mdbooth: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-metal3-capi-techpreview 3da26fb link false /test e2e-metal3-capi-techpreview

Full PR test history. Your PR dashboard.

Details

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

The bump to x/tools v0.39.0 changes the behaviour of the gosec linter,
which no longer complains about these valid conversions.
@openshift-ci-robot
Copy link

openshift-ci-robot commented Jan 9, 2026

@mdbooth: This pull request references OCPCLOUD-3327 which is a valid jira issue.

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

Details

In response to this:

Rewrite manifests-gen to support embedding CAPI installer manifests in the provider image instead of in a transport configmap.

Update the CAPI installer controller to support the new embedded manifests in addition to the existing transport configmaps. This allows us to have a smooth transition period while we update all providers.

Summary by CodeRabbit

  • New Features

  • Provider image metadata support added for improved manifest generation and provider image caching.

  • Infrastructure

  • New RBAC Role and RoleBinding to allow reading pull-secret.

  • Deployment updated with provider-image cache (env var, volume and mount).

  • Manifests / Tooling

  • New manifest generator emits manifests.yaml and metadata.yaml and adds kustomize component for local secrets.

✏️ Tip: You can customize this high-level summary in your review settings.

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
manifests-gen/go.mod (1)

3-6: Reconcile toolchain Go version inconsistency between manifests-gen and hack/tools submodules.

The Go 1.24.0 requirement is justified—the codebase uses slices.Collect() at line 223 of cmd/cluster-capi-operator/main.go, which requires Go 1.24+. However, manifests-gen/go.mod pins toolchain go1.24.4 while hack/tools/go.mod pins toolchain go1.24.10. Consider updating manifests-gen to match the newer toolchain version used elsewhere in the repo for consistency.

The replace github.com/openshift/cluster-capi-operator => .. directive is appropriate for this submodule and the project uses .ci-operator.yaml (OpenShift CI), which should have Go 1.24+ support. Note that docker/cli v29.0.3 appears as an indirect dependency in manifests-gen/go.mod, inherited from google/go-containerregistry.

🤖 Fix all issues with AI agents
In @cmd/cluster-capi-operator/main.go:
- Around line 218-230: Replace the current unconditional os.Exit on provider
image read failures by using a signal-aware startup context and a bounded
timeout: create a single ctx via ctrl.SetupSignalHandler() (use it for manager
startup), wrap providerimages.ReadProviderImages with context.WithTimeout to
enforce a deadline, call providerimages.ReadProviderImages(ctxWithTimeout, ...)
instead of context.Background(), and on error log the failure (including err)
but do not call os.Exit—leave providerImages nil so the legacy ConfigMap path
can proceed; apply the same pattern to the other provider image read sites (the
calls around the blocks that set providerImages and similar reads at 231-243 and
259-263).

In @go.mod:
- Line 12: The go.mod update pins github.com/docker/cli to v29.0.3 while
go-containerregistry is v0.20.7 (tested against docker v28.x); verify
compatibility by testing the combination in staging focusing on daemon API
usage, content trust and cgroup behavior, and if any breakage appears pin
github.com/docker/cli back to the v28.x series in go.mod (or add a go.mod
replace) to match go-containerregistry’s tested environment until you can
upgrade go-containerregistry or validate v29; run your container
registry-related integration tests and CI to confirm no runtime/API regressions.

In @pkg/controllers/capiinstaller/capi_installer_controller.go:
- Around line 181-183: When reconcileProviderImages(ctx, log) returns an error,
call r.setDegradedCondition(ctx, "ProviderImagesReconcileFailed", err) (or the
same setDegradedCondition signature used for ConfigMap errors) before returning
so the controller sets the degraded condition consistently; mirror the pattern
used for ConfigMap processing errors (the calls around ConfigMap handling) and
include the error in the degraded condition message, then return the wrapped
error as currently done.
🧹 Nitpick comments (6)
manifests-gen/util.go (1)

21-25: Use mustConvert carefully in non-initialization code paths.

The mustConvert function panics on conversion errors, which is appropriate for programming errors (type mismatches) but should be avoided in runtime reconciliation loops where conversion failures could occur due to malformed resources. Ensure this function is only used in contexts where conversion is guaranteed to succeed (e.g., well-known internal types, initialization code).

pkg/providerimages/pullsecret.go (2)

29-40: Consider treating “missing pull-secret key” differently than “empty pull-secret”.

len(pullSecret)==0 returning authn.DefaultKeychain can silently hide a misconfigured Secret (e.g., missing .dockerconfigjson). If you want stricter behavior, have the caller distinguish between “Secret key absent” vs “present but empty”.


48-75: Make auth lookup more robust: avoid struct-equality emptiness checks; consider alternate registry keys.

Two nits that can turn into hard-to-diagnose auth failures:

  • cfg == (types.AuthConfig{}) after mutating ServerAddress is fragile; better to explicitly check the credential/token fields you actually use.
  • Some docker configs store registry keys with a scheme/prefix; a fallback lookup (e.g., try key, then https:// variants) would improve compatibility.
Proposed adjustment (field-based emptiness + fallback keys)
 func (k *configFileKeychain) Resolve(resource authn.Resource) (authn.Authenticator, error) {
 	// Try to get auth config for the registry
 	key := resource.RegistryStr()
 	if key == name.DefaultRegistry {
 		key = authn.DefaultAuthKey
 	}
 
-	cfg, err := k.cf.GetAuthConfig(key)
-	if err != nil {
-		return nil, fmt.Errorf("failed to get auth config for %s: %w", key, err)
-	}
+	cfg, err := k.cf.GetAuthConfig(key)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get auth config for %s: %w", key, err)
+	}
+	// Fallback for configs that include a scheme in the auth key.
+	if cfg == (types.AuthConfig{}) && !strings.HasPrefix(key, "https://") && !strings.HasPrefix(key, "http://") {
+		if alt, altErr := k.cf.GetAuthConfig("https://" + key); altErr == nil {
+			cfg = alt
+		}
+	}
 
-	// Check if we got an empty config
-	empty := types.AuthConfig{}
-	cfg.ServerAddress = "" // Clear for comparison
-
-	if cfg == empty {
+	if cfg.Username == "" && cfg.Password == "" && cfg.Auth == "" && cfg.IdentityToken == "" && cfg.RegistryToken == "" {
 		return authn.Anonymous, nil
 	}
 
 	return authn.FromConfig(authn.AuthConfig{
 		Username:      cfg.Username,
 		Password:      cfg.Password,
 		Auth:          cfg.Auth,
 		IdentityToken: cfg.IdentityToken,
 		RegistryToken: cfg.RegistryToken,
 	}), nil
 }

(You’d need to add strings to imports.)

manifests-gen/main.go (2)

21-47: allowedPlatformTypes is fine, but it will drift—add a guardrail.

Given this list is manually curated, consider adding a small unit test (or a comment pointing to the upstream enum source) so future platform additions don’t silently reject new values.


111-147: Validation flow is solid; improve error detail for invalid semver and output to stderr.

Two small tweaks:

  • Include the semantic parse error (%w) so callers know why it failed.
  • Print validation/generation errors to stderr.
Proposed tweak
 	if err := validateFlags(opts); err != nil {
-		fmt.Println(err)
+		fmt.Fprintln(os.Stderr, err)
 		os.Exit(1)
 	}
 
 	if err := generateManifests(opts); err != nil {
-		fmt.Println(err)
+		fmt.Fprintln(os.Stderr, err)
 		os.Exit(1)
 	}
@@
 			if opts.version != "" {
 				if _, err := version.ParseSemantic(opts.version); err != nil {
-					return fmt.Errorf("invalid version %s for provider %s", opts.version, opts.name)
+					return fmt.Errorf("invalid version %q for provider %q: %w", opts.version, opts.name, err)
 				}
 			}
 			return nil
 		}(),
pkg/providerimages/providerimages_test.go (1)

63-93: Minor test determinism nit: tar file entry order depends on map iteration.

Probably fine (logic likely looks up by path), but if you ever debug layer contents or add logic that depends on traversal order, consider sorting path keys before writing headers.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 3da26fb and b883ae9.

⛔ Files ignored due to path filters (266)
  • e2e/go.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
  • go.work.sum is excluded by !**/*.sum
  • hack/tools/go.sum is excluded by !**/*.sum
  • manifests-gen/go.sum is excluded by !**/*.sum
  • vendor/github.com/MakeNowJust/heredoc/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/MakeNowJust/heredoc/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/MakeNowJust/heredoc/heredoc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/AUTHORS is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/CONTRIBUTORS is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/PATENTS is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/bitcurves/bitcurve.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/brainpool/brainpool.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/brainpool/rcurve.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/eax/eax.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/eax/eax_test_vectors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/eax/random_vectors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/internal/byteutil/byteutil.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/ocb/ocb.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/ocb/random_vectors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_a.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_b.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/armor/encode.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/canonical_text.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/ecdsa/ecdsa.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/eddsa/eddsa.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/hash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve_info.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curves.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed25519.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed448.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/x448.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/encoding.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/mpi.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/oid.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/keys_test_data.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_crypter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/literal.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/notation.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/ocfb.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/opaque.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key_test_data.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key_test_data.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/reader.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_aead.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_mdc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userid.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/read.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ProtonMail/go-crypto/openpgp/write.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/CODE_OF_CONDUCT.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/base_dirs.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/codecov.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/internal/pathutil/pathutil.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/internal/pathutil/pathutil_plan9.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/internal/pathutil/pathutil_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/internal/pathutil/pathutil_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/internal/userdirs/config_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/internal/userdirs/userdirs.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/paths_darwin.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/paths_plan9.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/paths_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/paths_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/adrg/xdg/xdg.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x25519/curve.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.h is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x25519/curve_generic.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x25519/curve_noasm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x25519/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x25519/key.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x25519/table.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x448/curve.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.h is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x448/curve_generic.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x448/curve_noasm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x448/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x448/key.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/dh/x448/table.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/ecc/goldilocks/constants.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/ecc/goldilocks/isogeny.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/ecc/goldilocks/scalar.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/ecc/goldilocks/twistPoint.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/ecc/goldilocks/twistTables.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/ecc/goldilocks/twist_basemult.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/internal/conv/conv.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/internal/sha3/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/internal/sha3/hashes.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/internal/sha3/rc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/internal/sha3/sha3.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/internal/sha3/sha3_s390x.s is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/internal/sha3/shake.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/internal/sha3/xor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/internal/sha3/xor_generic.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/internal/sha3/xor_unaligned.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp25519/fp.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.h is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp25519/fp_generic.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp25519/fp_noasm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp448/fp.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.h is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp448/fp_generic.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp448/fp_noasm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/fp448/fuzzer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/integer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/mlsbset/power.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/primes.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/math/wnaf.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/sign/ed25519/modular.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/sign/ed25519/mult.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/sign/ed25519/point.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/sign/ed25519/pubkey.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/sign/ed25519/pubkey112.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/sign/ed25519/tables.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/sign/ed448/ed448.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/sign/ed448/signapi.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/cloudflare/circl/sign/sign.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/containerd/stargz-snapshotter/estargz/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/containerd/stargz-snapshotter/estargz/build.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/containerd/stargz-snapshotter/estargz/errorutil/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/containerd/stargz-snapshotter/estargz/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/.gitattributes is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/.golangci.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/CODE-OF-CONDUCT.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/GOVERNANCE.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/MAINTAINERS is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/Makefile is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/SECURITY.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/distribution-logo.svg is excluded by !**/*.svg, !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/normalize.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/reference.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/regexp.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/sort.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/AUTHORS is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/NOTICE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/configfile/file.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/configfile/file_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/configfile/file_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/credentials/credentials.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/credentials/default_store.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/credentials/default_store_darwin.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/credentials/default_store_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/credentials/default_store_unsupported.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/credentials/default_store_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/credentials/file_store.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/credentials/native_store.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/memorystore/store.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/cli/cli/config/types/authconfig.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/distribution/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/distribution/registry/client/auth/challenge/addr.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/distribution/registry/client/auth/challenge/authchallenge.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/docker-credential-helpers/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/docker-credential-helpers/client/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/docker-credential-helpers/client/command.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/docker-credential-helpers/credentials/credentials.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/docker-credential-helpers/credentials/error.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/docker-credential-helpers/credentials/helper.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/docker/docker-credential-helpers/credentials/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/internal/and/and_closer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/internal/compression/compression.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/internal/estargz/estargz.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/internal/gzip/zip.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/internal/redact/redact.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/internal/retry/retry.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/internal/retry/wait/kubernetes_apimachinery_wait.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/internal/verify/verify.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/internal/zstd/zstd.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/authn/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/authn/anon.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/authn/auth.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/authn/authn.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/authn/basic.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/authn/bearer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/authn/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/authn/multikeychain.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/compression/compression.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/logs/logs.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/name/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/name/check.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/name/digest.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/name/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/name/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/name/options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/name/ref.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/name/registry.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/name/repository.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/name/tag.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/empty/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/empty/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/empty/image.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/empty/index.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/hash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/image.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/index.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/layer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/manifest.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/match/match.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/mutate/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/mutate/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/mutate/image.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/mutate/index.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/mutate/rebase.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/partial/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/partial/compressed.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/partial/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/partial/image.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-containerregistry/pkg/v1/partial/index.go is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (23)
  • cmd/cluster-capi-operator/main.go
  • e2e/go.mod
  • go.mod
  • hack/tools/go.mod
  • manifests-gen/customizations.go
  • manifests-gen/generate.go
  • manifests-gen/go.mod
  • manifests-gen/kustomization.yaml
  • manifests-gen/main.go
  • manifests-gen/providercustomizations.go
  • manifests-gen/providers.go
  • manifests-gen/util.go
  • manifests/0000_30_cluster-api_03_rbac_roles.yaml
  • manifests/0000_30_cluster-api_04_rbac_bindings.yaml
  • manifests/0000_30_cluster-api_11_deployment.yaml
  • pkg/controllers/capiinstaller/capi_installer_controller.go
  • pkg/controllers/capiinstaller/capi_installer_controller_test.go
  • pkg/controllers/infracluster/azure.go
  • pkg/conversion/capi2mapi/aws.go
  • pkg/providerimages/providerimages.go
  • pkg/providerimages/providerimages_test.go
  • pkg/providerimages/pullsecret.go
  • pkg/util/readconfig.go
💤 Files with no reviewable changes (3)
  • manifests-gen/providers.go
  • pkg/util/readconfig.go
  • manifests-gen/providercustomizations.go
✅ Files skipped from review due to trivial changes (1)
  • pkg/conversion/capi2mapi/aws.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/controllers/capiinstaller/capi_installer_controller_test.go
  • hack/tools/go.mod
🧰 Additional context used
🧬 Code graph analysis (4)
pkg/providerimages/providerimages_test.go (1)
pkg/providerimages/providerimages.go (1)
  • ProviderImageManifests (56-63)
cmd/cluster-capi-operator/main.go (1)
pkg/providerimages/providerimages.go (2)
  • ReadProviderImages (117-131)
  • ProviderImageManifests (56-63)
manifests-gen/generate.go (1)
pkg/providerimages/providerimages.go (1)
  • ProviderMetadata (66-72)
pkg/controllers/capiinstaller/capi_installer_controller.go (1)
pkg/providerimages/providerimages.go (1)
  • ProviderImageManifests (56-63)
🪛 Checkov (3.2.334)
manifests/0000_30_cluster-api_11_deployment.yaml

[medium] 2-96: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 2-96: Minimize the admission of root containers

(CKV_K8S_23)

🔇 Additional comments (32)
pkg/controllers/infracluster/azure.go (1)

279-279: LGTM—Safe to remove the nolint directive.

The conversion from int64 to int32 is safe because strconv.ParseInt on line 216 uses bitSize: 32, which guarantees the parsed value fits within the int32 range. Additionally, valid port numbers (0–65535) are well within int32 bounds.

manifests/0000_30_cluster-api_11_deployment.yaml (1)

38-39: LGTM! Provider image infrastructure properly configured.

The environment variable, volume mount, and emptyDir volume are correctly configured to support the provider image caching mechanism. Using an emptyDir volume is appropriate for storing ephemeral provider manifest data extracted from container images.

Also applies to: 58-59, 95-96

manifests-gen/util.go (2)

13-19: LGTM! GVK preservation after conversion is correct.

The explicit copy of GroupVersionKind from source to target after scheme.Convert is necessary and correct, as the conversion process doesn't automatically preserve GVK metadata.


13-19: No action required. The scheme variable is properly initialized in the package scope at manifests-gen/main.go:48 as a package-level variable via runtime.NewScheme(), and is fully configured with necessary types in the init() function. Since util.go is in the same package, the convert function can safely access it.

go.mod (2)

19-19: No action needed. The version github.com/google/go-containerregistry v0.20.7 is the latest release (Nov 24, 2025) and has no publicly assigned security vulnerabilities.


22-22: Dependencies verified—all versions are valid with no known security advisories.

The dependency updates for container image operations are confirmed:

  • github.com/klauspost/compress v1.18.1
  • golang.org/x/sync v0.18.0
  • golang.org/x/tools v0.39.0
  • Supporting indirect dependencies for OCI/container operations (stargz-snapshotter, docker-credential-helpers, opencontainers packages, tar-split)

All versions have been cross-checked and no CVEs or active security advisories were found for any of these versions as of January 2026.

e2e/go.mod (1)

80-80: Indirect dependency versions verified and safe.

The three updated indirect dependencies have been checked:

  • github.com/klauspost/compress v1.18.1: No known CVEs; safe for use
  • golang.org/x/oauth2 v0.33.0: Well above the patched version for CVE-2025-22868; secure
  • golang.org/x/tools v0.39.0: No known vulnerabilities in this version

All versions are valid releases and free from published security vulnerabilities.

manifests/0000_30_cluster-api_03_rbac_roles.yaml (1)

36-55: Least-privilege RBAC for pull-secret access looks right.

Granting only get on secrets with resourceNames: [pull-secret] in openshift-config is appropriately scoped for a direct GET of the pull secret. Consider double-checking the pullSecretName/pullSecretNamespace constants in pkg/providerimages match openshift-config/pull-secret.

manifests/0000_30_cluster-api_04_rbac_bindings.yaml (1)

38-56: RoleBinding correctly grants the SA access in openshift-config.

Binding the openshift-cluster-api/cluster-capi-operator ServiceAccount to the openshift-config Role is the right pattern for narrowly scoped access to pull-secret.

pkg/providerimages/providerimages_test.go (1)

165-599: Nice table coverage; please verify Go version support for t.Context().

The matrix hits the important edges (missing metadata/manifests, invalid YAML/ref, error aggregation, cancellation, and layer precedence). One thing to confirm is repository/CI Go version compatibility with testing.T.Context() (and any other newer APIs used in this package).

cmd/cluster-capi-operator/main.go (1)

275-318: Plumbing providerImages through reconcilers/controller init looks consistent.

The updated signatures and the final handoff to capiinstaller.CapiInstallerController{ProviderImages: providerImages} are coherent and keep the dataflow explicit.

Also applies to: 320-373

pkg/controllers/capiinstaller/capi_installer_controller.go (5)

188-235: LGTM: Clean provider image reconciliation with proper sorting.

The reconciliation logic correctly filters by platform, sorts by type priority (core → infrastructure → other) with stable name-based tie-breaking, and propagates errors with context.


237-262: LGTM: Proper resource cleanup with errors.Join.

The deferred errors.Join pattern ensures both processing errors and reader close errors are properly propagated.


358-362: LGTM: Empty manifest filtering prevents downstream errors.

Skipping empty manifests avoids unnecessary parsing errors and simplifies downstream processing.


517-532: LGTM: Supports both text and compressed ConfigMap formats.

The reader handles both legacy text format and zstd-compressed binary format with proper error handling.


534-541: ManifestsPath is properly validated upstream and is safe to open.

The path is constructed safely in pkg/providerimages/providerimages.go (line 223) as filepath.Join(outputDir, manifestsFile), where manifestsFile is a hardcoded constant "manifests.yaml" and outputDir is built from a sanitized image reference. The sanitizeImageRef function removes forward slashes, colons, and @ characters, effectively preventing directory traversal attacks. No additional validation is needed in providerManifestReader.

manifests-gen/generate.go (4)

31-57: LGTM: Well-structured orchestration with clear error propagation.

The function cleanly sequences resource generation, processing, and writing with contextual error messages at each step.


59-93: LGTM: Proper kustomize integration with nil-safe resource handling.

The nil check at line 74 prevents panics from malformed kustomize output, and the JSON → Unstructured conversion path is correct.


98-98: Verify file permissions are appropriate for the deployment environment.

Both manifests.yaml and metadata.yaml are created with 0600 permissions (owner read/write only). If these files need to be read by other processes, users, or during container image builds, more permissive permissions like 0644 may be required.

Also applies to: 133-133


95-128: LGTM: Robust YAML writing with proper separators and cleanup.

The incremental write pattern with document separators (---) and deferred flush/close using errors.Join ensures both correctness and proper resource cleanup.

pkg/providerimages/providerimages.go (7)

117-131: LGTM: Clean separation of concerns with keychain initialization.

Fetching the pull secret, parsing Docker config, and delegating to the internal implementation with an abstracted fetcher is well-structured.


139-189: LGTM: Effective concurrent processing with controlled parallelism.

The errgroup with a limit of 5 concurrent fetches balances throughput and resource usage. Aggregating errors via channels while returning nil from goroutines (line 156) is the correct pattern for collecting all errors without short-circuiting.


145-145: Verify concurrency limit is appropriate for production load.

The hardcoded limit of 5 concurrent image fetches may need tuning based on:

  • Network bandwidth and registry rate limits
  • Memory consumption per image fetch
  • Startup time requirements

Consider making this configurable if production metrics indicate the limit is too conservative or too aggressive.


246-306: LGTM: Secure tar extraction with proper layer overwrite semantics.

Iterating layers top-to-bottom (line 259) correctly implements OCI layer semantics. The error handling distinguishes between missing directories (skip) and missing required files (error), which is appropriate.


308-347: LGTM: Path traversal protection via normalization.

Using path.Clean with a leading "/" (line 329) correctly normalizes tar entry paths and prevents ../ traversal attacks.


363-388: LGTM: Atomic write with simultaneous hash computation.

The io.MultiWriter pattern (line 374) efficiently computes the SHA256 hash while writing, and the string replacer (lines 377-378) correctly substitutes placeholder image names.


349-358: LGTM: Simple but effective image reference sanitization.

Replacing /, :, and @ with _ produces filesystem-safe directory names. Since these characters are required in image references, collisions are unlikely in practice.

manifests-gen/customizations.go (5)

34-99: LGTM: Clean group/kind dispatch with client.Object migration.

The refactored dispatch logic using getGroup and getKind is cleaner than per-kind branching. Filtering cert-manager resources (lines 86-90) and handling core API resources correctly maintains backward compatibility.


173-205: LGTM: Strong image registry validation prevents supply chain risks.

Enforcing that all images originate from registry.ci.openshift.org (lines 194-201) is a solid security control. The clear error messages help developers quickly identify misconfigured images.


242-308: LGTM: Well-structured admission policy for InfraCluster protection.

The policy correctly:

  • Matches DELETE operations on the target CRD (lines 259-265)
  • Validates against the Infrastructure parameter (line 271)
  • Scopes binding to the CAPI namespace (lines 290-295)
  • Strips redundant status field (line 305)

310-318: LGTM: Clean status field removal via unstructured conversion.

Converting to unstructured, deleting the status field, and converting back is the correct approach for stripping fields from typed objects.


58-58: Panics on conversion failure are acceptable for a build-time tool.

The mustConvert calls will panic if type conversion fails. Since this is a manifest generation tool run at build time with controlled inputs, failing fast on unexpected types is appropriate and helps catch issues early.

Also applies to: 123-123, 133-133, 147-147, 159-159, 175-175

Comment on lines 218 to 230
providerImageDir := os.Getenv(providerImageDirEnvVar)
if providerImageDir == "" {
providerImageDir = defaultProviderImageDirPath
}

containerImageRefs := slices.Collect(maps.Values(containerImages))

providerImages, err := providerimages.ReadProviderImages(context.Background(), mgr.GetAPIReader(), mgr.GetLogger(), containerImageRefs, providerImageDir)
if err != nil {
klog.Error(err, "unable to get provider image metadata")
os.Exit(1)
}

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid hard-failing operator startup on provider image fetch; add cancellation + timeout.

Right now, any failure to read the pull-secret / reach registries / write cache dir will os.Exit(1). During the transition period (ConfigMap transport still supported), that’s a significant availability risk—clusters could lose reconciliation entirely due to a transient registry outage.

Suggested approach:

  • Use a single signal-aware context for startup + manager (ctx := ctrl.SetupSignalHandler() once).
  • Bound provider image reads with a timeout.
  • On failure, log and continue with providerImages == nil (so legacy ConfigMap path can still function).
Proposed change
@@
 func main() {
+	ctx := ctrl.SetupSignalHandler()
+
 	scheme := runtime.NewScheme()
 	initScheme(scheme)
@@
-	providerImages, err := providerimages.ReadProviderImages(context.Background(), mgr.GetAPIReader(), mgr.GetLogger(), containerImageRefs, providerImageDir)
+	startupCtx, cancel := context.WithTimeout(ctx, 2*time.Minute)
+	defer cancel()
+
+	providerImages, err := providerimages.ReadProviderImages(startupCtx, mgr.GetAPIReader(), mgr.GetLogger(), containerImageRefs, providerImageDir)
 	if err != nil {
-		klog.Error(err, "unable to get provider image metadata")
-		os.Exit(1)
+		// Keep backwards-compat during transition: fall back to transport ConfigMaps.
+		klog.Error(err, "unable to get provider image metadata; continuing without provider images")
+		providerImages = nil
 	}
 
-	infra, err := util.GetInfra(context.Background(), mgr.GetAPIReader())
+	infra, err := util.GetInfra(ctx, mgr.GetAPIReader())
@@
-	platform, err := util.GetPlatform(context.Background(), infra)
+	platform, err := util.GetPlatform(ctx, infra)
@@
-	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
+	if err := mgr.Start(ctx); err != nil {
 		klog.Error(err, "problem running manager")
 		os.Exit(1)
 	}
 }

Also applies to: 231-243, 259-263

🤖 Prompt for AI Agents
In @cmd/cluster-capi-operator/main.go around lines 218 - 230, Replace the
current unconditional os.Exit on provider image read failures by using a
signal-aware startup context and a bounded timeout: create a single ctx via
ctrl.SetupSignalHandler() (use it for manager startup), wrap
providerimages.ReadProviderImages with context.WithTimeout to enforce a
deadline, call providerimages.ReadProviderImages(ctxWithTimeout, ...) instead of
context.Background(), and on error log the failure (including err) but do not
call os.Exit—leave providerImages nil so the legacy ConfigMap path can proceed;
apply the same pattern to the other provider image read sites (the calls around
the blocks that set providerImages and similar reads at 231-243 and 259-263).

)

require (
github.com/docker/cli v29.0.3+incompatible
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cd / && git ls-files go.mod

Repository: openshift/cluster-capi-operator

Length of output: 145


🏁 Script executed:

cat -n go.mod | head -20

Repository: openshift/cluster-capi-operator

Length of output: 1015


🌐 Web query:

docker/cli v29.0.3 release stability and compatibility

💡 Result:

Short summary — stability and compatibility for docker/cli v29.0.3

  • What v29.0.3 is: a patch-level release in the v29 series that fixes CLI output/format bugs (e.g., restores BuildTime format, fixes imageFormat handling) and includes corresponding daemon/networking fixes. [1][2]

  • Compatibility / breaking changes to be aware of:

    • Docker Engine v29 (the same major line) raises the minimum daemon API to v1.44 (clients older than v25 may be incompatible). Upgrade client and daemon together or ensure API negotiation is supported. [1]
    • Several v29 breaking changes affect ecosystems (Go module changes, Docker Content Trust removed from the CLI and moved to a plugin, cgroup v1 deprecated). Review the v29 release notes before upgrading. [1]
    • Third‑party tooling may need updates (some tools like Portainer, cAdvisor, Watchtower reported compatibility issues initially). Test your tooling/agents against v29 in staging. [3][4]
  • Stability recommendation:

    • v29.0.3 itself is a patch release addressing known bugs — it is reasonable for production use if you confirm your toolchain supports the raised API and other v29 changes.
    • If you rely on third‑party management/monitoring GUIs or older clients, hold or test first; otherwise upgrade both CLI and Engine (or pin API compatibility) and monitor for issues. [1][3]

Sources

  • Docker Engine / release notes (v29.0.3 details and v29 breaking changes). [1]
  • docker/cli repository (project and changelogs). [2]
  • Compatibility reports / vendor notices (examples: Harness CI guidance, Portainer community reports). [3][4]

If you want, I can: (a) list the exact changed CLI fields/PR IDs in v29.0.3, (b) check a specific third‑party tool for v29 compatibility, or (c) give a short upgrade checklist.


🌐 Web query:

go-containerregistry v0.20.7 docker/cli compatibility requirements

💡 Result:

Short answer: go-containerregistry v0.20.7 expects the Docker engine/Go SDK compatibility introduced in the v0.20.x line — it bumped its docker/docker dependency to the v28.x series (i.e., github.com/docker/docker v28.0.0+incompatible) and the release deprecates the library’s DockerVersion field. If you rely on docker/cli SDKs, expect compatibility with the docker/docker (v28.x) / docker/cli calver used around that bump; newer docker v29+ breaking changes have been discussed as a potential future incompatibility. [1][2][3]

Sources

  • go-containerregistry v0.20.7 release notes (changes include deprecating DockerVersion and dependency updates). [1]
  • go-containerregistry v0.20.4 / v0.20.x changelog noting bump of github.com/docker/docker to v28.0.0+incompatible. [2]
  • Issue discussing future docker v29.0.0 breaking changes impacting ggcr. [3]

References
[1] https://github.com/google/go-containerregistry/releases/tag/v0.20.7
[2] https://github.com/google/go-containerregistry/releases/tag/v0.20.4
[3] google/go-containerregistry#2160


Verify docker/cli v29.0.3 compatibility with go-containerregistry v0.20.7.

The docker/cli v29.0.3 release is stable but introduces breaking changes (minimum daemon API raised to v1.44, Docker Content Trust moved to plugin, cgroup v1 deprecated). However, go-containerregistry v0.20.7 was tested and built against docker v28.x, not v29.x. Test this version combination in staging to ensure the v29 breaking changes do not conflict with your containerregistry usage, or consider pinning docker/cli to the v28 series to match go-containerregistry's tested dependencies.

🤖 Prompt for AI Agents
In @go.mod at line 12, The go.mod update pins github.com/docker/cli to v29.0.3
while go-containerregistry is v0.20.7 (tested against docker v28.x); verify
compatibility by testing the combination in staging focusing on daemon API
usage, content trust and cgroup behavior, and if any breakage appears pin
github.com/docker/cli back to the v28.x series in go.mod (or add a go.mod
replace) to match go-containerregistry’s tested environment until you can
upgrade go-containerregistry or validate v29; run your container
registry-related integration tests and CI to confirm no runtime/API regressions.

Comment on lines +1 to +17
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component

namespace: openshift-cluster-api

patches:

# Retain Secrets internally for reference tracking, but don't emit them
- target:
kind: Secret
patch: |
apiVersion: v1
kind: Secret
metadata:
name: __ignored__
annotations:
config.kubernetes.io/local-config: "true"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Kustomize patch target all resources of kind without name

💡 Result:

Yes — use the newer "patches" (or patchesStrategicMerge) with a target that specifies kind (and group/version if needed) but no name; Kustomize will apply that patch to all matching resources of that kind. Example:

kustomization.yaml

  • patches:
    • path: patch.yaml
      target:
      kind: ConfigMap

      optionally: group: "" # for core API, or group: apps, etc.

      optionally: version: v1

patch.yaml (strategic merge or json patch content as appropriate)

References: Kubernetes Kustomize docs (patches target fields) and Kustomize discussion explaining patches can match multiple resources. [1][2]

Sources:
[1] Kubernetes docs — Declarative Management of Kubernetes Objects Using Kustomize (patches target fields).
[2] Stack Overflow — explanation that "patches" can match more than one resource (unlike patchesJson6902).


🌐 Web query:

Kustomize config.kubernetes.io/local-config annotation behavior

💡 Result:

Summary — meaning and behavior

  • Purpose: config.kubernetes.io/local-config marks a resource as "local-only" (a configuration for local tools, not intended to be sent to the Kubernetes API server). Examples: kustomization.yaml or other helper/config resources. [1]

  • Semantics: tools SHOULD treat resources with this annotation as not-for-apply/send-to-server. Kustomize and related tooling use it so local config is skipped when producing/applying live resources. [1][2]

  • Value: set as a string (commonly "true"). Any value other than the literal "false" is treated as local; avoid unquoted YAML booleans. [2]

  • Practical effect: resources annotated with config.kubernetes.io/local-config are not applied to the cluster by tools that honor the annotation (they are kept only for local processing). [2]

Sources
[1] sigs.k8s.io/kustomize (Configuration IO API docs).
[2] kpt documentation for local-config annotation.


🌐 Web query:

Kustomize strategic merge patch metadata.name placeholder __ignored__

💡 Result:

Short answer: metadata.name in a strategic-merge patch is used to identify the target resource and cannot be treated as a free placeholder. Putting a fake name like "ignored" will prevent Kustomize from matching the patch. Use one of these instead:

  • Give the real metadata.name in the patch so it matches the resource. [1][2]
  • Use the patch "target" (group/version/kind plus name or labelSelector) so you don't need metadata.name inside the patch body. Example: use patches with a target: labelSelector to match by label. [1][3]
  • Use a JSON6902 patch when you need to patch a resource without depending on metadata.name matching. [1][2]

References:

  • Kustomize/Kubernetes docs (patch matching rules, JSON6902 vs strategic merge). [1]
  • Kustomize examples / warning that metadata.name must match. [2]
  • StackOverflow/notes on using target/labelSelector and deprecation notes for older fields. [3]
  • Community notes that you cannot change or ignore name when using strategic merge. [4]

Remove metadata.name placeholder from Secret patch — it will prevent the annotation from being applied.

The patch uses metadata.name: __ignored__ in a strategic-merge patch, but this placeholder will prevent Kustomize from matching any actual Secret resources. In strategic-merge patches, metadata.name must match the actual resource name to apply the patch.

To add the config.kubernetes.io/local-config: "true" annotation to all Secrets, use one of these approaches:

  • Specify individual Secret names in the target for each Secret that needs the annotation
  • Use a labelSelector in the target to match Secrets by label instead of relying on metadata.name matching
  • Use JSON6902 patches instead of strategic-merge, which don't depend on metadata.name matching for multi-resource application

The annotation purpose (marking Secrets as local-only, preventing emission) is correct, but the patch mechanism needs to be fixed.

Comment on lines +181 to +183
if err := r.reconcileProviderImages(ctx, log); err != nil {
return ctrl.Result{}, fmt.Errorf("error reconciling CAPI provider images: %w", err)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing degraded condition on provider image reconciliation error.

When reconcileProviderImages returns an error, the controller should call setDegradedCondition before returning, consistent with how ConfigMap processing errors are handled at lines 143-145 and 159-161.

🔧 Proposed fix
 	if err := r.reconcileProviderImages(ctx, log); err != nil {
+		if err := r.setDegradedCondition(ctx, log); err != nil {
+			return ctrl.Result{}, fmt.Errorf("failed to set conditions for CAPI Installer controller: %w", err)
+		}
+
 		return ctrl.Result{}, fmt.Errorf("error reconciling CAPI provider images: %w", err)
 	}
📝 Committable suggestion

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

Suggested change
if err := r.reconcileProviderImages(ctx, log); err != nil {
return ctrl.Result{}, fmt.Errorf("error reconciling CAPI provider images: %w", err)
}
if err := r.reconcileProviderImages(ctx, log); err != nil {
if err := r.setDegradedCondition(ctx, log); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to set conditions for CAPI Installer controller: %w", err)
}
return ctrl.Result{}, fmt.Errorf("error reconciling CAPI provider images: %w", err)
}
🤖 Prompt for AI Agents
In @pkg/controllers/capiinstaller/capi_installer_controller.go around lines 181
- 183, When reconcileProviderImages(ctx, log) returns an error, call
r.setDegradedCondition(ctx, "ProviderImagesReconcileFailed", err) (or the same
setDegradedCondition signature used for ConfigMap errors) before returning so
the controller sets the degraded condition consistently; mirror the pattern used
for ConfigMap processing errors (the calls around ConfigMap handling) and
include the error in the degraded condition message, then return the wrapped
error as currently done.

Adds a flag, profile-name allowing specification of a profile (and
therefore subdirectory) to output manifests and metadata to.
TODO: merge into rewrite commit
When parsing images, the logic now checks for multiple 'profiles' (sub
directories) under /capi-operator-manifests.

If multiple are found, we return them all.
We've been referring to a slice of []providerImagesManifests as
providerImages, which is misleading. With us now having profiles, this
makes more sense being named 'providerProfiles', each slice is a
representation of metadata and manifests for a named profile.
manifests-gen outputs to profile directory
@openshift-ci-robot
Copy link

openshift-ci-robot commented Jan 14, 2026

@mdbooth: This pull request references OCPCLOUD-3327 which is a valid jira issue.

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

Details

In response to this:

Rewrite manifests-gen to support embedding CAPI installer manifests in the provider image instead of in a transport configmap.

Update the CAPI installer controller to support the new embedded manifests in addition to the existing transport configmaps. This allows us to have a smooth transition period while we update all providers.

Summary by CodeRabbit

  • New Features

  • Provider image metadata support and runtime provider-image caching for improved manifest generation and installation.

  • Infrastructure

  • RBAC Role and RoleBinding added to allow reading pull-secret.

  • Deployment updated with provider-image cache (env var, volume mount).

  • Manifests / Tooling

  • New manifest generator emits manifests.yaml and metadata.yaml and adds kustomize component handling for local secrets.

✏️ Tip: You can customize this high-level summary in your review settings.

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@manifests-gen/main.go`:
- Line 72: The flag help text for profileName (the flag.String call assigning
profileName) has a typo with an extra single quote and misplaced period; update
the help string to correct punctuation and matching quotes—e.g., change the text
to something like "Name of the profile, e.g. 'featuregate-foo' (default:
'default')." ensuring quotes and the final period are placed correctly.

In `@pkg/providerimages/providerimages.go`:
- Around line 206-228: The outputDir created for each image (via sanitizedRef
from sanitizeImageRef) is reused and never cleared before calling
extractCapiManifestsToDir, causing stale files and incorrect manifests; before
extraction, remove or empty outputDir (e.g., os.RemoveAll(outputDir) then
recreate) to ensure a clean extraction surface, and if images may delete files
across layers implement OCI whiteout handling in extractCapiManifestsToDir so
deletions in higher layers are honored; keep discoverProfiles usage unchanged
after a fresh extraction.
- Around line 95-118: Update the ReadProviderImages docblock to match the actual
function signature and directory layout: state that containerImages is a
[]string of image references (not a map), describe that providerImageDir is a
cache root where each image is written to a subdirectory named for the image
reference, and clarify the manifest layout is
/capi-operator-manifests/<profile>/<metadata.yaml and
/capi-operator-manifests/<profile>/<manifests.yaml> (i.e., profiles are
required), also mention that missing profile files cause an error and that
manifestImageName replacements are applied when writing to the cache.
♻️ Duplicate comments (1)
cmd/cluster-capi-operator/main.go (1)

218-230: Don’t hard-fail operator startup on provider image read errors during the transition period.

Right now any pull-secret/registry/cache-dir issue exits the operator even though transport ConfigMaps are still supported. This is a significant availability risk; use a signal-aware context + timeout and fall back to providerProfiles == nil on error.

Proposed change
 func main() {
+	ctx := ctrl.SetupSignalHandler()
+
 	scheme := runtime.NewScheme()
 	initScheme(scheme)
@@
-	providerProfiles, err := providerimages.ReadProviderImages(context.Background(), mgr.GetAPIReader(), mgr.GetLogger(), containerImageRefs, providerImageDir)
+	startupCtx, cancel := context.WithTimeout(ctx, 2*time.Minute)
+	defer cancel()
+	providerProfiles, err := providerimages.ReadProviderImages(startupCtx, mgr.GetAPIReader(), mgr.GetLogger(), containerImageRefs, providerImageDir)
 	if err != nil {
-		klog.Error(err, "unable to get provider image metadata")
-		os.Exit(1)
+		klog.Error(err, "unable to get provider image metadata; continuing without provider images")
+		providerProfiles = nil
 	}
@@
-	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
+	if err := mgr.Start(ctx); err != nil {
 		klog.Error(err, "problem running manager")
 		os.Exit(1)
 	}
 }

Also applies to: 259-262

🧹 Nitpick comments (5)
manifests-gen/main.go (1)

125-133: Consider preserving the original parse error for better diagnostics.

When ParseSemantic fails, the original error is discarded. Including it would help users understand why their version string is invalid (e.g., missing "v" prefix, invalid format).

Suggested fix
 		func() error {
 			// If set, provider version must be valid
 			if opts.version != "" {
 				if _, err := version.ParseSemantic(opts.version); err != nil {
-					return fmt.Errorf("invalid version %s for provider %s", opts.version, opts.name)
+					return fmt.Errorf("invalid version %s for provider %s: %w", opts.version, opts.name, err)
 				}
 			}
 			return nil
 		}(),
pkg/providerimages/providerimages.go (3)

119-129: Add an explicit check for missing .dockerconfigjson key.

Right now pullSecret := secret.Data[pullSecretKey] will pass nil to parseDockerConfig if the key is missing, which makes the failure mode less actionable.

Proposed change
 	pullSecret := secret.Data[pullSecretKey]
+	if len(pullSecret) == 0 {
+		return nil, fmt.Errorf("pull secret %s/%s missing key %q", pullSecretNamespace, pullSecretName, pullSecretKey)
+	}
 
 	keychain, err := parseDockerConfig(pullSecret)

146-193: errgroup is currently not used to propagate errors/cancellation; simplify or make it effective.

g.Go always returns nil and g.Wait() is ignored, so errgroup isn’t doing much beyond the concurrency limit. Consider either:

  • return err from the goroutine and rely on g.Wait() (and still collect per-image errors), or
  • drop errgroup and use a simple worker pool with context handling.

474-499: Write manifests atomically to avoid partial/corrupt cache entries.

If the process is interrupted mid-write, downstream readers may see truncated manifests.yaml. Writing to a temp file + os.Rename would make this safer.

pkg/providerimages/providerimages_test.go (1)

166-678: Test suite coverage looks solid for profiles + layering + replacement + cancellation.

The cases hit the important edges for this feature (multi-profile, layered overrides, and error aggregation).
One optional improvement: make createTarLayer write files in sorted key order to avoid incidental nondeterminism if assertions tighten later.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between b883ae9 and 92fb887.

📒 Files selected for processing (5)
  • cmd/cluster-capi-operator/main.go
  • manifests-gen/generate.go
  • manifests-gen/main.go
  • pkg/providerimages/providerimages.go
  • pkg/providerimages/providerimages_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • manifests-gen/generate.go
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/cluster-capi-operator/main.go (1)
pkg/providerimages/providerimages.go (2)
  • ReadProviderImages (118-132)
  • ProviderImageManifests (56-64)
🔇 Additional comments (2)
cmd/cluster-capi-operator/main.go (1)

20-23: The review comment is incorrect. The code is correct as written.

In Go 1.22+, maps.Values() returns an iterator, not a slice. Therefore, slices.Collect(maps.Values(containerImages)) is the correct and necessary way to materialize that iterator into a []string slice for use with ReadProviderImages(). Both the "maps" and "slices" imports are required and appropriate for Go 1.24.0.

The proposed change to remove slices and use maps.Values(containerImages) directly would be incorrect—it would assign an iterator to containerImageRefs, causing a type mismatch.

Likely an incorrect or invalid review comment.

pkg/providerimages/providerimages.go (1)

148-159: The range variable capture issue described does not apply to this codebase. The project targets Go 1.24.0 (as specified in go.mod), which is well above Go 1.22 where automatic per-iteration loop variable scoping was introduced as a language feature. In Go 1.22+, the imageRef variable in the range loop is automatically scoped to each iteration, preventing the goroutine closure from observing stale values across iterations. The proposed shadowing fix is unnecessary.

Likely an incorrect or invalid review comment.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

func main() {
var (
manifestsPath = flag.String("manifests-path", "", "Path to the desired directory where to output the generated manifests. Required.")
profileName = flag.String("profile-name", "default", "Name of the profile, e.g 'featuregate-foo' (default: 'default'.'")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Typo in flag help text.

There's an extra single quote and period in the help text.

Suggested fix
-		profileName   = flag.String("profile-name", "default", "Name of the profile, e.g 'featuregate-foo' (default: 'default'.'")
+		profileName   = flag.String("profile-name", "default", "Name of the profile, e.g. 'featuregate-foo' (default: 'default')")
📝 Committable suggestion

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

Suggested change
profileName = flag.String("profile-name", "default", "Name of the profile, e.g 'featuregate-foo' (default: 'default'.'")
profileName = flag.String("profile-name", "default", "Name of the profile, e.g. 'featuregate-foo' (default: 'default')")
🤖 Prompt for AI Agents
In `@manifests-gen/main.go` at line 72, The flag help text for profileName (the
flag.String call assigning profileName) has a typo with an extra single quote
and misplaced period; update the help string to correct punctuation and matching
quotes—e.g., change the text to something like "Name of the profile, e.g.
'featuregate-foo' (default: 'default')." ensuring quotes and the final period
are placed correctly.

Comment on lines +206 to +228
// Create output directory for this provider image
sanitizedRef := sanitizeImageRef(imageRef)
outputDir := filepath.Join(providerImageDir, sanitizedRef)

if err := os.MkdirAll(outputDir, 0750); err != nil {
return nil, fmt.Errorf("failed to create output directory: %w", err)
}

// Extract files from the image to disk
if err := extractCapiManifestsToDir(img, outputDir); err != nil {
return nil, err
}

// Discover profiles from extracted files
profiles, err := discoverProfiles(outputDir)
if err != nil {
if errors.Is(err, errNoCapiManifests) {
// Image doesn't contain /capi-operator-manifests, skip it
return nil, nil
}

return nil, err
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Cache coherency risk: stale files + missing layer deletion (whiteout) semantics can produce wrong manifests across upgrades.

  • outputDir is reused and never cleared.
  • Extraction skips existing files and doesn’t interpret OCI whiteouts, so a file deleted in a higher layer can still be written from a lower layer.

At minimum, clear outputDir before extraction; if you expect deletions across layers, you’ll also need whiteout handling.

Minimal hardening (clear output dir)
 	outputDir := filepath.Join(providerImageDir, sanitizedRef)
 
+	// Ensure cache dir reflects only the current image contents.
+	if err := os.RemoveAll(outputDir); err != nil {
+		return nil, fmt.Errorf("failed to clear output directory: %w", err)
+	}
 	if err := os.MkdirAll(outputDir, 0750); err != nil {
 		return nil, fmt.Errorf("failed to create output directory: %w", err)
 	}

Also applies to: 356-441

🤖 Prompt for AI Agents
In `@pkg/providerimages/providerimages.go` around lines 206 - 228, The outputDir
created for each image (via sanitizedRef from sanitizeImageRef) is reused and
never cleared before calling extractCapiManifestsToDir, causing stale files and
incorrect manifests; before extraction, remove or empty outputDir (e.g.,
os.RemoveAll(outputDir) then recreate) to ensure a clean extraction surface, and
if images may delete files across layers implement OCI whiteout handling in
extractCapiManifestsToDir so deletions in higher layers are honored; keep
discoverProfiles usage unchanged after a fresh extraction.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Jan 15, 2026

@mdbooth: This pull request references OCPCLOUD-3327 which is a valid jira issue.

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

Details

In response to this:

Rewrite manifests-gen to support embedding CAPI installer manifests in the provider image instead of in a transport configmap.

Update the CAPI installer controller to support the new embedded manifests in addition to the existing transport configmaps. This allows us to have a smooth transition period while we update all providers.

Summary by CodeRabbit

  • New Features

  • Provider image metadata support with runtime caching to surface provider manifests used during installation.

  • Infrastructure

  • RBAC Role and RoleBinding added to allow reading the image pull-secret.

  • Operator Deployment updated to mount a provider-image cache and set the cache directory env var.

  • Manifests / Tooling

  • New manifest generator writes manifests.yaml and metadata.yaml and supports kustomize components.

  • Tests

  • Comprehensive tests added for provider image extraction and processing.

✏️ Tip: You can customize this high-level summary in your review settings.

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

@theobarberbany
Copy link
Contributor

/testwith openshift/cluster-capi-operator/main/e2e-aws-ovn-techpreview openshift/cluster-api-provider-aws#584 openshift/cluster-api#259

@theobarberbany
Copy link
Contributor

/testwith openshift/cluster-capi-operator/main/regression-clusterinfra-aws-ipi-techpreview-capi openshift/cluster-api-provider-aws#584 openshift/cluster-api#259

@theobarberbany
Copy link
Contributor

/testwith openshift/cluster-capi-operator/main/e2e-aws-capi-techpreview openshift/cluster-api-provider-aws#584 openshift/cluster-api#259

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

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants