Skip to content

fix(network): disable prune on self-referencing cloudflare Kustomizations - #1415

Merged
Aviator-Coding merged 1 commit into
mainfrom
fm/homeops-split-s1-cloudflare
Aug 24, 2026
Merged

fix(network): disable prune on self-referencing cloudflare Kustomizations#1415
Aviator-Coding merged 1 commit into
mainfrom
fm/homeops-split-s1-cloudflare

Conversation

@Aviator-Coding

Copy link
Copy Markdown
Owner

Intent

Step 1 of a deliberate 3-PR sequence that removes a self-deletion landmine from the Flux Kustomizations network/cloudflare-dns and network/cloudflare-tunnel. This PR must contain ONLY the two-line change setting spec.prune from true to false on those two ks.yaml files - nothing else.

Background a reviewer cannot see in the diff: both Kustomizations set spec.path to their own directory (./kubernetes/apps/network/), and neither directory has a kustomization.yaml. Flux's kustomize-controller therefore autodetects every yaml under that path, which includes each ks.yaml itself, so each Kustomization renders and owns a copy of itself and carries its own __kustomize.toolkit.fluxcd.io_Kustomization entry in status.inventory. This was re-verified live against the cluster immediately before this change: those two are the ONLY objects in the entire cluster that self-reference, both with prune=true, matching the structure scout's report section Q5.

That makes the planned spec.path move destructive. Moving the path drops the self entry from the inventory, and with prune enabled each Kustomization garbage-collects ITSELF, cascading into the cloudflare tunnel Deployment, DNSEndpoint, PodDisruptionBudget, ExternalSecret and OCIRepository - i.e. all public ingress for the cluster goes down.

The mitigation is deliberately split into three separately landed and live-verified PRs, and combining them would reintroduce exactly the outage this is preventing:
PR 1 (this one): prune: false on both, so nothing can be pruned.
PR 2 (later, separate): the actual spec.path move for both, plus an explicit kustomization.yaml per directory listing only the real resources (the existing kubernetes/apps/ai/searxng pattern) so the self-render shape cannot regress.
PR 3 (later, separate): restore prune: true on both once the inventories are clean.

So prune: false is intentional and temporary, NOT a regression or an oversight, and it is correct that this PR does not also perform the path move or add the kustomization.yaml files - those are deliberately out of scope here and are gated on this PR being merged and live-verified first. Do not expand this PR's scope to include them.

Note on validation: 'kustomize build' cannot reproduce the self-render locally because it requires an explicit kustomization.yaml and errors without one, whereas Flux's controller autodetects. The live status.inventory self-entry is the authoritative evidence, and it was captured before this change (cloudflare-dns 5 inventory entries, cloudflare-tunnel 7, each including itself). Static local tooling is expected to show no behavioral difference for this diff.

What Changed

  • Set spec.prune from true to false on kubernetes/apps/network/cloudflare-dns/ks.yaml.
  • Set spec.prune from true to false on kubernetes/apps/network/cloudflare-tunnel/ks.yaml.

Risk Assessment

✅ Low: The change is exactly the two-line prune:true→prune:false edit on both ks.yaml files described in the intent, with no scope creep (no path move, no kustomization.yaml added); disabling prune is a strictly safer, non-destructive state for self-referencing Kustomizations.

Testing

Confirmed via git diff that the change is exactly the intended two-line prune:true->false flip on the two cloudflare ks.yaml files and nothing else. Since prune is a kustomize-controller GC toggle with no representation in rendered manifests, no local tool can show behavioral difference between the two states (as the intent itself notes); instead I verified the surrounding structural claims live in the repo - both directories lack a kustomization.yaml, kustomize build fails identically on both with a missing-kustomization-file error, and flux-local (installed locally via the project's own mise-pinned toolchain) successfully resolves and builds both Kustomization targets from kubernetes/flux/cluster with no errors attributable to this change. No CI-equivalent full flux-local test suite was run, per the targeted-validation scope for this phase. Transient .venv created by the mise install was removed afterward; the worktree is clean.

Evidence: git diff confirming exact 2-line scope
diff --git a/kubernetes/apps/network/cloudflare-dns/ks.yaml b/kubernetes/apps/network/cloudflare-dns/ks.yaml
- prune: true
+ prune: false
diff --git a/kubernetes/apps/network/cloudflare-tunnel/ks.yaml b/kubernetes/apps/network/cloudflare-tunnel/ks.yaml
- prune: true
+ prune: false
Evidence: kustomize build failure confirming no local kustomization.yaml (matches intent background)
Error: unable to find one of 'kustomization.yaml', 'kustomization.yml' or 'Kustomization' in directory '.../kubernetes/apps/network/cloudflare-dns'
Error: unable to find one of 'kustomization.yaml', 'kustomization.yml' or 'Kustomization' in directory '.../kubernetes/apps/network/cloudflare-tunnel'
Evidence: flux-local get kustomization output for both targets
network cloudflare-dns kubernetes/apps/network/cloudflare-dns HELMREPOS=0 OCIREPOS=1 RELEASES=1
network cloudflare-tunnel kubernetes/apps/network/cloudflare-tunnel HELMREPOS=0 OCIREPOS=1 RELEASES=1

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • git diff 4e2f4e8f496eb87bf1bc2338bffa196d517bbe71 15b7c2e863050fc264ab946b6ec03a0977bb6f02 -- to confirm the diff is scoped to exactly the two prune lines in the two ks.yaml files
  • ls kubernetes/apps/network/cloudflare-dns/ and .../cloudflare-tunnel/ to confirm neither directory has a kustomization.yaml (the structural precondition the intent's background section relies on)
  • kustomize build kubernetes/apps/network/cloudflare-dns --load-restrictor LoadRestrictionsNone and the same for cloudflare-tunnel, both failing with 'unable to find one of kustomization.yaml/kustomization.yml/Kustomization' - confirming static kustomize tooling cannot reproduce Flux's self-render autodetection, exactly as the intent states
  • flux-local get kustomization cloudflare-dns --path kubernetes/flux/cluster -A -o wide and the same for cloudflare-tunnel, confirming flux-local can resolve/build both Kustomization targets at the target commit with no configuration errors caused by the prune change
⚠️ **Document** - 1 info
  • ℹ️ The diff (prune: true -> false on network/cloudflare-dns and network/cloudflare-tunnel ks.yaml) introduces no stale documentation: no existing doc (AGENTS.md, docs/, or a per-namespace README) currently states or assumes prune=true for these two Kustomizations, and neither ks.yaml carries an inline comment that now contradicts the new value. Nothing to fix in this pass. Once PR2 (path move + explicit kustomization.yaml) and PR3 (prune: true restore) land and are live-verified, the self-referencing-Kustomization footgun (spec.path pointing at a directory with no kustomization.yaml, causing kustomize-controller to autodetect and own a copy of the ks.yaml itself) is worth a durable NOTES entry in AGENTS.md, in the same style as the existing postBuild.substitute collision entry - documenting the invariant so it isn't silently reintroduced by a future app. Deliberately not added now: user intent requires this PR to contain only the two-line prune change, and the full picture (path move + kustomization.yaml) doesn't exist yet to document accurately.
✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

…ions

network/cloudflare-dns and network/cloudflare-tunnel both set spec.path to
their own directory, and neither directory has a kustomization.yaml. Flux's
kustomize-controller therefore autodetects every yaml under the path, which
includes each ks.yaml itself, so each Kustomization renders and owns a copy
of itself. Both carry their own
<ns>_<name>_kustomize.toolkit.fluxcd.io_Kustomization entry in
status.inventory - verified live, and they are the only two objects in the
cluster that do.

That makes a later spec.path move destructive: the move drops the self entry
from the inventory, and with prune enabled the Kustomization garbage-collects
itself, cascading into the tunnel Deployment, DNSEndpoint, PodDisruptionBudget,
ExternalSecret and OCIRepository - all public ingress.

This is step 1 of 3. Disabling prune first means the path move in step 2
cannot delete anything; step 3 restores prune: true once the inventories are
clean.

Refs: split S1a
@mortyops

mortyops Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor
--- kubernetes/apps/network/cloudflare-dns Kustomization: network/cloudflare-dns Kustomization: network/cloudflare-dns

+++ kubernetes/apps/network/cloudflare-dns Kustomization: network/cloudflare-dns Kustomization: network/cloudflare-dns

@@ -15,13 +15,13 @@

   interval: 1h
   path: ./kubernetes/apps/network/cloudflare-dns
   postBuild:
     substituteFrom:
     - kind: Secret
       name: cluster-secrets
-  prune: true
+  prune: false
   retryInterval: 2m
   sourceRef:
     kind: GitRepository
     name: flux-system
     namespace: flux-system
   targetNamespace: network
--- kubernetes/apps Kustomization: flux-system/cluster-apps Kustomization: network/cloudflare-dns

+++ kubernetes/apps Kustomization: flux-system/cluster-apps Kustomization: network/cloudflare-dns

@@ -40,13 +40,13 @@

       kind: HelmRelease
   path: ./kubernetes/apps/network/cloudflare-dns
   postBuild:
     substituteFrom:
     - kind: Secret
       name: cluster-secrets
-  prune: true
+  prune: false
   retryInterval: 2m
   sourceRef:
     kind: GitRepository
     name: flux-system
     namespace: flux-system
   targetNamespace: network
--- kubernetes/apps Kustomization: flux-system/cluster-apps Kustomization: network/cloudflare-tunnel

+++ kubernetes/apps Kustomization: flux-system/cluster-apps Kustomization: network/cloudflare-tunnel

@@ -43,13 +43,13 @@

       kind: HelmRelease
   path: ./kubernetes/apps/network/cloudflare-tunnel
   postBuild:
     substituteFrom:
     - kind: Secret
       name: cluster-secrets
-  prune: true
+  prune: false
   sourceRef:
     kind: GitRepository
     name: flux-system
     namespace: flux-system
   targetNamespace: network
   wait: false
--- kubernetes/apps/network/cloudflare-tunnel Kustomization: network/cloudflare-tunnel Kustomization: network/cloudflare-tunnel

+++ kubernetes/apps/network/cloudflare-tunnel Kustomization: network/cloudflare-tunnel Kustomization: network/cloudflare-tunnel

@@ -18,13 +18,13 @@

   interval: 1h
   path: ./kubernetes/apps/network/cloudflare-tunnel
   postBuild:
     substituteFrom:
     - kind: Secret
       name: cluster-secrets
-  prune: true
+  prune: false
   sourceRef:
     kind: GitRepository
     name: flux-system
     namespace: flux-system
   targetNamespace: network
   wait: false

@Aviator-Coding
Aviator-Coding merged commit cc67b9b into main Aug 24, 2026
12 checks passed
Aviator-Coding added a commit that referenced this pull request Aug 24, 2026
Final step of the three-part de-self-referencing sequence. Step 1 (#1415)
disabled prune so nothing could be garbage-collected; step 2 (#1420) pointed
both Kustomizations at their app/ subdirectory so they stopped rendering and
owning a copy of themselves.

Both are now verified clean live at the new path:

  cloudflare-dns     Ready, inventory 5 -> 4 entries
  cloudflare-tunnel  Ready, inventory 7 -> 6 entries

The <ns>_<name>_kustomize.toolkit.fluxcd.io_Kustomization self entry is gone
from both, every real resource is retained, and the cluster-wide scan for
self-referencing Kustomizations now returns nothing.

With the inventories settled and matching what the new path renders, prune can
safely go back on: restoring it produces no inventory diff, so nothing is
collected. This returns both Kustomizations to the repo default and to the
same posture as their six siblings in this namespace.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant