Skip to content

feat(cilium): release the homogeneous-device rollout gate - #3035

Merged
devantler merged 6 commits into
mainfrom
claude/release-cilium-rollout-gate-3028
Aug 9, 2026
Merged

feat(cilium): release the homogeneous-device rollout gate#3035
devantler merged 6 commits into
mainfrom
claude/release-cilium-rollout-gate-3028

Conversation

@devantler

@devantler devantler commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Why

The Cilium rollout gate reached its 14-day hard-fail bound and has been failing every prod deploy. It suppresses ksail cluster update — the pipeline's only Talos machine-config sync — so machine config in Git has been diverging from the nodes, and #2922/#2938 sat blocked behind it.

The rollout it was gating is now finished. All nine agents run the widened device set at the current DaemonSet generation, stepped one node at a time and verified individually: every node kept a private primary address, and the fleet reports zero stale pods and zero non-private InternalIPs.

What

1. Releases the gate. Removes the two temporary overrides the component carried only for the operator-stepped rollout — updateStrategy: OnDelete and the Helm spec.upgrade.disableWait handoff. The DaemonSet returns to the chart's normal rolling update; every agent is already at the current template, so this rolls nothing. Removing OnDelete is precisely what releases the gate (the guard computes it as component referenced AND component carries type: OnDelete). The component reference stays, so the widened device set stays.

2. Holds Kubernetes at the running version, so the resumed sync upgrades the OS alone. The gate suppressed machine-config sync long enough for Renovate to queue two upgrades behind it — Kubernetes v1.36.3 and Talos v1.13.7. With both pins forward, the first deploy would roll one fleet-wide upgrade carrying both, across 8 of 9 nodes. This deployment rolls Kubernetes and OS upgrades separately, so Kubernetes is held at v1.36.2 and Renovate's existing bump PR becomes the reviewed second step.

What merging this actually does

The next deploy performs an in-place rolling Talos upgrade to v1.13.7 — 8 of 9 nodes, one at a time, each rebooting. Worth knowing before it runs:

  • 9 PDBs currently allow zero disruptions: 5 Longhorn instance-manager pods (the classic cause of a stalled Talos drain) and 4 single-replica CNPG primaries (backstage, coroot, umami, wedding), which take brief downtime as their node reboots.
  • prod-worker-1 already runs Kubernetes v1.36.3, so the hold moves that one node back a patch release until the follow-up returns it.

Fixes #3028

Unblocks the merge queue: a merge_group deploy currently fails at this gate and evicts the PR, so #3032 and #3034 cannot land until this merges.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Deployment

    • Completed the Cilium homogeneous-device rollout across production nodes.
    • Restored standard rolling updates and normal autoscaling behavior after deployment revisions are confirmed ready.
    • Improved safeguards for staged rollouts and post-deployment recovery.
  • Configuration

    • Kubernetes production version is temporarily pinned to v1.36.2 while the Talos upgrade proceeds separately.
  • Documentation

    • Updated deployment and rollback guidance to reflect the completed rollout, verification steps, and support for newly added nodes.
  • Tests

    • Expanded validation for rollout sequencing, autoscaler restoration, and completed production rollout behavior.

All nine Cilium agents now run the widened device set ("en+ eth+") at the
current DaemonSet generation, verified per node: each kept a private
primary address (10.0.1.x) and the fleet reports zero stale pods and zero
non-private InternalIPs.

Remove the temporary operator-stepping overrides the component carried for
the rollout — `updateStrategy: OnDelete` and the Helm
`spec.upgrade.disableWait` handoff — so the DaemonSet returns to the
chart's normal rolling update. Every agent is already at the current
template, so this rolls nothing.

Removing the OnDelete override is what releases the deploy gate: the guard
computes it as the component being referenced AND the component carrying
`type: OnDelete`. The component reference stays, so the widened device set
stays. `ksail cluster update` therefore resumes on the next deploy, ending
the 14-day machine-config sync suppression that had reached its hard-fail
bound and was blocking every prod deploy.

Drop the activation marker with it, and describe the component's current
state rather than the rollout that produced it.

Fixes #3028
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

⚠️MegaLinter analysis: Success with warnings

⚠️ BASH / bash-exec - 6 errors
Results of bash-exec linter (version 5.3.9)
See documentation on https://megalinter.io/9.6.0/descriptors/bash_bash_exec/
-----------------------------------------------

✅ [SUCCESS] scripts/dr-rebuild-supersession-guard.sh
❌ [ERROR] scripts/ghcr-auth-lib.sh
    Error: File:[scripts/ghcr-auth-lib.sh] is not executable

✅ [SUCCESS] scripts/guard-cilium-homogeneous-device-rollout.sh
✅ [SUCCESS] scripts/guard-shared-publish-workflow-pin.sh
✅ [SUCCESS] scripts/megalinter-scan-counts.sh
✅ [SUCCESS] scripts/normalize-sarif-paths.sh
❌ [ERROR] scripts/refresh-flux-ghcr-auth-safety.sh
    Error: File:[scripts/refresh-flux-ghcr-auth-safety.sh] is not executable

✅ [SUCCESS] scripts/refresh-flux-ghcr-auth.sh
✅ [SUCCESS] scripts/report-cilium-rollout-gate-suppression.sh
✅ [SUCCESS] scripts/run-ksail-prod-with-pull-auth.sh
✅ [SUCCESS] scripts/summarize-sarif-findings.sh
✅ [SUCCESS] scripts/tests/test-cilium-bandwidth-manager-component.sh
✅ [SUCCESS] scripts/tests/test-cilium-homogeneous-devices-activation.sh
✅ [SUCCESS] scripts/tests/test-cilium-homogeneous-devices-autoscaler-gate.sh
✅ [SUCCESS] scripts/tests/test-cilium-homogeneous-devices-flux-wait.sh
✅ [SUCCESS] scripts/tests/test-cilium-mutual-auth-policy-regressions.sh
✅ [SUCCESS] scripts/tests/test-cilium-mutual-auth-policy.sh
✅ [SUCCESS] scripts/tests/test-cilium-rollout-gate-suppression-signal.sh
✅ [SUCCESS] scripts/tests/test-crossplane-sync-exporter.sh
✅ [SUCCESS] scripts/tests/test-dr-rebuild-supersession-guard.sh
✅ [SUCCESS] scripts/tests/test-github-config-role-activation-parity.sh
✅ [SUCCESS] scripts/tests/test-kyverno-admission-vpa.sh
❌ [ERROR] scripts/tests/test-megalinter-scan-counts-ignorefile.sh
    Error: File:[scripts/tests/test-megalinter-scan-counts-ignorefile.sh] is not executable

❌ [ERROR] scripts/tests/test-normalize-sarif-paths.sh
    Error: File:[scripts/tests/test-normalize-sarif-paths.sh] is not executable

✅ [SUCCESS] scripts/tests/test-openbao-oidc-role.sh
❌ [ERROR] scripts/tests/test-opencost-usage-scraper.sh
    Error: File:[scripts/tests/test-opencost-usage-scraper.sh] is not executable

❌ [ERROR] scripts/tests/test-refresh-flux-ghcr-auth-safety.sh
    Error: File:[scripts/tests/test-refresh-flux-ghcr-auth-safety.sh] is not executable

✅ [SUCCESS] scripts/tests/test-restrict-tenant-secret-stores.sh
✅ [SUCCESS] scripts/tests/test-summarize-sarif-findings.sh
✅ [SUCCESS] scripts/tests/test-verify-published-evidence.sh
✅ [SUCCESS] scripts/update-vendored-operators.sh
✅ [SUCCESS] scripts/validate-alert-coverage.sh
✅ [SUCCESS] scripts/verify-published-evidence.sh
✅ [SUCCESS] scripts/wait-for-platform-flux-revision.sh
⚠️ REPOSITORY / checkov - 12 errors
2026-08-09 19:06:41,789 [MainThread  ] [ERROR]  YAML error parsing k8s/bases/infrastructure/controllers/kubevirt/kubevirt-operator.yaml: expected a single document in the stream
  in "<unicode string>", line 2, column 1
but found another document
  in "<unicode string>", line 9, column 1
cloudformation scan results:

Passed checks: 0, Failed checks: 0, Skipped checks: 0, Parsing errors: 1

kubernetes scan results:

Passed checks: 1972, Failed checks: 12, Skipped checks: 30

Check: CKV_K8S_35: "Prefer using secrets as files over secrets as environment variables"
	FAILED for resource: Deployment.minio.minio
	File: /k8s/providers/docker/infrastructure/controllers/minio/deployment.yaml:12-104
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-33

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_35: "Prefer using secrets as files over secrets as environment variables"
	FAILED for resource: Job.minio.minio-create-bucket
	File: /k8s/providers/docker/infrastructure/controllers/minio/job.yaml:4-76
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-33

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_25: "Minimize the admission of containers with added capability"
	FAILED for resource: Deployment.kube-system.coredns
	File: /k8s/providers/docker/infrastructure/controllers/coredns/deployment.yaml:2-146
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-24

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_11: "CPU limits should be set"
	FAILED for resource: Deployment.kube-system.coredns
	File: /k8s/providers/docker/infrastructure/controllers/coredns/deployment.yaml:2-146
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-10

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_40: "Containers should run as a high UID to avoid host conflict"
	FAILED for resource: Job.userns-longhorn-smoke.userns-longhorn-smoke
	File: /k8s/providers/hetzner/apps/userns-longhorn-smoke/job.yaml:5-154
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-37

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_35: "Prefer using secrets as files over secrets as environment variables"
	FAILED for resource: CronJob.umami.umami-provision-tenants
	File: /k8s/bases/apps/umami/cron-job.yaml:44-318
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-33

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_22: "Use read-only filesystem for containers where possible"
	FAILED for resource: CronJob.umami.umami-provision-tenants
	File: /k8s/bases/apps/umami/cron-job.yaml:44-318
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-21

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_40: "Containers should run as a high UID to avoid host conflict"
	FAILED for resource: Job.openbao.vault-config
	File: /k8s/bases/infrastructure/vault-config/job.yaml:36-1200
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-37

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_40: "Containers should run as a high UID to avoid host conflict"
	FAILED for resource: CronJob.openbao.vault-snapshot
	File: /k8s/bases/infrastructure/vault-backup/cron-job.yaml:23-197
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-37

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_40: "Containers should run as a high UID to avoid host conflict"
	FAILED for resource: Job.openbao.vault-snapshot-init
	File: /k8s/bases/infrastructure/vault-backup/job.yaml:23-191
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-37

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_38: "Ensure that Service Account Tokens are only mounted where necessary"
	FAILED for resource: CronJob.observability.cnpg-degraded-alert
	File: /k8s/bases/infrastructure/controllers/coroot/cron-job-cnpg-degraded-alert.yaml:56-202
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-35

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_35: "Prefer using secrets as files over secrets as environment variables"
	FAILED for resource: CronJob.observability.cnpg-degraded-alert
	File: /k8s/bases/infrastructure/controllers/coroot/cron-job-cnpg-degraded-alert.yaml:56-202
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-33

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
github_actions scan results:

Passed checks: 112, Failed checks: 0, Skipped checks: 0
⚠️ SPELL / cspell - 3103 errors
"descheduler",
        "descheduling",
        "desynchronising",
        "devantler",
        "diffable",
        "dispositioned",
        "distroless",
        "dockerconfigjson",
        "docstrings",
        "dorny",
        "dpkg",
        "drainable",
        "emptydir",
        "endgroup",
        "entrys",
        "envsubst",
        "esac",
        "etcdctl",
        "evictable",
        "extensionless",
        "externalsecret",
        "externalsecrets",
        "fanout",
        "featureflagsource",
        "fleetdm",
        "fluxinstance",
        "fromdateiso",
        "gatewayapi",
        "generatable",
        "generatingpolicies",
        "genkey",
        "gethomepage",
        "gitops",
        "gocritic's",
        "golangci",
        "gosec",
        "grjtvs",
        "growfs",
        "growpart",
        "healthchecks",
        "healthz",
        "helmrelease",
        "helmreleases",
        "helmv",
        "homelab",
        "hostnames",
        "httproute",
        "idempotently",
        "ignorefile",
        "imagetools",
        "imagevalidatingpolicy",
        "imranismail",
        "injective",
        "inspectable",
        "iscsi",
        "italicise",
        "ivpol",
        "keylessly",
        "keypair",
        "kprobes",
        "kptr",
        "krew",
        "ksail",
        "ksail's",
        "ksailcd",
        "kubeconfig",
        "kubeconform",
        "kubeconform's",
        "kubelet",
        "kubelet's",
        "kubelets",
        "kubelogin",
        "kubescape",
        "kubespan",
        "kubevirt",
        "kubevuln",
        "kustomization",
        "kustomizations",
        "kyverno",
        "letsencrypt",
        "libc",
        "libgnutls",
        "lintable",
        "livez",
        "loadtester",
        "locationless",
        "luks",
        "lycheeignore",
        "machineconfig",
        "materialise",
        "materialised",
        "materialises",
        "maxage",
        "maxbackup",
        "maxsize",
        "maxx",
        "metacharacters",
        "microtime",
        "misconfig",
        "misconfigs",
        "misordered",
        "mistargeted",
        "mktemp",
        "mlock",
        "mutatingpolicies",
        "mutatingwebhookconfigurations",
        "myapp",
        "najsk",
        "neighbour",
        "nenv",
        "netlink",
        "netpol",
        "netpols",
        "neutralises",
        "neutralising",
        "nextjs",
        "nftables",
        "nilnil",
        "nobuckets",
        "nodepod",
        "nodeport",
        "nolint",
        "nonroot",
        "normalisation",
        "normalised",
        "normalises",
        "normalising",
        "nosec",
        "nullglob",
        "ocirepository",
        "openbao",
        "opencost",
        "openfeature",
        "oras",
        "overprovisioning",
        "parallelised",
        "pasteable",
        "permissioning",
        "pipefail",
        "policyignore",
        "policyreports",
        "portforward",
        "preemptible",
        "preservingly",
        "prioritisable",
        "prioritisation",
        "prioritised",
        "privesc",
        "providerconfigs",
        "pseudonymization",
        "pseudonymized",
        "pseudonymizes",
        "publishapp",
        "publishprovider",
        "pushsecret",
        "pushsecrets",
        "pycache",
        "randomises",
        "rdqwpktr",
        "readyz",
        "reassertions",
        "recognisable",
        "recognisably",
        "recognise",
        "recognised",
        "recolour",
        "reconverges",
        "refreshfluxghcrauth",
        "regenerable",
        "releaserc",
        "rematerialise",
        "rematerialised",
        "replicaset",
        "repoint",
        "repointed",
        "repoints",
        "repositoryrulesets",
        "resizer",
        "restrictor",
        "retabbed",
        "retarget",
        "rmem",
        "rolebindings",
        "rollouts",
        "rshared",
        "sanitised",
        "sanitiser",
        "sanitising",
        "sarif",
        "scheckov",
        "schedulability",
        "schedulable",
        "scopeable",
        "scopeless",
        "seccomp",
        "secretbox",
        "secretstore",
        "seedable",
        "serialised",
        "serverside",
        "serviceaccount",
        "serviceaccounts",
        "sgdisk",
        "shellcheck",
        "shfmt",
        "shopt",
        "siderolabs",
        "siderolink",
        "sigstore",
        "skmde",
        "slurpfile",
        "sngle",
        "specnull",
        "spiffe",
        "srole",
        "startswith",
        "statefulset",
        "statemanager",
        "stdlib",
        "storageclass",
        "subtest",
        "summarised",
        "surfaceless",
        "syft",
        "syscall",
        "sysctls",
        "talosconfig",
        "talosctl",
        "tanzu",
        "templatesyncignore",
        "thresholded",
        "tlsv",
        "tmpl",
        "tostring",
        "tracepoints",
        "trixie",
        "trueish",
        "trustd",
        "ture",
        "uids",
        "umami",
        "umami's",
        "unablated",
        "unclickable",
        "uncompilable",
        "uncordon",
        "uncordoned",
        "undecoded",
        "undercounts",
        "undispositioned",
        "unevidenced",
        "unexcepted",
        "unfiled",
        "ungated",
        "ungenerated",
        "unifi",
        "uninvoked",
        "unmarshalling",
        "unmarshals",
        "unmodelled",
        "unparseable",
        "unprovisioned",
        "unrecognisable",
        "unrecognised",
        "unrepresentable",
        "unreviewed",
        "unroutable",
        "unrun",
        "unshippable",
        "unskipped",
        "untrackable",
        "unvalidated",
        "unwired",
        "upbound",
        "updatekeys",
        "upjet",
        "upstreaming",
        "urlencode",
        "userinfo",
        "userns",
        "ushfn",
        "validatable",
        "validatealertcoverage",
        "validatingwebhookconfigurations",
        "vcunav",
        "velero",
        "virt",
        "volumesnapshot",
        "vpas",
        "vulnerabilitymanifests",
        "vulnerabilitymanifestsummary",
        "vulns",
        "vxlan",
        "wffc",
        "wgpolicyk",
        "wildcarded",
        "wlid",
        "wmem",
        "workloadconfigurationscans",
        "workloadconfigurationscansummary",
        "worktrees",
        "yannh",
        "yubikey",
        "yzwvjjmcyfnl",
        "zizmor"
    ]
}


You can also copy-paste megalinter-reports/.cspell.json at the root of your repository

(Truncated to last 6666 characters out of 551455)
⚠️ COPYPASTE / jscpd - 185 errors
tokens)
   scripts/tests/refresh-flux-ghcr-auth/rollout_safety_test.go [468:57 - 485:5]
Clone found (go)
 - scripts/tests/refresh-flux-ghcr-auth/rollout_safety_test.go [492:77 - 508:11] (17 lines, 118 tokens)
   scripts/tests/refresh-flux-ghcr-auth/rollout_safety_test.go [519:110 - 535:11]
Clone found (bash)
 - scripts/tests/test-cilium-bandwidth-manager-component.sh [9:1 - 54:2] (46 lines, 202 tokens)
   scripts/tests/test-cilium-homogeneous-devices-activation.sh [9:1 - 54:2]
Clone found (bash)
 - scripts/tests/test-cilium-bandwidth-manager-component.sh [52:5 - 72:2] (21 lines, 67 tokens)
   scripts/tests/test-cilium-homogeneous-devices-activation.sh [80:23 - 100:2]
Clone found (bash)
 - scripts/tests/test-cilium-bandwidth-manager-component.sh [54:1 - 72:2] (19 lines, 65 tokens)
   scripts/tests/test-opencost-usage-scraper.sh [15:1 - 33:2]
Clone found (bash)
 - scripts/tests/test-cilium-mutual-auth-policy.sh [28:29 - 41:10] (14 lines, 78 tokens)
   scripts/tests/test-cilium-mutual-auth-policy.sh [79:33 - 92:10]
Clone found (bash)
 - scripts/tests/test-cilium-mutual-auth-policy.sh [98:33 - 107:54] (10 lines, 57 tokens)
   scripts/tests/test-cilium-mutual-auth-policy.sh [118:32 - 127:54]
Clone found (bash)
 - scripts/tests/test-crossplane-sync-exporter.sh [56:3 - 118:11] (63 lines, 338 tokens)
   scripts/tests/test-opencost-usage-scraper.sh [22:45 - 84:11]
Clone found (bash)
 - scripts/tests/test-refresh-flux-ghcr-auth-safety.sh [177:5 - 185:51] (9 lines, 76 tokens)
   scripts/tests/test-refresh-flux-ghcr-auth-safety.sh [186:5 - 194:51]
Clone found (python)
 - scripts/tests/test_validate_homepage_bookmarks.py [46:57 - 54:54] (9 lines, 58 tokens)
   scripts/tests/test_validate_homepage_bookmarks.py [100:53 - 109:54]
Clone found (go)
 - scripts/validate-dr-signing/main_test.go [1007:13 - 1015:2] (9 lines, 51 tokens)
   scripts/validate-dr-signing/main_test.go [1075:12 - 1083:2]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [244:50 - 249:24] (6 lines, 103 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [756:31 - 761:24]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [276:14 - 282:4] (7 lines, 115 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [603:43 - 609:4]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [302:13 - 311:7] (10 lines, 158 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [828:18 - 837:7]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [311:1 - 316:8] (6 lines, 93 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [838:1 - 843:8]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [388:5 - 393:2] (6 lines, 82 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [574:8 - 579:9]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [389:1 - 399:23] (11 lines, 220 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [666:60 - 677:3]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [393:15 - 404:2] (12 lines, 185 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [494:17 - 505:2]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [440:15 - 451:12] (12 lines, 264 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [649:1 - 662:3]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [503:2 - 509:19] (7 lines, 89 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [688:7 - 694:19]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [503:2 - 509:33] (7 lines, 103 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1013:58 - 1019:33]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [503:2 - 509:4] (7 lines, 74 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1126:5 - 1132:4]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [596:30 - 601:8] (6 lines, 50 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [623:44 - 628:8]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [710:22 - 716:2] (7 lines, 135 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1212:22 - 1218:2]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [951:33 - 959:11] (9 lines, 118 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [963:130 - 971:11]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [1158:47 - 1163:2] (6 lines, 166 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1238:46 - 1243:2]
Clone found (go)
 - scripts/validate-flux-verify/instance_test.go [109:62 - 126:31] (18 lines, 57 tokens)
   scripts/validate-flux-verify/instance_test.go [161:57 - 178:31]
Clone found (go)
 - scripts/validate-flux-verify/instance_test.go [109:62 - 128:35] (20 lines, 62 tokens)
   scripts/validate-flux-verify/instance_test.go [198:55 - 217:26]
Clone found (python)
 - scripts/validate-naming.py [126:52 - 132:25] (7 lines, 53 tokens)
   scripts/validate-naming.py [171:82 - 177:29]
┌────────┬────────────────┬─────────────┬──────────────┬──────────────┬──────────────────┬───────────────────┐
│ Format │ Files analyzed │ Total lines │ Total tokens │ Clones found │ Duplicated lines │ Duplicated tokens │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ bash   │ 37             │ 11411       │ 44098        │ 20           │ 295 (2.59%)      │ 1797 (4.08%)      │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ go     │ 36             │ 29819       │ 180248       │ 99           │ 804 (2.70%)      │ 7637 (4.24%)      │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ python │ 4              │ 807         │ 5606         │ 2            │ 14 (1.73%)       │ 111 (1.98%)       │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ txt    │ 57             │ 3378        │ 109125       │ 64           │ 2417 (71.55%)    │ 80219 (73.51%)    │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ Total: │ 134            │ 45415       │ 339077       │ 185          │ 3530 (7.77%)     │ 89764 (26.47%)    │
└────────┴────────────────┴─────────────┴──────────────┴──────────────┴──────────────────┴───────────────────┘
Found 185 clones.
HTML report saved to megalinter-reports/copy-paste/jscpd-report.html
ERROR: jscpd found too many duplicates (7.8%) over threshold (0.0%)
time: 1.34s

(Truncated to last 6666 characters out of 39333)
⚠️ MARKDOWN / markdownlint - 62 errors
; Actual: 838]
AGENTS.md:24 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
AGENTS.md:101:401 error MD013/line-length Line length [Expected: 400; Actual: 1769]
AGENTS.md:105:401 error MD013/line-length Line length [Expected: 400; Actual: 1126]
AGENTS.md:106:401 error MD013/line-length Line length [Expected: 400; Actual: 1447]
AGENTS.md:159:401 error MD013/line-length Line length [Expected: 400; Actual: 649]
AGENTS.md:161:401 error MD013/line-length Line length [Expected: 400; Actual: 971]
AGENTS.md:188:401 error MD013/line-length Line length [Expected: 400; Actual: 970]
AGENTS.md:210:401 error MD013/line-length Line length [Expected: 400; Actual: 1510]
AGENTS.md:278:401 error MD013/line-length Line length [Expected: 400; Actual: 1016]
AGENTS.md:279:401 error MD013/line-length Line length [Expected: 400; Actual: 491]
AGENTS.md:280:401 error MD013/line-length Line length [Expected: 400; Actual: 468]
AGENTS.md:286:401 error MD013/line-length Line length [Expected: 400; Actual: 532]
AGENTS.md:288:401 error MD013/line-length Line length [Expected: 400; Actual: 523]
AGENTS.md:291:401 error MD013/line-length Line length [Expected: 400; Actual: 613]
AGENTS.md:292:401 error MD013/line-length Line length [Expected: 400; Actual: 714]
AGENTS.md:296:401 error MD013/line-length Line length [Expected: 400; Actual: 502]
AGENTS.md:300:401 error MD013/line-length Line length [Expected: 400; Actual: 441]
AGENTS.md:305:401 error MD013/line-length Line length [Expected: 400; Actual: 427]
AGENTS.md:408:401 error MD013/line-length Line length [Expected: 400; Actual: 1139]
AGENTS.md:410:401 error MD013/line-length Line length [Expected: 400; Actual: 1240]
AGENTS.md:426:401 error MD013/line-length Line length [Expected: 400; Actual: 1137]
AGENTS.md:437:401 error MD013/line-length Line length [Expected: 400; Actual: 790]
AGENTS.md:442:401 error MD013/line-length Line length [Expected: 400; Actual: 515]
CLAUDE.md:1 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "@AGENTS.md"]
docs/dr/alerting.md:226:28 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:22:389 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:23:264 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:27:35 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:27:161 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:27:239 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:114 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Custody recommendations"]
docs/dr/crypto-custody.md:245 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Custody recommendations"]
docs/dr/crypto-custody.md:251 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "What to do if it leaks"]
docs/dr/crypto-custody.md:258 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "What to do if it is *lost* (no..."]
docs/dr/restore-drill.md:42 error MD028/no-blanks-blockquote Blank line inside blockquote
docs/dr/runbook.md:23:102 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/runbook.md:23:487 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/runbook.md:34 error MD028/no-blanks-blockquote Blank line inside blockquote
docs/dr/runbook.md:41 error MD028/no-blanks-blockquote Blank line inside blockquote
docs/dr/runbook.md:50 error MD028/no-blanks-blockquote Blank line inside blockquote
docs/dr/runbook.md:489:92 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/spire-server-ha.md:93 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/dr/velero-cnpg.md:11 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/dr/velero-cnpg.md:56:78 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/velero-cnpg.md:56:166 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/velero-cnpg.md:57:78 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/velero-cnpg.md:57:227 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/velero-cnpg.md:58:78 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/velero-cnpg.md:58:166 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/github-management.md:38:401 error MD013/line-length Line length [Expected: 400; Actual: 419]
docs/github-management.md:40:401 error MD013/line-length Line length [Expected: 400; Actual: 522]
docs/node-autoscaling.md:14 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/oidc-kubectl.md:95 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/runtime-security.md:114 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/rwx-storage.md:9 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/unifi-management.md:14 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/unifi-management.md:62 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
README.md:116:401 error MD013/line-length Line length [Expected: 400; Actual: 540]
README.md:237:32 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
README.md:237:36 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]

(Truncated to last 6666 characters out of 6911)
⚠️ REPOSITORY / trivy - 1 error
astructure/vertical-pod-autoscalers/hubble-relay.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: Deployment
  11 └     name: hubble-relay
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/hubble-ui.yaml (kubernetes)
=========================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'hubble-ui' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/hubble-ui.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: Deployment
  11 └     name: hubble-ui
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/metrics-server.yaml (kubernetes)
==============================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'metrics-server' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/metrics-server.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: Deployment
  11 └     name: metrics-server
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/snapshot-controller.yaml (kubernetes)
===================================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'snapshot-controller' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/snapshot-controller.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: Deployment
  11 └     name: snapshot-controller
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/spire-agent.yaml (kubernetes)
===========================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'spire-agent' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/spire-agent.yaml:9-13
────────────────────────────────────────
   9 ┌ spec:
  10 │   targetRef:
  11 │     apiVersion: apps/v1
  12 │     kind: DaemonSet
  13 └     name: spire-agent
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/spire-server.yaml (kubernetes)
============================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'spire-server' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/spire-server.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: StatefulSet
  11 └     name: spire-server
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/tetragon-operator.yaml (kubernetes)
=================================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'tetragon-operator' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/tetragon-operator.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: Deployment
  11 └     name: tetragon-operator
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/tetragon.yaml (kubernetes)
========================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'tetragon' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/tetragon.yaml:9-13
────────────────────────────────────────
   9 ┌ spec:
  10 │   targetRef:
  11 │     apiVersion: apps/v1
  12 │     kind: DaemonSet
  13 └     name: tetragon
────────────────────────────────────────



📣 Notices:
  - Version 0.73.0 of Trivy is now available, current version is 0.71.2

To suppress version checks, run Trivy scans with the --skip-version-check flag

(Truncated to last 6666 characters out of 340601)

✅ Linters with no issues

actionlint, betterleaks, git_diff, golangci-lint, grype, jsonlint, lychee, osv-scanner, prettier, prettier, revive, secretlint, shellcheck, shfmt, syft, trivy-sbom, trufflehog, v8r, v8r, yamllint, zizmor

Notices

📣 MegaLinter 9.5.0 is out! Discover the new features and security recommendations in the release announcement. (Skip this info by defining SECURITY_SUGGESTIONS: false)

See detailed reports in MegaLinter artifacts

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

…ease

Releasing the rollout gate re-enables `ksail cluster update`, and the gate
suppressed that sync long enough for Renovate to queue two upgrades behind
it: Kubernetes v1.36.3 and Talos v1.13.7. With both pins forward the first
deploy would roll one fleet-wide upgrade carrying the OS and Kubernetes at
once, across eight of nine nodes.

This deployment rolls those separately. Hold Kubernetes at v1.36.2 — the
version eight of the nine nodes are already running — so the resumed sync
performs the Talos OS upgrade alone. Renovate tracks this pin and does not
automerge it, so its existing bump PR is the reviewed second step once the
OS upgrade has settled.

prod-worker-1 already runs v1.36.3, so it is the one node this pin moves
backward by a patch release before the follow-up returns it.
Three guards pinned the transitional state, so completing the rollout made
them red. Each now pins the completed state.

The activation test required a top-level `updateStrategy` carrying
`type: OnDelete` and a `disableWait: true` upgrade handoff. It now asserts
their ABSENCE rather than dropping the assertions: a silently reintroduced
gate would suppress the pipeline's only Talos machine-config sync again,
which is the failure that took prod deploys down for fourteen days. The
device-selection guards are untouched — they protect the datapath whatever
the rollout state.

The autoscaler-gate test copied the live component into its fixture and so
inherited whatever gate state the repository shipped (platform#3031). With
the overrides removed the fixture started inactive and its active-gate
assertions failed for the wrong reason. It now constructs the active gate
it exercises, so it keeps covering the gate no matter what the repository
currently ships.

The EKS authorization surface fingerprint moved because the rendered Cilium
HelmRelease legitimately changed. Re-approved with the measurement the
constant's own convention requires: all five roots rendered from both trees
and diffed — four byte-identical, membership unchanged, and exactly four
lines moving, all of them rollout mechanics inside one HelmRelease, none
reaching an identity, binding, policy document, or service account. The
value is CI's, because the local toolchain is a refused renderer.
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated with Claude Code

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@devantler I will review the changes.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The production Cilium rollout gate is released. Normal rolling updates and Talos machine-config synchronization resume. The deployment action restores autoscaling after Flux revision readiness. Tests verify released and active-gate states. Kubernetes is pinned to v1.36.2 during the Talos upgrade.

Changes

Cilium rollout completion

Layer / File(s) Summary
Restore normal Cilium updates
k8s/providers/hetzner/infrastructure/controllers/cilium/components/homogeneous-devices/kustomization.yaml, k8s/providers/hetzner/infrastructure/controllers/kustomization.yaml, AGENTS.md
Documentation records completed rollout status, normal rolling updates, resumed Talos synchronization, rollback guidance, and future gate activation conditions.
Release autoscaling after revision readiness
scripts/guard-cilium-homogeneous-device-rollout.sh, .github/actions/deploy-prod/action.yml, scripts/tests/test-cilium-homogeneous-devices-autoscaler-gate.sh, scripts/tests/test-cilium-homogeneous-devices-activation.sh
The guard and deploy action support autoscaler restoration after revision readiness. Tests validate call ordering, active-gate fixtures, and released production configuration.

Release baseline updates

Layer / File(s) Summary
Update release validation baselines
ksail.prod.yaml, scripts/validate-eks-ci-role-policy/main.go
Kubernetes is pinned to v1.36.2 during the Talos upgrade. The approved rendered authorization-surface measurement and fingerprint are updated.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DeployAction
  participant Flux
  participant RolloutGuard
  participant Talos
  DeployAction->>Flux: wait for exact published revision
  Flux-->>DeployAction: return revision Ready
  DeployAction->>RolloutGuard: invoke --after-revision-ready
  RolloutGuard->>RolloutGuard: restore owned autoscaler suspension
  DeployAction->>Talos: run cluster update
Loading

Possibly related issues

Possibly related PRs

Suggested labels: enhancement, kubernetes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive The PR addresses #3028 by releasing the gate and updating validation, but completion of a production deploy with Talos sync is not yet verified. Merge and verify that a production deploy completes with ksail cluster update running, then record the result.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The changes stay within #3028: gate release, Talos synchronization, documentation, autoscaler handling, and related validation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title clearly and concisely describes the main change: releasing the Cilium homogeneous-device rollout gate.
Description check ✅ Passed The description directly explains why the rollout gate is released and how the changes affect Cilium and Talos upgrades.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/release-cilium-rollout-gate-3028

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.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated with Claude Code

CodeRabbit reports Review rate limited at this head, so advancing to the next lane.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a17998a316

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

AGENTS.md is the repository's first-reference operational guide, and it
still stated that the temporary component sets `disableWait` and `OnDelete`,
that Cilium pods remain operator-stepped, and that the deploy skips
`cluster update`. With the gate released all three are false, and a stale
description here misleads exactly when it is read: during maintenance and
incident response.

State that no gate is active and that every deploy runs its Talos
machine-config sync. The guard's behaviour is retained as conditional
machinery for the next staged rollout, with the condition that actually
governs it — the component referenced AND carrying `type: OnDelete` —
written down rather than implied.
@github-code-quality

github-code-quality Bot commented Aug 9, 2026

Copy link
Copy Markdown

Code Coverage Overview

Languages: Go

Go / code-coverage/go

The overall coverage in commit c8d6692 in the claude/release-ciliu... branch is 80%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main claude/release-ciliu... c8d6692 +/-
scripts/kubesca...ridge/issues.go 99%
scripts/validat...-verify/main.go 97%
scripts/kubesca...e/exceptions.go 96%
scripts/kubesca...-bridge/main.go 93%
scripts/validat...ify/instance.go 87%
scripts/validat...signing/main.go 85%
scripts/validat...-policy/main.go 80%
scripts/generat...eptions/main.go 75%
scripts/kubesca...ridge/client.go 74%
scripts/annotat...checkov/main.go 54%

Updated August 09, 2026 19:09 UTC

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated with Claude Code

The AGENTS.md finding from the last round is fixed and its thread resolved. New head, so re-reviewing.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@devantler I will review the changes at the new head commit.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated with Claude Code

The previous review returned only an acknowledgement — no review object, no findings, and the incremental system reported it would not re-review already-reviewed commits. Escaping that with a full review.

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@devantler I will perform a full review of PR #3035.

⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 55 minutes.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated with Claude Code

CodeRabbit reports Review rate limited at this head, and both requests returned only acknowledgements with no review object. Advancing to the next lane.

Since the last Codex pass, the only change is the AGENTS.md fix for its own finding — the gate release and the Kubernetes hold are unchanged.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8da566116a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Removing the numbered runbook left a dangling reference:
report-cilium-rollout-gate-suppression.sh tells an operator to "follow step
4-5 of the runbook" in this component, and two more messages point at "the
component runbook". Those fire exactly when the gate's 7-day warning or
14-day failure does — the situation that needs the procedure most, and the
one prod was in this morning.

Restore it as forward-looking guidance for the next change to this device
set rather than a record of the completed rollout, since the gate machinery
is still here and reintroducing the two overrides is what re-arms it. Steps
4 and 5 remain the release and post-release verification the reporter names.

Comment-only: the rendered controllers root is byte-identical, so the
approved authorization surface fingerprint is untouched.
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated with Claude Code

The runbook finding is fixed and its thread resolved. New head, so re-reviewing.

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: db0c8a3bc6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated with Claude Code

Readiness

Programmatically tested. 26/26 checks green. The four gate-aware guards pass with the completed state pinned rather than deleted, and the EKS authorization surface was re-approved from CI's own render after diffing all five roots from both trees — four byte-identical, membership unchanged, four lines moving, none of them an identity, binding, policy document, or service account. The runbook restoration is comment-only and the controllers render is byte-identical to that approved measurement.

Reviewed. Codex green at this exact head (db0c8a3bc6); CodeRabbit Review rate limited at this head with no review object, after a plain review returned only an acknowledgement and a full review the same.

Exercised. The rollout this releases was executed and verified node by node: all nine agents at DaemonSet generation 26, zero stale, and zero non-private CiliumNode InternalIPs — the property the gate existed to protect. I confirmed the guard's release condition directly in guard-cilium-homogeneous-device-rollout.sh (component referenced and carrying type: OnDelete) rather than inferring it, and confirmed the autoscaler carries previous-replicas: "1" so restore_autoscaler_if_owned restores it when the gate reads inactive.

Not exercised: that the next deploy actually resumes ksail cluster update. That cannot be observed without merging, since merging is what releases the gate. Flagging the limit rather than implying I saw it.

What merging does: the merge_group deploy performs an in-place rolling Talos upgrade to v1.13.7 across 8 of 9 nodes, one at a time, each rebooting. Kubernetes stays at v1.36.2 by the hold in this PR. Nine PDBs allow zero disruptions — five Longhorn instance-manager pods and four single-replica CNPG primaries, which take brief downtime as their node reboots. Maintainer confirmed this sequencing.

@devantler
devantler marked this pull request as ready for review August 9, 2026 17:59
@devantler
devantler added this pull request to the merge queue Aug 9, 2026
The deploy that released the gate failed at its own config sync:

  waiting for cluster-autoscaler ... rollout: failed to poll for readiness:
  ... client rate limiter Wait returned an error: context deadline exceeded

The rate limiter is the symptom, not the cause. KSail's readiness check
returns not-ready for `Status.Replicas == 0`
(pkg/k8s/readiness/deployment.go), so it polls to its deadline. The
Deployment it was waiting on was held at zero replicas by the rollout gate's
own suspension: releasing the gate re-enables `ksail cluster update`, but the
suspension was only restored in the post-deploy phase — after the step that
waits on it.

Restore in a new phase between the exact-revision proof and cluster update.
Both bounds matter. Not earlier: autoscaling may not resume before the safe
artifact is deployed, which the pre-publish assertion pins. Not later: the
step that waits on the autoscaler runs before the post-deploy phase. An
active gate stays suspended in every phase, unchanged.

The post-deploy restore stays as the failure-path net, and is a no-op once
this phase has cleared the ownership marker.
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Aug 9, 2026
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated with Claude Code

New head: the first merge-queue attempt failed at ksail cluster update, and this fixes the cause. KSail's readiness check treats a zero-replica Deployment as never-ready, and the cluster-autoscaler was held at zero by this gate's own suspension — which was only restored after the step that waits on it. A third guard phase now restores it between the exact-revision proof and cluster update. Restoring at pre-publish would have been simpler but violates the existing "must not restore autoscaling before the safe artifact is deployed" assertion, so that approach was reverted rather than the assertion relaxed.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== HEAD and changed files =='
git rev-parse HEAD
git diff --name-only HEAD^ HEAD

printf '%s\n' '== Guard script outline and relevant sections =='
ast-grep outline scripts/guard-cilium-homogeneous-device-rollout.sh --items all || true
rg -n -C 8 -- '--after-revision-ready|restore_autoscaler_if_owned|suspend_autoscaler|gate_active|usage' \
  scripts/guard-cilium-homogeneous-device-rollout.sh

printf '%s\n' '== Deploy action ordering =='
ast-grep outline .github/actions/deploy-prod/action.yml --items all || true
rg -n -C 12 -- 'guard-cilium-homogeneous-device-rollout|revision|ksail cluster update|cluster-autoscaler' \
  .github/actions/deploy-prod/action.yml

printf '%s\n' '== Focused test assertions =='
ast-grep outline scripts/tests/test-cilium-homogeneous-devices-autoscaler-gate.sh --items all || true
rg -n -C 8 -- 'after-revision-ready|cluster update|revision|restore|autoscaler|guard' \
  scripts/tests/test-cilium-homogeneous-devices-autoscaler-gate.sh

printf '%s\n' '== Exact patch for relevant files =='
git diff HEAD^ HEAD -- \
  .github/actions/deploy-prod/action.yml \
  scripts/guard-cilium-homogeneous-device-rollout.sh \
  scripts/tests/test-cilium-homogeneous-devices-autoscaler-gate.sh

Length of output: 40699


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Restore and readiness helper implementation =='
sed -n '294,370p' scripts/guard-cilium-homogeneous-device-rollout.sh

printf '%s\n' '== Full guard phase dispatch =='
sed -n '385,440p' scripts/guard-cilium-homogeneous-device-rollout.sh

printf '%s\n' '== Deploy action conditions around revision, restore, and cluster update =='
sed -n '206,265p' .github/actions/deploy-prod/action.yml

printf '%s\n' '== Focused test fixture: kubectl scale/status emulation =='
sed -n '130,275p' scripts/tests/test-cilium-homogeneous-devices-autoscaler-gate.sh

printf '%s\n' '== Search for the guard phases at every call site =='
rg -n -C 4 --glob '*.yml' --glob '*.yaml' --glob '*.sh' \
  'guard-cilium-homogeneous-device-rollout\.sh (?:--before-publish|--after-revision-ready|--after-deploy)' \
  .

Length of output: 17073


@devantler I found no blocking issues.

The new phase restores only a suspension owned by the released gate. It runs after the exact Flux revision is Ready and before ksail cluster update. It waits for the remembered replica count before it clears the ownership annotations.

An active OnDelete gate still calls suspend_autoscaler in this phase. A restore failure prevents the later cluster_update step from running.

The focused test covers the required ordering, restoration before cluster update, ownership-marker removal, and the no-op post-deploy restore path. I did not execute repository scripts because the sandbox policy prohibits executing repository files.

⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@devantler
devantler added this pull request to the merge queue Aug 9, 2026
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated with Claude Code

CodeRabbit's commit status reads Review completed at this head but it has produced no review object and no inline comments in ~25 minutes, so the lane has not delivered. Advancing.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c8d669236f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +114 to +115
# the post-deploy guard restores the recorded autoscaler replica count.
# Verify the FIRST autoscaler-created node afterwards like a stepped one —

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore autoscaling before cluster update in the runbook

For the next stepped rollout, this release instruction still says the post-deploy guard restores the autoscaler after ksail cluster update, but the new --after-revision-ready phase was added precisely because KSail waits indefinitely on the zero-replica autoscaler during that update. Following this canonical runbook would therefore reproduce the failed release ordering; direct operators to run the new phase after the exact-revision readiness proof and before cluster update.

AGENTS.md reference: AGENTS.md:L3-L5

Useful? React with 👍 / 👎.

shell: bash
env:
HCLOUD_TOKEN: ${{ inputs.hcloud-token }}
run: ./scripts/guard-cilium-homogeneous-device-rollout.sh --after-revision-ready

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep scale-up fenced until its machine template is refreshed

When a future gate is released while the cluster is below its node limit and pending or CapacityBuffer demand exists, this call starts Cluster Autoscaler before the following cluster update refreshes its machine template. Because the gate may have suppressed that sync for days, the autoscaler can provision a server from stale Talos or pull-credential data in this gap, while the pre-publish bridge verified only nodes that already existed; refresh the template before allowing scale-up, or keep scale-up disabled while satisfying KSail's readiness check.

AGENTS.md reference: AGENTS.md:L187-L188

Useful? React with 👍 / 👎.

# the very deploy that releases the gate. Restoring in --after-deploy is too
# late for that wait, and restoring in --before-publish would do it before the
# safe artifact is deployed, which the gate deliberately forbids.
restore_autoscaler_if_owned

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle a remembered zero replica count before cluster update

If the autoscaler was already manually scaled to zero when a gate was activated, suspend_autoscaler accepts and records previous_replicas=0; this release phase then “restores” zero and clears the ownership marker. The immediately following cluster update consequently sees the same zero-replica Deployment that this patch says KSail treats as never-ready, reproducing the timeout while losing the state needed for a retry. Preserve the manual suspension by skipping the update in this case, or avoid treating zero as a releasable owned count.

AGENTS.md reference: AGENTS.md:L210-L210

Useful? React with 👍 / 👎.

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

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

The Cilium rollout gate has reached its 14-day hard-fail bound and is blocking prod deploys

1 participant