Stage 2 — the restructure. Woodpecker moves from (app under the catch-all apps KS + DB under seed-woodpecker) to a single dedicated woodpecker KS, matching every other app.
Changes
New clusters/homelab/woodpecker.yaml — dedicated KS over apps/woodpecker with the infrastructure-cnpg-barman dep + CNPG Cluster healthCheckExprs (moved off seed-woodpecker), so the CNPG concerns are isolated here instead of contaminating the shared apps KS.
Remove woodpecker/ from apps/kustomization.yaml.
git mv the 4 DB manifests + MIGRATION.md from seed/woodpecker/ → apps/woodpecker/, added to its kustomization.
Delete seed-woodpecker.yaml + the now-empty seed/woodpecker/.
bootstrap.sh: add wait_kustomization woodpecker (was covered by wait apps); e2e-test.sh: add woodpecker to the KS checks.
Safe dual ownership transfer (nothing pruned)
Every object carries prune: disabled from stage 1 (#394) — app objects via commonAnnotations, DB objects per-file. So when the apps KS drops woodpecker/andseed-woodpecker is deleted, both GC sweeps skip these live objects, and the new woodpecker KS adopts them in place. No CNPG restart (Cluster isn't a Deployment); no app restart (manifests unchanged — only the owning-KS label flips).
Verified
kubectl kustomize apps/woodpecker → 17 objects (13 app + 4 DB incl. Cluster/wp-pg), all prune-protected
bash -n on bootstrap.sh + e2e-test.sh OK
wp-pg is the sole CNPG cluster in apps ns and hetzner-s3-creds is used only by wp-pg-store (no shared-ownership risk)
seed/woodpecker/ fully removed
Post-merge check
seed-woodpecker gone; woodpecker KS Ready; wp-pg pod not restarted + still owned (adopted) by woodpecker; server/agent still Running; ownership labels on all 17 objects flipped to woodpecker.
Stage 3 (follow-up) drops the transient commonAnnotations — one more accepted app roll.
**Stage 2** — the restructure. Woodpecker moves from (app under the catch-all `apps` KS + DB under `seed-woodpecker`) to a single dedicated `woodpecker` KS, matching every other app.
### Changes
- **New `clusters/homelab/woodpecker.yaml`** — dedicated KS over `apps/woodpecker` with the `infrastructure-cnpg-barman` dep + CNPG Cluster `healthCheckExprs` (moved off `seed-woodpecker`), so the CNPG concerns are isolated here instead of contaminating the shared `apps` KS.
- Remove `woodpecker/` from `apps/kustomization.yaml`.
- `git mv` the 4 DB manifests + `MIGRATION.md` from `seed/woodpecker/` → `apps/woodpecker/`, added to its kustomization.
- Delete `seed-woodpecker.yaml` + the now-empty `seed/woodpecker/`.
- `bootstrap.sh`: add `wait_kustomization woodpecker` (was covered by `wait apps`); `e2e-test.sh`: add `woodpecker` to the KS checks.
### Safe dual ownership transfer (nothing pruned)
Every object carries `prune: disabled` from stage 1 (#394) — app objects via `commonAnnotations`, DB objects per-file. So when the `apps` KS drops `woodpecker/` **and** `seed-woodpecker` is deleted, both GC sweeps **skip** these live objects, and the new `woodpecker` KS adopts them in place. No CNPG restart (Cluster isn't a Deployment); no app restart (manifests unchanged — only the owning-KS label flips).
### Verified
- `kubectl kustomize apps/woodpecker` → 17 objects (13 app + 4 DB incl. `Cluster/wp-pg`), all prune-protected
- `bash -n` on `bootstrap.sh` + `e2e-test.sh` OK
- `wp-pg` is the **sole** CNPG cluster in `apps` ns and `hetzner-s3-creds` is used only by `wp-pg-store` (no shared-ownership risk)
- `seed/woodpecker/` fully removed
### Post-merge check
`seed-woodpecker` gone; `woodpecker` KS Ready; `wp-pg` pod **not restarted** + still owned (adopted) by `woodpecker`; server/agent still Running; ownership labels on all 17 objects flipped to `woodpecker`.
**Stage 3** (follow-up) drops the transient `commonAnnotations` — one more accepted app roll.
Restructures woodpecker into its own Flux Kustomization instead of splitting its
app across the catch-all apps KS and its DB across seed-woodpecker.
- Add clusters/homelab/woodpecker.yaml: dedicated KS over apps/woodpecker with
the infrastructure-cnpg-barman dep + CNPG Cluster healthCheckExprs (moved off
seed-woodpecker) so the CNPG concerns live here, not in the shared apps KS.
- Remove woodpecker/ from apps/kustomization.yaml (catch-all apps KS no longer
owns the woodpecker app objects).
- git mv seed/woodpecker/{cluster,objectstore,scheduled-backup,
hetzner-creds-externalsecret}.yaml + MIGRATION.md -> apps/woodpecker/, and add
the four DB manifests to apps/woodpecker/kustomization.yaml.
- Delete clusters/homelab/seed-woodpecker.yaml and the now-empty
kubernetes/seed/woodpecker/.
- bootstrap.sh: add a wait_kustomization woodpecker entry (it used to be covered
by 'wait apps'); e2e-test.sh: add woodpecker to the KS readiness checks.
Safe dual ownership transfer (nothing pruned): every object carries prune:
disabled from stage 1 (#394) — the app objects via commonAnnotations, the DB
objects per-file — so when the apps KS drops woodpecker/ and seed-woodpecker is
deleted, both GC sweeps skip these live objects and the new woodpecker KS adopts
them in place. No CNPG restart (Cluster is not a Deployment); no app restart
(manifests unchanged, only the owning KS label flips).
Verified: kubectl kustomize apps/woodpecker builds 17 objects (13 app + 4 DB
incl. wp-pg Cluster), all prune-protected; bash -n bootstrap.sh + e2e-test.sh
OK; wp-pg is the sole CNPG cluster in apps ns and hetzner-s3-creds is used only
by wp-pg-store; seed/woodpecker fully removed.
Stage 3 will drop the transient commonAnnotations (one more accepted app roll).
Co-Authored-By: Claude Bot <claude-bot@renner.uno>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🤖Automated review — model claude-sonnet-5 (complexity: unknown), commit 6900271f8620982d829b6368d5b46c78a9992cff.
Advisory review by the review-bot pipeline. It never approves; a human merges. Push new commits to get a fresh review.
Summary
Mechanical stage-2 restructuring: Woodpecker's app manifests (still under apps/kustomization.yaml) and its wp-pg CNPG DB manifests (previously under the transient seed-woodpecker KS) are consolidated into a single dedicated woodpecker Kustomization/directory. I verified the ownership-transfer safety claims in the PR body against the actual checkout (not just the diff) and they hold. No blocking issues found.
🟡 Suggestions
kubernetes/apps/woodpecker/hetzner-creds-externalsecret.yaml:19-21 — the FOLLOW-UP comment says woodpecker should get its own OpenBao hetzner-creds path instead of reusing seed/paperless/hetzner-creds. Not a blocker for this stage (values are identical today), but this cross-app coupling means a future rotation/change to paperless's Hetzner creds silently affects woodpecker's backups too. Worth a tracking issue if one doesn't already exist, so it isn't forgotten once OpenBao becomes writable.
kubernetes/clusters/homelab/woodpecker.yaml:12 — timeout: 30m combined with interval: 10m and retryInterval: 2m matches the sibling seed-* KSs exactly, but worth double-checking during the post-merge check that the CNPG Cluster adoption (label-only object handoff between owning KSs) doesn't trip any Flux "resource already exists / owned by different Kustomization" conflict on first reconcile — the PR body says this was verified conceptually but the actual post-merge behavior is the real test here.
Tests
This is infra-as-config (Kustomize/Flux manifests + bootstrap/e2e shell scripts) — there's no unit-test harness to speak of, and the PR's own verification steps (kubectl kustomize, bash -n, manual checks of prune annotations and CNPG-cluster uniqueness) are the appropriate substitute. I independently re-verified the key safety claims against the checkout:
Every moved DB object (cluster.yaml, objectstore.yaml, scheduled-backup.yaml, hetzner-creds-externalsecret.yaml) does carry kustomize.toolkit.fluxcd.io/prune: disabled per-file — confirmed.
apps/woodpecker/kustomization.yaml's commonAnnotations still applies prune: disabled to the app objects — confirmed.
wp-pg is indeed the only CNPG Cluster in the apps namespace (the other in-repo cluster, gf-pg, lives in monitoring) — confirmed.
hetzner-s3-creds in the apps namespace is referenced only by wp-pg-store's ObjectStore; the same-named ExternalSecrets for authentik/immich/paperless live in their own namespaces, so no cross-namespace or same-namespace name collision — confirmed.
No stray seed-woodpecker / kubernetes/seed/woodpecker references remain anywhere in the repo, and bootstrap.sh/e2e-test.sh each reference woodpecker exactly once — confirmed.
dependsOn list (infrastructure, infrastructure-crds, infrastructure-ceph-cluster, infrastructure-cnpg-barman) and healthCheckExprs on the new woodpecker KS are byte-for-byte consistent with the sibling seed-authentik/seed-immich/seed-paperless KSs, and infrastructure-cnpg-barman does exist as a Kustomization — confirmed.
Given the change is a pure ownership/location refactor with no manifest content changes (confirmed via the git mv/100%-similarity renames in the diff), this level of verification is appropriate and I found nothing contradicting the PR's claims.
Recommendation
Looks reasonable — no blocking issues; comments above are optional.
🤖 **Automated review** — model `claude-sonnet-5` (complexity: unknown), commit `6900271f8620982d829b6368d5b46c78a9992cff`.
> Advisory review by the `review-bot` pipeline. It never approves; a human merges. Push new commits to get a fresh review.
---
## Summary
Mechanical stage-2 restructuring: Woodpecker's app manifests (still under `apps/kustomization.yaml`) and its `wp-pg` CNPG DB manifests (previously under the transient `seed-woodpecker` KS) are consolidated into a single dedicated `woodpecker` Kustomization/directory. I verified the ownership-transfer safety claims in the PR body against the actual checkout (not just the diff) and they hold. No blocking issues found.
## 🟡 Suggestions
- `kubernetes/apps/woodpecker/hetzner-creds-externalsecret.yaml:19-21` — the FOLLOW-UP comment says woodpecker should get its own OpenBao `hetzner-creds` path instead of reusing `seed/paperless/hetzner-creds`. Not a blocker for this stage (values are identical today), but this cross-app coupling means a future rotation/change to paperless's Hetzner creds silently affects woodpecker's backups too. Worth a tracking issue if one doesn't already exist, so it isn't forgotten once OpenBao becomes writable.
- `kubernetes/clusters/homelab/woodpecker.yaml:12` — `timeout: 30m` combined with `interval: 10m` and `retryInterval: 2m` matches the sibling `seed-*` KSs exactly, but worth double-checking during the post-merge check that the CNPG Cluster adoption (label-only object handoff between owning KSs) doesn't trip any Flux "resource already exists / owned by different Kustomization" conflict on first reconcile — the PR body says this was verified conceptually but the actual post-merge behavior is the real test here.
## Tests
This is infra-as-config (Kustomize/Flux manifests + bootstrap/e2e shell scripts) — there's no unit-test harness to speak of, and the PR's own verification steps (`kubectl kustomize`, `bash -n`, manual checks of prune annotations and CNPG-cluster uniqueness) are the appropriate substitute. I independently re-verified the key safety claims against the checkout:
- Every moved DB object (`cluster.yaml`, `objectstore.yaml`, `scheduled-backup.yaml`, `hetzner-creds-externalsecret.yaml`) does carry `kustomize.toolkit.fluxcd.io/prune: disabled` per-file — confirmed.
- `apps/woodpecker/kustomization.yaml`'s `commonAnnotations` still applies `prune: disabled` to the app objects — confirmed.
- `wp-pg` is indeed the only CNPG `Cluster` in the `apps` namespace (the other in-repo cluster, `gf-pg`, lives in `monitoring`) — confirmed.
- `hetzner-s3-creds` in the `apps` namespace is referenced only by `wp-pg-store`'s `ObjectStore`; the same-named ExternalSecrets for authentik/immich/paperless live in their own namespaces, so no cross-namespace or same-namespace name collision — confirmed.
- No stray `seed-woodpecker` / `kubernetes/seed/woodpecker` references remain anywhere in the repo, and `bootstrap.sh`/`e2e-test.sh` each reference `woodpecker` exactly once — confirmed.
- `dependsOn` list (`infrastructure`, `infrastructure-crds`, `infrastructure-ceph-cluster`, `infrastructure-cnpg-barman`) and `healthCheckExprs` on the new `woodpecker` KS are byte-for-byte consistent with the sibling `seed-authentik`/`seed-immich`/`seed-paperless` KSs, and `infrastructure-cnpg-barman` does exist as a Kustomization — confirmed.
Given the change is a pure ownership/location refactor with no manifest content changes (confirmed via the `git mv`/100%-similarity renames in the diff), this level of verification is appropriate and I found nothing contradicting the PR's claims.
## Recommendation
Looks reasonable — no blocking issues; comments above are optional.
<!-- pr-review:sha=6900271f8620982d829b6368d5b46c78a9992cff -->
hetzner-creds cross-app coupling — pre-existing (the FOLLOW-UP comment travelled in with the git mv, not introduced here). Filed a tracking issue so it isn't forgotten once OpenBao is writable: k.renner/homelab#397
CNPG adoption / Flux ownership-conflict on first reconcile — this is exactly the load-bearing post-merge check I'll run: confirm wp-pg is adopted by the woodpecker KS (label flip) with RESTARTS=0 and no already managed by another Kustomization error. Reporting back after merge.
No code changes — merging as-is.
Thanks — both 🟡s addressed:
1. **hetzner-creds cross-app coupling** — pre-existing (the FOLLOW-UP comment travelled in with the `git mv`, not introduced here). Filed a tracking issue so it isn't forgotten once OpenBao is writable: https://gitea.renner.uno/k.renner/homelab/issues/397
2. **CNPG adoption / Flux ownership-conflict on first reconcile** — this is exactly the load-bearing post-merge check I'll run: confirm `wp-pg` is adopted by the `woodpecker` KS (label flip) with `RESTARTS=0` and no `already managed by another Kustomization` error. Reporting back after merge.
No code changes — merging as-is.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Stage 2 — the restructure. Woodpecker moves from (app under the catch-all
appsKS + DB underseed-woodpecker) to a single dedicatedwoodpeckerKS, matching every other app.Changes
clusters/homelab/woodpecker.yaml— dedicated KS overapps/woodpeckerwith theinfrastructure-cnpg-barmandep + CNPG ClusterhealthCheckExprs(moved offseed-woodpecker), so the CNPG concerns are isolated here instead of contaminating the sharedappsKS.woodpecker/fromapps/kustomization.yaml.git mvthe 4 DB manifests +MIGRATION.mdfromseed/woodpecker/→apps/woodpecker/, added to its kustomization.seed-woodpecker.yaml+ the now-emptyseed/woodpecker/.bootstrap.sh: addwait_kustomization woodpecker(was covered bywait apps);e2e-test.sh: addwoodpeckerto the KS checks.Safe dual ownership transfer (nothing pruned)
Every object carries
prune: disabledfrom stage 1 (#394) — app objects viacommonAnnotations, DB objects per-file. So when theappsKS dropswoodpecker/andseed-woodpeckeris deleted, both GC sweeps skip these live objects, and the newwoodpeckerKS adopts them in place. No CNPG restart (Cluster isn't a Deployment); no app restart (manifests unchanged — only the owning-KS label flips).Verified
kubectl kustomize apps/woodpecker→ 17 objects (13 app + 4 DB incl.Cluster/wp-pg), all prune-protectedbash -nonbootstrap.sh+e2e-test.shOKwp-pgis the sole CNPG cluster inappsns andhetzner-s3-credsis used only bywp-pg-store(no shared-ownership risk)seed/woodpecker/fully removedPost-merge check
seed-woodpeckergone;woodpeckerKS Ready;wp-pgpod not restarted + still owned (adopted) bywoodpecker; server/agent still Running; ownership labels on all 17 objects flipped towoodpecker.Stage 3 (follow-up) drops the transient
commonAnnotations— one more accepted app roll.Restructures woodpecker into its own Flux Kustomization instead of splitting its app across the catch-all apps KS and its DB across seed-woodpecker. - Add clusters/homelab/woodpecker.yaml: dedicated KS over apps/woodpecker with the infrastructure-cnpg-barman dep + CNPG Cluster healthCheckExprs (moved off seed-woodpecker) so the CNPG concerns live here, not in the shared apps KS. - Remove woodpecker/ from apps/kustomization.yaml (catch-all apps KS no longer owns the woodpecker app objects). - git mv seed/woodpecker/{cluster,objectstore,scheduled-backup, hetzner-creds-externalsecret}.yaml + MIGRATION.md -> apps/woodpecker/, and add the four DB manifests to apps/woodpecker/kustomization.yaml. - Delete clusters/homelab/seed-woodpecker.yaml and the now-empty kubernetes/seed/woodpecker/. - bootstrap.sh: add a wait_kustomization woodpecker entry (it used to be covered by 'wait apps'); e2e-test.sh: add woodpecker to the KS readiness checks. Safe dual ownership transfer (nothing pruned): every object carries prune: disabled from stage 1 (#394) — the app objects via commonAnnotations, the DB objects per-file — so when the apps KS drops woodpecker/ and seed-woodpecker is deleted, both GC sweeps skip these live objects and the new woodpecker KS adopts them in place. No CNPG restart (Cluster is not a Deployment); no app restart (manifests unchanged, only the owning KS label flips). Verified: kubectl kustomize apps/woodpecker builds 17 objects (13 app + 4 DB incl. wp-pg Cluster), all prune-protected; bash -n bootstrap.sh + e2e-test.sh OK; wp-pg is the sole CNPG cluster in apps ns and hetzner-s3-creds is used only by wp-pg-store; seed/woodpecker fully removed. Stage 3 will drop the transient commonAnnotations (one more accepted app roll). Co-Authored-By: Claude Bot <claude-bot@renner.uno> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>🤖 Automated review — model
claude-sonnet-5(complexity: unknown), commit6900271f8620982d829b6368d5b46c78a9992cff.Summary
Mechanical stage-2 restructuring: Woodpecker's app manifests (still under
apps/kustomization.yaml) and itswp-pgCNPG DB manifests (previously under the transientseed-woodpeckerKS) are consolidated into a single dedicatedwoodpeckerKustomization/directory. I verified the ownership-transfer safety claims in the PR body against the actual checkout (not just the diff) and they hold. No blocking issues found.🟡 Suggestions
kubernetes/apps/woodpecker/hetzner-creds-externalsecret.yaml:19-21— the FOLLOW-UP comment says woodpecker should get its own OpenBaohetzner-credspath instead of reusingseed/paperless/hetzner-creds. Not a blocker for this stage (values are identical today), but this cross-app coupling means a future rotation/change to paperless's Hetzner creds silently affects woodpecker's backups too. Worth a tracking issue if one doesn't already exist, so it isn't forgotten once OpenBao becomes writable.kubernetes/clusters/homelab/woodpecker.yaml:12—timeout: 30mcombined withinterval: 10mandretryInterval: 2mmatches the siblingseed-*KSs exactly, but worth double-checking during the post-merge check that the CNPG Cluster adoption (label-only object handoff between owning KSs) doesn't trip any Flux "resource already exists / owned by different Kustomization" conflict on first reconcile — the PR body says this was verified conceptually but the actual post-merge behavior is the real test here.Tests
This is infra-as-config (Kustomize/Flux manifests + bootstrap/e2e shell scripts) — there's no unit-test harness to speak of, and the PR's own verification steps (
kubectl kustomize,bash -n, manual checks of prune annotations and CNPG-cluster uniqueness) are the appropriate substitute. I independently re-verified the key safety claims against the checkout:cluster.yaml,objectstore.yaml,scheduled-backup.yaml,hetzner-creds-externalsecret.yaml) does carrykustomize.toolkit.fluxcd.io/prune: disabledper-file — confirmed.apps/woodpecker/kustomization.yaml'scommonAnnotationsstill appliesprune: disabledto the app objects — confirmed.wp-pgis indeed the only CNPGClusterin theappsnamespace (the other in-repo cluster,gf-pg, lives inmonitoring) — confirmed.hetzner-s3-credsin theappsnamespace is referenced only bywp-pg-store'sObjectStore; the same-named ExternalSecrets for authentik/immich/paperless live in their own namespaces, so no cross-namespace or same-namespace name collision — confirmed.seed-woodpecker/kubernetes/seed/woodpeckerreferences remain anywhere in the repo, andbootstrap.sh/e2e-test.sheach referencewoodpeckerexactly once — confirmed.dependsOnlist (infrastructure,infrastructure-crds,infrastructure-ceph-cluster,infrastructure-cnpg-barman) andhealthCheckExprson the newwoodpeckerKS are byte-for-byte consistent with the siblingseed-authentik/seed-immich/seed-paperlessKSs, andinfrastructure-cnpg-barmandoes exist as a Kustomization — confirmed.Given the change is a pure ownership/location refactor with no manifest content changes (confirmed via the
git mv/100%-similarity renames in the diff), this level of verification is appropriate and I found nothing contradicting the PR's claims.Recommendation
Looks reasonable — no blocking issues; comments above are optional.
Thanks — both 🟡s addressed:
git mv, not introduced here). Filed a tracking issue so it isn't forgotten once OpenBao is writable: k.renner/homelab#397wp-pgis adopted by thewoodpeckerKS (label flip) withRESTARTS=0and noalready managed by another Kustomizationerror. Reporting back after merge.No code changes — merging as-is.