Skip to content

CNTRLPLANE-3363: Inject health reporter as sidecar container#2317

Open
ardaguclu wants to merge 1 commit into
openshift:masterfrom
ardaguclu:inject-health-reporter
Open

CNTRLPLANE-3363: Inject health reporter as sidecar container#2317
ardaguclu wants to merge 1 commit into
openshift:masterfrom
ardaguclu:inject-health-reporter

Conversation

@ardaguclu

@ardaguclu ardaguclu commented Jun 19, 2026

Copy link
Copy Markdown
Member

This PR injects health reporter container into apiserver pods, if any kms plugin container is added.

Summary by CodeRabbit

  • New Features

    • Added health reporting support for KMS plugin pods. A health-reporter sidecar container can now be configured and injected into KMS plugin deployments to enable health monitoring and reporting capabilities.
  • Tests

    • Added comprehensive test coverage for health reporter injection and configuration in KMS plugin pod specs.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jun 19, 2026
@openshift-ci-robot

openshift-ci-robot commented Jun 19, 2026

Copy link
Copy Markdown

@ardaguclu: This pull request references CNTRLPLANE-3363 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:

This PR injects health reporter container into apiserver pods, if any kms plugin container is added.

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

@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jun 19, 2026
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

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

Adds a kms-health-reporter init-container to KMS plugin pods. KMSPluginBuilder gains a WithHealthReporter method and internal fields; applyHealthReporter validates config and injects the sidecar with socket args, NODE_NAME downward API, hardened security context, and static-pod kubeconfig support. Public AddKMSPluginSidecar* functions are extended with operatorCmd and operatorImage parameters.

Changes

KMS Plugin Health Reporter Sidecar

Layer / File(s) Summary
KMSPluginBuilder fields, WithHealthReporter, and Apply socket wiring
pkg/operator/encryption/kms/pluginlifecycle/builder.go, pkg/operator/encryption/kms/pluginlifecycle/sidecar.go
Adds four internal fields (enableHealthReporter, healthReporterContainerName, healthReporterOperatorCmd, healthReporterImage) to KMSPluginBuilder, a WithHealthReporter builder method, the healthReporterContainerName constant, a sockets slice built from extracted KMS configs in Apply, and a conditional applyHealthReporter call at the end of Apply.
healthReporter struct and container spec construction
pkg/operator/encryption/kms/pluginlifecycle/health_reporter.go
Implements applyHealthReporter (validates config, wires kubeconfig for static-pod mode, creates healthReporter, mounts KMS socket and optionally resource dir). Implements healthReporter with Name() and BuildSidecarContainer() setting command/args (--kms-sockets, optional --kubeconfig), NODE_NAME via downward API, fixed resource requests, restart/termination policies, and a hardened security context.
AddKMSPluginSidecar* signature extensions
pkg/operator/encryption/kms/pluginlifecycle/sidecar.go
Extends AddKMSPluginSidecarToStaticPodSpec and AddKMSPluginSidecarToPodSpec with operatorCmd string and operatorImage string parameters and threads them into the builder chain via WithHealthReporter.
Health reporter and sidecar tests
pkg/operator/encryption/kms/pluginlifecycle/health_reporter_test.go, pkg/operator/encryption/kms/pluginlifecycle/sidecar_test.go
Adds TestKMSPluginBuilder_WithHealthReporter covering normal injection, static-pod (root UID + kubeconfig arg), absent reporter (no init-container), and empty-image error. Refactors sidecar_test.go to use a shared expectedHealthReporter(sockets) helper and supplies the new operator image argument to AddKMSPluginSidecarToPodSpec call sites.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 14 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (14 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 change: injecting a health reporter as a sidecar container for KMS plugin support.
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 All test names in the PR are stable and deterministic. The new test file (health_reporter_test.go) uses 4 static test names via t.Run(), and sidecar_test.go uses 11 static table-driven test names....
Test Structure And Quality ✅ Passed The custom check specifies "Review Ginkgo test code" but this PR contains standard Go tests using testing.T, not Ginkgo. The check is not applicable to this PR context per instructions.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added in this PR. The new test file (health_reporter_test.go) and updated test files use standard Go unit testing (testing.T, t.Run), not Ginkgo patterns.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No Ginkgo e2e tests added. PR only contains standard Go unit tests in pkg/operator/encryption/kms/pluginlifecycle using testing.T pattern.
Topology-Aware Scheduling Compatibility ✅ Passed PR adds topology-agnostic health reporter sidecar injection; no scheduling constraints (affinity, anti-affinity, nodeSelector, tolerations, PDB, topologySpread) introduced.
Ote Binary Stdout Contract ✅ Passed PR modifies library code with no main(), init(), TestMain() or suite setup functions. All logging uses klog/v2 which writes to stderr by default. No fmt.Print/Println/Printf calls found. Test code...
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests added. The new health_reporter_test.go uses standard Go testing package, not Ginkgo framework. Check is not applicable.
No-Weak-Crypto ✅ Passed No weak cryptographic algorithms, custom crypto, or non-constant-time comparisons found in modified files. PR only modifies KMS plugin health-reporter container injection logic.
Container-Privileges ✅ Passed The health reporter container disables privilege escalation (AllowPrivilegeEscalation: false), drops all capabilities (Drop ["ALL"]), uses RuntimeDefault seccomp, and read-only root filesystem. Roo...
No-Sensitive-Data-In-Logs ✅ Passed No logging of sensitive data found. Args containing socket paths and kubeconfig are only stored in container spec, never logged. All klog statements log non-sensitive information (counts, standard...

✏️ 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.

@openshift-ci openshift-ci Bot requested review from dgrisonnet and p0lyn0mial June 19, 2026 07:11
@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jun 19, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
pkg/operator/encryption/kms/pluginlifecycle/sidecar_test.go (1)

576-585: ⚡ Quick win

Add a wrapper-level negative test for empty operatorImage.

Now that AddKMSPluginSidecarToPodSpec requires operatorImage, add a table case (and idempotency guard if needed) asserting empty image returns the expected validation error from the builder. This protects the new public API contract from silent regressions.

Also applies to: 601-605

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

In `@pkg/operator/encryption/kms/pluginlifecycle/sidecar_test.go` around lines 576
- 585, Add a new test case to the tests table in the table-driven test that
validates empty operatorImage parameter rejection. Create a test case entry
where operatorImage is set to an empty string (instead of
"quay.io/test/operator:latest") and set the corresponding tt.wantErr field to
match the validation error message that AddKMSPluginSidecarToPodSpec should
return when operatorImage is empty. This ensures the function properly validates
the required operatorImage parameter and protects the public API contract from
regression.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/operator/encryption/kms/pluginlifecycle/builder_test.go`:
- Around line 208-218: The Apply method in the KMSPluginBuilder currently
validates healthReporterImage after mutating podSpec, which violates atomicity
on error. In the test case for empty image, add an assertion that verifies
podSpec remains unchanged after Apply returns an error (by comparing the podSpec
state before and after the call). Additionally, move the healthReporterImage
validation logic earlier in the Apply method implementation to occur before any
mutations to podSpec are made, ensuring that validation failures cannot leave
partial sidecar or volume mutations behind.

In `@pkg/operator/encryption/kms/pluginlifecycle/builder.go`:
- Around line 176-179: The health reporter container receives a kubeconfig
argument but the corresponding volume mount is not being added. After the
healthReporterSocketMount logic (around lines 176-179) where
ensureVolumeMountInContainer is called with kmsPluginSocketMount, add similar
logic to check if b.healthReporterKubeconfig is non-empty, and if so, create a
volume mount for the kubeconfig file and add it to the podSpec using
ensureVolumeMountInContainer. Additionally, ensure the actual volume is added to
the pod spec using ensureVolumeInPodSpec to mount the kubeconfig file from the
host filesystem, since the container has ReadOnlyRootFilesystem set to true.

---

Nitpick comments:
In `@pkg/operator/encryption/kms/pluginlifecycle/sidecar_test.go`:
- Around line 576-585: Add a new test case to the tests table in the
table-driven test that validates empty operatorImage parameter rejection. Create
a test case entry where operatorImage is set to an empty string (instead of
"quay.io/test/operator:latest") and set the corresponding tt.wantErr field to
match the validation error message that AddKMSPluginSidecarToPodSpec should
return when operatorImage is empty. This ensures the function properly validates
the required operatorImage parameter and protects the public API contract from
regression.
🪄 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: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 109d0e12-62d3-48a4-aec4-350f6df91146

📥 Commits

Reviewing files that changed from the base of the PR and between b0f5231 and 0744aff.

📒 Files selected for processing (4)
  • pkg/operator/encryption/kms/pluginlifecycle/builder.go
  • pkg/operator/encryption/kms/pluginlifecycle/builder_test.go
  • pkg/operator/encryption/kms/pluginlifecycle/sidecar.go
  • pkg/operator/encryption/kms/pluginlifecycle/sidecar_test.go

Comment on lines +208 to +218
t.Run("empty image: returns error", func(t *testing.T) {
podSpec := &corev1.PodSpec{
Containers: []corev1.Container{{Name: "kube-apiserver"}},
Volumes: []corev1.Volume{f.resourceDirVolume},
}
err := NewKMSPluginBuilder().
FromEncryptionConfig("encryption-config", cfg).
WithHealthReporter("kms-health-reporter", "", "").
Apply(podSpec, "kube-apiserver")
require.ErrorContains(t, err, "health reporter image is required")
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve atomicity on error for the empty-image path.

This case only checks the error message, but Apply currently validates healthReporterImage after mutating podSpec. Add an unchanged-on-error assertion here and move the image validation earlier in Apply so this path cannot leave partial sidecar/volume mutations behind.

Suggested test hardening in this subtest
 	t.Run("empty image: returns error", func(t *testing.T) {
 		podSpec := &corev1.PodSpec{
 			Containers: []corev1.Container{{Name: "kube-apiserver"}},
 			Volumes:    []corev1.Volume{f.resourceDirVolume},
 		}
+		original := podSpec.DeepCopy()
 		err := NewKMSPluginBuilder().
 			FromEncryptionConfig("encryption-config", cfg).
 			WithHealthReporter("kms-health-reporter", "", "").
 			Apply(podSpec, "kube-apiserver")
 		require.ErrorContains(t, err, "health reporter image is required")
+		require.Equal(t, original, podSpec, "pod spec should be unchanged on error")
 	})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/operator/encryption/kms/pluginlifecycle/builder_test.go` around lines 208
- 218, The Apply method in the KMSPluginBuilder currently validates
healthReporterImage after mutating podSpec, which violates atomicity on error.
In the test case for empty image, add an assertion that verifies podSpec remains
unchanged after Apply returns an error (by comparing the podSpec state before
and after the call). Additionally, move the healthReporterImage validation logic
earlier in the Apply method implementation to occur before any mutations to
podSpec are made, ensuring that validation failures cannot leave partial sidecar
or volume mutations behind.

Comment thread pkg/operator/encryption/kms/pluginlifecycle/builder.go Outdated
@ardaguclu

Copy link
Copy Markdown
Member Author

/uncc @dgrisonnet
/cc @ibihim @bertinatto

@openshift-ci openshift-ci Bot requested review from bertinatto and ibihim and removed request for dgrisonnet June 19, 2026 07:49
@ardaguclu ardaguclu force-pushed the inject-health-reporter branch from 555fb53 to 870ba88 Compare June 19, 2026 10:56

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
pkg/operator/encryption/kms/pluginlifecycle/builder.go (1)

243-248: 💤 Low value

Consider adding resource limits for the health reporter container.

Only resource requests are set (32Mi memory, 10m CPU) without corresponding limits. While this is sometimes intentional for sidecar containers to avoid OOM kills during spikes, it could also lead to resource contention on nodes if the health reporter misbehaves. Consider whether setting limits (or documenting why they're omitted) would be appropriate for this security-sensitive component.

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

In `@pkg/operator/encryption/kms/pluginlifecycle/builder.go` around lines 243 -
248, The ResourceRequirements object in the health reporter container
configuration only defines Requests (32Mi memory and 10m CPU) without
corresponding Limits. Add a Limits field to the ResourceRequirements struct with
appropriate memory and CPU limits (typically equal to or slightly higher than
the requests) to prevent resource contention and ensure proper resource
governance for this security-sensitive component. Alternatively, if limits are
intentionally omitted, add a code comment explaining the rationale.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/operator/encryption/kms/pluginlifecycle/builder.go`:
- Around line 243-248: The ResourceRequirements object in the health reporter
container configuration only defines Requests (32Mi memory and 10m CPU) without
corresponding Limits. Add a Limits field to the ResourceRequirements struct with
appropriate memory and CPU limits (typically equal to or slightly higher than
the requests) to prevent resource contention and ensure proper resource
governance for this security-sensitive component. Alternatively, if limits are
intentionally omitted, add a code comment explaining the rationale.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 5951874d-d325-418c-81bb-753aa4cdbf66

📥 Commits

Reviewing files that changed from the base of the PR and between 555fb53 and 870ba88.

📒 Files selected for processing (4)
  • pkg/operator/encryption/kms/pluginlifecycle/builder.go
  • pkg/operator/encryption/kms/pluginlifecycle/builder_test.go
  • pkg/operator/encryption/kms/pluginlifecycle/sidecar.go
  • pkg/operator/encryption/kms/pluginlifecycle/sidecar_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/operator/encryption/kms/pluginlifecycle/builder_test.go
  • pkg/operator/encryption/kms/pluginlifecycle/sidecar_test.go


var kubeconfig string
if b.staticPod {
kubeconfig = defaultStaticPodKubeconfig

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: I know that it is idiomatic in K8s code, but the apply function is very long. We could split it up?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good idea. I've moved the logic inside applyHealthReporter.

// TODO: move to a dedicated least-privilege kubeconfig once available.
const defaultStaticPodKubeconfig = "/etc/kubernetes/static-pod-resources/configmaps/kube-apiserver-cert-syncer-kubeconfig/kubeconfig"

type healthReporter struct {

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: I know that long files are also idiomatic in K8s, but maybe it would deserve its own file?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good idea. I've moved this logic inside health_reporter.go.

// It is a no-op when the KMSEncryption feature gate is not enabled or the encryption-config secret does not exist.
// The secretClient should be uncached to avoid injecting sidecars based on a stale encryption configuration.
func AddKMSPluginSidecarToStaticPodSpec(ctx context.Context, podSpec *corev1.PodSpec, containerName string, encryptionConfigNamespace string, encryptionConfigSecretName string, secretClient corev1client.SecretsGetter, featureGateAccessor featuregates.FeatureGateAccess) error {
func AddKMSPluginSidecarToStaticPodSpec(ctx context.Context, podSpec *corev1.PodSpec, containerName string, encryptionConfigNamespace string, encryptionConfigSecretName string, secretClient corev1client.SecretsGetter, featureGateAccessor featuregates.FeatureGateAccess, operatorImage string) error {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: there are more than 4 args, worth considering functional arguments or a config instead. I know it is idiomatic to have plenty of args in Kubernetes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It makes sense. But I'd prefer keeping this PR only focusing on health reporter changes without refactoring the other bits.

corev1.ResourceCPU: resource.MustParse("10m"),
},
},
SecurityContext: &corev1.SecurityContext{

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.

I reviewed a PR from Fabio, where this was being set. Is this the same? Does it make sense to have one specific one that can be referenced or called?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

They are identical. But is there a guarantee that kms plugins and health reporter use the same security context?. I think, they should be configured separately?

encryptionConfigSecretName string
staticPod bool

enableHealthReporter bool

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.

Is there a scenario, where we don't want to enable the health reporter?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yes, preflight checker won't use health reporter.

@ibihim ibihim Jun 22, 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.

Now that you say it, it is obvious. And we won't need a comment, because sidecar.go will contain a function for the preflight scenario, right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That makes sense. I've updated with documentation.

@ardaguclu ardaguclu force-pushed the inject-health-reporter branch from 870ba88 to f5987de Compare June 22, 2026 06:14
@ardaguclu

ardaguclu commented Jun 22, 2026

Copy link
Copy Markdown
Member Author

/retitle CNTRLPLANE-3363: Inject health reporter as sidecar container

@openshift-ci openshift-ci Bot changed the title WIP: CNTRLPLANE-3363: Inject health reporter as sidecar container CNTRLPLANE-3363: Inject health reporter as sidecar container Jun 22, 2026
@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 Jun 22, 2026
@ardaguclu

Copy link
Copy Markdown
Member Author

/hold
until CI is green

@openshift-ci openshift-ci Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jun 22, 2026
@ardaguclu ardaguclu force-pushed the inject-health-reporter branch from f5987de to 0d22375 Compare June 22, 2026 07:26

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
pkg/operator/encryption/kms/pluginlifecycle/health_reporter_test.go (2)

29-34: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider extracting the init-container search to a helper.

The loop that searches InitContainers for a container by name is duplicated in lines 29-34 and lines 68-73. Extracting this to a helper function would reduce duplication:

func findInitContainer(podSpec *corev1.PodSpec, name string) *corev1.Container {
    for i := range podSpec.InitContainers {
        if podSpec.InitContainers[i].Name == name {
            return &podSpec.InitContainers[i]
        }
    }
    return nil
}

That said, the duplication is minimal and each test remains self-contained, so this is a minor style preference.

Also applies to: 68-73

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

In `@pkg/operator/encryption/kms/pluginlifecycle/health_reporter_test.go` around
lines 29 - 34, Extract the duplicated init-container search logic into a helper
function. Create a new function called findInitContainer that takes a
*corev1.PodSpec and a name string as parameters and returns a *corev1.Container
by iterating through InitContainers to find a match. Replace both occurrences of
the loop (the one searching for "kms-health-reporter" and any other similar
loops at lines 68-73) with calls to this new helper function to eliminate the
code duplication.

94-104: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider testing empty operatorCmd and containerName for completeness.

The error validation in applyHealthReporter checks that all three parameters (image, command, container name) are non-empty. The current test only exercises the empty image case. For thorough coverage, you could add subtests for empty operatorCmd and empty containerName as well.

Since the validation logic is identical for all three parameters, the current test does confirm the error path works correctly, so this is purely a completeness suggestion.

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

In `@pkg/operator/encryption/kms/pluginlifecycle/health_reporter_test.go` around
lines 94 - 104, Add two additional subtests to provide complete coverage of the
validation logic in applyHealthReporter. Create a subtest for the "empty
operatorCmd: returns error" case by calling WithHealthReporter with an empty
second parameter (command) while keeping image and containerName populated, and
verify it returns an error containing "command" or similar. Similarly, add
another subtest for "empty containerName: returns error" by calling
WithHealthReporter with an empty third parameter (containerName) while keeping
image and operatorCmd populated, and verify it returns the expected error. Both
tests should follow the same pattern as the existing "empty image" test,
ensuring all three validation checks in applyHealthReporter are covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/operator/encryption/kms/pluginlifecycle/health_reporter_test.go`:
- Around line 29-34: Extract the duplicated init-container search logic into a
helper function. Create a new function called findInitContainer that takes a
*corev1.PodSpec and a name string as parameters and returns a *corev1.Container
by iterating through InitContainers to find a match. Replace both occurrences of
the loop (the one searching for "kms-health-reporter" and any other similar
loops at lines 68-73) with calls to this new helper function to eliminate the
code duplication.
- Around line 94-104: Add two additional subtests to provide complete coverage
of the validation logic in applyHealthReporter. Create a subtest for the "empty
operatorCmd: returns error" case by calling WithHealthReporter with an empty
second parameter (command) while keeping image and containerName populated, and
verify it returns an error containing "command" or similar. Similarly, add
another subtest for "empty containerName: returns error" by calling
WithHealthReporter with an empty third parameter (containerName) while keeping
image and operatorCmd populated, and verify it returns the expected error. Both
tests should follow the same pattern as the existing "empty image" test,
ensuring all three validation checks in applyHealthReporter are covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 02d9fbd0-8da7-438b-ad24-06f1ea495ec7

📥 Commits

Reviewing files that changed from the base of the PR and between f5987de and 0d22375.

📒 Files selected for processing (5)
  • pkg/operator/encryption/kms/pluginlifecycle/builder.go
  • pkg/operator/encryption/kms/pluginlifecycle/health_reporter.go
  • pkg/operator/encryption/kms/pluginlifecycle/health_reporter_test.go
  • pkg/operator/encryption/kms/pluginlifecycle/sidecar.go
  • pkg/operator/encryption/kms/pluginlifecycle/sidecar_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • pkg/operator/encryption/kms/pluginlifecycle/sidecar.go
  • pkg/operator/encryption/kms/pluginlifecycle/sidecar_test.go
  • pkg/operator/encryption/kms/pluginlifecycle/builder.go
  • pkg/operator/encryption/kms/pluginlifecycle/health_reporter.go

@ardaguclu ardaguclu force-pushed the inject-health-reporter branch from 0d22375 to dc77060 Compare June 22, 2026 09:22
@ardaguclu

Copy link
Copy Markdown
Member Author

Unrelated
/retest

@ibihim

ibihim commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jun 22, 2026
@openshift-ci

openshift-ci Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: ardaguclu, ibihim

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


if b.staticPod {
resourceDirMount := corev1.VolumeMount{Name: resourceDirVolumeName, MountPath: resourcesDir, ReadOnly: true}
if err := ensureVolumeMountInContainer(podSpec.InitContainers, reporter.Name(), resourceDirMount); err != nil {

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.

I find it very elegant that you reused ensureSidecarContaienr, ensureVolumeMountInContainer

enableHealthReporter bool
healthReporterContainerName string
healthReporterOperatorCmd string
healthReporterImage string

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.

would it make sense to create the healthReport here instead? Also, if we make it a pointer, we wouldn't need the boolean

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, it makes sense. Updated.

},
},
},
},

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.

what do we need this env for? Can we add a comment?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Necessity is documented.

return corev1.Container{
Name: h.name,
Image: h.image,
Command: []string{h.operatorCmd, h.name},

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.

do you need to specify Command because KASO doesn't have an entrypoint?

in your KASO proof PR I see:

if err := kmspluginlifecycle.AddKMSPluginSidecarToStaticPodSpec(ctx, &required.Spec, "kube-apiserver", operatorclient.TargetNamespace, "encryption-config", secretClient, featureGateAccessor, "cluster-kube-apiserver-operator", operatorImagePullSpec); err != nil {

so I think Command here will be cluster-kube-apiserver-operator kms-health-reporter. This makes me wonder if we need to make sure the PATH is correctly set or if we need to use the whole path (/usr/bin/cluster-kube-apiserver-operator).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I've updated the code to also support empty commands, so that entrpoint will be automatically used (if command is passed as empty). But it is caller's responsibility to verify the presence of the binary IMO.

}

func (h *healthReporter) Name() string {
return h.name

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.

it seems like h.name is both the container name (for which it's correctly used in this method), and also the operator cli command. It'd be nice to make that distinction visible somehow

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I agree that it is confusing. I've updated by using subcommand (which refers to the command name in health/cmd.go). Please let me know your thoughts.

}
if h.kubeconfig != "" {
args = append(args, fmt.Sprintf("--kubeconfig=%s", h.kubeconfig))
}

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.

isn't the kubeconfig required for all health reporters?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

cluster-kube-apiserver-operator requires kubeconfig but others won't need it (they will use in-cluster kubeconfig)


func (h *healthReporter) BuildSidecarContainer() (corev1.Container, error) {
args := []string{
fmt.Sprintf("--kms-sockets=%s", strings.Join(h.sockets, ",")),

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.

do we need to validate for an empty slice?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, it is better to validate it. Updated.

// It is a no-op when the KMSEncryption feature gate is not enabled or the encryption-config secret does not exist.
// The secretClient should be uncached to avoid injecting sidecars based on a stale encryption configuration.
func AddKMSPluginSidecarToPodSpec(ctx context.Context, podSpec *corev1.PodSpec, containerName string, encryptionConfigNamespace string, encryptionConfigSecretName string, secretClient corev1client.SecretsGetter, featureGateAccessor featuregates.FeatureGateAccess) error {
func AddKMSPluginSidecarToPodSpec(ctx context.Context, podSpec *corev1.PodSpec, containerName string, encryptionConfigNamespace string, encryptionConfigSecretName string, secretClient corev1client.SecretsGetter, featureGateAccessor featuregates.FeatureGateAccess, operatorCmd string, operatorImage string) error {

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.

interesting, I see that the authentication operator has the entreypoint correctly set to /usr/bin/authentication-operator, so we wouldn't need operatorCmd here, right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I agree, if we pass operatorCmd empty (to fallback to entrypoint), mechanism should work. So I've updated the code to handle that case.

AllowPrivilegeEscalation: ptr.To(false),
Capabilities: &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}},
SeccompProfile: &corev1.SeccompProfile{Type: corev1.SeccompProfileTypeRuntimeDefault},
},

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.

can we be more strict with the health reporter?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

There is nothing left apart from RunAsRoot: false?. KAS-o needs to run as root (uid: 0)

// It is a no-op when the KMSEncryption feature gate is not enabled or the encryption-config secret does not exist.
// The secretClient should be uncached to avoid injecting sidecars based on a stale encryption configuration.
func AddKMSPluginSidecarToPodSpec(ctx context.Context, podSpec *corev1.PodSpec, containerName string, encryptionConfigNamespace string, encryptionConfigSecretName string, secretClient corev1client.SecretsGetter, featureGateAccessor featuregates.FeatureGateAccess) error {
func AddKMSPluginSidecarToPodSpec(ctx context.Context, podSpec *corev1.PodSpec, containerName string, encryptionConfigNamespace string, encryptionConfigSecretName string, secretClient corev1client.SecretsGetter, featureGateAccessor featuregates.FeatureGateAccess, operatorCmd string, operatorImage string) error {

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.

nit: the params ordering seems a bit off. IMO the feature gate acessor fits better at the end. What about something like this?

  func AddKMSPluginSidecarToStaticPodSpec(
      ctx context.Context,
      podSpec *corev1.PodSpec,
      containerName string,
      encryptionConfigNamespace string,
      encryptionConfigSecretName string,
      operatorCmd string,
      operatorImage string,
      secretClient corev1client.SecretsGetter, // this is not necessarily tied to the encryptionConfig*
      featureGateAccessor featuregates.FeatureGateAccess,
  ) error

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated.

@ardaguclu ardaguclu force-pushed the inject-health-reporter branch from dc77060 to a74f1ee Compare June 23, 2026 06:16
@openshift-ci openshift-ci Bot removed the lgtm Indicates that a PR is ready to be merged. label Jun 23, 2026
@openshift-ci

openshift-ci Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

New changes are detected. LGTM label has been removed.

@openshift-ci

openshift-ci Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

@ardaguclu: all tests passed!

Full PR test history. Your PR dashboard.

Details

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

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. do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. 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