From 7f2312485224251c4c26ff89a5534f1092a38570 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sun, 5 Jul 2026 03:38:07 +0200 Subject: [PATCH 1/2] feat(tenants): prune-protect the ascoachingogvaner skeleton for the KRO handover MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase A of the #1932 ownership-transition design: annotate all 10 skeleton objects with kustomize.toolkit.fluxcd.io/prune: disabled so the later skeleton->Tenant-CR swap de-inventories them without Flux garbage-collecting them (kro adopts in place via forced SSA). The tenant Namespace holds the CNPG database and the tenant Kustomization's finalizer would GC the whole app — delete-then-recreate is data loss, so prune-protection must be live before the swap. No runtime behavior change today. Fixes #2486 Co-Authored-By: Claude Fable 5 --- k8s/bases/apps/ascoachingogvaner/cluster-role-binding.yaml | 6 ++++++ k8s/bases/apps/ascoachingogvaner/external-secret.yaml | 6 ++++++ k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml | 5 +++++ k8s/bases/apps/ascoachingogvaner/namespace.yaml | 6 ++++++ k8s/bases/apps/ascoachingogvaner/network-policy.yaml | 6 ++++++ k8s/bases/apps/ascoachingogvaner/oci-repository.yaml | 6 ++++++ .../ascoachingogvaner/role-binding-ascoachingogvaner.yaml | 6 ++++++ .../role-binding-external-dns-kube-system.yaml | 6 ++++++ .../apps/ascoachingogvaner/role-binding-external-dns.yaml | 6 ++++++ k8s/bases/apps/ascoachingogvaner/service-account.yaml | 6 ++++++ 10 files changed, 59 insertions(+) diff --git a/k8s/bases/apps/ascoachingogvaner/cluster-role-binding.yaml b/k8s/bases/apps/ascoachingogvaner/cluster-role-binding.yaml index e46808ac1..219f5cb89 100644 --- a/k8s/bases/apps/ascoachingogvaner/cluster-role-binding.yaml +++ b/k8s/bases/apps/ascoachingogvaner/cluster-role-binding.yaml @@ -3,6 +3,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: + annotations: + # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO + # swap de-inventories this object from the `apps` Kustomization, Flux must + # NOT garbage-collect it — kro adopts it in place. Also guards against + # accidental skeleton deletion meanwhile. Remove after Phase C. + kustomize.toolkit.fluxcd.io/prune: disabled name: ascoachingogvaner-external-dns roleRef: apiGroup: rbac.authorization.k8s.io diff --git a/k8s/bases/apps/ascoachingogvaner/external-secret.yaml b/k8s/bases/apps/ascoachingogvaner/external-secret.yaml index 2efaecece..b5db43c09 100644 --- a/k8s/bases/apps/ascoachingogvaner/external-secret.yaml +++ b/k8s/bases/apps/ascoachingogvaner/external-secret.yaml @@ -13,6 +13,12 @@ apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: + annotations: + # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO + # swap de-inventories this object from the `apps` Kustomization, Flux must + # NOT garbage-collect it — kro adopts it in place. Also guards against + # accidental skeleton deletion meanwhile. Remove after Phase C. + kustomize.toolkit.fluxcd.io/prune: disabled name: ghcr-auth namespace: ascoachingogvaner labels: diff --git a/k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml b/k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml index a405901a3..b5656bc6d 100644 --- a/k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml +++ b/k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml @@ -6,6 +6,11 @@ metadata: app.kubernetes.io/managed-by: ksail annotations: ksail.devantler.tech/reconcile-exclude: "true" + # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO + # swap de-inventories this object from the `apps` Kustomization, Flux must + # NOT garbage-collect it — kro adopts it in place. Also guards against + # accidental skeleton deletion meanwhile. Remove after Phase C. + kustomize.toolkit.fluxcd.io/prune: disabled name: ascoachingogvaner namespace: ascoachingogvaner spec: diff --git a/k8s/bases/apps/ascoachingogvaner/namespace.yaml b/k8s/bases/apps/ascoachingogvaner/namespace.yaml index 3f24945c2..a2c29def7 100644 --- a/k8s/bases/apps/ascoachingogvaner/namespace.yaml +++ b/k8s/bases/apps/ascoachingogvaner/namespace.yaml @@ -1,6 +1,12 @@ apiVersion: v1 kind: Namespace metadata: + annotations: + # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO + # swap de-inventories this object from the `apps` Kustomization, Flux must + # NOT garbage-collect it — kro adopts it in place. Also guards against + # accidental skeleton deletion meanwhile. Remove after Phase C. + kustomize.toolkit.fluxcd.io/prune: disabled labels: app.kubernetes.io/managed-by: ksail pod-security.kubernetes.io/enforce: restricted diff --git a/k8s/bases/apps/ascoachingogvaner/network-policy.yaml b/k8s/bases/apps/ascoachingogvaner/network-policy.yaml index 0b9f52c90..c2abb3cf7 100644 --- a/k8s/bases/apps/ascoachingogvaner/network-policy.yaml +++ b/k8s/bases/apps/ascoachingogvaner/network-policy.yaml @@ -8,6 +8,12 @@ apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: + annotations: + # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO + # swap de-inventories this object from the `apps` Kustomization, Flux must + # NOT garbage-collect it — kro adopts it in place. Also guards against + # accidental skeleton deletion meanwhile. Remove after Phase C. + kustomize.toolkit.fluxcd.io/prune: disabled name: default-deny namespace: ascoachingogvaner spec: diff --git a/k8s/bases/apps/ascoachingogvaner/oci-repository.yaml b/k8s/bases/apps/ascoachingogvaner/oci-repository.yaml index 88c66ddee..3b8482882 100644 --- a/k8s/bases/apps/ascoachingogvaner/oci-repository.yaml +++ b/k8s/bases/apps/ascoachingogvaner/oci-repository.yaml @@ -2,6 +2,12 @@ apiVersion: source.toolkit.fluxcd.io/v1 kind: OCIRepository metadata: + annotations: + # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO + # swap de-inventories this object from the `apps` Kustomization, Flux must + # NOT garbage-collect it — kro adopts it in place. Also guards against + # accidental skeleton deletion meanwhile. Remove after Phase C. + kustomize.toolkit.fluxcd.io/prune: disabled labels: app.kubernetes.io/managed-by: ksail name: ascoachingogvaner diff --git a/k8s/bases/apps/ascoachingogvaner/role-binding-ascoachingogvaner.yaml b/k8s/bases/apps/ascoachingogvaner/role-binding-ascoachingogvaner.yaml index c91a9400e..c21d32798 100644 --- a/k8s/bases/apps/ascoachingogvaner/role-binding-ascoachingogvaner.yaml +++ b/k8s/bases/apps/ascoachingogvaner/role-binding-ascoachingogvaner.yaml @@ -1,6 +1,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: + annotations: + # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO + # swap de-inventories this object from the `apps` Kustomization, Flux must + # NOT garbage-collect it — kro adopts it in place. Also guards against + # accidental skeleton deletion meanwhile. Remove after Phase C. + kustomize.toolkit.fluxcd.io/prune: disabled labels: app.kubernetes.io/managed-by: ksail name: ascoachingogvaner diff --git a/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns-kube-system.yaml b/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns-kube-system.yaml index 933377584..af299a612 100644 --- a/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns-kube-system.yaml +++ b/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns-kube-system.yaml @@ -4,6 +4,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: + annotations: + # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO + # swap de-inventories this object from the `apps` Kustomization, Flux must + # NOT garbage-collect it — kro adopts it in place. Also guards against + # accidental skeleton deletion meanwhile. Remove after Phase C. + kustomize.toolkit.fluxcd.io/prune: disabled name: ascoachingogvaner-external-dns namespace: kube-system roleRef: diff --git a/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns.yaml b/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns.yaml index 407067029..94a7799ee 100644 --- a/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns.yaml +++ b/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns.yaml @@ -10,6 +10,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: + annotations: + # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO + # swap de-inventories this object from the `apps` Kustomization, Flux must + # NOT garbage-collect it — kro adopts it in place. Also guards against + # accidental skeleton deletion meanwhile. Remove after Phase C. + kustomize.toolkit.fluxcd.io/prune: disabled name: ascoachingogvaner-external-dns namespace: ascoachingogvaner roleRef: diff --git a/k8s/bases/apps/ascoachingogvaner/service-account.yaml b/k8s/bases/apps/ascoachingogvaner/service-account.yaml index 0da43e54a..3b67293f8 100644 --- a/k8s/bases/apps/ascoachingogvaner/service-account.yaml +++ b/k8s/bases/apps/ascoachingogvaner/service-account.yaml @@ -1,6 +1,12 @@ apiVersion: v1 kind: ServiceAccount metadata: + annotations: + # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO + # swap de-inventories this object from the `apps` Kustomization, Flux must + # NOT garbage-collect it — kro adopts it in place. Also guards against + # accidental skeleton deletion meanwhile. Remove after Phase C. + kustomize.toolkit.fluxcd.io/prune: disabled labels: app.kubernetes.io/managed-by: ksail name: ascoachingogvaner From 2b66aa1c7737d4fadb562db579029c999c22da10 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sun, 5 Jul 2026 03:43:17 +0200 Subject: [PATCH 2/2] refactor(tenants): apply prune-protection via commonAnnotations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per CodeRabbit review: one commonAnnotations block instead of 10 per-file annotations — same rendered output (verified identical annotated object set), auto-covers any file added before Phase B, and none of these resources carries a pod template so the propagation caveat is void. Co-Authored-By: Claude Fable 5 --- .../apps/ascoachingogvaner/cluster-role-binding.yaml | 6 ------ k8s/bases/apps/ascoachingogvaner/external-secret.yaml | 6 ------ .../apps/ascoachingogvaner/flux-kustomization.yaml | 5 ----- k8s/bases/apps/ascoachingogvaner/kustomization.yaml | 10 ++++++++++ k8s/bases/apps/ascoachingogvaner/namespace.yaml | 6 ------ k8s/bases/apps/ascoachingogvaner/network-policy.yaml | 6 ------ k8s/bases/apps/ascoachingogvaner/oci-repository.yaml | 6 ------ .../role-binding-ascoachingogvaner.yaml | 6 ------ .../role-binding-external-dns-kube-system.yaml | 6 ------ .../ascoachingogvaner/role-binding-external-dns.yaml | 6 ------ k8s/bases/apps/ascoachingogvaner/service-account.yaml | 6 ------ 11 files changed, 10 insertions(+), 59 deletions(-) diff --git a/k8s/bases/apps/ascoachingogvaner/cluster-role-binding.yaml b/k8s/bases/apps/ascoachingogvaner/cluster-role-binding.yaml index 219f5cb89..e46808ac1 100644 --- a/k8s/bases/apps/ascoachingogvaner/cluster-role-binding.yaml +++ b/k8s/bases/apps/ascoachingogvaner/cluster-role-binding.yaml @@ -3,12 +3,6 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - annotations: - # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO - # swap de-inventories this object from the `apps` Kustomization, Flux must - # NOT garbage-collect it — kro adopts it in place. Also guards against - # accidental skeleton deletion meanwhile. Remove after Phase C. - kustomize.toolkit.fluxcd.io/prune: disabled name: ascoachingogvaner-external-dns roleRef: apiGroup: rbac.authorization.k8s.io diff --git a/k8s/bases/apps/ascoachingogvaner/external-secret.yaml b/k8s/bases/apps/ascoachingogvaner/external-secret.yaml index b5db43c09..2efaecece 100644 --- a/k8s/bases/apps/ascoachingogvaner/external-secret.yaml +++ b/k8s/bases/apps/ascoachingogvaner/external-secret.yaml @@ -13,12 +13,6 @@ apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: - annotations: - # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO - # swap de-inventories this object from the `apps` Kustomization, Flux must - # NOT garbage-collect it — kro adopts it in place. Also guards against - # accidental skeleton deletion meanwhile. Remove after Phase C. - kustomize.toolkit.fluxcd.io/prune: disabled name: ghcr-auth namespace: ascoachingogvaner labels: diff --git a/k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml b/k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml index b5656bc6d..a405901a3 100644 --- a/k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml +++ b/k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml @@ -6,11 +6,6 @@ metadata: app.kubernetes.io/managed-by: ksail annotations: ksail.devantler.tech/reconcile-exclude: "true" - # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO - # swap de-inventories this object from the `apps` Kustomization, Flux must - # NOT garbage-collect it — kro adopts it in place. Also guards against - # accidental skeleton deletion meanwhile. Remove after Phase C. - kustomize.toolkit.fluxcd.io/prune: disabled name: ascoachingogvaner namespace: ascoachingogvaner spec: diff --git a/k8s/bases/apps/ascoachingogvaner/kustomization.yaml b/k8s/bases/apps/ascoachingogvaner/kustomization.yaml index 7cc3b9a90..2fa952c71 100644 --- a/k8s/bases/apps/ascoachingogvaner/kustomization.yaml +++ b/k8s/bases/apps/ascoachingogvaner/kustomization.yaml @@ -1,6 +1,16 @@ --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization +# Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO swap +# de-inventories these objects from the `apps` Kustomization, Flux must NOT +# garbage-collect them — kro adopts them in place (the tenant namespace holds +# the live database; the tenant Kustomization's finalizer would GC the whole +# app). Applied once here rather than per file so it also covers any object +# added to the skeleton before Phase B; none of these resources carries a pod +# template, so the annotation propagates to top-level metadata only. The whole +# directory is deleted at Phase B. +commonAnnotations: + kustomize.toolkit.fluxcd.io/prune: disabled resources: # external-dns-rbac stays platform-side: it grants the tenant's external-dns # SA privileged cross-namespace reads (the kube-system Gateway, cluster-wide diff --git a/k8s/bases/apps/ascoachingogvaner/namespace.yaml b/k8s/bases/apps/ascoachingogvaner/namespace.yaml index a2c29def7..3f24945c2 100644 --- a/k8s/bases/apps/ascoachingogvaner/namespace.yaml +++ b/k8s/bases/apps/ascoachingogvaner/namespace.yaml @@ -1,12 +1,6 @@ apiVersion: v1 kind: Namespace metadata: - annotations: - # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO - # swap de-inventories this object from the `apps` Kustomization, Flux must - # NOT garbage-collect it — kro adopts it in place. Also guards against - # accidental skeleton deletion meanwhile. Remove after Phase C. - kustomize.toolkit.fluxcd.io/prune: disabled labels: app.kubernetes.io/managed-by: ksail pod-security.kubernetes.io/enforce: restricted diff --git a/k8s/bases/apps/ascoachingogvaner/network-policy.yaml b/k8s/bases/apps/ascoachingogvaner/network-policy.yaml index c2abb3cf7..0b9f52c90 100644 --- a/k8s/bases/apps/ascoachingogvaner/network-policy.yaml +++ b/k8s/bases/apps/ascoachingogvaner/network-policy.yaml @@ -8,12 +8,6 @@ apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: - annotations: - # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO - # swap de-inventories this object from the `apps` Kustomization, Flux must - # NOT garbage-collect it — kro adopts it in place. Also guards against - # accidental skeleton deletion meanwhile. Remove after Phase C. - kustomize.toolkit.fluxcd.io/prune: disabled name: default-deny namespace: ascoachingogvaner spec: diff --git a/k8s/bases/apps/ascoachingogvaner/oci-repository.yaml b/k8s/bases/apps/ascoachingogvaner/oci-repository.yaml index 3b8482882..88c66ddee 100644 --- a/k8s/bases/apps/ascoachingogvaner/oci-repository.yaml +++ b/k8s/bases/apps/ascoachingogvaner/oci-repository.yaml @@ -2,12 +2,6 @@ apiVersion: source.toolkit.fluxcd.io/v1 kind: OCIRepository metadata: - annotations: - # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO - # swap de-inventories this object from the `apps` Kustomization, Flux must - # NOT garbage-collect it — kro adopts it in place. Also guards against - # accidental skeleton deletion meanwhile. Remove after Phase C. - kustomize.toolkit.fluxcd.io/prune: disabled labels: app.kubernetes.io/managed-by: ksail name: ascoachingogvaner diff --git a/k8s/bases/apps/ascoachingogvaner/role-binding-ascoachingogvaner.yaml b/k8s/bases/apps/ascoachingogvaner/role-binding-ascoachingogvaner.yaml index c21d32798..c91a9400e 100644 --- a/k8s/bases/apps/ascoachingogvaner/role-binding-ascoachingogvaner.yaml +++ b/k8s/bases/apps/ascoachingogvaner/role-binding-ascoachingogvaner.yaml @@ -1,12 +1,6 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - annotations: - # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO - # swap de-inventories this object from the `apps` Kustomization, Flux must - # NOT garbage-collect it — kro adopts it in place. Also guards against - # accidental skeleton deletion meanwhile. Remove after Phase C. - kustomize.toolkit.fluxcd.io/prune: disabled labels: app.kubernetes.io/managed-by: ksail name: ascoachingogvaner diff --git a/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns-kube-system.yaml b/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns-kube-system.yaml index af299a612..933377584 100644 --- a/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns-kube-system.yaml +++ b/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns-kube-system.yaml @@ -4,12 +4,6 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - annotations: - # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO - # swap de-inventories this object from the `apps` Kustomization, Flux must - # NOT garbage-collect it — kro adopts it in place. Also guards against - # accidental skeleton deletion meanwhile. Remove after Phase C. - kustomize.toolkit.fluxcd.io/prune: disabled name: ascoachingogvaner-external-dns namespace: kube-system roleRef: diff --git a/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns.yaml b/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns.yaml index 94a7799ee..407067029 100644 --- a/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns.yaml +++ b/k8s/bases/apps/ascoachingogvaner/role-binding-external-dns.yaml @@ -10,12 +10,6 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - annotations: - # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO - # swap de-inventories this object from the `apps` Kustomization, Flux must - # NOT garbage-collect it — kro adopts it in place. Also guards against - # accidental skeleton deletion meanwhile. Remove after Phase C. - kustomize.toolkit.fluxcd.io/prune: disabled name: ascoachingogvaner-external-dns namespace: ascoachingogvaner roleRef: diff --git a/k8s/bases/apps/ascoachingogvaner/service-account.yaml b/k8s/bases/apps/ascoachingogvaner/service-account.yaml index 3b67293f8..0da43e54a 100644 --- a/k8s/bases/apps/ascoachingogvaner/service-account.yaml +++ b/k8s/bases/apps/ascoachingogvaner/service-account.yaml @@ -1,12 +1,6 @@ apiVersion: v1 kind: ServiceAccount metadata: - annotations: - # Phase A of the skeleton->Tenant-CR handover (#1932/#2486): when the KRO - # swap de-inventories this object from the `apps` Kustomization, Flux must - # NOT garbage-collect it — kro adopts it in place. Also guards against - # accidental skeleton deletion meanwhile. Remove after Phase C. - kustomize.toolkit.fluxcd.io/prune: disabled labels: app.kubernetes.io/managed-by: ksail name: ascoachingogvaner