CI: валидировать values HelmRelease против схемы чарта (ловить «values don't meet the specifications of the schema») #72

Closed
opened 2026-09-20 19:06:41 +00:00 by hermes · 1 comment
hermes commented 2026-09-20 19:06:41 +00:00 (Migrated from git.grachevko.ru)

Зачем

20.09.2026 PR #70 смёржен, но реконсиляция упала: Helm upgrade failed ... values don't meet the specifications of the schema(s) — в controllers.hermes.containers.app.env использован valueFrom.secretKeyRef со свойством optional, которого нет в values.schema.json чарта app-template 5.2.1. CI этого не поймал: Flate проверяет только сборку kustomize, а values против схемы чарта не валидирует. Ошибка всплыла только в кластере, в ивентах и статусе HelmRelease.

Что должно быть

Пайплайн на PR краснеет, если values любого HelmRelease не соответствуют схеме его чарта (или если манифесты не рендерятся).

Варианты реализации

  1. flux-local (test --all или build --all) — рендерит Flux-объекты, тянет OCI-чарты и прогоняет helm template с values из git. Самый близкий к реальности вариант; так делают в публичных home-ops-репозиториях.
  2. Точечный helm template по каждому helmrelease.yaml: вытащить spec.chartRef и spec.values, скормить helm template — ловит именно values don't meet the specifications of the schema.
  3. kubeconform/kubeval по отрендеренному — ловит ошибки API-схемы, но не values.schema.json чарта, то есть нашу конкретную ошибку не поймает (в отличие от 1 и 2).

Рекомендация: 1 как основной, 2 — как дешёвый минимум, если flux-local в Gitea Actions не заводится.

Ограничения, которые учесть

  • CI крутится на Gitea Actions (.github/workflows/flate.yaml), а не на GitHub: часть экшенов и синтаксиса молча не работает — см. скилл home-ops-cluster, references/gitea-actions-portability.md.
  • Нужен сетевой доступ к ghcr.io за OCI-чартами и, вероятно, kubeconfig для части режимов flux-local (для build — не нужен).
  • Проверка должна ловить не только текущий класс ошибок, но и, например, strategy: Recreate для Deployment в app-template (тоже схемой валидируется).

Критерий готовности

Ветка с заведомо неверными values (например, env.FOO.valueFrom.secretKeyRef.optional: true для app-template 5.2.1) валит CI, а не реконсиляцию в кластере.

## Зачем 20.09.2026 PR #70 смёржен, но реконсиляция упала: `Helm upgrade failed ... values don't meet the specifications of the schema(s)` — в `controllers.hermes.containers.app.env` использован `valueFrom.secretKeyRef` со свойством `optional`, которого нет в `values.schema.json` чарта app-template 5.2.1. CI этого не поймал: Flate проверяет только сборку kustomize, а values против схемы чарта не валидирует. Ошибка всплыла только в кластере, в ивентах и статусе HelmRelease. ## Что должно быть Пайплайн на PR краснеет, если values любого HelmRelease не соответствуют схеме его чарта (или если манифесты не рендерятся). ## Варианты реализации 1. **`flux-local`** (`test --all` или `build --all`) — рендерит Flux-объекты, тянет OCI-чарты и прогоняет `helm template` с values из git. Самый близкий к реальности вариант; так делают в публичных home-ops-репозиториях. 2. **Точечный `helm template`** по каждому `helmrelease.yaml`: вытащить `spec.chartRef` и `spec.values`, скормить `helm template` — ловит именно `values don't meet the specifications of the schema`. 3. **`kubeconform`/`kubeval`** по отрендеренному — ловит ошибки API-схемы, но **не** `values.schema.json` чарта, то есть нашу конкретную ошибку не поймает (в отличие от 1 и 2). Рекомендация: 1 как основной, 2 — как дешёвый минимум, если `flux-local` в Gitea Actions не заводится. ## Ограничения, которые учесть - CI крутится на Gitea Actions (`.github/workflows/flate.yaml`), а не на GitHub: часть экшенов и синтаксиса молча не работает — см. скилл `home-ops-cluster`, `references/gitea-actions-portability.md`. - Нужен сетевой доступ к `ghcr.io` за OCI-чартами и, вероятно, kubeconfig для части режимов `flux-local` (для `build` — не нужен). - Проверка должна ловить не только текущий класс ошибок, но и, например, `strategy: Recreate` для `Deployment` в app-template (тоже схемой валидируется). ## Критерий готовности Ветка с заведомо неверными values (например, `env.FOO.valueFrom.secretKeyRef.optional: true` для app-template 5.2.1) валит CI, а не реконсиляцию в кластере.
Collaborator

Closed as implemented by the Flux Local gate (PR #209).

What now runs on every pull request touching kubernetes/**:

  • Flux Local - Test inflates the cluster with helm (--enable-helm --all-namespaces) and validates the values of every HelmRelease against its chart's values.schema.json. That is exactly this issue's class: a value the schema rejects used to reach the rendered output with exit code 0 and fail only in the cluster.
  • Flux Local - Diff renders the HelmReleases at the head and at the base branch and posts the difference as a review comment, so a value bump shows its blast radius where it is reviewed.

Negative control, the case from this issue: a stray optional: true under valueFrom.secretKeyRef fails the run with additional properties 'optional' not allowed. On the current tree the same command reports 128 passed and no failures, and the workflow runs green in our own runner (run 179, jobs Test and Diff both success).

Two releases used to be the exception: the harbor and vault charts came from a git repository, because their upstream chart repositories sit behind CloudFront and are unusable from our network, and a chart in a git repository is exactly what flux-local cannot inflate. Both now come from our own registry as OCI artifacts (oci://harbor.grachevko.ru/charts/<name>) via PR #207 and the mirror in grachevko/charts, with the internal-CA trust for source-controller added in PR #208. The gate therefore covers every release without exceptions.

Not covered here, tracked separately:

  • reference integrity of secretKeyRef/configMapKeyRef/volumes (#74) — rendering does not resolve references;
  • execution of ESO templates (#64) — templates run in the controller, not at render time;
  • the namespace half of #81 (objects of a Kustomization without targetNamespace must carry their own namespace). The other half of #81 — a HelmRelease source has to exist in the render — is covered by this same gate: renaming a chartRef target fails the run with Unable to find OCIRepository for <name> for HelmRelease <release>.
Closed as implemented by the `Flux Local` gate (PR #209). What now runs on every pull request touching `kubernetes/**`: - `Flux Local - Test` inflates the cluster with helm (`--enable-helm --all-namespaces`) and validates the values of every HelmRelease against its chart's `values.schema.json`. That is exactly this issue's class: a value the schema rejects used to reach the rendered output with exit code 0 and fail only in the cluster. - `Flux Local - Diff` renders the HelmReleases at the head and at the base branch and posts the difference as a review comment, so a value bump shows its blast radius where it is reviewed. Negative control, the case from this issue: a stray `optional: true` under `valueFrom.secretKeyRef` fails the run with `additional properties 'optional' not allowed`. On the current tree the same command reports 128 passed and no failures, and the workflow runs green in our own runner (run 179, jobs `Test` and `Diff` both success). Two releases used to be the exception: the harbor and vault charts came from a git repository, because their upstream chart repositories sit behind CloudFront and are unusable from our network, and a chart in a git repository is exactly what flux-local cannot inflate. Both now come from our own registry as OCI artifacts (`oci://harbor.grachevko.ru/charts/<name>`) via PR #207 and the mirror in grachevko/charts, with the internal-CA trust for source-controller added in PR #208. The gate therefore covers every release without exceptions. Not covered here, tracked separately: - reference integrity of `secretKeyRef`/`configMapKeyRef`/volumes (#74) — rendering does not resolve references; - execution of ESO templates (#64) — templates run in the controller, not at render time; - the namespace half of #81 (objects of a Kustomization without `targetNamespace` must carry their own namespace). The other half of #81 — a HelmRelease source has to exist in the render — is covered by this same gate: renaming a `chartRef` target fails the run with `Unable to find OCIRepository for <name> for HelmRelease <release>`.
Sign in to join this conversation.
No labels
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
grachevko/home-ops#72
No description provided.