Skip to content

feat: defaults-only sidecar injection without AgentRuntime CR#276

Merged
pdettori merged 3 commits intokagenti:mainfrom
varshaprasad96:feat/merge
Apr 15, 2026
Merged

feat: defaults-only sidecar injection without AgentRuntime CR#276
pdettori merged 3 commits intokagenti:mainfrom
varshaprasad96:feat/merge

Conversation

@varshaprasad96
Copy link
Copy Markdown
Contributor

@varshaprasad96 varshaprasad96 commented Apr 13, 2026

Summary

  • Webhook now injects sidecars using defaults-only config (platform + namespace defaults) when no AgentRuntime CR exists, instead of skipping injection entirely
  • New DefaultsConfigReconciler watches cluster and namespace ConfigMaps and updates kagenti.io/config-hash on workloads not managed by an AgentRuntime CR, triggering rolling updates when defaults change
  • Handles ConfigMap deletion events by re-hashing affected workloads
  • Errors from individual workload updates are accumulated and returned for requeue

Closes: RHAIENG-4177

Changes

File Description
internal/webhook/injector/pod_mutator.go Remove early return when no AgentRuntime CR found — inject with defaults
internal/webhook/injector/defaults_config_reconciler.go New reconciler for ConfigMap-driven config propagation to orphaned workloads
internal/webhook/injector/defaults_config_reconciler_test.go 18 unit tests covering all reconciler paths
internal/webhook/injector/pod_mutator_test.go Updated to expect injection with specific container names
internal/webhook/v1alpha1/authbridge_webhook_test.go Updated integration test for defaults-only injection
cmd/main.go Register new reconciler inside authBridgeWebhooksEnabled() guard

Test plan

  • TestInjectAuthBridge_NoAgentRuntime_InjectsWithDefaults — verifies envoy-proxy, spiffe-helper, proxy-init injected
  • TestDefaultsConfigReconciler_UpdatesUnmanagedWorkload — config-hash set on orphaned Deployment
  • TestDefaultsConfigReconciler_SkipsManagedWorkload — managed workloads untouched
  • TestDefaultsConfigReconciler_ConfigMapDeleted_UpdatesWorkloads — deletion triggers re-hash
  • TestDefaultsConfigReconciler_MultiNamespaceFanOut — cluster ConfigMap change fans out to all namespaces
  • TestDefaultsConfigReconciler_MixedManagedAndUnmanaged — only unmanaged workloads updated
  • TestDefaultsConfigReconciler_IdempotentWhenHashUnchanged — no spurious updates
  • Integration test: webhook injects sidecars for pods with kagenti.io/type=agent and no CR
  • All existing tests continue to pass

Signed-off-by: Varsha Prasad Narsing varshaprasad96@gmail.com

@varshaprasad96 varshaprasad96 requested a review from a team as a code owner April 13, 2026 21:04
…CR exists

The webhook previously skipped sidecar injection when no AgentRuntime CR
was found. This change removes that gate so workloads with the
kagenti.io/type label receive sidecars using platform + namespace
defaults even without a CR.

A new DefaultsConfigReconciler watches cluster and namespace ConfigMaps
and updates the kagenti.io/config-hash annotation on workloads that are
not managed by an AgentRuntime CR, triggering rolling updates when
defaults change.

Closes: RHAIENG-4177

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Scheme *runtime.Scheme
}

func (r *DefaultsConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
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 is a part of webhook for now. Ideally we would want the WH to be light weight, and eventually this should be a separate reconciler added to the operator.

- Remove unused `defaultsLog` variable (golangci-lint/unused)
- Fix gofmt alignment in test struct literals (golangci-lint/gofmt)
- Add `kagenti.io/inject: disabled` to noproto-agent E2E fixture so
  sidecar injection doesn't break the pause container deployment

Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Copy link
Copy Markdown
Collaborator

@cwiklik cwiklik left a comment

Choose a reason for hiding this comment

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

Review Summary

Well-structured feature that fills an important gap: pods with kagenti.io/type label now get sidecar injection even without an AgentRuntime CR, using platform + namespace defaults. The new DefaultsConfigReconciler correctly watches cluster/namespace ConfigMaps and propagates config-hash changes to unmanaged workloads. Pod mutator change is minimal (3-line removal of early return).

The reconciler uses proper controller-runtime patterns: retry.RetryOnConflict, client.IgnoreNotFound, error accumulation via errors.Join, and server-side label filtering for namespace listing. Test coverage is comprehensive (18 tests covering happy path, managed/unmanaged, deletion, multi-namespace, idempotency, feature gates).

Areas reviewed: Go (reconciler, pod mutator, tests), E2E fixtures
Commits: 2 commits, all signed-off ✓
CI status: all passing (E2E pending trigger)

}

// isClusterConfigMapKey checks whether a NamespacedName refers to one of the
// cluster-level defaults ConfigMaps. Used for both live objects and deletion
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

suggestion (non-blocking): namespacesWithKagentiWorkloads() lists all Deployments + StatefulSets cluster-wide with the kagenti.io/type label on every cluster ConfigMap change. The label selector makes this server-side filtered, which is fine for moderate clusters. For very large clusters, consider adding a cache or index to avoid the double full-list. Low priority — current approach is correct and simple.

}
if arOverrides == nil {
mutatorLog.Info("Skipping mutation: no matching AgentRuntime CR found",
mutatorLog.Info("No AgentRuntime CR found, injecting with defaults-only config",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

👍 Clean change — removing the early return and letting ResolveConfig handle nil overrides is the right call. The log message clearly distinguishes this path.

labels:
app.kubernetes.io/name: noproto-agent
kagenti.io/type: agent
kagenti.io/inject: disabled
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: Worth adding a comment explaining why noproto-agent needs kagenti.io/inject: disabled — it's not obvious to future readers that this fixture specifically tests operator behavior without sidecar injection, and the new defaults-only path would otherwise inject into it.

Copy link
Copy Markdown
Contributor

@pdettori pdettori left a comment

Choose a reason for hiding this comment

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

Review Summary

Well-structured PR that changes a key behavior: the webhook now injects sidecars using platform/namespace defaults even when no AgentRuntime CR exists, making CR creation optional rather than a prerequisite. The new DefaultsConfigReconciler propagates ConfigMap changes to unmanaged workloads. Tests are comprehensive (18 new unit tests + updated integration test).

Two lint issues must be fixed before merge, and the E2E failure needs a rerun to determine if it's a flake.

CI Status

  • Build, Unit Tests, Integration Tests, DCO, Helm Lint, CodeQL, Trivy, Hadolint, ShellCheck, YAML Lint — all pass
  • Lint: unused var defaultsLog + gofmt formatting in test file
  • E2E: AgentCard > should not create AgentCard for workload without protocol label — webhook service unreachable (context deadline exceeded). This looks like a timing flake (webhook pod not ready), not a logic regression, but should be confirmed with a rerun since this PR touches the webhook.

Areas reviewed: Go (reconciler, webhook, tests), CI

All AgentCard E2E fixtures (echo-agent, audit-agent, signed-agent) now
set kagenti.io/inject=disabled on their PodTemplateSpec. These tests
validate AgentCard sync behaviour, not sidecar injection, and the
defaults-only injection path would otherwise inject sidecars whose
infrastructure dependencies are not present in the E2E environment.

Also adds a TODO for field indexer optimisation on
namespacesWithKagentiWorkloads per reviewer feedback.

Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Copy link
Copy Markdown
Contributor

@pdettori pdettori left a comment

Choose a reason for hiding this comment

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

lgtm

@pdettori pdettori merged commit c69f880 into kagenti:main Apr 15, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants