Skip to content

CNTRLPLANE-625: Add support for custom trust bundle for AWS API endpoints#8280

Open
hypershift-jira-solve-ci[bot] wants to merge 10 commits into
openshift:mainfrom
hypershift-community:fix-CNTRLPLANE-625-v2
Open

CNTRLPLANE-625: Add support for custom trust bundle for AWS API endpoints#8280
hypershift-jira-solve-ci[bot] wants to merge 10 commits into
openshift:mainfrom
hypershift-community:fix-CNTRLPLANE-625-v2

Conversation

@hypershift-jira-solve-ci

@hypershift-jira-solve-ci hypershift-jira-solve-ci Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

Guest cluster operators (e.g. cloud-network-config-controller, cluster-ingress-operator) need the additional trust bundle to communicate with AWS API endpoints that use custom certificates, such as when using a proxy or private AWS endpoints. Previously, the trust bundle was only synced to the user-ca-bundle ConfigMap in the guest cluster's openshift-config namespace, but AWS guest operators did not pick it up from there.

This PR syncs the additional trust bundle into the cloud-provider-config ConfigMap in the guest cluster and sets infra.Spec.CloudConfig on the Infrastructure resource to reference it, following the same pattern already used by Azure and OpenStack platforms.

Changes

  • Sync trust bundle to cloud-provider-config (AWS): The AWS case in reconcileCloudConfig now creates a cloud-provider-config ConfigMap containing the AWS cloud config (aws.conf) and, when additionalTrustBundle is set, the CA bundle (ca-bundle.pem). When the trust bundle is removed, the CA bundle key is cleaned up.
  • Set Infrastructure CloudConfig for AWS: ReconcileInfrastructure now sets infra.Spec.CloudConfig.Name and infra.Spec.CloudConfig.Key for AWS, so guest operators discover the cloud config via the standard Infrastructure resource.
  • Graceful handling of missing user-ca-bundle: If the user-ca-bundle ConfigMap is not yet available (e.g. during bootstrap), the reconciler logs and continues syncing the base AWS config without the CA bundle, rather than failing.
  • Use constant for CA bundle key: Introduced aws.CABundleKey constant instead of magic strings.

Which issue(s) this PR fixes:

Fixes https://redhat.atlassian.net/browse/CNTRLPLANE-625

Special notes for your reviewer:

  • This follows the same pattern already established for Azure (reconcileCloudConfig Azure case) and OpenStack.
  • The user-ca-bundle ConfigMap may not exist during early bootstrap; the code handles IsNotFound gracefully to avoid blocking reconciliation.

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

Always review AI generated responses prior to use.
Generated with Claude Code via /jira:solve [CNTRLPLANE-625](https://redhat.atlassian.net/browse/CNTRLPLANE-625)


Note: This PR was auto-generated by the jira-agent periodic CI job in response to CNTRLPLANE-625. See the full report for token usage, cost breakdown, and detailed phase output.

Summary by CodeRabbit

  • New Features

    • AWS platform now syncs cloud-provider configuration to guest clusters and can include a custom CA bundle when configured; cloud-provider config name is now standardized.
  • Bug Fixes

    • Reconciliation removes a previously-synced CA bundle when it's no longer configured and skips CA sync if the user bundle is missing or empty; handles missing provider config errors.
  • Tests

    • Added comprehensive tests covering AWS cloud-config reconciliation and CA bundle presence/absence and error scenarios.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

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-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Apr 20, 2026
@openshift-ci-robot

openshift-ci-robot commented Apr 20, 2026

Copy link
Copy Markdown

@hypershift-jira-solve-ci[bot]: This pull request references CNTRLPLANE-625 which is a valid jira issue.

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

Details

In response to this:

What this PR does / why we need it:

Guest cluster operators (e.g. cloud-network-config-controller, cluster-ingress-operator) need the additional trust bundle to communicate with AWS API endpoints that use custom certificates, such as when using a proxy or private AWS endpoints. Previously, the trust bundle was only synced to the user-ca-bundle ConfigMap in the guest cluster's openshift-config namespace, but AWS guest operators did not pick it up from there.

This PR syncs the additional trust bundle into the cloud-provider-config ConfigMap in the guest cluster and sets infra.Spec.CloudConfig on the Infrastructure resource to reference it, following the same pattern already used by Azure and OpenStack platforms.

Changes

  • Sync trust bundle to cloud-provider-config (AWS): The AWS case in reconcileCloudConfig now creates a cloud-provider-config ConfigMap containing the AWS cloud config (aws.conf) and, when additionalTrustBundle is set, the CA bundle (ca-bundle.pem). When the trust bundle is removed, the CA bundle key is cleaned up.
  • Set Infrastructure CloudConfig for AWS: ReconcileInfrastructure now sets infra.Spec.CloudConfig.Name and infra.Spec.CloudConfig.Key for AWS, so guest operators discover the cloud config via the standard Infrastructure resource.
  • Graceful handling of missing user-ca-bundle: If the user-ca-bundle ConfigMap is not yet available (e.g. during bootstrap), the reconciler logs and continues syncing the base AWS config without the CA bundle, rather than failing.
  • Use constant for CA bundle key: Introduced aws.CABundleKey constant instead of magic strings.

Which issue(s) this PR fixes:

Fixes https://redhat.atlassian.net/browse/CNTRLPLANE-625

Special notes for your reviewer:

  • This follows the same pattern already established for Azure (reconcileCloudConfig Azure case) and OpenStack.
  • The user-ca-bundle ConfigMap may not exist during early bootstrap; the code handles IsNotFound gracefully to avoid blocking reconciliation.

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

Always review AI generated responses prior to use.
Generated with Claude Code via /jira:solve [CNTRLPLANE-625](https://redhat.atlassian.net/browse/CNTRLPLANE-625)

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

@openshift-ci
openshift-ci Bot requested review from csrwng and sjenning April 20, 2026 09:21
@openshift-ci openshift-ci Bot added area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release area/platform/aws PR/issue for AWS (AWSPlatform) platform and removed do-not-merge/needs-area labels Apr 20, 2026
@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds exported AWS constant CABundleKey = "ca-bundle.pem". Reconcile logic now copies the management-cluster AWS provider ConfigMap value into the guest openshift-config/cloud-provider-config and conditionally synchronizes a CA bundle when spec.AdditionalTrustBundle or proxy TrustedCA is configured by reading a managed trust-bundle ConfigMap; it also removes the CA bundle key when no trust data exists. Centralizes CloudProviderCMName usage and adds unit tests covering presence, absence, removal, and error cases for the provider config and CA bundle.

Sequence Diagram

sequenceDiagram
    participant Reconciler as Reconciler
    participant MgmtCluster as Management Cluster
    participant GuestCluster as Guest Cluster

    Reconciler->>Reconciler: Detect platform == AWS
    Reconciler->>MgmtCluster: Get AWS provider-config ConfigMap (provider key)
    MgmtCluster-->>Reconciler: Return provider config or NotFound/Error
    alt AdditionalTrustBundle or TrustedCA set
        Reconciler->>MgmtCluster: Get managed trust-bundle ConfigMap
        alt Trust-bundle exists and non-empty
            MgmtCluster-->>Reconciler: Return CA bundle data
        else Missing or empty
            MgmtCluster-->>Reconciler: NotFound or empty
        end
    end
    Reconciler->>GuestCluster: Create/Update openshift-config/cloud-provider-config with provider config
    alt CA bundle available
        Reconciler->>GuestCluster: Set aws.CABundleKey = CA data
    else No CA bundle
        Reconciler->>GuestCluster: Ensure aws.CABundleKey absent
    end
    GuestCluster-->>Reconciler: Acknowledge write or return error
    Reconciler->>Reconciler: Finish reconciliation
Loading
🚥 Pre-merge checks | ✅ 11 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (11 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding support for custom trust bundle for AWS API endpoints, which directly aligns with the primary objective of syncing trust bundles into guest clusters for AWS.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed Test files use standard Go testing patterns, not Ginkgo. All test case names are static, descriptive strings with no dynamic values, timestamps, UUIDs, or generated identifiers.
Test Structure And Quality ✅ Passed The custom check is designed for Ginkgo tests (Describe/It blocks), but the PR contains standard Go unit tests using table-driven patterns with Gomega assertions.
Microshift Test Compatibility ✅ Passed No Ginkgo e2e tests are added; only standard Go unit tests using testing.T with fake clients.
Single Node Openshift (Sno) Test Compatibility ✅ Passed Pull request adds only standard Go unit tests, not Ginkgo e2e tests, so custom check for new Ginkgo e2e tests is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed Changes are limited to ConfigMap configuration and metadata—no scheduling constraints, affinity rules, or topology assumptions that would break on SNO, TNF, TNA, or HyperShift.
Ote Binary Stdout Contract ✅ Passed The PR introduces no OTE Binary Stdout Contract violations; all modified files contain standard Go unit tests and controller reconciliation logic with no process-level stdout-writing calls.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Added tests are standard Go unit tests, not Ginkgo e2e tests, and contain no IPv4 assumptions or external connectivity requirements.

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

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

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go`:
- Line 2446: Check that reference.Data[aws.ProviderConfigKey] is present and
non-empty before assigning it into cm.Data[aws.ProviderConfigKey]; if it's
missing or empty, return an error (fail fast) instead of writing an empty
aws.conf. Update the sync logic around cm and reference (the block that
currently does cm.Data[aws.ProviderConfigKey] =
reference.Data[aws.ProviderConfigKey]) to validate the value, log/return a
descriptive error when absent, and only set cm.Data when the provider config is
valid.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro Plus

Run ID: 34913917-4951-4a83-8093-81ebed65cba8

📥 Commits

Reviewing files that changed from the base of the PR and between ad1df60 and 7c4531d.

📒 Files selected for processing (5)
  • control-plane-operator/controllers/hostedcontrolplane/cloud/aws/providerconfig.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
  • support/globalconfig/infrastructure.go
  • support/globalconfig/infrastructure_test.go

@codecov

codecov Bot commented Apr 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.00000% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 43.79%. Comparing base (d45a465) to head (4864818).
⚠️ Report is 35 commits behind head on main.

Files with missing lines Patch % Lines
...rconfigoperator/controllers/resources/resources.go 76.47% 9 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8280      +/-   ##
==========================================
+ Coverage   43.77%   43.79%   +0.02%     
==========================================
  Files         772      772              
  Lines       95941    95999      +58     
==========================================
+ Hits        41994    42041      +47     
- Misses      51035    51043       +8     
- Partials     2912     2915       +3     
Files with missing lines Coverage Δ
support/globalconfig/infrastructure.go 100.00% <100.00%> (ø)
...rconfigoperator/controllers/resources/resources.go 57.94% <76.47%> (+0.35%) ⬆️
Flag Coverage Δ
cmd-support 37.39% <100.00%> (+0.01%) ⬆️
cpo-hostedcontrolplane 45.91% <ø> (ø)
cpo-other 45.24% <76.47%> (+0.13%) ⬆️
hypershift-operator 54.03% <ø> (ø)
other 32.08% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor Author

Re: review PRR_kwDOE7ekcc72sY6X

Thanks for the review. The actionable finding about validating aws.ProviderConfigKey before syncing has been addressed — added a fail-fast check and two new test cases covering missing/empty key scenarios.


AI-assisted response via Claude Code

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor Author

Re: #8280 (comment)

Thanks for the walkthrough summary — it accurately describes the changes. No action needed.


AI-assisted response via Claude Code

@csrwng csrwng left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This change is ok, but it doesn't enable the use of custom trust bundles for the entire control plane. Maybe handling the rest of the control plane components (capi provider, control-plane-operator, etc) can be done under a separate story.

Comment thread support/globalconfig/infrastructure.go Outdated

switch platformType {
case hyperv1.AWSPlatform:
infra.Spec.CloudConfig.Name = "cloud-provider-config"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This should use a constant. Ideally the same constant used by resources.go

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. Defined CloudProviderCMName constant in the globalconfig package and updated both infrastructure.go and resources.go to use it. The resources package now references globalconfig.CloudProviderCMName instead of its own duplicate literal. Also updated the infrastructure tests to use the constant.


AI-assisted response via Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. Extracted a CloudProviderConfigName constant to the support/globalconfig package and updated both infrastructure.go and resources.go to use it. The CloudProviderCMName in resources.go now references globalconfig.CloudProviderConfigName instead of a local string literal.


AI-assisted response via Claude Code

}

var caBundle string
if hcp.Spec.AdditionalTrustBundle != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should use the aggregate of of spec.AdditionalTrustBundle and .spec.configuration.Proxy.TrustedCA

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. Switched to using the aggregated trusted-ca-bundle-managed ConfigMap (via cpomanifests.TrustedCABundleConfigMap) which the HCP controller already populates by combining both spec.AdditionalTrustBundle and spec.Configuration.Proxy.TrustedCA. The condition now triggers on either source being set. Added a test case for the proxy TrustedCA path.


AI-assisted response via Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. Switched from UserCAConfigMap (which only contains AdditionalTrustBundle) to TrustedCABundleConfigMap (trusted-ca-bundle-managed), which already contains the aggregate of both spec.AdditionalTrustBundle and .spec.configuration.Proxy.TrustedCA — built by the CPO's reconcileManagedTrustedCABundle. Also updated the condition to check for either source being set, and added a test case for proxy-only TrustedCA.


AI-assisted response via Claude Code

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor Author

Re: review PRR_kwDOE7ekcc73B2Hd

Agreed — this PR focuses on the cloud-provider-config for the guest cluster's AWS SDK usage. Extending custom trust bundle support to the remaining control plane components (CAPI provider, control-plane-operator, etc.) should be tracked under a separate story to keep the scope manageable.


AI-assisted response via Claude Code

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor Author

Re: review 4144456157

Agreed — this PR focuses on the cloud-provider-config use case for AWS. Extending custom trust bundle support to other control plane components (CAPI provider, control-plane-operator, etc.) can be tracked and handled under a separate story.


AI-assisted response via Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go`:
- Around line 2423-2443: The reconcile can stall because when
cpomanifests.TrustedCABundleConfigMap(hcp.Namespace) or the AWS provider source
(cpomanifests.AWSProviderConfig) is expected but not present the controller
neither watches those management-cluster ConfigMaps nor requeues for retry;
update the controller to either (A) add watches for those management-cluster
ConfigMap sources in SetupWithManager (watch ConfigMap resources filtered by
name/namespace for the TrustedCABundle and aws-cloud-config so guest reconciles
are triggered when they appear/change) or (B) when cpClient.Get(...) returns
IsNotFound for the managed trusted CA (the branch inside the reconcile where you
currently log and skip), return a requeue result (e.g.,
ctrl.Result{RequeueAfter: <reasonable backoff>}) so the reconcile will retry
until the bundle appears; reference cpomanifests.TrustedCABundleConfigMap,
cpomanifests.AWSProviderConfig, aws.ProviderConfigKey, SetupWithManager and the
reconcile path that calls r.cpClient.Get.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro Plus

Run ID: e8d0cfdf-1e1d-470d-8230-bd36caa5c574

📥 Commits

Reviewing files that changed from the base of the PR and between 55275ba and 9fe2933.

📒 Files selected for processing (4)
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
  • support/globalconfig/infrastructure.go
  • support/globalconfig/infrastructure_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • support/globalconfig/infrastructure_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go

Comment on lines +2423 to +2443
reference := cpomanifests.AWSProviderConfig(hcp.Namespace)
if err := r.cpClient.Get(ctx, client.ObjectKeyFromObject(reference), reference); err != nil {
return fmt.Errorf("failed to fetch %s/%s configmap from management cluster: %w", reference.Namespace, reference.Name, err)
}
providerConfig, ok := reference.Data[aws.ProviderConfigKey]
if !ok || strings.TrimSpace(providerConfig) == "" {
return fmt.Errorf("source configmap %s/%s is missing required key %q", reference.Namespace, reference.Name, aws.ProviderConfigKey)
}

// Use the aggregated trust bundle that combines spec.AdditionalTrustBundle
// and spec.Configuration.Proxy.TrustedCA, managed by the HCP controller.
var caBundle string
if hcp.Spec.AdditionalTrustBundle != nil ||
(hcp.Spec.Configuration != nil && hcp.Spec.Configuration.Proxy != nil && hcp.Spec.Configuration.Proxy.TrustedCA.Name != "") {
managedTrustBundle := cpomanifests.TrustedCABundleConfigMap(hcp.Namespace)
if err := r.cpClient.Get(ctx, client.ObjectKeyFromObject(managedTrustBundle), managedTrustBundle); err != nil {
if !apierrors.IsNotFound(err) {
return fmt.Errorf("failed to fetch managed trusted CA bundle from management cluster: %w", err)
}
ctrl.LoggerFrom(ctx).Info("managed trusted CA bundle ConfigMap not found, skipping CA bundle sync", "configmap", client.ObjectKeyFromObject(managedTrustBundle))
} else {

@coderabbitai coderabbitai Bot Apr 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

This sync can get stuck after bootstrap.

When a trust bundle is configured, Line 2438 logs and skips if trusted-ca-bundle-managed is absent. But this controller does not watch the management-cluster trusted-ca-bundle-managed or aws-cloud-config ConfigMaps, so the guest cloud-provider-config may never pick up the CA bundle once it appears, or later source updates, until some unrelated reconcile happens. Please add CP-cluster watches for those source ConfigMaps, or explicitly requeue while the managed bundle is expected but missing.

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

In
`@control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go`
around lines 2423 - 2443, The reconcile can stall because when
cpomanifests.TrustedCABundleConfigMap(hcp.Namespace) or the AWS provider source
(cpomanifests.AWSProviderConfig) is expected but not present the controller
neither watches those management-cluster ConfigMaps nor requeues for retry;
update the controller to either (A) add watches for those management-cluster
ConfigMap sources in SetupWithManager (watch ConfigMap resources filtered by
name/namespace for the TrustedCABundle and aws-cloud-config so guest reconciles
are triggered when they appear/change) or (B) when cpClient.Get(...) returns
IsNotFound for the managed trusted CA (the branch inside the reconcile where you
currently log and skip), return a requeue result (e.g.,
ctrl.Result{RequeueAfter: <reasonable backoff>}) so the reconcile will retry
until the bundle appears; reference cpomanifests.TrustedCABundleConfigMap,
cpomanifests.AWSProviderConfig, aws.ProviderConfigKey, SetupWithManager and the
reconcile path that calls r.cpClient.Get.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The concern is valid in the abstract, but in practice this controller is not at risk of stalling for this case. Here's why:

  1. HCP is watched (line 288): The HCP controller creates the trusted-ca-bundle-managed ConfigMap during HCP reconciliation, and HCP status updates are frequent — any HCP object change triggers an HCCO reconcile.

  2. Broad guest-cluster watches (lines 245-276): The controller watches 20+ resource types on the guest cluster (ConfigMaps, Secrets, Services, etc.), so reconciles fire very frequently during and after bootstrap.

  3. Intentional graceful degradation: The "log and skip" pattern at line 2442 is deliberate — the cloud-provider-config should be created promptly even if the optional CA bundle isn't available yet. The next reconcile (triggered by HCP or guest-cluster changes) picks it up. Returning an error or requeueing would block the entire reconcile for a non-critical optional field.

  4. Consistent with existing patterns: Other management-cluster resources like the aws-cloud-config ConfigMap (line 2423), pull secrets (line 366), and numerous other cpClient.Get calls throughout this controller also lack explicit CP-cluster watches — they all rely on HCP or guest-cluster changes to trigger reconciles. Adding watches only for these two ConfigMaps would be inconsistent.

The aws-cloud-config case at line 2423 does return a hard error (which causes controller-runtime to requeue), but that's because the provider config is required — the cloud config cannot be built without it. The trust bundle is optional additional trust, and the ConfigMap is still created successfully without it.


AI-assisted response via Claude Code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skipped: comment is from another GitHub bot.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This concern is not actionable for this controller. The HCP watch at line 288 ensures any HostedControlPlane change triggers a full reconcile — and HCP status updates are frequent during and after bootstrap. This is the same mechanism that drives every other cpClient.Get call in this controller (pull secrets, root CAs, OIDC secrets, etc.), none of which have dedicated ConfigMap watches either.

The "log and skip" pattern here is intentional: the cloud-provider-config ConfigMap should be created promptly with the provider config even if the optional CA bundle isn't available yet. The next HCP- or guest-cluster-triggered reconcile picks it up. Returning an error would block the entire reconcile for an optional field.


AI-assisted response via Claude Code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skipped: comment is from another GitHub bot.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Only repository collaborators, contributors, or members can run CodeRabbit commands.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirming the previous responses are correct — this is not a practical concern.

The HCCO resources controller watches HostedControlPlane (line 198: For(&hyperv1.HostedControlPlane{})), and the HCP controller is what creates the trusted-ca-bundle-managed ConfigMap. HCP status updates are frequent during and after bootstrap, which triggers this controller to re-reconcile and pick up the ConfigMap once it exists. This is the same pattern used by all ~20+ cpClient.Get calls in this controller (pull secrets, certs, cloud configs, etc.) — none have dedicated watches; they all rely on the HCP watch for re-reconciliation.


AI-assisted response via Claude Code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skipped: comment is from another GitHub bot.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Reviewed. The concern is not actionable — the controller already watches HostedControlPlane (line 288) on the CP cluster, so any HCP change (including when the HCP controller creates the managed trust bundle ConfigMap) triggers a full reconcile. The "log and skip" pattern here is intentional graceful degradation for an optional field, consistent with how all other cpClient.Get calls in this controller work. No watches or requeue needed.


AI-assisted response via Claude Code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skipped: comment is from another GitHub bot.

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor Author

Re: #8280 (review)

Thanks for the review. The one actionable inline comment about potential stalling of the trust bundle sync has been addressed with an inline reply — the current "log and skip" pattern is intentional graceful degradation, consistent with the controller's existing architecture. See the inline thread for detailed rationale.


AI-assisted response via Claude Code

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor Author

Re: #8280 (review)

Acknowledged. The single actionable comment about the reconcile potentially stalling has been addressed in the inline thread. In short: the concern is valid in the abstract, but not a practical risk here. The aws-cloud-config not-found case returns a hard error which triggers controller-runtime's exponential backoff requeue. The trusted-ca-bundle-managed not-found case is handled gracefully (logs and skips). This pattern is consistent with ~25+ other cpClient.Get calls in the same controller, none of which have dedicated watches. The controller reconciles frequently via its broad guest-cluster watches and the HCP watch, so eventual consistency is achieved.


AI-assisted response via Claude Code

openshift-merge-bot Bot pushed a commit to openshift/release that referenced this pull request Apr 21, 2026
The comment analyzer flags review bodies and review threads
independently. When an approved bot (e.g. CodeRabbit) submits a review
with both a body and inline comments, both get flagged as separate
needs_attention items. Claude addresses each independently, producing
duplicate responses.

Observed on openshift/hypershift#8280: CodeRabbit review #4146142149
had a body ("Actionable comments posted: 1") and one inline comment
about trust bundle sync stalling. The analyzer returned both as
separate items. Claude posted an inline reply to the thread at
11:04:10Z, then two issue comments at 11:04:20Z and 11:06:19Z —
both "Re: #pullrequestreview-4146142149" with overlapping content.

Root cause: analyze_review_bodies uses per-comment reply matching
(checking if any bot comment references the review ID/URL). Since no
bot comment had yet referenced review 4146142149, it was flagged.
Meanwhile, analyze_review_threads independently flagged the same
review's inline thread. Both items entered the needs_attention list.

Fix: add comments { totalCount } to the reviews GraphQL query and
skip approved bot review bodies when inline comments exist. Bot
review bodies are machine-generated summaries of their inline
comments (already handled by analyze_review_threads). Human review
bodies are always kept since they often contain distinct feedback.

Verified against PR #8280:
- CodeRabbit review 4146142149: SKIPPED (approved_bot, inline_count=1)
- CodeRabbit review 4138831511: SKIPPED (approved_bot, inline_count=1)
- csrwng review 4144456157: KEPT (human, inline_count=2)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go (2)

301-305: Make error-path assertions specific to avoid false positives.

The current expectError branch only checks that some error occurred. A different unintended failure would still pass. Please assert error type/message per case.

Proposed hardening
 type testCase struct {
   name         string
   hcp          *hyperv1.HostedControlPlane
   cpObjects    []client.Object
   guestObjects []client.Object
   expectError  bool
+  errContains  string
   verify       func(g Gomega, guestClient client.Client)
 }

 // ...
 {
   name: "When aws-cloud-config ConfigMap is missing, it should return an error",
   // ...
   cpObjects:   []client.Object{},
   expectError: true,
+  errContains: "not found",
 },
 // ...
 {
   name: "When aws-cloud-config ConfigMap is missing the provider config key, it should return an error",
   // ...
   expectError: true,
+  errContains: aws.ProviderConfigKey,
 },

 // ...
 err := r.reconcileCloudConfig(context.Background(), tc.hcp)
 if tc.expectError {
   g.Expect(err).To(HaveOccurred())
+  if tc.errContains != "" {
+    g.Expect(err.Error()).To(ContainSubstring(tc.errContains))
+  }
   return
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go`
around lines 301 - 305, The test's error branch only checks for any error; make
it assert specific error types/messages to avoid false positives by adding an
expected error indicator on each test case (e.g., tc.expectedErr or
tc.expectedErrMsg) and then change the branch that calls r.reconcileCloudConfig
to assert both presence and content/type: when tc.expectError is true assert the
error occurred and that err.Error() contains tc.expectedErrMsg (or use
errors.Is/As against tc.expectedErr for typed errors) instead of only
HaveOccurred, referencing the test case variable tc and the
reconcileCloudConfig(...) call to locate where to add the stricter assertions.

202-230: Add parity coverage for missing managed trust bundle with Proxy.TrustedCA.

You already test graceful fallback when AdditionalTrustBundle is set and the managed trust bundle ConfigMap is missing. Please add the equivalent case for Spec.Configuration.Proxy.TrustedCA to lock in behavior for both triggers.

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

In
`@control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go`
around lines 202 - 230, Add a parallel test case to the existing one that covers
the scenario where Spec.Configuration.Proxy.TrustedCA is set but the managed
trust bundle ConfigMap is missing: create a HostedControlPlane with
Spec.Configuration.Proxy.TrustedCA pointing to a LocalObjectReference (instead
of AdditionalTrustBundle), include fakeAWSCloudConfig() in cpObjects, and in the
verify closure fetch the ConfigMap by CloudProviderCMName and assert cm.Data has
aws.ProviderConfigKey with the base config and does NOT have aws.CABundleKey;
reuse the same structure and assertions as the AdditionalTrustBundle test but
target HostedControlPlane.Spec.Configuration.Proxy.TrustedCA to ensure parity.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go`:
- Around line 301-305: The test's error branch only checks for any error; make
it assert specific error types/messages to avoid false positives by adding an
expected error indicator on each test case (e.g., tc.expectedErr or
tc.expectedErrMsg) and then change the branch that calls r.reconcileCloudConfig
to assert both presence and content/type: when tc.expectError is true assert the
error occurred and that err.Error() contains tc.expectedErrMsg (or use
errors.Is/As against tc.expectedErr for typed errors) instead of only
HaveOccurred, referencing the test case variable tc and the
reconcileCloudConfig(...) call to locate where to add the stricter assertions.
- Around line 202-230: Add a parallel test case to the existing one that covers
the scenario where Spec.Configuration.Proxy.TrustedCA is set but the managed
trust bundle ConfigMap is missing: create a HostedControlPlane with
Spec.Configuration.Proxy.TrustedCA pointing to a LocalObjectReference (instead
of AdditionalTrustBundle), include fakeAWSCloudConfig() in cpObjects, and in the
verify closure fetch the ConfigMap by CloudProviderCMName and assert cm.Data has
aws.ProviderConfigKey with the base config and does NOT have aws.CABundleKey;
reuse the same structure and assertions as the AdditionalTrustBundle test but
target HostedControlPlane.Spec.Configuration.Proxy.TrustedCA to ensure parity.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro Plus

Run ID: a8eaacd9-0e27-4e9b-9f37-4a9f557c2411

📥 Commits

Reviewing files that changed from the base of the PR and between 9fe2933 and b274583.

📒 Files selected for processing (1)
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor Author

Re: #8280 (review)

Done. Addressed both nitpick suggestions:

  1. Error-path assertions: Added errContains field to the test struct and specific substring assertions — "not found" for the missing ConfigMap case and aws.ProviderConfigKey for the missing key case.
  2. Proxy TrustedCA parity: Added a new test case "When proxy TrustedCA is set but managed trust bundle ConfigMap is missing, it should sync base config without CA bundle" — mirrors the existing AdditionalTrustBundle coverage for the same graceful fallback scenario.

All 9 test cases pass.


AI-assisted response via Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go (2)

233-255: Add a whitespace-only provider-config test case for full branch coverage.

Line 234 currently validates a missing aws.ProviderConfigKey, but the reconciler also rejects whitespace-only values. Adding that case will lock in the strings.TrimSpace(...) == "" behavior.

➕ Proposed test case
 		{
 			name: "When aws-cloud-config ConfigMap is missing the provider config key, it should return an error",
 			hcp: &hyperv1.HostedControlPlane{
@@
 			expectError: true,
 			errContains: aws.ProviderConfigKey,
 		},
+		{
+			name: "When aws-cloud-config ConfigMap has whitespace-only provider config, it should return an error",
+			hcp: &hyperv1.HostedControlPlane{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test",
+					Namespace: hcpNamespace,
+				},
+				Spec: hyperv1.HostedControlPlaneSpec{
+					Platform: hyperv1.PlatformSpec{
+						Type: hyperv1.AWSPlatform,
+					},
+				},
+			},
+			cpObjects: []client.Object{
+				func() *corev1.ConfigMap {
+					cm := cpomanifests.AWSProviderConfig(hcpNamespace)
+					cm.Data = map[string]string{
+						aws.ProviderConfigKey: "   \n\t",
+					}
+					return cm
+				}(),
+			},
+			expectError: true,
+			errContains: aws.ProviderConfigKey,
+		},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go`
around lines 233 - 255, Add a new test case in reconcile_cloud_config_test.go
mirroring the existing missing-key case but instead set the aws provider config
key to a whitespace-only value (e.g., cm.Data[aws.ProviderConfigKey] = "   "),
keep expectError: true and errContains: aws.ProviderConfigKey so the test
exercises the strings.TrimSpace(... ) == "" branch; place it alongside the
current case so it covers the whitespace-only rejection path.

73-319: Consider extracting a small assertion helper to reduce repeated verify closures.

The repeated guestClient.Get(...) + provider-key assertions across multiple cases add maintenance overhead; a helper would make future case additions simpler and less error-prone.

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

In
`@control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go`
around lines 73 - 319, Extract a small test helper (e.g.,
assertCloudProviderConfig or verifyCloudProviderConfig) that wraps the repeated
guestClient.Get call and the assertions against aws.ProviderConfigKey and
aws.CABundleKey (and accepts parameters like Gomega, client.Client, expected
provider config value, and optional expected CA bundle or a flag indicating
absence) and replace the inline verify closures in tests that use
fakeAWSCloudConfig() and fakeManagedTrustBundle() with calls to this helper;
update test cases that expect no CA bundle to call the helper with an
empty/absent CA parameter and cases that expect a bundle to pass the exact
string, keeping references to guestClient.Get, aws.ProviderConfigKey,
aws.CABundleKey, fakeAWSCloudConfig, and fakeManagedTrustBundle to locate where
to change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go`:
- Around line 233-255: Add a new test case in reconcile_cloud_config_test.go
mirroring the existing missing-key case but instead set the aws provider config
key to a whitespace-only value (e.g., cm.Data[aws.ProviderConfigKey] = "   "),
keep expectError: true and errContains: aws.ProviderConfigKey so the test
exercises the strings.TrimSpace(... ) == "" branch; place it alongside the
current case so it covers the whitespace-only rejection path.
- Around line 73-319: Extract a small test helper (e.g.,
assertCloudProviderConfig or verifyCloudProviderConfig) that wraps the repeated
guestClient.Get call and the assertions against aws.ProviderConfigKey and
aws.CABundleKey (and accepts parameters like Gomega, client.Client, expected
provider config value, and optional expected CA bundle or a flag indicating
absence) and replace the inline verify closures in tests that use
fakeAWSCloudConfig() and fakeManagedTrustBundle() with calls to this helper;
update test cases that expect no CA bundle to call the helper with an
empty/absent CA parameter and cases that expect a bundle to pass the exact
string, keeping references to guestClient.Get, aws.ProviderConfigKey,
aws.CABundleKey, fakeAWSCloudConfig, and fakeManagedTrustBundle to locate where
to change.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro Plus

Run ID: 71bd9b3b-ea57-4f82-ab8b-5dff896f5cc7

📥 Commits

Reviewing files that changed from the base of the PR and between b274583 and dcd520b.

📒 Files selected for processing (1)
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/reconcile_cloud_config_test.go

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor Author

Re: #8280 (review)

Thanks for the nitpick suggestions!

  1. Whitespace-only provider-config test case (lines 233-255): Done. Added a test case that sets aws.ProviderConfigKey to " \n\t" to exercise the strings.TrimSpace(...) == "" branch. This locks in the whitespace-only rejection behavior alongside the existing missing-key test.

  2. Extract assertion helper (lines 73-319): Acknowledged — the repeated guestClient.Get + assertion pattern could benefit from a helper. Deferring for now since the current test count is manageable and each verify closure is self-documenting, but will keep in mind if more cases are added.


AI-assisted response via Claude Code

andrej1991 pushed a commit to andrej1991/release that referenced this pull request Jul 6, 2026
…hift#78134)

The comment analyzer flags review bodies and review threads
independently. When an approved bot (e.g. CodeRabbit) submits a review
with both a body and inline comments, both get flagged as separate
needs_attention items. Claude addresses each independently, producing
duplicate responses.

Observed on openshift/hypershift#8280: CodeRabbit review #4146142149
had a body ("Actionable comments posted: 1") and one inline comment
about trust bundle sync stalling. The analyzer returned both as
separate items. Claude posted an inline reply to the thread at
11:04:10Z, then two issue comments at 11:04:20Z and 11:06:19Z —
both "Re: #pullrequestreview-4146142149" with overlapping content.

Root cause: analyze_review_bodies uses per-comment reply matching
(checking if any bot comment references the review ID/URL). Since no
bot comment had yet referenced review 4146142149, it was flagged.
Meanwhile, analyze_review_threads independently flagged the same
review's inline thread. Both items entered the needs_attention list.

Fix: add comments { totalCount } to the reviews GraphQL query and
skip approved bot review bodies when inline comments exist. Bot
review bodies are machine-generated summaries of their inline
comments (already handled by analyze_review_threads). Human review
bodies are always kept since they often contain distinct feedback.

Verified against PR openshift#8280:
- CodeRabbit review 4146142149: SKIPPED (approved_bot, inline_count=1)
- CodeRabbit review 4138831511: SKIPPED (approved_bot, inline_count=1)
- csrwng review 4144456157: KEPT (human, inline_count=2)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

@csrwng csrwng left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall the approach is sound — follows the existing Azure/OpenStack pattern, gates on trust bundle presence, and has good test coverage. Two minor nits on the implementation.


if !hasTrustBundle {
cm := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Namespace: ConfigNamespace, Name: CloudProviderCMName}}
if err := r.client.Delete(ctx, cm); err != nil && !apierrors.IsNotFound(err) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: prefer using k8sutil.DeleteIfNeeded here for consistency with the rest of the file (e.g., lines 2105, 2130, 3122).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. Switched to k8sutil.DeleteIfNeeded for both cloud-provider-config and the new kube-cloud-config ConfigMaps.


AI-assisted response via Claude Code

if !apierrors.IsNotFound(err) {
return fmt.Errorf("failed to fetch managed trusted CA bundle from management cluster: %w", err)
}
ctrl.LoggerFrom(ctx).Info("managed trusted CA bundle ConfigMap not found, skipping CA bundle sync", "configmap", client.ObjectKeyFromObject(managedTrustBundle))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: The log says "skipping CA bundle sync" but execution continues into CreateOrUpdate below — nothing is actually skipped. The cloud-provider-config ConfigMap is still created/updated (just without the CA bundle key, because caBundle stays empty). Consider rewording to something like "managed trusted CA bundle ConfigMap not found, proceeding without CA bundle" to match the actual behavior.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. Reworded to "managed trusted CA bundle ConfigMap not found, proceeding without CA bundle" to match the actual behavior.


AI-assisted response via Claude Code

@bryan-cox

Copy link
Copy Markdown
Member

/test address-review-comments

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor Author

Review agent triggered. View job

@bryan-cox

Copy link
Copy Markdown
Member

/rebase

@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 10, 2026
@github-actions

Copy link
Copy Markdown

🤖 Rebasing PR onto main: workflow run

OpenShift CI Bot and others added 10 commits July 10, 2026 19:50
… for AWS

Guest cluster operators (e.g. cloud-network-config-controller, cluster-ingress-operator) need the
additional trust bundle to communicate with AWS API endpoints that use custom certificates, such as
when using a proxy or private AWS endpoints. Previously, the trust bundle was only synced to the
user-ca-bundle ConfigMap in the guest cluster's openshift-config namespace. With this change, we
also sync it to the cloud-provider-config ConfigMap in the guest cluster, and set
infra.Spec.CloudConfig on the Infrastructure resource to reference it, following the same pattern
used by Azure and OpenStack platforms.

The AWS case in reconcileCloudConfig now:
- Always creates a cloud-provider-config ConfigMap with the AWS cloud config (aws.conf)
- Includes the CA bundle (ca-bundle.pem) when additionalTrustBundle is set
- Removes the CA bundle key when additionalTrustBundle is unset

Ref: CNTRLPLANE-625

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ensure the new AWS cloud config reconciliation behavior is covered by unit tests:
- Verify cloud-provider-config is created with CA bundle when additionalTrustBundle is set
- Verify cloud-provider-config is created without CA bundle when additionalTrustBundle is not set
- Verify CA bundle key is removed from cloud-provider-config when trust bundle is removed
- Verify Infrastructure CloudConfig is set correctly for AWS platform

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-ca-bundle gracefully

Replace magic string "ca-bundle.crt" with certs.UserCABundleMapKey constant
in reconcileCloudConfig and tests. Handle apierrors.IsNotFound for
user-ca-bundle ConfigMap so the base aws.conf is still synced during
bootstrap when the CA bundle isn't ready yet. Add error path and edge
case tests for missing ConfigMaps and empty CA bundle values.

Ticket: CNTRLPLANE-625

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…egate trust bundles

Use globalconfig.CloudProviderCMName constant in both infrastructure.go
and resources.go instead of duplicated string literals. Also switch from
using only spec.AdditionalTrustBundle to the aggregated managed trust
bundle (trusted-ca-bundle-managed) that combines both
spec.AdditionalTrustBundle and spec.configuration.Proxy.TrustedCA,
consistent with the HCP controller's existing aggregation pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move configv1 import to the github.com/openshift group, separate from the
github.com/openshift/hypershift group, to satisfy the project's gci linter
configuration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add specific error message assertions (errContains) to error-path test
cases to prevent false positives from unintended failures. Add parity
test coverage for the Proxy.TrustedCA code path when the managed trust
bundle ConfigMap is missing, matching existing AdditionalTrustBundle
coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…balconfig

Move CABundleKey and cloud config key constants to support/globalconfig
to fix the import direction anti-pattern where support/ imported from
control-plane-operator/. This also deduplicates CABundleKey which was
identical between the AWS and OpenStack packages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Make infra.Spec.CloudConfig and cloud-provider-config ConfigMap creation
conditional on having a trust bundle configured (AdditionalTrustBundle or
Proxy.TrustedCA). This avoids introducing new CloudConfig and ConfigMap
resources into all existing AWS guest clusters, which could change guest
operator behavior.

When no trust bundle is configured, any previously-synced
cloud-provider-config ConfigMap is cleaned up and CloudConfig is cleared.

Also replaces aws.ProviderConfigKey usage in resources.go with the shared
globalconfig.AWSProviderConfigKey constant, removing the import
anti-pattern of support/ depending on control-plane-operator/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use k8sutil.DeleteIfNeeded for consistency with the rest of the file
- Reword misleading "skipping CA bundle sync" log message to match
  actual behavior (execution continues into CreateOrUpdate)
- Add kube-cloud-config ConfigMap in openshift-config-managed for AWS,
  mirroring the OpenStack pattern so CNO can pass the config to
  cloud-network-config-controller

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 10, 2026
@csrwng csrwng added the tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges. label Jul 14, 2026
@csrwng

csrwng commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

/approve

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 14, 2026

@bryan-cox bryan-cox left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 14, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aks
/test e2e-aws
/test e2e-aws-upgrade-hypershift-operator
/test e2e-azure-v2-self-managed
/test e2e-kubevirt-aws-ovn-reduced
/test e2e-v2-aws
/test e2e-v2-gke

@openshift-ci

openshift-ci Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: bryan-cox, csrwng, hypershift-jira-solve-ci[bot]

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

The pull request process is described 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

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor Author

Now I have all the data I need. Let me produce the final report:

Test Failure Analysis Complete

Job Information

Job 1: e2e-v2-aws

  • Prow Job: pull-ci-openshift-hypershift-main-e2e-v2-aws
  • Build ID: 2077096363815866368
  • Target: e2e-v2-aws
  • Cluster: build01
  • Duration: ~2h 54m

Job 2: e2e-aws

  • Prow Job: pull-ci-openshift-hypershift-main-e2e-aws
  • Build ID: 2077096363656482816
  • Target: e2e-aws
  • Cluster: build01
  • Duration: ~4h 15m

Test Failure Analysis

Error

Job 1 (e2e-v2-aws): Pod eviction due to CI node DiskPressure — infrastructure flake, unrelated to PR.

Job 2 (e2e-aws): TestNodePool/HostedCluster2/Main/TestAdditionalTrustBundlePropagation timed out after 20m.
  ValidGeneratedPayload=: InvalidConfig(failed to generate payload: error getting ignition payload:
    failed to execute machine-config-operator: machine-config-operator process failed: exit status 255)
  UpdatingConfig=True: AsExpected(Updating config in progress. Target config: 82520849)
  AllNodesHealthy=False: NodeProvisioning(1 of 2 machines are not healthy —
    Machine node-pool-6h576-test-additional-trust-bundle-propagation-rm496r: Waiting for a node
    with matching ProviderID to exist)
  ReachedIgnitionEndpoint=False: ignitionNotReached

Summary

Both jobs failed from different root causes. e2e-v2-aws is a pure CI infrastructure flake — all 473 executed tests passed, but two post-phase cleanup pods were evicted due to DiskPressure on the build01 node; a /retest will resolve it. e2e-aws failed due to TestAdditionalTrustBundlePropagation timing out when the machine-config-operator (MCO) crashed with exit status 255 while generating the ignition payload after the test applied an AdditionalTrustBundle. This PR modifies ReconcileInfrastructure to set infra.Spec.CloudConfig referencing cloud-provider-config/aws.conf when a trust bundle is configured — this is called by MCSParams which feeds the MCO ignition generation pipeline. The MCO failure is likely caused by the MCO attempting to consume the newly-referenced cloud-provider-config ConfigMap during payload generation, and either the ConfigMap not being fully propagated, or its content (aws.conf format) being incompatible with what the MCO expects at that stage. The test itself (pre-existing, not modified by this PR) uses a dummy non-PEM CA bundle string "dummy", which may also contribute to MCO confusion.

Root Cause

e2e-v2-aws: CI Infrastructure Flake (NOT PR-related)

The build01 CI cluster node experienced DiskPressure, causing Kubernetes to evict two post-phase pods (e2e-v2-aws-hypershift-k8sgpt and e2e-v2-aws-destroy) before they could execute. All actual test steps passed. This is a transient infrastructure issue.

e2e-aws: MCO Ignition Payload Generation Failure (Potentially PR-related)

The TestAdditionalTrustBundlePropagation test failed because the MCO process crashed (exit status 255) when generating the ignition payload after an AdditionalTrustBundle was applied to the HostedCluster. The causal chain is:

  1. Test action: Creates a ConfigMap with ca-bundle.crt: "dummy" and sets HostedCluster.Spec.AdditionalTrustBundle to reference it.

  2. PR's ReconcileInfrastructure change: Now sets infra.Spec.CloudConfig = {Name: "cloud-provider-config", Key: "aws.conf"} for AWS when AdditionalTrustBundle is configured. Previously, AWS had no CloudConfig reference on the Infrastructure CR.

  3. MCO ignition generation: The NodePool controller calls NewMCSParams()ReconcileInfrastructure() to build the Infrastructure object fed to the MCO. With the PR's changes, the Infrastructure CR now includes a CloudConfig reference. The MCO expects the referenced cloud-provider-config ConfigMap to be available with valid content when generating the ignition payload.

  4. Failure point: The MCO crashes with exit 255 — likely because:

    • The cloud-provider-config ConfigMap may not yet exist in the guest cluster when the MCO runs (race between HCCO reconciling the ConfigMap via reconcileCloudConfig and the MCO running), OR
    • The MCO does not expect/support the aws.conf cloud config format in this context, OR
    • The aws-cloud-config source ConfigMap in the HCP namespace may not have the expected content when the trust bundle is first applied.
  5. Cascade: MCO failure → ValidGeneratedPayload=InvalidConfig → ignition endpoint never reached → new node never provisions → UpdatingConfig stays True → 20-minute timeout → test failure → teardown failure (stuck resources).

The test file (nodepool_additionalTrustBundlePropagation_test.go) was NOT modified by this PR and pre-existed, but the PR changes the behavior that the test exercises by making ReconcileInfrastructure set a CloudConfig reference on the Infrastructure CR for AWS when trust bundles are present. This is a behavioral change in code path that the test now triggers.

Recommendations
  1. e2e-v2-aws: Simply /retest — this is a CI infrastructure flake (DiskPressure node eviction) completely unrelated to the PR.

  2. e2e-aws — investigate the MCO ignition generation path: The PR sets infra.Spec.CloudConfig for AWS in ReconcileInfrastructure, which is used by MCSParams to feed the MCO. Verify that:

    • The MCO's ignition generation can handle the aws.conf cloud config key and format.
    • The cloud-provider-config ConfigMap content is correctly assembled and available when the MCO runs (check for race conditions between the HCCO creating the ConfigMap and the NodePool controller generating ignition).
    • The MCO doesn't fail when the referenced cloud-provider-config ConfigMap doesn't exist yet in the guest cluster.
  3. Consider ordering: In resources.go, reconcileConfig() (which calls ReconcileInfrastructure) runs BEFORE reconcileNetworkingAndSecrets() (which calls reconcileCloudConfig). The Infrastructure CR references cloud-provider-config before it's created. While both happen in the same reconcile loop, external consumers (like the MCO via the NodePool controller) may see the Infrastructure CR update before the ConfigMap exists.

  4. Test the MCO path locally: Run the TestAdditionalTrustBundlePropagation e2e test in isolation to confirm whether this failure is reproducible with the PR changes. Also check whether the MCO handles the cloud-provider-config reference correctly by examining MCO logs from the hosted control plane.

  5. Consider a /retest: While the e2e-aws failure has a plausible connection to the PR changes, the MCO exit 255 could also be a transient infrastructure issue (resource pressure, image pull failure). A retest would help disambiguate.

Evidence
Evidence Detail
e2e-v2-aws failure type CI infrastructure flake — DiskPressure pod eviction on build01 node
e2e-v2-aws test results 473/473 tests passed, 0 failures. Post-phase pods evicted.
e2e-aws failing test TestNodePool/HostedCluster2/Main/TestAdditionalTrustBundlePropagation/AdditionalTrustBundlePropagationTest (1215s)
e2e-aws test results 617/623 passed, 6 failures (all from one cascade)
MCO error ValidGeneratedPayload=: InvalidConfig(failed to generate payload: error getting ignition payload: failed to execute machine-config-operator: machine-config-operator process failed: exit status 255)
NodePool stuck condition UpdatingConfig=True for 20m, never reached UpdatingConfig=False
Node provisioning stuck Machine rm496r: NodeProvisioning: Waiting for a node with matching ProviderID to exist
PR code change (infrastructure.go) ReconcileInfrastructure now sets infra.Spec.CloudConfig.Name = "cloud-provider-config" and Key = "aws.conf" when AdditionalTrustBundle or Proxy.TrustedCA is configured
PR code change (resources.go) New case hyperv1.AWSPlatform in reconcileCloudConfig creates cloud-provider-config ConfigMap with aws.conf key and optional ca-bundle.pem
MCSParams usage NewMCSParams() in mcs/params.go calls ReconcileInfrastructure() — the Infrastructure CR with CloudConfig is fed to the MCO for ignition generation
Reconcile ordering reconcileConfig (sets Infrastructure CloudConfig) runs BEFORE reconcileCloudConfig (creates the ConfigMap) in the HCCO reconcile loop
Test file modified by PR? No — nodepool_additionalTrustBundlePropagation_test.go was not changed
Test CA bundle content ca-bundle.crt: "dummy" — not a valid PEM certificate
Files changed by PR resources.go, infrastructure.go, infrastructure_test.go, reconcile_cloud_config_test.go (4 files)

@enxebre

enxebre commented Jul 15, 2026

Copy link
Copy Markdown
Member

/retest

@openshift-ci

openshift-ci Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

@hypershift-jira-solve-ci[bot]: 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-aws 4864818 link true /test e2e-aws

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.

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release area/platform/aws PR/issue for AWS (AWSPlatform) platform jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants