Skip to content

refactor(scripts): move the CI half to scripts/ci, index it with task - #2061

Merged
Smana merged 30 commits into
mainfrom
worktree-scripts-restructure
Sep 21, 2026
Merged

Smana merged 30 commits into
mainfrom
worktree-scripts-restructure

Conversation

@Smana

@Smana Smana commented Sep 18, 2026

Copy link
Copy Markdown
Owner

scripts/ held 55 flat executables for four audiences that share nothing but a parent directory: the gates CI runs, the test suites, day-2 ops tooling, and config drivers that terramate shells out to during an apply. This PR moves the CI half into scripts/ci/. It indexes every entry point with go-task, and replaces ci.yaml's hand-maintained suite list with a runner that discovers suites. PR 1 of 3.

flowchart LR
  subgraph before["before"]
    A["ci.yaml · 526 lines<br/>239 comment"] -->|"11 list entries +<br/>2 named steps"| B["scripts/<br/>55 flat files"]
  end
  subgraph after["after (PR 1)"]
    C["ci.yaml · 413 lines<br/>145 comment"] -->|"task ci:test<br/>task ci:validate"| D["taskfile.yaml"]
    H["a human"] -->|"task check<br/>(any directory)"| D
    D --> E["scripts/ci/<br/>gates"]
    D --> T["scripts/ci/tests/<br/>run.sh discovers"]
    D -.->|"PR 2"| F["ops/"]
    D -.->|"PR 3"| G["provision/"]
  end
  before ==> after

  classDef new fill:#d4edda,stroke:#28a745
  classDef pending fill:#f8f9fa,stroke:#adb5bd,stroke-dasharray:4
  class C,D,E,T new
  class F,G pending
Loading

📋 Design

This PR delivers PR 1 of the plan: scripts/ci/, the taskfile, and the gates.

What changed

scripts/ci/ 8 validators plus flux-schema/
scripts/ci/tests/run.sh Discovers test-*.sh and test-*.py, honours # requires:, and reports exit 77 as SKIP. A skip is always a printed line. Zero suites found is a failure.
taskfile.yaml + scripts/tasks.yaml task --list is the index. task check runs all six scripts/ci gates CI runs. Every task is a one-line script call, so scripts stay liftable. Tasks work from any directory.
test-script-paths.sh New gate: every script's self-resolved root, source target and suite subject still resolves.
ci.yaml The suite list and 94 comment lines are gone. Job names are unchanged, so the required checks on main are untouched.
mise.toml task = "3.53.1", an exact pin, so it goes through Renovate's release-age gate like every other tool.

Rebased onto #2057/#2058. main added test-ci-notify-main-broken.sh this week, together with the hand-written ci.yaml step it needed to run. That is exactly the "second act to forget" this PR removes. The suite now sits in scripts/ci/tests/, and its step is deleted because run.sh discovers it. Its missing-pyyaml skip used to exit 0, which the runner would have reported as PASS. It now exits 77 and shows as SKIP.

Review carefully: a move breaks scripts from the inside

42 of the 55 scripts compute paths from where they sit. The paths gate shipped before anything moved, and it is necessary, not sufficient. Reviews found breaks it could not see:

Break Why the gate missed it
check-substitution.py resolved its repo root one level short. It printed 0 Flux Kustomization(s) checked and exited 0. It is gate 1/6 of validate-manifests.sh. a Python parents[N]
test-no-secret-argv.sh, the credential-on-argv guard, scanned 0 files and still printed ok. a path passed to a function
That same guard used find -maxdepth 1. The move took 28 scripts out of its scan. a depth limit, not a path
The new notifier suite's ../.github depth a data path, not a root or source
gen-catalog.sh, validate-alertmanager-templates.sh, a bare directory reference a CLI argument, a Python string in a heredoc, no suffix

Each of these reported green. So the fix wave made every guard on this branch fail when it covers nothing: run.sh on zero suites, the paths gate below a coverage floor, check-substitution.py at 0 checked, and the argv guard on an empty scan root. The argv scan was set-compared against main, not counted: 69 files before ⊂ 74 after (comm -23 empty).

Rendered output is unchanged. I rendered origin/main and this branch in separate worktrees:

  • both gave 2115 resources found in 278 files - Valid: 2115, Invalid: 0 and 279 bundle files, measured before this branch was rebased onto chore(tooling): remove the Dagger engine and its runner scale set #2073, which removed Dagger's 10 resources;
  • every non-comment difference is Helm's per-render randomness (caBundle, tls.*, generated secrets);
  • the only deterministic differences are YAML comments that name the moved script paths.

Already broken, surfaced here

  1. test-flux-schema.sh has been dead for an unknown period. It asserts bundle filenames the render outgrew, and nothing caught it because nothing ran it. It is quarantined, not repaired, under scripts/ci/tests/quarantine/ with a README. A hasty fix to a guard risks making it vacuous. validate-manifests.sh itself covers the chartRefs it named.
  2. sed -i turns a symlink into a regular file even when nothing matches. A *.md glob would have flattened all ten CLAUDE.md symlinks and silently undone ADR-0038. The rewrite selects files with git grep -l. All 13 repo symlinks are intact.

Not done here

  • Spec criterion 1 ("no loose executables") is not met. 33 files remain at scripts/ root until PRs 2 and 3.
  • 14 suites carry temporary ../../ subject paths. They cover 7 subjects that move later: cnpg-promote-seed.sh, openbao-config.sh, openbao-snapshot.sh, tm-provisioner.sh, zitadel-idp.sh, zitadel-oidc-clients.sh and secret-store.sh. Each carries a destination-neutral revisit comment, and test-script-paths.sh covers them.
  • # requires: headers: three suites declare one (python3, openssl, vector). The commit message on 7b54499b says "four", which is wrong; it disappears in the squash.
  • test-vector-vrl skips in CI, because vector is not installed there. That was also true before this PR. validate-vector-vrl.sh needs docker and no CI job runs it; task ci:vector-vrl now at least names it.

Expect these on this PR

  • The render-diff comment will look like everything was added. The base checkout has no scripts/ci/, so the base render fails. The local comparison above is the real diff.
  • openbao-snapshot gets rebuilt on merge. A comment edit in container-images/openbao-snapshot/openbao-snapshot.sh matches the image workflow's path filter. Deployments pin <branch>-<sha> tags, so nothing rolls out.
  • Trivy exits 1 locally, as it does on main. The three flagged files this branch touches produce identical findings on origin/main: the same 3, with the same hash. CI's Trivy step only uploads SARIF.

Follow-ups (not filed)

  • A run.sh self-test covering pass, missing tool, 77, fail, and nested .py.
  • main's gh-repo-removed case in the notifier suite accepts any non-zero exit.
  • Dagger leftovers: tooling/base/dagger-engine/, ci-workflows.md:248, and docs/architecture/ci-pipeline.drawio.
  • taskfile.yaml default should call {{.TASK_EXE}} so a bare task outside mise uses the pinned version.
  • validate-manifests.sh:20 has a working-directory-relative # shellcheck source=.

Evidence

Rebased again on 2026-09-21 onto main with #2072 (GCP drift) and #2073 (Dagger removal); both merged cleanly into the new layout. The render and suite lines below come from this PR's CI run on the rebased head (Kubernetes validation). The rest were re-run locally:

$ task check                                  # exit 0
Summary: 2105 resources found in 276 files - Valid: 2105, Invalid: 0, Skipped: 0
==> All gates passed
22 passed, 1 skipped, 0 failed                # SKIP test-vector-vrl  missing: vector
==> All relative Markdown links resolve (0 allowlisted).
==> All 30 documentation claims match the repository (51 page checks).
==> identity provider topology is consistent: aws hosts, all other clouds suspended.
==> Every repository path named in the docs site exists.

$ ./scripts/ci/validate-vmrules.sh            # exit 0
==> 47 PromQL expression(s) in 11 group(s) parse. 1 group(s) / 1 rule(s) skipped and NOT checked (listed above).

# criterion 5: a new suite runs with no edit to ci.yaml, invoked from scripts/ci/tests/
$ printf '#!/usr/bin/env bash\nexit 0\n' > scripts/ci/tests/test-zz-discovery-proof.sh
$ task ci:test | grep -E 'zz-discovery|passed,'
PASS  test-zz-discovery-proof                    (0s)
23 passed, 1 skipped, 0 failed

Job names are equal to origin/main's (7/7, including the display name:). ShellCheck passes with CI's exact find.

Closes #1951.

@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

🔍 Rendered manifest diff — this PR vs main (desired state)

0 changed · 995 added · 0 removed

Rendered with kustomize build + helm template (source of truth = git), so Helm-expanded workloads are included. Shows what Flux will apply — not a diff against live cluster state (drift is alerted on separately), and not CRD-defaulted / webhook-mutated output. Secret values are redacted; per-render noise (webhook caBundles, checksum/* annotations, render timestamps) is normalized out.

🟢 added — actions.github.com/v1alpha1/AutoscalingRunnerSet/tooling/default-gha-runner-scale-set
--- a/actions.github.com/v1alpha1/AutoscalingRunnerSet/tooling/default-gha-runner-scale-set
+++ b/actions.github.com/v1alpha1/AutoscalingRunnerSet/tooling/default-gha-runner-scale-set
@@ -0,0 +1,63 @@
+apiVersion: actions.github.com/v1alpha1
+kind: AutoscalingRunnerSet
+metadata:
+  annotations:
+    actions.github.com/cleanup-kubernetes-mode-role-binding-name: default-gha-runner-scale-set-gha-rs-kube-mode
+    actions.github.com/cleanup-kubernetes-mode-role-name: default-gha-runner-scale-set-gha-rs-kube-mode
+    actions.github.com/cleanup-kubernetes-mode-service-account-name: default-gha-runner-scale-set-gha-rs-kube-mode
+    actions.github.com/cleanup-manager-role-binding: default-gha-runner-scale-set-gha-rs-manager
+    actions.github.com/cleanup-manager-role-name: default-gha-runner-scale-set-gha-rs-manager
+    actions.github.com/values-hash: b35326c9da2a7a8f3b8b82dfe526f60b2feb51eeaa7d17f7e30077420c39842
+  labels:
+    actions.github.com/scale-set-name: default-gha-runner-scale-set
+    actions.github.com/scale-set-namespace: tooling
+    app.kubernetes.io/component: autoscaling-runner-set
+    app.kubernetes.io/instance: default-gha-runner-scale-set
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: default-gha-runner-scale-set
+    app.kubernetes.io/part-of: gha-rs
+    app.kubernetes.io/version: 0.9.3
+    helm.sh/chart: gha-rs-0.9.3
+  name: default-gha-runner-scale-set
+  namespace: tooling
+spec:
+  githubConfigSecret: gha-runner-scale-set
+  githubConfigUrl: https://github.com/Smana/cloud-native-ref
+  maxRunners: 5
+  runnerGroup: default
+  template:
+    spec:
+      containers:
+      - command:
+        - /home/runner/run.sh
+        env:
+        - name: ACTIONS_RUNNER_CONTAINER_HOOKS
+          value: /home/runner/k8s/index.js
+        - name: ACTIONS_RUNNER_POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        - name: ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER
+          value: 'true'
+        image: ghcr.io/actions/actions-runner:2.337.0
+        name: runner
+        volumeMounts:
+        - mountPath: /home/runner/_work
+          name: work
+      restartPolicy: Never
+      securityContext:
+        fsGroup: 1000
+        runAsGroup: 123
+        runAsUser: 1001
+      serviceAccountName: default-gha-runner-scale-set-gha-rs-kube-mode
+      volumes:
+      - ephemeral:
+          volumeClaimTemplate:
+            spec:
+              accessModes:
+              - ReadWriteOnce
+              resources:
+                requests:
+                  storage: 10Gi
+              storageClassName: gp3
+        name: work
🟢 added — admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/aws-load-balancer-webhook
--- a/admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/aws-load-balancer-webhook
+++ b/admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/aws-load-balancer-webhook
@@ -0,0 +1,192 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+  labels:
+    app.kubernetes.io/instance: aws-load-balancer-controller
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: aws-load-balancer-controller
+    app.kubernetes.io/version: v3.5.0
+    helm.sh/chart: aws-load-balancer-controller-3.5.0
+  name: aws-load-balancer-webhook
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: aws-load-balancer-webhook-service
+      namespace: kube-system
+      path: /mutate-v1-pod
+  failurePolicy: Ignore
+  name: mpod.elbv2.k8s.aws
+  namespaceSelector:
+    matchExpressions:
+    - key: elbv2.k8s.aws/pod-readiness-gate-inject
+      operator: In
+      values:
+      - enabled
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - aws-load-balancer-controller
+  rules:
+  - apiGroups:
+    - ''
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    resources:
+    - pods
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: aws-load-balancer-webhook-service
+      namespace: kube-system
+      path: /mutate-v1-pod-server-id
+  failurePolicy: Fail
+  name: quicid.elbv2.k8s.aws
+  namespaceSelector:
+    matchExpressions:
+    - key: elbv2.k8s.aws/quic-server-id-inject
+      operator: In
+      values:
+      - enabled
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - aws-load-balancer-controller
+  rules:
+  - apiGroups:
+    - ''
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    resources:
+    - pods
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: aws-load-balancer-webhook-service
+      namespace: kube-system
+      path: /mutate-v1-service
+  failurePolicy: Ignore
+  name: mservice.elbv2.k8s.aws
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - aws-load-balancer-controller
+  rules:
+  - apiGroups:
+    - ''
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    resources:
+    - services
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: aws-load-balancer-webhook-service
+      namespace: kube-system
+      path: /mutate-alb-target-control-namespace-v1-pod
+  failurePolicy: Fail
+  name: alb-target-control.namespace.elbv2.k8s.aws
+  namespaceSelector:
+    matchExpressions:
+    - key: elbv2.k8s.aws/alb-target-control-agent-injection
+      operator: In
+      values:
+      - enabled
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - aws-load-balancer-controller
+    - key: elbv2.k8s.aws/alb-target-control-agent-inject
+      operator: NotIn
+      values:
+      - 'false'
+  rules:
+  - apiGroups:
+    - ''
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    resources:
+    - pods
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: aws-load-balancer-webhook-service
+      namespace: kube-system
+      path: /mutate-alb-target-control-object-v1-pod
+  failurePolicy: Fail
+  name: alb-target-control.object.elbv2.k8s.aws
+  namespaceSelector:
+    matchExpressions:
+    - key: elbv2.k8s.aws/alb-target-control-agent-injection
+      operator: DoesNotExist
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - aws-load-balancer-controller
+    - key: elbv2.k8s.aws/alb-target-control-agent-inject
+      operator: In
+      values:
+      - 'true'
+  rules:
+  - apiGroups:
+    - ''
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    resources:
+    - pods
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: aws-load-balancer-webhook-service
+      namespace: kube-system
+      path: /mutate-elbv2-k8s-aws-v1beta1-targetgroupbinding
+  failurePolicy: Fail
+  name: mtargetgroupbinding.elbv2.k8s.aws
+  rules:
+  - apiGroups:
+    - elbv2.k8s.aws
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - targetgroupbindings
+  sideEffects: None
🟢 added — admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/cert-manager-webhook
--- a/admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/cert-manager-webhook
+++ b/admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/cert-manager-webhook
@@ -0,0 +1,36 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+  annotations:
+    cert-manager.io/inject-ca-from-secret: security/cert-manager-webhook-ca
+  labels:
+    app: webhook
+    app.kubernetes.io/component: webhook
+    app.kubernetes.io/instance: cert-manager
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: webhook
+    app.kubernetes.io/version: v1.21.2
+    helm.sh/chart: cert-manager-v1.21.2
+  name: cert-manager-webhook
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: cert-manager-webhook
+      namespace: security
+      path: /mutate
+  failurePolicy: Fail
+  matchPolicy: Equivalent
+  name: webhook.cert-manager.io
+  rules:
+  - apiGroups:
+    - cert-manager.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    resources:
+    - certificaterequests
+  sideEffects: None
+  timeoutSeconds: 10
🟢 added — admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/cnpg-mutating-webhook-configuration
--- a/admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/cnpg-mutating-webhook-configuration
+++ b/admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/cnpg-mutating-webhook-configuration
@@ -0,0 +1,95 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+  labels:
+    app.kubernetes.io/instance: cloudnative-pg
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: cloudnative-pg
+    app.kubernetes.io/version: 1.30.0
+    helm.sh/chart: cloudnative-pg-0.29.0
+  name: cnpg-mutating-webhook-configuration
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: cnpg-webhook-service
+      namespace: infrastructure
+      path: /mutate-postgresql-cnpg-io-v1-backup
+      port: 443
+  failurePolicy: Fail
+  name: mbackup.cnpg.io
+  rules:
+  - apiGroups:
+    - postgresql.cnpg.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - backups
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: cnpg-webhook-service
+      namespace: infrastructure
+      path: /mutate-postgresql-cnpg-io-v1-cluster
+      port: 443
+  failurePolicy: Fail
+  name: mcluster.cnpg.io
+  rules:
+  - apiGroups:
+    - postgresql.cnpg.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - clusters
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: cnpg-webhook-service
+      namespace: infrastructure
+      path: /mutate-postgresql-cnpg-io-v1-database
+      port: 443
+  failurePolicy: Fail
+  name: mdatabase.cnpg.io
+  rules:
+  - apiGroups:
+    - postgresql.cnpg.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - databases
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: cnpg-webhook-service
+      namespace: infrastructure
+      path: /mutate-postgresql-cnpg-io-v1-scheduledbackup
+      port: 443
+  failurePolicy: Fail
+  name: mscheduledbackup.cnpg.io
+  rules:
+  - apiGroups:
+    - postgresql.cnpg.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - scheduledbackups
+  sideEffects: None
🟢 added — admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/envoy-ai-gateway-gateway-pod-mutator.envoy-ai-gateway-system
--- a/admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/envoy-ai-gateway-gateway-pod-mutator.envoy-ai-gateway-system
+++ b/admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/envoy-ai-gateway-gateway-pod-mutator.envoy-ai-gateway-system
@@ -0,0 +1,29 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+  name: envoy-ai-gateway-gateway-pod-mutator.envoy-ai-gateway-system
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: ai-gateway-controller
+      namespace: envoy-ai-gateway-system
+      path: /mutate
+      port: 9443
+  failurePolicy: Fail
+  name: ai-gateway-controller.envoy-ai-gateway-system.svc.cluster.local
+  objectSelector:
+    matchLabels:
+      app.kubernetes.io/managed-by: envoy-gateway
+  rules:
+  - apiGroups:
+    - ''
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    resources:
+    - pods
+  sideEffects: None
+  timeoutSeconds: 10
🟢 added — admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/envoy-gateway-topology-injector.envoy-gateway-system
--- a/admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/envoy-gateway-topology-injector.envoy-gateway-system
+++ b/admissionregistration.k8s.io/v1/MutatingWebhookConfiguration/-/envoy-gateway-topology-injector.envoy-gateway-system
@@ -0,0 +1,41 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+  annotations:
+    helm.sh/hook: pre-install, pre-upgrade
+    helm.sh/hook-weight: '-1'
+  labels:
+    app.kubernetes.io/component: topology-injector
+    app.kubernetes.io/instance: envoy-gateway
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/version: v1.9.1
+    helm.sh/chart: gateway-helm-1.9.1
+  name: envoy-gateway-topology-injector.envoy-gateway-system
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: envoy-gateway
+      namespace: envoy-gateway-system
+      path: /inject-pod-topology
+      port: 9443
+  failurePolicy: Ignore
+  name: topology.webhook.gateway.envoyproxy.io
+  namespaceSelector:
+    matchExpressions:
+    - key: kubernetes.io/metadata.name
+      operator: In
+      values:
+      - envoy-gateway-system
+  rules:
+  - apiGroups:
+    - ''
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    resources:
+    - pods/binding
+  sideEffects: None
🟢 added — admissionregistration.k8s.io/v1/ValidatingAdmissionPolicy/-/safe-upgrades.gateway.networking.k8s.io
--- a/admissionregistration.k8s.io/v1/ValidatingAdmissionPolicy/-/safe-upgrades.gateway.networking.k8s.io
+++ b/admissionregistration.k8s.io/v1/ValidatingAdmissionPolicy/-/safe-upgrades.gateway.networking.k8s.io
@@ -0,0 +1,27 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingAdmissionPolicy
+metadata:
+  annotations:
+    gateway.networking.k8s.io/bundle-version: v1.6.1
+    gateway.networking.k8s.io/channel: standard
+  name: safe-upgrades.gateway.networking.k8s.io
+spec:
+  failurePolicy: Fail
+  matchConstraints:
+    resourceRules:
+    - apiGroups:
+      - apiextensions.k8s.io
+      apiVersions:
+      - v1
+      operations:
+      - CREATE
+      - UPDATE
+      resources:
+      - '*'
+  validations:
+  - expression: object.spec.group != 'gateway.networking.k8s.io' || oldObject == null || ( has(object.metadata.annotations) && object.metadata.annotations.exists(k, k == 'gateway.networking.k8s.io/channel') && object.metadata.annotations['gateway.networking.k8s.io/channel'] == 'standard' ) || ( oldObject != null && has(oldObject.metadata.annotations) && oldObject.metadata.annotations.exists(k, k == 'gateway.networking.k8s.io/channel') && oldObject.metadata.annotations['gateway.networking.k8s.io/channel'] == 'experimental' )
+    message: Installing experimental CRDs on top of standard channel CRDs is prohibited by default. Uninstall ValidatingAdmissionPolicy safe-upgrades.gateway.networking.k8s.io to install experimental CRDs on top of standard channel CRDs.
+    reason: Invalid
+  - expression: "object.spec.group != 'gateway.networking.k8s.io' ||\n(has(object.metadata.annotations) && object.metadata.annotations.exists(k, k == 'gateway.networking.k8s.io/bundle-version') &&\n(object.metadata.annotations['gateway.networking.k8s.io/bundle-version'] == 'v0.0.0-dev' ||\n(object.metadata.annotations['gateway.networking.k8s.io/bundle-version'].startsWith('v1.') &&\n !matches(object.metadata.annotations['gateway.networking.k8s.io/bundle-version'], '^v1\\\\.[0-4](\\\\.|$)'))))\n"
+    message: Installing CRDs with version other than v0.0.0-dev or v1.5+ is prohibited by default. Uninstall ValidatingAdmissionPolicy safe-upgrades.gateway.networking.k8s.io to install other versions.
+    reason: Invalid
🟢 added — admissionregistration.k8s.io/v1/ValidatingAdmissionPolicyBinding/-/safe-upgrades.gateway.networking.k8s.io
--- a/admissionregistration.k8s.io/v1/ValidatingAdmissionPolicyBinding/-/safe-upgrades.gateway.networking.k8s.io
+++ b/admissionregistration.k8s.io/v1/ValidatingAdmissionPolicyBinding/-/safe-upgrades.gateway.networking.k8s.io
@@ -0,0 +1,22 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingAdmissionPolicyBinding
+metadata:
+  annotations:
+    gateway.networking.k8s.io/bundle-version: v1.6.1
+    gateway.networking.k8s.io/channel: standard
+  name: safe-upgrades.gateway.networking.k8s.io
+spec:
+  matchResources:
+    resourceRules:
+    - apiGroups:
+      - apiextensions.k8s.io
+      apiVersions:
+      - v1
+      operations:
+      - CREATE
+      - UPDATE
+      resources:
+      - customresourcedefinitions
+  policyName: safe-upgrades.gateway.networking.k8s.io
+  validationActions:
+  - Deny
🟢 added — admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/aws-load-balancer-webhook
--- a/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/aws-load-balancer-webhook
+++ b/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/aws-load-balancer-webhook
@@ -0,0 +1,81 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+  labels:
+    app.kubernetes.io/instance: aws-load-balancer-controller
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: aws-load-balancer-controller
+    app.kubernetes.io/version: v3.5.0
+    helm.sh/chart: aws-load-balancer-controller-3.5.0
+  name: aws-load-balancer-webhook
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: aws-load-balancer-webhook-service
+      namespace: kube-system
+      path: /validate-elbv2-k8s-aws-v1beta1-ingressclassparams
+  failurePolicy: Fail
+  name: vingressclassparams.elbv2.k8s.aws
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - aws-load-balancer-controller
+  rules:
+  - apiGroups:
+    - elbv2.k8s.aws
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - ingressclassparams
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: aws-load-balancer-webhook-service
+      namespace: kube-system
+      path: /validate-elbv2-k8s-aws-v1beta1-targetgroupbinding
+  failurePolicy: Fail
+  name: vtargetgroupbinding.elbv2.k8s.aws
+  rules:
+  - apiGroups:
+    - elbv2.k8s.aws
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - targetgroupbindings
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: aws-load-balancer-webhook-service
+      namespace: kube-system
+      path: /validate-networking-v1-ingress
+  failurePolicy: Fail
+  matchPolicy: Equivalent
+  name: vingress.elbv2.k8s.aws
+  rules:
+  - apiGroups:
+    - networking.k8s.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - ingresses
+  sideEffects: None
🟢 added — admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/cert-manager-webhook
--- a/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/cert-manager-webhook
+++ b/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/cert-manager-webhook
@@ -0,0 +1,44 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+  annotations:
+    cert-manager.io/inject-ca-from-secret: security/cert-manager-webhook-ca
+  labels:
+    app: webhook
+    app.kubernetes.io/component: webhook
+    app.kubernetes.io/instance: cert-manager
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: webhook
+    app.kubernetes.io/version: v1.21.2
+    helm.sh/chart: cert-manager-v1.21.2
+  name: cert-manager-webhook
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: cert-manager-webhook
+      namespace: security
+      path: /validate
+  failurePolicy: Fail
+  matchPolicy: Equivalent
+  name: webhook.cert-manager.io
+  namespaceSelector:
+    matchExpressions:
+    - key: cert-manager.io/disable-validation
+      operator: NotIn
+      values:
+      - 'true'
+  rules:
+  - apiGroups:
+    - cert-manager.io
+    - acme.cert-manager.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - '*/*'
+  sideEffects: None
+  timeoutSeconds: 10
🟢 added — admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/cnpg-validating-webhook-configuration
--- a/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/cnpg-validating-webhook-configuration
+++ b/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/cnpg-validating-webhook-configuration
@@ -0,0 +1,116 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+  labels:
+    app.kubernetes.io/instance: cloudnative-pg
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: cloudnative-pg
+    app.kubernetes.io/version: 1.30.0
+    helm.sh/chart: cloudnative-pg-0.29.0
+  name: cnpg-validating-webhook-configuration
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: cnpg-webhook-service
+      namespace: infrastructure
+      path: /validate-postgresql-cnpg-io-v1-backup
+      port: 443
+  failurePolicy: Fail
+  name: vbackup.cnpg.io
+  rules:
+  - apiGroups:
+    - postgresql.cnpg.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - backups
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: cnpg-webhook-service
+      namespace: infrastructure
+      path: /validate-postgresql-cnpg-io-v1-cluster
+      port: 443
+  failurePolicy: Fail
+  name: vcluster.cnpg.io
+  rules:
+  - apiGroups:
+    - postgresql.cnpg.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - clusters
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: cnpg-webhook-service
+      namespace: infrastructure
+      path: /validate-postgresql-cnpg-io-v1-scheduledbackup
+      port: 443
+  failurePolicy: Fail
+  name: vscheduledbackup.cnpg.io
+  rules:
+  - apiGroups:
+    - postgresql.cnpg.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - scheduledbackups
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: cnpg-webhook-service
+      namespace: infrastructure
+      path: /validate-postgresql-cnpg-io-v1-database
+      port: 443
+  failurePolicy: Fail
+  name: vdatabase.cnpg.io
+  rules:
+  - apiGroups:
+    - postgresql.cnpg.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - databases
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: cnpg-webhook-service
+      namespace: infrastructure
+      path: /validate-postgresql-cnpg-io-v1-pooler
+      port: 443
+  failurePolicy: Fail
+  name: vpooler.cnpg.io
+  rules:
+  - apiGroups:
+    - postgresql.cnpg.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - poolers
+  sideEffects: None
🟢 added — admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/externalsecret-validate
--- a/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/externalsecret-validate
+++ b/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/externalsecret-validate
@@ -0,0 +1,36 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+  labels:
+    app.kubernetes.io/instance: external-secrets
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: external-secrets-webhook
+    app.kubernetes.io/version: v2.10.0
+    external-secrets.io/component: webhook
+    helm.sh/chart: external-secrets-2.10.0
+  name: externalsecret-validate
+webhooks:
+- admissionReviewVersions:
+  - v1
+  - v1beta1
+  clientConfig:
+    service:
+      name: external-secrets-webhook
+      namespace: security
+      path: /validate-external-secrets-io-v1-externalsecret
+  failurePolicy: Fail
+  name: validate.externalsecret.external-secrets.io
+  rules:
+  - apiGroups:
+    - external-secrets.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    - DELETE
+    resources:
+    - externalsecrets
+    scope: Namespaced
+  sideEffects: None
+  timeoutSeconds: 5
🟢 added — admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/keda-admission
--- a/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/keda-admission
+++ b/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/keda-admission
@@ -0,0 +1,157 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+  labels:
+    app.kubernetes.io/component: operator
+    app.kubernetes.io/instance: keda
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: keda-admission-webhooks
+    app.kubernetes.io/part-of: keda-operator
+    app.kubernetes.io/version: 2.20.2
+    helm.sh/chart: keda-2.20.2
+  name: keda-admission
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: keda-admission-webhooks
+      namespace: keda
+      path: /validate-keda-sh-v1alpha1-scaledobject
+  failurePolicy: Ignore
+  matchPolicy: Equivalent
+  name: vscaledobject.kb.io
+  namespaceSelector: {}
+  objectSelector: {}
+  rules:
+  - apiGroups:
+    - keda.sh
+    apiVersions:
+    - v1alpha1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - scaledobjects
+  sideEffects: None
+  timeoutSeconds: 10
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: keda-admission-webhooks
+      namespace: keda
+      path: /validate-keda-sh-v1alpha1-scaledjob
+  failurePolicy: Ignore
+  matchPolicy: Equivalent
+  name: vscaledjob.kb.io
+  namespaceSelector: {}
+  objectSelector: {}
+  rules:
+  - apiGroups:
+    - keda.sh
+    apiVersions:
+    - v1alpha1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - scaledjobs
+  sideEffects: None
+  timeoutSeconds: 10
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: keda-admission-webhooks
+      namespace: keda
+      path: /validate-keda-sh-v1alpha1-triggerauthentication
+  failurePolicy: Ignore
+  matchPolicy: Equivalent
+  name: vstriggerauthentication.kb.io
+  namespaceSelector: {}
+  objectSelector: {}
+  rules:
+  - apiGroups:
+    - keda.sh
+    apiVersions:
+    - v1alpha1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - triggerauthentications
+  sideEffects: None
+  timeoutSeconds: 10
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: keda-admission-webhooks
+      namespace: keda
+      path: /validate-keda-sh-v1alpha1-clustertriggerauthentication
+  failurePolicy: Ignore
+  matchPolicy: Equivalent
+  name: vsclustertriggerauthentication.kb.io
+  namespaceSelector: {}
+  objectSelector: {}
+  rules:
+  - apiGroups:
+    - keda.sh
+    apiVersions:
+    - v1alpha1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - clustertriggerauthentications
+  sideEffects: None
+  timeoutSeconds: 10
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: keda-admission-webhooks
+      namespace: keda
+      path: /validate-eventing-keda-sh-v1alpha1-cloudeventsource
+  failurePolicy: Ignore
+  matchPolicy: Equivalent
+  name: vcloudeventsource.kb.io
+  namespaceSelector: {}
+  objectSelector: {}
+  rules:
+  - apiGroups:
+    - eventing.keda.sh
+    apiVersions:
+    - v1alpha1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - cloudeventsources
+  sideEffects: None
+  timeoutSeconds: 10
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: keda-admission-webhooks
+      namespace: keda
+      path: /validate-eventing-keda-sh-v1alpha1-clustercloudeventsource
+  failurePolicy: Ignore
+  matchPolicy: Equivalent
+  name: vclustercloudeventsource.kb.io
+  namespaceSelector: {}
+  objectSelector: {}
+  rules:
+  - apiGroups:
+    - eventing.keda.sh
+    apiVersions:
+    - v1alpha1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - clustercloudeventsources
+  sideEffects: None
+  timeoutSeconds: 10
🟢 added — admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/secretstore-validate
--- a/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/secretstore-validate
+++ b/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/secretstore-validate
@@ -0,0 +1,60 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+  labels:
+    app.kubernetes.io/instance: external-secrets
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: external-secrets-webhook
+    app.kubernetes.io/version: v2.10.0
+    external-secrets.io/component: webhook
+    helm.sh/chart: external-secrets-2.10.0
+  name: secretstore-validate
+webhooks:
+- admissionReviewVersions:
+  - v1
+  - v1beta1
+  clientConfig:
+    service:
+      name: external-secrets-webhook
+      namespace: security
+      path: /validate-external-secrets-io-v1-secretstore
+  failurePolicy: Fail
+  name: validate.secretstore.external-secrets.io
+  rules:
+  - apiGroups:
+    - external-secrets.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    - DELETE
+    resources:
+    - secretstores
+    scope: Namespaced
+  sideEffects: None
+  timeoutSeconds: 5
+- admissionReviewVersions:
+  - v1
+  - v1beta1
+  clientConfig:
+    service:
+      name: external-secrets-webhook
+      namespace: security
+      path: /validate-external-secrets-io-v1-clustersecretstore
+  failurePolicy: Fail
+  name: validate.clustersecretstore.external-secrets.io
+  rules:
+  - apiGroups:
+    - external-secrets.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    - DELETE
+    resources:
+    - clustersecretstores
+    scope: Cluster
+  sideEffects: None
+  timeoutSeconds: 5
🟢 added — admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/victoria-metrics-k8s-stack-victoria-metrics-operator-admission
--- a/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/victoria-metrics-k8s-stack-victoria-metrics-operator-admission
+++ b/admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration/-/victoria-metrics-k8s-stack-victoria-metrics-operator-admission
@@ -0,0 +1,711 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+  labels:
+    app.kubernetes.io/instance: victoria-metrics-k8s-stack
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: victoria-metrics-operator
+    app.kubernetes.io/version: v0.74.1
+    helm.sh/chart: victoria-metrics-operator-0.67.3
+  name: victoria-metrics-k8s-stack-victoria-metrics-operator-admission
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1-vlagent
+      port: 9443
+  failurePolicy: Ignore
+  name: vlagents.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vlagents
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1-vlcluster
+      port: 9443
+  failurePolicy: Ignore
+  name: vlclusters.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vlclusters
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1alpha1-vldistributed
+      port: 9443
+  failurePolicy: Ignore
+  name: vldistributed.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1alpha1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vldistributed
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vlogs
+      port: 9443
+  failurePolicy: Ignore
+  name: vlogs.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vlogs
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1-vlsingle
+      port: 9443
+  failurePolicy: Ignore
+  name: vlsingles.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vlsingles
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmagent
+      port: 9443
+  failurePolicy: Ignore
+  name: vmagents.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmagents
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmalertmanagerconfig
+      port: 9443
+  failurePolicy: Ignore
+  name: vmalertmanagerconfigs.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmalertmanagerconfigs
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmalertmanager
+      port: 9443
+  failurePolicy: Ignore
+  name: vmalertmanagers.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmalertmanagers
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmalert
+      port: 9443
+  failurePolicy: Ignore
+  name: vmalerts.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmalerts
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1-vmanomaly
+      port: 9443
+  failurePolicy: Ignore
+  name: vmanomalies.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmanomalies
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1-vmanomalyconfig
+      port: 9443
+  failurePolicy: Ignore
+  name: vmanomalyconfigs.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmanomalyconfigs
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmauth
+      port: 9443
+  failurePolicy: Ignore
+  name: vmauths.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmauths
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmcluster
+      port: 9443
+  failurePolicy: Ignore
+  name: vmclusters.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmclusters
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1alpha1-vmdistributed
+      port: 9443
+  failurePolicy: Ignore
+  name: vmdistributed.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1alpha1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmdistributed
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmnodescrape
+      port: 9443
+  failurePolicy: Ignore
+  name: vmnodescrapes.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmnodescrapes
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmpodscrape
+      port: 9443
+  failurePolicy: Ignore
+  name: vmpodscrapes.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmpodscrapes
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmprobe
+      port: 9443
+  failurePolicy: Ignore
+  name: vmprobes.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmprobes
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmrule
+      port: 9443
+  failurePolicy: Ignore
+  name: vmrules.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmrules
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmscrapeconfig
+      port: 9443
+  failurePolicy: Ignore
+  name: vmscrapeconfigs.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmscrapeconfigs
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmservicescrape
+      port: 9443
+  failurePolicy: Ignore
+  name: vmservicescrapes.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmservicescrapes
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmsingle
+      port: 9443
+  failurePolicy: Ignore
+  name: vmsingles.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmsingles
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmstaticscrape
+      port: 9443
+  failurePolicy: Ignore
+  name: vmstaticscrapes.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmstaticscrapes
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1beta1-vmuser
+      port: 9443
+  failurePolicy: Ignore
+  name: vmusers.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vmusers
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1-vtcluster
+      port: 9443
+  failurePolicy: Ignore
+  name: vtclusters.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vtclusters
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    caBundle: <redacted by diff-bundles>
+    service:
+      name: victoria-metrics-k8s-stack-victoria-metrics-operator
+      namespace: observability
+      path: /validate-operator-victoriametrics-com-v1-vtsingle
+      port: 9443
+  failurePolicy: Ignore
+  name: vtsingles.operator.victoriametrics.com
+  objectSelector:
+    matchExpressions:
+    - key: app.kubernetes.io/name
+      operator: NotIn
+      values:
+      - victoria-metrics-operator
+  rules:
+  - apiGroups:
+    - operator.victoriametrics.com
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - vtsingles
+  sideEffects: None
🟢 added — aigateway.envoyproxy.io/v1alpha1/AIGatewayRoute/llm/llm-fleet
--- a/aigateway.envoyproxy.io/v1alpha1/AIGatewayRoute/llm/llm-fleet
+++ b/aigateway.envoyproxy.io/v1alpha1/AIGatewayRoute/llm/llm-fleet
@@ -0,0 +1,36 @@
+apiVersion: aigateway.envoyproxy.io/v1alpha1
+kind: AIGatewayRoute
+metadata:
+  name: llm-fleet
+  namespace: llm
+spec:
+  parentRefs:
+  - group: gateway.networking.k8s.io
+    kind: Gateway
+    name: ai-gateway
+    namespace: envoy-ai-gateway-system
+  rules:
+  - backendRefs:
+    - name: xplane-qwen-coder-fim
+      weight: 100
+    matches:
+    - headers:
+      - name: x-ai-eg-model
+        type: Exact
+        value: xplane-qwen-coder-fim
+  - backendRefs:
+    - name: xplane-qwen3-8b
+      weight: 100
+    matches:
+    - headers:
+      - name: x-ai-eg-model
+        type: Exact
+        value: xplane-qwen3-8b
+  - backendRefs:
+    - name: xplane-llamaguard3-1b
+      weight: 100
+    matches:
+    - headers:
+      - name: x-ai-eg-model
+        type: Exact
+        value: xplane-llamaguard3-1b
🟢 added — aigateway.envoyproxy.io/v1alpha1/AIServiceBackend/llm/xplane-llamaguard3-1b
--- a/aigateway.envoyproxy.io/v1alpha1/AIServiceBackend/llm/xplane-llamaguard3-1b
+++ b/aigateway.envoyproxy.io/v1alpha1/AIServiceBackend/llm/xplane-llamaguard3-1b
@@ -0,0 +1,12 @@
+apiVersion: aigateway.envoyproxy.io/v1alpha1
+kind: AIServiceBackend
+metadata:
+  name: xplane-llamaguard3-1b
+  namespace: llm
+spec:
+  backendRef:
+    group: gateway.envoyproxy.io
+    kind: Backend
+    name: xplane-llamaguard3-1b-direct
+  schema:
+    name: OpenAI
🟢 added — aigateway.envoyproxy.io/v1alpha1/AIServiceBackend/llm/xplane-qwen-coder-fim
--- a/aigateway.envoyproxy.io/v1alpha1/AIServiceBackend/llm/xplane-qwen-coder-fim
+++ b/aigateway.envoyproxy.io/v1alpha1/AIServiceBackend/llm/xplane-qwen-coder-fim
@@ -0,0 +1,12 @@
+apiVersion: aigateway.envoyproxy.io/v1alpha1
+kind: AIServiceBackend
+metadata:
+  name: xplane-qwen-coder-fim
+  namespace: llm
+spec:
+  backendRef:
+    group: gateway.envoyproxy.io
+    kind: Backend
+    name: xplane-qwen-coder-fim-direct
+  schema:
+    name: OpenAI
🟢 added — aigateway.envoyproxy.io/v1alpha1/AIServiceBackend/llm/xplane-qwen3-8b
--- a/aigateway.envoyproxy.io/v1alpha1/AIServiceBackend/llm/xplane-qwen3-8b
+++ b/aigateway.envoyproxy.io/v1alpha1/AIServiceBackend/llm/xplane-qwen3-8b
@@ -0,0 +1,12 @@
+apiVersion: aigateway.envoyproxy.io/v1alpha1
+kind: AIServiceBackend
+metadata:
+  name: xplane-qwen3-8b
+  namespace: llm
+spec:
+  backendRef:
+    group: gateway.envoyproxy.io
+    kind: Backend
+    name: xplane-qwen3-8b-direct
+  schema:
+    name: OpenAI
🟢 added — apiextensions.crossplane.io/v1alpha1/ManagedResourceActivationPolicy/-/aws-resources
--- a/apiextensions.crossplane.io/v1alpha1/ManagedResourceActivationPolicy/-/aws-resources
+++ b/apiextensions.crossplane.io/v1alpha1/ManagedResourceActivationPolicy/-/aws-resources
@@ -0,0 +1,20 @@
+apiVersion: apiextensions.crossplane.io/v1alpha1
+kind: ManagedResourceActivationPolicy
+metadata:
+  name: aws-resources
+spec:
+  activate:
+  - roles.iam.aws.m.upbound.io
+  - policies.iam.aws.m.upbound.io
+  - rolepolicyattachments.iam.aws.m.upbound.io
+  - users.iam.aws.m.upbound.io
+  - accesskeys.iam.aws.m.upbound.io
+  - userpolicyattachments.iam.aws.m.upbound.io
+  - podidentityassociations.eks.aws.m.upbound.io
+  - buckets.s3.aws.m.upbound.io
+  - bucketversionings.s3.aws.m.upbound.io
+  - bucketlifecycleconfigurations.s3.aws.m.upbound.io
+  - bucketserversideencryptionconfigurations.s3.aws.m.upbound.io
+  - bucketpublicaccessblocks.s3.aws.m.upbound.io
+  - keys.kms.aws.m.upbound.io
+  - aliases.kms.aws.m.upbound.io
🟢 added — apiextensions.crossplane.io/v1alpha1/ManagedResourceActivationPolicy/-/gcp-resources
--- a/apiextensions.crossplane.io/v1alpha1/ManagedResourceActivationPolicy/-/gcp-resources
+++ b/apiextensions.crossplane.io/v1alpha1/ManagedResourceActivationPolicy/-/gcp-resources
@@ -0,0 +1,9 @@
+apiVersion: apiextensions.crossplane.io/v1alpha1
+kind: ManagedResourceActivationPolicy
+metadata:
+  name: gcp-resources
+spec:
+  activate:
+  - projectiammembers.cloudplatform.gcp.m.upbound.io
+  - buckets.storage.gcp.m.upbound.io
+  - bucketiammembers.storage.gcp.m.upbound.io
🟢 added — apiextensions.crossplane.io/v1beta1/EnvironmentConfig/crossplane-system/eks-environment
--- a/apiextensions.crossplane.io/v1beta1/EnvironmentConfig/crossplane-system/eks-environment
+++ b/apiextensions.crossplane.io/v1beta1/EnvironmentConfig/crossplane-system/eks-environment
@@ -0,0 +1,16 @@
+apiVersion: apiextensions.crossplane.io/v1beta1
+data:
+  CIDRBlock: 10.0.0.0/16
+  accountId: 123456789012
+  cloud: aws
+  clusterName: foobar
+  oidcArn: arn:aws:iam::123456789012:oidc-provider/oidc.eks
+  oidcHost: oidc.eks.eu-west-3.amazonaws.com
+  oidcUrl: https://oidc.eks.eu-west-3.amazonaws.com
+  privateDomainName: priv.cluster.local
+  region: eu-west-3
+  vpcId: vpc-0123456789abcdef0
+kind: EnvironmentConfig
+metadata:
+  name: eks-environment
+  namespace: crossplane-system
🟢 added — apiextensions.crossplane.io/v1beta1/EnvironmentConfig/crossplane-system/gke-environment
--- a/apiextensions.crossplane.io/v1beta1/EnvironmentConfig/crossplane-system/gke-environment
+++ b/apiextensions.crossplane.io/v1beta1/EnvironmentConfig/crossplane-system/gke-environment
@@ -0,0 +1,15 @@
+apiVersion: apiextensions.crossplane.io/v1beta1
+data:
+  cloud: gcp
+  clusterName: foobar
+  networkName: vpc-foobar
+  privateDomainName: priv.gcp.cluster.local
+  projectID: ogenki-435905
+  projectNumber: 323586397743
+  region: europe-west4
+  workloadPool: ogenki-435905.svc.id.goog
+  zone: europe-west4-a
+kind: EnvironmentConfig
+metadata:
+  name: gke-environment
+  namespace: crossplane-system

⚠️ Diff truncated to fit the comment size limit — full human-readable diff (job summary on the run page; also downloadable as the rendered-diff artifact).

scripts/ is 55 flat executables mixing CI gates, unit suites, day-2 ops
tooling and apply-time config drivers. Reorganise by audience, index the
entry points with go-task, and replace ci.yaml's hand-maintained test
list with a `# requires:` declaration the runner reads.

Measured rather than assumed: 1246 references to scripts/, of which 359
are live and 887 sit in dated plans and specs no validator can see. The
archive stays as written.

Deploy-time invocation does not follow the directory split -- 11 of 18
ops scripts and 2 CI validators are reached from terramate -- so the PR
sequence is ordered by that, not by directory.
The design measured external references and missed the larger one: 42 of
55 scripts resolve paths from their own location, so a git mv breaks them
whether or not every external reference is rewritten. 11 hardcode a "/.."
to reach the repo root, 25 build paths from HERE/SCRIPT_DIR, and 14 source
lines across 9 scripts reach lib/ by a scripts-root-relative path.

Six of those nine are deploy-time invoked, so a wrong depth fails during
an apply -- the PR-3 failure mode, through a door the reference rewrite
does not cover.

Records the fix (correct each depth in the commit that moves the file) and
the gate that makes it reviewable (test-script-paths.sh, shipped in PR 1
so later phases move underneath it).
…cture

Covers the CI half only: scripts/ci/, the taskfile index, the discovering
test runner, and the test-script-paths.sh gate. PRs 2 and 3 get their own
plans -- each phase produces working software on its own, and planning the
moves is far cheaper once the gate exists.

Task order is deliberate: the three safety nets are built on the unmoved
tree and proved green before any file relocates, so each move has a check
in front of it rather than behind it.
Every task body is a single-line call to a script that still runs
standalone, so the scripts stay liftable into another repo. The ci:test
task points at a runner that Task 3 creates.
Measuring the gate's regexes against the tree before dispatching it found
that two lines in test-cloud-secret-store.sh source through nested quoting,
so the extraction yields a bare quote and the gate would check it as a
filename -- two failures on a correct tree.

Adds a suffix guard, and replaces the guessed verification counts with
measured ones: 12 roots, 19 sources, 15 subjects.
The first implementation attempt came back blocked, correctly. Both bugs
were in the plan, not in any repo script, and both reproduced in isolation:

A literal ${BASH_SOURCE[0]} inside a ${var//pat/rep} ends the expansion at
its own closing brace, so bash appends the remainder as text instead of
substituting -- every source check was silently comparing garbage. The
patterns now live in variables.

The gate also scanned itself, and its own explanatory comment matched its
own subject detector, reporting a failure that existed only in its docs.

Fixing those surfaced a third: the quote-delimited extraction truncated at
the inner quote of `. "$(dirname "$0")/lib/x.sh"` -- the dominant idiom in
this repo -- so the check could never have examined the lines it exists
for. Check 2 now strips quotes before resolving.

Verification changes with it: both fixture failures must fire, and the
assertion is 0 failed plus a coverage floor of 20 sources rather than an
exact count, because a low count is the tell that the checker stopped
checking.
42 of 55 scripts compute paths from where they sit, so a git mv breaks
them whether or not every external reference is rewritten. A wrong /..
depth makes cd succeed at the wrong directory, and six of the nine
lib/-sourcing scripts run during a terramate apply.

Ships before anything moves, so the restructure relocates files
underneath a check that already passes.
test-validate-idp-topology.sh was to declare `kustomize`, on the strength
of a grep hit that turns out to be `apiVersion: kustomize.toolkit.fluxcd.io/v1`
written into a YAML fixture. validate-idp-topology.sh never invokes the
binary.

Declaring it would have made the suite skip permanently on any machine
without kustomize, silently dropping the ADR-0027 gate -- the exact
failure the requires mechanism exists to prevent, caused by the mechanism.

The remaining three headers were each confirmed against the source: the
tool is actually executed, not merely mentioned.
Replaces a hand-maintained list of 11 with a glob over all 20. Each suite
declares what it needs on PATH; the runner skips what is absent and says
which tool was missing, so 'did not run' can never read as 'passed'.
… dead

Running the suites for the first time proved test-flux-schema.sh asserts
against hardcoded bundle filenames the render's naming scheme outgrew.
Nothing caught it because nothing ran it -- all three mentions of it in
ci.yaml are comments.

Checked before ruling: the six chartRef HelmReleases it names ARE in the
rendered bundle, so this is not a gap in validate-manifests.sh.

Quarantined rather than repaired. Fixing assertions inside a guard is not
relocation, and a hasty fix risks making it vacuous. Spec criterion 4 drops
to 19 discovered plus 1 quarantined, and the plan now says so.
It asserts against hardcoded bundle filenames the render's naming scheme
outgrew. Nothing caught it because nothing ran it: all three mentions in
ci.yaml are comments.

Not repaired here. Fixing assertions inside a guard is not relocation, and
a hasty fix risks making it vacuous -- which is worse than red, because a
vacuous guard reports success forever.

Also corrected its self-resolved REPO_ROOT: one level up reached the repo
root from scripts/, not from the new scripts/ci/tests/quarantine/. Caught
by test-script-paths.sh, which scans quarantine too -- a suite need not run
to have a checkable self-location.
Depths corrected in the same commit as the move, and test-script-paths.sh
proves every self-resolved root still lands on the repo root.

Also fixed test-validate-idp-topology.sh's subject reference, which the
move broke and which test-script-paths.sh's subject-defaults check (a
$HERE/subject.sh idiom, single segment) could not statically re-verify
until the reference was written bare rather than braced -- matching the
convention every other test-*.sh in this directory already uses.

validate-manifests.sh's flux-schema/ references now point at Task 5's
destination and do not resolve until that task lands; test-script-paths.sh
still reports that one FAIL, as expected.
gen-catalog.sh went from one level deep to two, so its repo-root hop goes
from /../.. to /../../.. -- the depth-coupling the gate exists to catch.

Also fixed two references the gate cannot see, since neither is a source
statement or a HERE/SCRIPT_DIR subject: gen-catalog.sh's vendored-crds
extract call, and the quarantined test-flux-schema.sh's own preflight.sh
source line, both still pointing at the pre-move path.

render-both.sh's base-checkout render (line 34, cwd /tmp/base) also now
reads scripts/ci/flux-schema/render-bundle.py. That base checkout predates
this move on any PR based off pre-refactor main, so render-diff CI breaks
transiently for such PRs; every base after this merges has the new layout.
Sixteen suites reach their subject by a relative path, and thirteen of
those subjects do not move until a later phase -- so those paths are
temporary and carry a comment saying so. The gate covers all of them.

Also fixed three references the gate cannot see:

- test-tm-provisioner.sh used $(dirname "$0")/tm-provisioner.sh inline
  rather than a HERE variable, so the gate's subject-default check (which
  only matches $HERE/SCRIPT_DIR) never looked at it. Rewritten onto the
  same HERE idiom every other suite here uses -- both to fix the runtime
  break and because the inline dirname form false-positived the gate's
  self-resolved-root check (category 1 pattern-matches any dirname+$0
  next to a /.. sequence, root climb or not). It moves to scripts/provision/
  with the rest of the provision-phase scripts, so it gets the same
  temporary-path comment as the other twelve.
- validate-alertmanager-templates.sh's FIXTURE_DIR is a Python string
  literal inside a heredoc, invisible to a shell-oriented gate; it still
  pointed at scripts/alertmanager-fixtures. Re-verified end to end with
  task ci:validate (gate 3 still renders and matches golden).
- validate-vector-vrl.sh's VRL_DIR is a $SCRIPT_DIR reference to a
  directory, not a .sh/.py file, so the gate's regex (which requires that
  suffix) never checked it either.

scripts/lib/ and scripts/openbao-snapshot.sh are not part of the sixteen:
per the design doc's target layout, lib/ is "unchanged -- already
correct" and openbao-snapshot.sh is a symlink that never moves, so
neither gets the revisit comment.
Task 7 selected files with a *.md glob, which covers all ten symlinked
CLAUDE.md files. `sed -i` replaces a symlink with a regular file even when
the pattern matches nothing -- measured -- so the rewrite would have
converted every one and silently undone ADR-0038, merged five days ago.
It now selects with `git grep -l` on the moved basenames and passes
--follow-symlinks.

The same glob both over- and under-selected: 180 files chosen to rewrite
56, while clusters/, observability/, infrastructure/, flux/ and every
opentofu .tf/.tm.hcl went unselected despite holding live references.

Task 9 said to create docs/specs/README.md, which already exists and
carries the retired-workflow notice. It now appends.
Five files kept a depth the moves invalidated; none is visible to
test-script-paths.sh, since none is a self-resolved root, a source
statement, or a $HERE/$SCRIPT_DIR reference ending in .sh/.py -- the
gate's three categories, by design.

- test-no-secret-argv.sh: scan_dir_for_argv_leaks was rooted two levels
  too deep, so its four scan roots (scripts/*.sh, lib/, workflows/,
  opentofu/) resolved to nothing and the credential-leak guard passed
  over an empty set while still printing "ok".
- check-substitution.py and render-bundle.py: REPO_ROOT used
  parents[2], correct one move ago, wrong by one now. The former made
  validate-manifests.sh's step [1/6] report "0 Flux Kustomization(s)
  checked; consistent" -- a false green I had already captured in this
  report's Task 5/6 evidence and read past. The latter made
  render-bundle.py's own mise.toml lookup miss silently and made
  test-render-bundle.py's "real HelmReleases" case find 0.
- preflight.sh: same off-by-one on its own REPO_ROOT, same silent
  mise.toml miss, falling back to a bare PATH lookup for
  flux/helm/kustomize with no error.
- test-check-substitution.py and test-render-bundle.py: loaded their
  subject relative to their own directory, two levels short of where
  Task 5 actually put it; both raised FileNotFoundError.

Also: added the "subject moves later" comment to the two
openbao-snapshot.sh references, on review's adjudication that the
symlink's final home is not yet settled despite Task 6's "never moves"
reasoning.

Verified by running each fixed thing directly, not by re-running the
gate: check-substitution.py now reports 68 Kustomizations (was 0), the
argv scan's four roots cover 39 files again (was ~0), both flux-schema
unit-test files run to completion, task ci:validate still renders 2115
resources in 278 files with all three gates green, and task ci:test
stays 0 failed.
…e split

-maxdepth 1 on the first scan root was correct while every script lived
flat in scripts/; Task 4/5/6 split scripts/ into subdirectories, and the
flag silently dropped every moved file (28 scripts) from a
credential-leak guard that kept reporting "ok". Same failure class as
fix round 1, this time introduced by the moves rather than merely
exposed by them.

Dropped -maxdepth 1 and made the first root fully recursive; removed
the now-redundant separate lib/ root, since it is inside scripts/ and
the recursive root already reaches it. The two external roots
(.github/workflows, opentofu/) are unchanged. Reworded the self-test
fixture's stale "lives under scripts/ too" comment, which assumed a
depth this suite no longer sits at and will move from again.

Verified with canaries planted in the newly-covered territory
(scripts/ci/ and scripts/ci/tests/), not by re-running the gate: both
caught and correctly named, both removed, tree confirmed clean
afterward. First root now covers 62 files (26 former top level + 33
under ci/ + 3 lib/, folded into one root instead of two) -- more than
the pre-fix estimate, not less, since nothing previously covered
dropped out.
…ed state

The quarantine moved test-flux-schema.sh out of scripts/ci/tests/, so
Task 7's basename list is 36 entries, not 37, and must not map the
quarantined suite.

Task 7 now carries the 11 doc paths verify-doc-paths.sh actually reports,
as its acceptance criterion, rather than leaving the implementer to
discover them.

Task 9 gains a step for commands.md, which still advertises the quarantined
suite as working. A bare filename is not a repo path, so no gate flags it.

Also corrects the temporary-subject note: 17 lines over 8 subjects, and the
openbao-snapshot pair does carry a revisit comment, per my own earlier
adjudication. Two prior drafts of that note were wrong.
Anchored on moved basenames rather than the bare 'scripts/' token, so the
module-local opentofu/**/cluster/scripts/ directories are untouched. The
dated plan and spec archive keeps its original paths.

Also fixes scripts/ci/tests/test-no-secret-argv.sh's docstring, which still
described the pre-split scan (non-recursive, separate lib/ pass): the scan
has been fully recursive since the test suites moved under scripts/ci/tests/.
The 60 lines arguing for which suites to name are replaced by a requires
header on the four suites that need one. Job names are unchanged, so the
required-check list on main is untouched.
…uite

main added test-ci-notify-main-broken.sh at scripts/ root with a hand-added
step in the links job. This branch replaces hand-added steps with discovery
under scripts/ci/tests/, where run.sh never looked for it.

- Move the suite to scripts/ci/tests/ and fix its workflow path depth
  (../ -> ../../../).
- run.sh: exit 77 is a skip. It prints SKIP with the suite's last output line
  as the reason and counts toward skipped, not passed or failed.
- The suite exits 77 without pyyaml instead of 0, closing the known gap its
  comment recorded.
- Drop the links job's notifier step; task ci:test in kubernetes-validation
  runs it, after that job's pyyaml install. Job names are unchanged.
- scripts/AGENTS.md says where it runs now.
ADR-0039 also gives the 2026-07 Dagger decommission a durable home; until
now its only trace was three orphaned comments in ci.yaml.

The commands reference now marks test-flux-schema.sh as quarantined. No
gate would have flagged the stale row: verify-doc-paths.sh skips a bare
filename, because it is not a repository path.
c1c86f9 said the Dagger decommission's only trace was three orphaned
comments in ci.yaml. That was wrong: ci.yaml:63-73 explains why the last
Dagger step left (tflint's anonymous rate limit). What had no durable home
was the decision itself: why it was made, and that it covers every job.

task check now runs every scripts/ci gate the workflows run, adding
doc-claims, idp-topology and doc-paths. CI still calls them one per job,
because a required check is a job.
A pure rename, so history follows the file. go-task stops its upward
search at the first taskfile it finds, so from under scripts/ the old name
shadowed the root taskfile and no ci:* task existed there.
A bare `task` called a task named `--list` and exited 201. From under
scripts/, the included taskfile's commands resolved to scripts/scripts/ci/;
they are now anchored on {{.TASKFILE_DIR}}, so nothing depends on the
directory task was started from.

go-task floated on `task = "3"` while every other tool is pinned exactly;
it is now 3.53.1. ci:vector-vrl joins the index so `task --list` names
every entry point; it stays out of `check` because CI does not run it.

ADR-0039 and the root AGENTS.md now say only what is true: three of seven
ci.yaml jobs run mise-action, the links job runs three gates, 19 of 21
shell suites ran from the old list, and `check` is a hand-kept mirror of
the workflows.
run.sh exits 1 when it finds no suite, test-script-paths.sh when its
coverage falls below the floor measured when it was written (20 sources),
check-substitution.py when it checked no Kustomization, and
test-no-secret-argv.sh when any scan root yields no file. Each of these
reported green over an empty input before.

run.sh also discovers top-level test-*.py, so "every suite in this
directory" is true, prints "no reason given" for a silent exit 77, and its
header records exit 77 as a deliberate, narrow exception to the design.
Revisit comments said the subjects move to scripts/provision/. That is
wrong for cnpg-promote-seed.sh, which is an operator script, and unsettled
for openbao-snapshot.sh, so every one now says only that the path moves
with its subject. test-secret-store-lint.sh gains the same note.

The quarantined flux-schema suite and the .gitignore comment now name
scripts/ci/flux-schema/, and the quarantine README drops a ci.yaml line
number that no longer exists and says how to move the suite back out.
The suites moved to the Kubernetes validation job, but jq was still
installed in the shellcheck job "for the test suites below". It now
installs in the job that runs them, and the shellcheck job installs only
shellcheck.

The manifest gate runs even when a suite fails, so a red suite no longer
hides whether the manifests validate; the job still fails. Job names are
unchanged, since they are the required-check contexts.
@Smana
Smana force-pushed the worktree-scripts-restructure branch from 7ec01df to 6c50b14 Compare September 21, 2026 21:21
@Smana
Smana merged commit affdd50 into main Sep 21, 2026
15 checks passed
@Smana
Smana deleted the worktree-scripts-restructure branch September 21, 2026 21:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: 12 scripts/test-*.sh exist and CI runs none of them

1 participant