Skip to content

[cozystack-controller] Ancestor tracking webhook - #1400

Merged
Timofei Larkin (lllamnyp) merged 1 commit into
mainfrom
feat/webhook-workload-monitors
Sep 12, 2025
Merged

[cozystack-controller] Ancestor tracking webhook#1400
Timofei Larkin (lllamnyp) merged 1 commit into
mainfrom
feat/webhook-workload-monitors

Conversation

@lllamnyp

@lllamnyp Timofei Larkin (lllamnyp) commented Sep 8, 2025

Copy link
Copy Markdown
Member

What this PR does

Many resources created as part of managed apps in cozystack (pods, secrets, etc) do not carry predictable labels that unambiguously indicate which app originally triggered their creation. Some resources are managed by controllers and other custom resources and this indirection can lead to loss of information. Other controllers sometimes simply do not allow setting labels on controlled resources and the latter do not inherit labels from the owner. This patch implements a webhook that sidesteps this problem with a universal solution. On creation of a pod/secret/PVC etc it walks through the owner references until a HelmRelease is found that can be matched with a managed app dynamically registered in the Cozystack API server. The pod is mutated with labels identifying the managed app.

Release note

[cozystack-controller] Add a mutating webhook to identify the Cozystack
managed app that ultimately owns low-level resources created in the
cluster and label these resources with a reference to said app.

Summary by CodeRabbit

  • New Features

    • Adds an admission webhook that injects application lineage labels on resource create/update for improved observability and ownership tracing.
    • Adds a runtime-updatable mapping for resolving HelmRelease → application, and registers both the lineage controller and webhook during startup.
    • Adds Deployment, Service, and cert-manager templates to enable and secure the webhook (in-cluster TLS, service routing).
  • Tests

    • Adds a test to exercise lineage traversal and validate ownership-graph resolution and labeling.

@coderabbitai

coderabbitai Bot commented Sep 8, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a LineageControllerWebhook: a controller that builds an in-memory chart→app map from CozystackResourceDefinition CRs and a mutating admission webhook that walks ownership graphs to compute and inject lineage labels; includes lineage traversal utilities, an AppMapper, tests, and Helm templates for webhook TLS/service.

Changes

Cohort / File(s) Summary
Manager wiring
cmd/cozystack-controller/main.go
Imports and instantiates LineageControllerWebhook; registers it as both a controller and a webhook with the manager; exits on setup errors.
Webhook types & runtime config
internal/lineagecontrollerwebhook/types.go, internal/lineagecontrollerwebhook/config.go
Adds LineageControllerWebhook struct with decoder/dynamic client/mapper/config, a runtimeConfig holder, initConfig, and Map(hr *helmv2.HelmRelease) (string,string,string,error) to resolve chart→app mappings.
Controller (chart→app map builder)
internal/lineagecontrollerwebhook/controller.go
Adds SetupWithManagerAsController and Reconcile that list CozystackResourceDefinition in cozy-system, construct chartRef→appRef mappings (dedup first-wins), and store them atomically.
Mutating webhook implementation
internal/lineagecontrollerwebhook/webhook.go
Adds SetupWithManagerAsWebhook, InjectDecoder, Handle, computeLabels, applyLabels, decodeUnstructured; registers /mutate-lineage, uses dynamic client + REST mapper, sentinel errors NoAncestors/AncestryAmbiguous, and emits patches/warnings.
Lineage traversal utilities
pkg/lineage/lineage.go
Adds ObjectID type, GetUnstructured, WalkOwnershipGraph (recursive owner traversal with HelmRelease mapping and cycle prevention), helpers to resolve GVKs and fetch unstructured resources, and HelmRelease constants.
AppMapper + stub mapper
pkg/lineage/mapper.go
Introduces AppMapper interface and a stubMapper implementation with a static source/chart -> apiVersion/kind/prefix map; returns mapped apiVersion, kind, prefix or error.
Tests
pkg/lineage/lineage_test.go
Adds an integration-style test that initializes dynamic client/mapper and logger; TestWalkingOwnershipGraph fetches a Pod by args and prints traversal nodes.
Helm templates: TLS, service, webhook, deployment
packages/system/cozystack-controller/templates/certmanager.yaml, .../service.yaml, .../mutatingwebhookconfiguration.yaml, .../deployment.yaml
Adds cert-manager Issuer/Certificate for webhook CA and cert, ClusterIP cozystack-controller service exposing port 443→targetPort 9443, MutatingWebhookConfiguration for /mutate-lineage (pods/secrets/services/pvcs), and adds container port webhook: 9443 + webhook cert volumeMounts to deployment; removed explicit namespace from deployment metadata.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant M as Manager
  participant LC as LineageControllerWebhook
  participant K8s as API Server

  rect rgba(200,220,255,0.15)
  note over M,LC: Startup wiring
  M->>LC: SetupWithManagerAsController()
  M->>LC: SetupWithManagerAsWebhook()
  LC->>M: Registered controller + /mutate-lineage webhook
  end

  rect rgba(220,255,220,0.15)
  note over LC,K8s: Controller reconcile updates runtime map
  LC->>K8s: List CozystackResourceDefinition (cozy-system)
  LC->>LC: Build chart→app map
  LC->>LC: Store map (atomic)
  end
Loading
sequenceDiagram
  autonumber
  participant AP as API Server
  participant WH as LineageControllerWebhook
  participant DC as Dynamic Client
  participant RM as REST Mapper
  participant LU as lineage.WalkOwnershipGraph

  rect rgba(255,245,200,0.15)
  AP->>WH: AdmissionReview (create/update object)
  WH->>WH: decodeUnstructured(req)
  WH->>LU: WalkOwnershipGraph(ctx, DC, RM, AppMapper, obj)
  LU->>DC: Fetch owner resources (resolve via RM)
  LU-->>WH: ancestor ObjectID(s) or none/ambiguous
  alt ancestor found
    WH->>DC: Get ancestor Unstructured
    WH->>WH: computeLabels -> applyLabels
    WH-->>AP: Patch response (labels)
  else none / ambiguous
    WH-->>AP: Allow (may include warning)
  end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • kvaps
  • klinch0

Poem

I thump my paws along the trail,
I map each chart, each owner tale.
I stitch on labels, neat and bright,
Breadcrumbs glint in morning light.
Hooray — lineage found, I hop with delight! 🥕

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

Pre-merge checks (2 passed, 1 warning)

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "[cozystack-controller] Ancestor tracking webhook" is concise and accurately summarizes the primary change — adding an ancestor-traversing mutating webhook to the cozystack-controller — making the PR intent clear to reviewers scanning history.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/webhook-workload-monitors

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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: 12

🧹 Nitpick comments (13)
pkg/lineage/mapper.go (1)

16-40: Clarify stub-only mapping and avoid drift with the real mapper.

Document or gate stubMapper behind a build tag to ensure it’s not used in production and doesn’t diverge from the webhook/controller mapping logic.

Example doc:

 type stubMapper struct{}
 
+// NOTE: stubMapper is intended for local dev/tests only. Production mapping is
+// provided by the webhook/controller. Keep entries in sync or remove before release.
 var stubMapperMap = map[string]string{
pkg/lineage/lineage.go (3)

87-91: Use structured logging instead of stderr prints.

Library code should not write to stderr directly; use the request-scoped logger.

-		if err != nil {
-			fmt.Fprintf(os.Stderr, "Could not fetch owner %s/%s (%s): %v\n", obj.GetNamespace(), owner.Name, owner.Kind, err)
-			continue
-		}
+		if err != nil {
+			l.Error(err, "could not fetch owner",
+				"namespace", obj.GetNamespace(), "name", owner.Name, "kind", owner.Kind)
+			continue
+		}

71-77: Clarify variadic-args error message.

Current log miscounts and confuses total vs variadic args.

 	if len(memory) != 0 && len(memory) != 1 {
 		l.Error(
 			fmt.Errorf("invalid argument count"), "could not parse variadic arguments to WalkOwnershipGraph",
-			"args passed", len(memory)+5, "expected args", "4|5",
+			"memory args", len(memory), "expected memory args", "0|1",
 		)
 		return out
 	}

101-130: Flatten the single-iteration loop for readability.

Replace the for { ... break } pattern with early returns/guards to simplify control flow.

cmd/cozystack-controller/main.go (1)

41-41: Nit: clearer alias would help readability.

Consider aliasing as lineagewebhook or lineage for clarity over lcw.

internal/lineagecontrollerwebhook/types.go (1)

14-21: Use a pointer decoder to follow controller-runtime patterns and avoid unnecessary copies.

Change decoder to a pointer; InjectDecoder can then assign directly.

 type LineageControllerWebhook struct {
   Scheme *runtime.Scheme
   client.Client
-  decoder   admission.Decoder
+  decoder   *admission.Decoder
   dynClient dynamic.Interface
   mapper    meta.RESTMapper
   config    atomic.Value
 }
internal/lineagecontrollerwebhook/config.go (1)

21-24: Key may collide across namespaces/kinds; consider including SourceRef.Kind/Namespace.

Using only SourceRef.Name and Chart risks collisions. Consider a key like "///" and update the controller to match.

internal/lineagecontrollerwebhook/controller.go (2)

31-31: Prefer keyed struct literal for runtimeConfig

Prevents accidental field-order bugs if struct changes.

-	c.config.Store(&runtimeConfig{newConfig})
+	c.config.Store(&runtimeConfig{chartAppMap: newConfig})

22-22: Hard-coded namespace “cozy-system”

If CRDs ever move or are cluster-scoped, this will silently miss them.

Make the namespace configurable (env/flag) or handle cluster-scoped CRDs by omitting Namespace in ListOptions.

internal/lineagecontrollerwebhook/webhook.go (4)

66-71: No-op for non-CREATE operations (unless configured otherwise)

PR text says “on creation”; guard here in case the webhook config isn’t restricted to CREATE.

 	warn := make(admission.Warnings, 0)
 
+	if req.Operation != admissionv1.Create {
+		return admission.Allowed("no-op for non-CREATE operations")
+	}

Add import:

-	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+	admissionv1 "k8s.io/api/admission/v1"

73-89: Simplify error handling flow

The for-loop is harder to read; a switch is clearer.

-	labels, err := h.computeLabels(ctx, obj)
-	for {
-		if err != nil && errors.Is(err, NoAncestors) {
-			return admission.Allowed("object not managed by app")
-		}
-		if err != nil && errors.Is(err, AncestryAmbiguous) {
-			warn = append(warn, "object ancestry ambiguous, using first ancestor found")
-			break
-		}
-		if err != nil {
-			return admission.Errored(500, fmt.Errorf("error computing lineage labels: %w", err))
-		}
-		if err == nil {
-			break
-		}
-	}
+	labels, err := h.computeLabels(ctx, obj)
+	switch {
+	case err == nil:
+	case errors.Is(err, NoAncestors):
+		return admission.Allowed("object not managed by app")
+	case errors.Is(err, AncestryAmbiguous):
+		warn = append(warn, "object ancestry ambiguous, using first ancestor found")
+	default:
+		return admission.Errored(500, fmt.Errorf("error computing lineage labels: %w", err))
+	}

92-97: Generalize log/error text (“pod” → “object”)

This webhook handles many kinds, not just Pods.

-	mutated, err := json.Marshal(obj)
-	if err != nil {
-		return admission.Errored(500, fmt.Errorf("marshal mutated pod: %w", err))
-	}
-	logger.V(1).Info("mutated pod", "namespace", obj.GetNamespace(), "name", obj.GetName())
+	mutated, err := json.Marshal(obj)
+	if err != nil {
+		return admission.Errored(500, fmt.Errorf("marshal mutated object: %w", err))
+	}
+	logger.V(1).Info("mutated object", "gvk", obj.GroupVersionKind().String(), "namespace", obj.GetNamespace(), "name", obj.GetName())

131-140: Label overwrite policy

applyLabels unconditionally overwrites existing values. If these keys are reserved for this webhook, fine; otherwise consider not overriding.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f1975d and 246e0fc.

📒 Files selected for processing (8)
  • cmd/cozystack-controller/main.go (2 hunks)
  • internal/lineagecontrollerwebhook/config.go (1 hunks)
  • internal/lineagecontrollerwebhook/controller.go (1 hunks)
  • internal/lineagecontrollerwebhook/types.go (1 hunks)
  • internal/lineagecontrollerwebhook/webhook.go (1 hunks)
  • pkg/lineage/lineage.go (1 hunks)
  • pkg/lineage/lineage_test.go (1 hunks)
  • pkg/lineage/mapper.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
cmd/cozystack-controller/main.go (1)
internal/lineagecontrollerwebhook/types.go (1)
  • LineageControllerWebhook (14-21)
pkg/lineage/lineage_test.go (1)
pkg/lineage/lineage.go (1)
  • WalkOwnershipGraph (40-143)
internal/lineagecontrollerwebhook/webhook.go (2)
internal/lineagecontrollerwebhook/types.go (1)
  • LineageControllerWebhook (14-21)
pkg/lineage/lineage.go (1)
  • WalkOwnershipGraph (40-143)
internal/lineagecontrollerwebhook/config.go (2)
internal/lineagecontrollerwebhook/types.go (1)
  • LineageControllerWebhook (14-21)
api/v1alpha1/cozystackresourcedefinitions_types.go (1)
  • SourceRef (60-69)
internal/lineagecontrollerwebhook/types.go (1)
pkg/apiserver/apiserver.go (1)
  • Scheme (41-41)
pkg/lineage/lineage.go (1)
pkg/lineage/mapper.go (1)
  • AppMapper (10-12)
internal/lineagecontrollerwebhook/controller.go (2)
internal/lineagecontrollerwebhook/types.go (1)
  • LineageControllerWebhook (14-21)
api/v1alpha1/cozystackresourcedefinitions_types.go (3)
  • CozystackResourceDefinition (26-31)
  • CozystackResourceDefinitionList (36-40)
  • SourceRef (60-69)
pkg/lineage/mapper.go (1)
api/v1alpha1/cozystackresourcedefinitions_types.go (1)
  • SourceRef (60-69)
🔇 Additional comments (2)
cmd/cozystack-controller/main.go (1)

218-231: Verify webhook init order and readiness behavior.

If the webhook receives traffic before its runtime mapping is populated, the handler must allow the request (no-op) rather than error. Please confirm SetupWithManagerAsController populates a default config before SetupWithManagerAsWebhook serves, or that the handler tolerates “uninitialized mapping” gracefully.

internal/lineagecontrollerwebhook/webhook.go (1)

53-56: Correct InjectDecoder signature per controller-runtime API
The admission.DecoderInjector interface expects InjectDecoder(d *admission.Decoder) error, not a value receiver; with the current signature the method won’t be called and h.decoder remains nil (github.com, chinalhr.github.io)

-func (h *LineageControllerWebhook) InjectDecoder(d admission.Decoder) error {
+func (h *LineageControllerWebhook) InjectDecoder(d *admission.Decoder) error {
     h.decoder = d
     return nil
}

Also update the struct field in internal/lineagecontrollerwebhook/types.go:

-   decoder   admission.Decoder
+   decoder   *admission.Decoder

Likely an incorrect or invalid review comment.

Comment thread internal/lineagecontrollerwebhook/config.go Outdated
Comment thread internal/lineagecontrollerwebhook/config.go
Comment thread internal/lineagecontrollerwebhook/controller.go
Comment thread internal/lineagecontrollerwebhook/controller.go
Comment thread internal/lineagecontrollerwebhook/controller.go Outdated
Comment thread internal/lineagecontrollerwebhook/webhook.go
Comment thread pkg/lineage/lineage_test.go
Comment thread pkg/lineage/lineage_test.go
Comment thread pkg/lineage/lineage.go
Comment thread pkg/lineage/mapper.go

@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: 6

♻️ Duplicate comments (1)
internal/lineagecontrollerwebhook/webhook.go (1)

43-49: Initialize runtime config before registering the webhook

Prevent nil deref in Map() during early requests by seeding an empty config before registration.

Apply this diff:

 cachedDisco := memory.NewMemCacheClient(discoClient)
 h.mapper = restmapper.NewDeferredDiscoveryRESTMapper(cachedDisco)

+// Safe default: empty mapping to avoid nil deref before the controller populates it.
+// Adjust the concrete type/field names if they differ.
+h.config.Store(&runtimeConfig{chartAppMap: map[string]string{}})
+
 // Register HTTP path -> handler.
 mgr.GetWebhookServer().Register("/mutate-lineage", &admission.Webhook{Handler: h})
🧹 Nitpick comments (6)
internal/lineagecontrollerwebhook/webhook.go (2)

73-88: Simplify error handling; the for-loop is unnecessary

The loop executes at most once. A switch makes intent clear.

Apply this diff:

-	labels, err := h.computeLabels(ctx, obj)
-	for {
-		if err != nil && errors.Is(err, NoAncestors) {
-			return admission.Allowed("object not managed by app")
-		}
-		if err != nil && errors.Is(err, AncestryAmbiguous) {
-			warn = append(warn, "object ancestry ambiguous, using first ancestor found")
-			break
-		}
-		if err != nil {
-			return admission.Errored(500, fmt.Errorf("error computing lineage labels: %w", err))
-		}
-		if err == nil {
-			break
-		}
-	}
+	labels, err := h.computeLabels(ctx, obj)
+	switch {
+	case err == nil:
+		// proceed
+	case errors.Is(err, NoAncestors):
+		return admission.Allowed("object not managed by app")
+	case errors.Is(err, AncestryAmbiguous):
+		warn = append(warn, "object ancestry ambiguous, using first ancestor found")
+	default:
+		return admission.Errored(500, fmt.Errorf("error computing lineage labels: %w", err))
+	}

92-97: Fix log/message wording: this webhook mutates generic objects, not just pods

Apply this diff:

-	if err != nil {
-		return admission.Errored(500, fmt.Errorf("marshal mutated pod: %w", err))
-	}
-	logger.V(1).Info("mutated pod", "namespace", obj.GetNamespace(), "name", obj.GetName())
+	if err != nil {
+		return admission.Errored(500, fmt.Errorf("marshal mutated object: %w", err))
+	}
+	logger.V(1).Info("mutated object", "namespace", obj.GetNamespace(), "name", obj.GetName())
packages/system/cozystack-controller/templates/service.yaml (1)

10-13: Optional: mark port as HTTPS for clarity

Set appProtocol for better intent and tooling hints.

Apply this diff:

   ports:
     - port: 443
       targetPort: 9443
       protocol: TCP
       name: webhook
+      appProtocol: https
packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml (2)

18-23: Expand resources to match PR intent and fix style nit

PR mentions labeling “pods, secrets, PVCs, etc.” The rules currently miss secrets. Also fix spacing after comma.

-        resources: ["pods","persistentvolumeclaims"]
+        resources: ["pods", "persistentvolumeclaims", "secrets"]

24-33: Namespace scoping looks good; confirm release ns exclusion

You exclude cozystack.io/system=true and kube-system. Ensure the release namespace is labeled cozystack.io/system=true so webhook won’t mutate its own certs/pods. If not guaranteed, add an explicit NotIn for the release namespace.

packages/system/cozystack-controller/templates/certmanager.yaml (1)

4-7: Template resource names to avoid cross-install collisions

If this chart can be installed per-tenant or multiple times, hardcoded Issuer/Certificate names may collide. Prefer fullname-based names.

Example pattern:

-  name: cozystack-controller-webhook-selfsigned
+  name: {{ include "cozystack-controller.fullname" . }}-webhook-selfsigned
...
-  name: cozystack-controller-webhook-ca
+  name: {{ include "cozystack-controller.fullname" . }}-webhook-ca
...
-  secretName: cozystack-controller-webhook-ca
+  secretName: {{ include "cozystack-controller.fullname" . }}-webhook-ca
...
-  name: cozystack-controller-webhook
+  name: {{ include "cozystack-controller.fullname" . }}-webhook
-  secretName: cozystack-controller-webhook-cert
+  secretName: {{ include "cozystack-controller.fullname" . }}-webhook-cert

If you adopt this, also update the inject-ca-from(-secret) and Service tls.secret mounts accordingly in other templates.

Also applies to: 12-20, 25-29, 34-38

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 246e0fc and 053cf59.

📒 Files selected for processing (12)
  • cmd/cozystack-controller/main.go (2 hunks)
  • internal/lineagecontrollerwebhook/config.go (1 hunks)
  • internal/lineagecontrollerwebhook/controller.go (1 hunks)
  • internal/lineagecontrollerwebhook/types.go (1 hunks)
  • internal/lineagecontrollerwebhook/webhook.go (1 hunks)
  • packages/system/cozystack-controller/templates/certmanager.yaml (1 hunks)
  • packages/system/cozystack-controller/templates/deployment.yaml (1 hunks)
  • packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml (1 hunks)
  • packages/system/cozystack-controller/templates/service.yaml (1 hunks)
  • pkg/lineage/lineage.go (1 hunks)
  • pkg/lineage/lineage_test.go (1 hunks)
  • pkg/lineage/mapper.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • pkg/lineage/lineage_test.go
  • internal/lineagecontrollerwebhook/types.go
  • internal/lineagecontrollerwebhook/config.go
  • cmd/cozystack-controller/main.go
  • pkg/lineage/lineage.go
  • pkg/lineage/mapper.go
  • internal/lineagecontrollerwebhook/controller.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-10T22:02:47.707Z
Learnt from: lllamnyp
PR: cozystack/cozystack#1380
File: internal/controller/kubeovnplunger/metrics.go:291-296
Timestamp: 2025-09-10T22:02:47.707Z
Learning: In the kubeovnplunger controller, r.lastLeader map is initialized in SetupWithManager method (line 151) with make(map[string]string) before any reconcile operations begin, making defensive nil checks unnecessary in the reconcile methods.

Applied to files:

  • internal/lineagecontrollerwebhook/webhook.go
📚 Learning: 2025-09-10T22:02:47.707Z
Learnt from: lllamnyp
PR: cozystack/cozystack#1380
File: internal/controller/kubeovnplunger/metrics.go:291-296
Timestamp: 2025-09-10T22:02:47.707Z
Learning: In the kubeovnplunger controller, r.lastLeader map is initialized in SetupWithManager method before any reconcile operations begin, making defensive nil checks unnecessary in the reconcile methods.

Applied to files:

  • internal/lineagecontrollerwebhook/webhook.go
🧬 Code graph analysis (1)
internal/lineagecontrollerwebhook/webhook.go (2)
internal/lineagecontrollerwebhook/types.go (1)
  • LineageControllerWebhook (14-21)
pkg/lineage/lineage.go (1)
  • WalkOwnershipGraph (40-143)
🪛 YAMLlint (1.37.1)
packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml

[warning] 22-22: too few spaces after comma

(commas)


[error] 6-6: syntax error: expected , but found ''

(syntax)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (2)
packages/system/cozystack-controller/templates/deployment.yaml (1)

32-34: Expose webhook port — looks good

Container port 9443 named "webhook" matches controller-runtime defaults and aligns with the Service.

internal/lineagecontrollerwebhook/webhook.go (1)

46-47: Verify MutatingWebhookConfiguration matches registered webhook path/service

internal/lineagecontrollerwebhook/webhook.go (lines 46–47) registers "/mutate-lineage" — scanned packages/ manifests and found MutatingWebhookConfiguration entries but none with clientConfig.service.name="cozystack-controller" and clientConfig.service.path="/mutate-lineage". Confirm the deployed manifests include a MutatingWebhookConfiguration whose clientConfig.service.name is "cozystack-controller" and path is "/mutate-lineage", or update the code/manifests to match.

Comment thread internal/lineagecontrollerwebhook/webhook.go
Comment thread packages/system/cozystack-controller/templates/certmanager.yaml Outdated
Comment thread packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml Outdated
Comment thread packages/system/cozystack-controller/templates/service.yaml

@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: 0

♻️ Duplicate comments (5)
packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml (2)

23-23: Set failurePolicy to Ignore to avoid cluster-wide CREATE outages if the webhook is down.

-    failurePolicy: Fail
+    failurePolicy: Ignore

4-9: Fix CA injection key and quote the value; scope the MWC name to the release (also resolves YAML parse error).

  • Use cert-manager’s secret-based injector and reference the actual secret (likely ...-webhook-cert).
  • Quote Helm expressions to satisfy yamllint and templating.
  • Give the cluster-scoped MutatingWebhookConfiguration a release-scoped name.
 metadata:
-  name: lineage
+  name: {{ include "cozystack-controller.fullname" . }}-lineage
   annotations:
-    cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/cozystack-controller-webhook
+    cert-manager.io/inject-ca-from-secret: '{{ .Release.Namespace }}/cozystack-controller-webhook-cert'
   labels:
     app: cozystack-controller
internal/lineagecontrollerwebhook/types.go (1)

14-14: Align kubebuilder marker with chart manifest: create-only and Ignore failures.

Prevents noisy updates and blocking behavior; keeps generator output consistent with the Helm manifest.

-// +kubebuilder:webhook:path=/mutate-lineage,mutating=true,failurePolicy=Fail,sideEffects=None,groups="",resources=pods,secrets,services,persistentvolumeclaims,verbs=create;update,versions=v1,name=mlineage.cozystack.io,admissionReviewVersions={v1}
+// +kubebuilder:webhook:path=/mutate-lineage,mutating=true,failurePolicy=Ignore,sideEffects=None,groups="",resources=pods,secrets,services,persistentvolumeclaims,verbs=create,versions=v1,name=mlineage.cozystack.io,admissionReviewVersions={v1}
internal/lineagecontrollerwebhook/config.go (1)

32-39: Guard against nil config to avoid panics on first requests.

initConfig isn’t called before Map; Load() can be nil leading to a nil deref.

 func (l *LineageControllerWebhook) Map(hr *helmv2.HelmRelease) (string, string, string, error) {
-	cfg := l.config.Load().(*runtimeConfig).chartAppMap
+	l.initConfig()
+	rc := l.config.Load().(*runtimeConfig)
+	cfg := rc.chartAppMap
 	s := &hr.Spec.Chart.Spec
 	val, ok := cfg[chartRef{s.SourceRef.Name, s.Chart}]
 	if !ok {
 		return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name)
 	}
 	return val.groupVersion, val.kind, val.prefix, nil
 }
pkg/lineage/lineage.go (1)

132-139: Guard against empty HR label; avoid Get(..., "").

If the label exists but is empty, this still calls Get with an empty name.

Apply:

-	name, ok := labels[HRLabel]
-	if !ok {
+	name, ok := labels[HRLabel]
+	if !ok || name == "" {
 		return
 	}
🧹 Nitpick comments (10)
packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml (2)

11-17: Add reinvocation policy and a shorter timeout.

Improves correctness when earlier webhooks mutate objects and prevents long API-server hangs.

     admissionReviewVersions: ["v1"]
     sideEffects: None
+    reinvocationPolicy: IfNeeded
+    timeoutSeconds: 5
     clientConfig:
       service:
         name: cozystack-controller
         namespace: {{ .Release.Namespace }}
         path: /mutate-lineage

22-22: Tidy list formatting flagged by yamllint.

-        resources: ["pods","secrets", "services", "persistentvolumeclaims"]
+        resources: ["pods", "secrets", "services", "persistentvolumeclaims"]
pkg/lineage/lineage.go (8)

96-100: Allow HR-label fallback when owners exist but none could be resolved.

The early return prevents falling back to the HR label if all owner fetches failed (RBAC, NotFound, unknown GVK). Return only when you actually appended results from owners.

Apply:

-	if len(ownerRefs) > 0 {
-		return
-	}
+	if len(ownerRefs) > 0 && len(out) > 0 {
+		return
+	}

85-94: Prefer controller owner when present.

Follow the OwnerReference with controller=true first; otherwise fall back to all owners. This reduces branching and avoids non-controller refs.

Apply:

-	ownerRefs := obj.GetOwnerReferences()
-	for _, owner := range ownerRefs {
+	ownerRefs := obj.GetOwnerReferences()
+	// prefer controller owner if present
+	var toVisit []metav1.OwnerReference
+	for i := range ownerRefs {
+		if ownerRefs[i].Controller != nil && *ownerRefs[i].Controller {
+			toVisit = []metav1.OwnerReference{ownerRefs[i]}
+			break
+		}
+	}
+	if len(toVisit) == 0 {
+		toVisit = ownerRefs
+	}
+	for _, owner := range toVisit {
 		ownerObj, err := getUnstructuredObject(ctx, client, mapper, owner.APIVersion, owner.Kind, obj.GetNamespace(), owner.Name)
 		if err != nil {
-			fmt.Fprintf(os.Stderr, "Could not fetch owner %s/%s (%s): %v\n", obj.GetNamespace(), owner.Name, owner.Kind, err)
+			l.Error(err, "Could not fetch owner", "namespace", obj.GetNamespace(), "name", owner.Name, "kind", owner.Kind)
 			continue
 		}
 
 		out = append(out, WalkOwnershipGraph(ctx, client, mapper, appMapper, ownerObj, visited)...)
 	}

6-6: Use structured logging; drop unused os import.

Keep logs consistent with controller-runtime.

Apply:

-import "os"
-			fmt.Fprintf(os.Stderr, "Could not fetch owner %s/%s (%s): %v\n", obj.GetNamespace(), owner.Name, owner.Kind, err)
+			l.Error(err, "Could not fetch owner", "namespace", obj.GetNamespace(), "name", owner.Name, "kind", owner.Kind)

Also applies to: 89-91


112-121: Validate prefix before TrimPrefix to avoid accidental name truncation.

Only strip when HR name actually has the returned prefix.

Apply:

-		a, k, p, err := appMapper.Map(hr)
+		a, k, p, err := appMapper.Map(hr)
 		if err != nil {
 			break
 		}
-		ownerObj, err := getUnstructuredObject(ctx, client, mapper, a, k, obj.GetNamespace(), strings.TrimPrefix(obj.GetName(), p))
+		ownerName := obj.GetName()
+		if p != "" {
+			if !strings.HasPrefix(ownerName, p) {
+				break
+			}
+			ownerName = strings.TrimPrefix(ownerName, p)
+		}
+		ownerObj, err := getUnstructuredObject(ctx, client, mapper, a, k, obj.GetNamespace(), ownerName)

71-77: Fix log message: expected arg count is 5|6.

Apply:

-			"args passed", len(memory)+5, "expected args", "4|5",
+			"args passed", len(memory)+5, "expected args", "5|6",

49-50: Consider using UID in visit-key to harden cycle detection.

APIVersion/Kind/Namespace/Name can be reused after deletion; including UID removes ambiguity in edge cases.

If acceptable, extend ObjectID with UID and set it from obj.GetUID() when computing id. I can draft a minimal patch if you want.

Also applies to: 79-84


146-183: Optional: cache REST mappings to cut discovery churn.

getUnstructuredObject resolves a RESTMapping for every hop. If this runs per admission, consider a RESTMapper with caching or a small GVK→Resource map in-memory.


40-48: Add tests for failure/fallback paths.

Please add unit tests covering: (1) owners present but all fetches fail → HR-label fallback triggers; (2) HR label empty → no Get call; (3) HR Map prefix mismatch → break without panic; (4) controller vs non-controller owners.

I can generate table-driven tests for these cases—want me to open a follow-up?

Also applies to: 132-144

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 053cf59 and e8fa1ac.

📒 Files selected for processing (12)
  • cmd/cozystack-controller/main.go (2 hunks)
  • internal/lineagecontrollerwebhook/config.go (1 hunks)
  • internal/lineagecontrollerwebhook/controller.go (1 hunks)
  • internal/lineagecontrollerwebhook/types.go (1 hunks)
  • internal/lineagecontrollerwebhook/webhook.go (1 hunks)
  • packages/system/cozystack-controller/templates/certmanager.yaml (1 hunks)
  • packages/system/cozystack-controller/templates/deployment.yaml (1 hunks)
  • packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml (1 hunks)
  • packages/system/cozystack-controller/templates/service.yaml (1 hunks)
  • pkg/lineage/lineage.go (1 hunks)
  • pkg/lineage/lineage_test.go (1 hunks)
  • pkg/lineage/mapper.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • packages/system/cozystack-controller/templates/service.yaml
  • internal/lineagecontrollerwebhook/webhook.go
  • cmd/cozystack-controller/main.go
  • pkg/lineage/mapper.go
  • pkg/lineage/lineage_test.go
  • packages/system/cozystack-controller/templates/deployment.yaml
  • packages/system/cozystack-controller/templates/certmanager.yaml
  • internal/lineagecontrollerwebhook/controller.go
🧰 Additional context used
🧬 Code graph analysis (3)
internal/lineagecontrollerwebhook/types.go (1)
pkg/apiserver/apiserver.go (1)
  • Scheme (41-41)
internal/lineagecontrollerwebhook/config.go (2)
internal/lineagecontrollerwebhook/types.go (1)
  • LineageControllerWebhook (15-23)
api/v1alpha1/cozystackresourcedefinitions_types.go (1)
  • SourceRef (60-69)
pkg/lineage/lineage.go (1)
pkg/lineage/mapper.go (1)
  • AppMapper (10-12)
🪛 YAMLlint (1.37.1)
packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml

[warning] 22-22: too few spaces after comma

(commas)


[error] 6-6: syntax error: expected , but found ''

(syntax)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (1)
internal/lineagecontrollerwebhook/types.go (1)

18-18: decoder should be a pointer to match admission.DecoderInjector.

controller-runtime expects InjectDecoder(d *admission.Decoder); storing a non-pointer will cause assignment/compile issues.

-	decoder   admission.Decoder
+	decoder   *admission.Decoder

Likely an incorrect or invalid review comment.

Many resources created as part of managed apps in cozystack (pods,
secrets, etc) do not carry predictable labels that unambiguously
indicate which app originally triggered their creation. Some resources
are managed by controllers and other custom resources and this
indirection can lead to loss of information. Other controllers sometimes
simply do not allow setting labels on controlled resources and the
latter do not inherit labels from the owner. This patch implements a
webhook that sidesteps this problem with a universal solution. On
creation of a pod/secret/PVC etc it walks through the owner references
until a HelmRelease is found that can be matched with a managed app
dynamically registered in the Cozystack API server. The pod is mutated
with labels identifying the managed app.

```release-note
[cozystack-controller] Add a mutating webhook to identify the Cozystack
managed app that ultimately owns low-level resources created in the
cluster and label these resources with a reference to said app.
```

Signed-off-by: Timofei Larkin <lllamnyp@gmail.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.

Actionable comments posted: 0

♻️ Duplicate comments (5)
packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml (3)

10-10: Rename webhook to a stable, descriptive DNS name

Past feedback still applies; prefer lineage-webhook.cozystack.io for clarity.

Apply:

-  - name: lineage.cozystack.io
+  - name: lineage-webhook.cozystack.io

23-23: Avoid blocking creates if webhook is down

Since this webhook only adds labels, prefer failurePolicy: Ignore to prevent outages.

Apply:

-    failurePolicy: Fail
+    failurePolicy: Ignore

6-6: Broken CA injection annotation and templating; also target the secret created by cert-manager

The value is unquoted Helm+literal causing YAML parse errors, and it points to a non-existent object. certmanager.yaml creates cozystack-controller-webhook-cert (a Secret). Use inject-ca-from-secret and quote.

Apply:

-    cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/cozystack-controller-webhook
+    cert-manager.io/inject-ca-from-secret: '{{ .Release.Namespace }}/cozystack-controller-webhook-cert'
pkg/lineage/lineage_test.go (2)

29-42: Don’t crash in init; handle config and client errors defensively

Using GetConfigOrDie and ignoring errors can crash tests. Initialize conditionally and skip when cluster config isn’t available.

Apply:

-func init() {
-	cfg := config.GetConfigOrDie()
-
-	dynClient, _ = dynamic.NewForConfig(cfg)
-
-	discoClient, _ := discovery.NewDiscoveryClientForConfig(cfg)
-
-	cachedDisco := memory.NewMemCacheClient(discoClient)
-	mapper = restmapper.NewDeferredDiscoveryRESTMapper(cachedDisco)
-
-	zapLogger, _ := zap.NewDevelopment()
-	l = zapr.NewLogger(zapLogger)
-	ctx = logr.NewContext(context.Background(), l)
-}
+func TestMain(m *testing.M) {
+	cfg, err := config.GetConfig()
+	if err != nil {
+		// No cluster; skip all tests gracefully.
+		os.Exit(0)
+	}
+	if dynClient, err = dynamic.NewForConfig(cfg); err != nil {
+		os.Exit(0)
+	}
+	discoClient, err := discovery.NewDiscoveryClientForConfig(cfg)
+	if err != nil {
+		os.Exit(0)
+	}
+	cachedDisco := memory.NewMemCacheClient(discoClient)
+	mapper = restmapper.NewDeferredDiscoveryRESTMapper(cachedDisco)
+	zapLogger, err := zap.NewDevelopment()
+	if err != nil {
+		os.Exit(0)
+	}
+	l = zapr.NewLogger(zapLogger)
+	ctx = logr.NewContext(context.Background(), l)
+	os.Exit(m.Run())
+}

44-53: Fix signature mismatch; avoid os.Args; gate as opt-in integration test

Call WalkOwnershipGraph with an AppMapper, read namespace/name from env (or flags), and log via t.Logf.

Apply:

-func TestWalkingOwnershipGraph(t *testing.T) {
-	obj, err := dynClient.Resource(schema.GroupVersionResource{"", "v1", "pods"}).Namespace(os.Args[1]).Get(ctx, os.Args[2], metav1.GetOptions{})
-	if err != nil {
-		t.Fatal(err)
-	}
-	nodes := WalkOwnershipGraph(ctx, dynClient, mapper, obj)
-	for _, node := range nodes {
-		fmt.Printf("%#v\n", node)
-	}
-}
+func TestWalkingOwnershipGraph(t *testing.T) {
+	if dynClient == nil || mapper == nil {
+		t.Skip("dynamic client/mapper not configured")
+	}
+	if os.Getenv("RUN_LINEAGE_INTEGRATION") != "true" {
+		t.Skip("opt-in via RUN_LINEAGE_INTEGRATION=true")
+	}
+	ns := os.Getenv("E2E_NS")
+	name := os.Getenv("E2E_NAME")
+	if ns == "" || name == "" {
+		t.Skip("set E2E_NS and E2E_NAME")
+	}
+	gvr := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
+	obj, err := dynClient.Resource(gvr).Namespace(ns).Get(ctx, name, metav1.GetOptions{})
+	if err != nil {
+		t.Fatal(err)
+	}
+	nodes := WalkOwnershipGraph(ctx, dynClient, mapper, noopMapper{}, obj)
+	for _, node := range nodes {
+		t.Logf("%#v", node)
+	}
+}

Add this helper in the file:

// Place near the imports.
import helmv2 "github.com/fluxcd/helm-controller/api/v2"

// Place above TestWalkingOwnershipGraph.
type noopMapper struct{}

func (noopMapper) Map(*helmv2.HelmRelease) (string, string, string, error) {
	return "", "", "", fmt.Errorf("no mapping")
}
🧹 Nitpick comments (4)
cmd/cozystack-controller/main.go (1)

218-231: Registering both controller and webhook is fine; consider a feature flag

Looks good as a dual registrar. Consider a cmd flag (e.g., --enable-lineage-webhook) to allow disabling during staged rollouts.

packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml (3)

4-4: Scope the object name to this chart/release

Bare “lineage” is too generic and risks collisions. Use a chart-scoped name.

Apply either:

-  name: lineage
+  name: cozystack-controller-lineage

or (if you have a fullname helper):

-  name: lineage
+  name: {{ include "cozystack-controller.fullname" . }}-lineage

11-17: Harden admission settings (reinvocation, timeout, match policy)

Add defensive defaults to avoid long API-server stalls and enable reinvocation.

Apply:

   - name: lineage.cozystack.io
     admissionReviewVersions: ["v1"]
     sideEffects: None
+    reinvocationPolicy: IfNeeded
+    timeoutSeconds: 5
+    matchPolicy: Equivalent
     clientConfig:

22-22: Style nit: add spaces after commas

Minor YAMLlint warning.

Apply:

-        resources: ["pods","secrets", "services", "persistentvolumeclaims"]
+        resources: ["pods", "secrets", "services", "persistentvolumeclaims"]
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e8fa1ac and e1b97e3.

📒 Files selected for processing (12)
  • cmd/cozystack-controller/main.go (2 hunks)
  • internal/lineagecontrollerwebhook/config.go (1 hunks)
  • internal/lineagecontrollerwebhook/controller.go (1 hunks)
  • internal/lineagecontrollerwebhook/types.go (1 hunks)
  • internal/lineagecontrollerwebhook/webhook.go (1 hunks)
  • packages/system/cozystack-controller/templates/certmanager.yaml (1 hunks)
  • packages/system/cozystack-controller/templates/deployment.yaml (1 hunks)
  • packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml (1 hunks)
  • packages/system/cozystack-controller/templates/service.yaml (1 hunks)
  • pkg/lineage/lineage.go (1 hunks)
  • pkg/lineage/lineage_test.go (1 hunks)
  • pkg/lineage/mapper.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • packages/system/cozystack-controller/templates/service.yaml
  • pkg/lineage/mapper.go
  • pkg/lineage/lineage.go
  • internal/lineagecontrollerwebhook/types.go
  • internal/lineagecontrollerwebhook/config.go
  • internal/lineagecontrollerwebhook/webhook.go
  • internal/lineagecontrollerwebhook/controller.go
  • packages/system/cozystack-controller/templates/certmanager.yaml
🧰 Additional context used
🧬 Code graph analysis (2)
pkg/lineage/lineage_test.go (1)
pkg/lineage/lineage.go (1)
  • WalkOwnershipGraph (40-144)
cmd/cozystack-controller/main.go (1)
internal/lineagecontrollerwebhook/types.go (1)
  • LineageControllerWebhook (15-23)
🪛 YAMLlint (1.37.1)
packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml

[warning] 22-22: too few spaces after comma

(commas)


[error] 6-6: syntax error: expected , but found ''

(syntax)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (4)
packages/system/cozystack-controller/templates/deployment.yaml (2)

31-37: Webhook port and cert mount — LGTM

Port 9443 and the serving-certs mount align with controller-runtime defaults. No concerns here.


38-42: Fix defaultMode and confirm non-root readability

  • File: packages/system/cozystack-controller/templates/deployment.yaml (lines 38–42)
  • Replace ambiguous octal literal with decimal:
-            defaultMode: 0400
+            # 0400 (octal) == 256 (decimal)
+            defaultMode: 256
  • If the pod runs as non-root, either set spec.securityContext.fsGroup to the container's group and use 0440 (288 decimal) so the group can read, or keep defaultMode 256 and run as root. Example (replace with the correct group id):
       spec:
+        securityContext:
+          fsGroup: <GID>
...
-            # 0400 (octal) == 256 (decimal)
-            defaultMode: 256
+            # 0440 (octal) == 288 (decimal)
+            defaultMode: 288
cmd/cozystack-controller/main.go (1)

41-41: Import alias for lineage controller/webhook — LGTM

Clear aliasing; no issues.

packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml (1)

18-22: Confirm resource scope (do you need to mutate Services?)

PR text mentions pods/secrets/PVCs “etc.” If Services aren’t mutated by implementation, remove to reduce blast radius.

@lllamnyp
Timofei Larkin (lllamnyp) merged commit 356fea6 into main Sep 12, 2025
20 checks passed
@lllamnyp
Timofei Larkin (lllamnyp) deleted the feat/webhook-workload-monitors branch September 12, 2025 07:44
Andrei Kvapil (kvaps) added a commit that referenced this pull request Sep 17, 2025
Reverts #1400

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* New Features
  * None
* Refactor
* Removed the lineage mutating admission webhook and its controller
logic; objects are no longer auto-labeled/mutated.
* Deployment now targets the cozy-system namespace and no longer exposes
a webhook port or mounts webhook certs.
* Chores
* Removed Service and cert-manager resources previously used for webhook
TLS; cert-manager is no longer required.
* Tests
  * Removed lineage-related tests.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

2 participants