diff --git a/stacks/novelapp/main.tf b/stacks/novelapp/main.tf index 63269ff2..e4a181cc 100644 --- a/stacks/novelapp/main.tf +++ b/stacks/novelapp/main.tf @@ -89,13 +89,24 @@ resource "kubernetes_deployment" "novelapp" { } annotations = { "reloader.stakater.com/auto" = "true" + # Override the Kyverno-stamped default (`patch`) with `all` so Keel picks + # up any new tag from mghee/novelapp. The `+()` anchor in the Kyverno + # ClusterPolicy preserves this explicit value; not in ignore_changes + # below so TF re-asserts it on every apply (otherwise the injector + # default would drift back in). + "keel.sh/policy" = "all" + "keel.sh/trigger" = "poll" + "keel.sh/pollSchedule" = "@every 1h" } } lifecycle { - # DRIFT_WORKAROUND: CI pipeline owns image tag (kubectl set image from Woodpecker/GHA). Reviewed 2026-04-18. ignore_changes = [ - spec[0].template[0].spec[0].container[0].image, - spec[0].template[0].spec[0].dns_config, # KYVERNO_LIFECYCLE_V1: Kyverno admission webhook mutates dns_config with ndots=2 + spec[0].template[0].spec[0].container[0].image, # KEEL_IGNORE_IMAGE — Keel manages tag updates + spec[0].template[0].spec[0].dns_config, # KYVERNO_LIFECYCLE_V1: Kyverno admission webhook mutates dns_config with ndots=2 + metadata[0].annotations["keel.sh/match-tag"], # Kyverno actively strips this legacy annotation + metadata[0].annotations["kubernetes.io/change-cause"], # Keel writes this on each auto-upgrade + metadata[0].annotations["deployment.kubernetes.io/revision"], # K8s increments this on every rollout + spec[0].template[0].metadata[0].annotations["keel.sh/update-time"], # KEEL_LIFECYCLE_V1 — Keel writes on update ] } spec {