Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6371f60eeb
|
No files matched your search
@@ -356,7 +356,13 @@ Reference implementation: `template-chart/values.schema.json` and `template-char
|
||||
|
||||
**Two things about the mechanics that are easy to lose:**
|
||||
|
||||
- **`null` reaches the schema in one case and not the other.** For a key **with** a chart default, Helm's coalescing treats the `null` as a deletion and removes it *before* schema validation — the schema never sees it, and only the helper can catch it. For a key **without** a default (e.g. `resources.limits`), there is nothing to delete, the `null` survives into validation, and a strict `"type": "object"` aborts the render. That is why the helper **and** the widened `["object", "null"]` types are both needed: each covers a case the other cannot. Everything else stays strictly typed.
|
||||
- **`null` reaches the schema in two cases out of three, and which one you are in depends on the chart's default, not on what the user wrote.** Measured on Helm 3.22.0 with a probe chart, because the wording here was wrong before and was applied to exactly the case it got wrong:
|
||||
- a user `null` over a **non-null** chart default (`--set x=null`, or `x: null` in a values file) is treated as a deletion and the key is removed *before* schema validation — the schema never sees it, and only the helper can catch it;
|
||||
- a **`null` chart default** survives into validation with or without a user `null` on top of it, because there is nothing to delete it against, and the schema sees the key present with value `null`;
|
||||
- a key **without any default** (e.g. `resources.limits`) likewise survives, and a strict `"type": "object"` aborts the render.
|
||||
|
||||
That is why the helper **and** the widened `["object", "null"]` / `["string", "null"]` types are both needed: each covers a case the other cannot. Everything else stays strictly typed.
|
||||
- **A value that has no valid default cannot be enforced by `values.schema.json` at all, and `required()` is the whole enforcement.** The chain is short and it has no exit (#18): the key ships as `null`, so it is *present* at validation time, and JSON Schema's `required` tests presence and not null-ness — the array never fires, under any input. The two ways to make it fire both break the rule that `helm lint --strict` passes on chart defaults, since lint validates those defaults against the schema: dropping the `null` default gives `missing property '<key>'`, and narrowing `["string", "null"]` to `"string"` gives `got null, want string` — each a red `validate-charts` run on a chart nobody touched. So such a key is guarded with `required()` in the template and **described** as required in the schema; a `required` array next to it would be a guard that cannot fire, which is the same defect as a value that does nothing, dressed as a safeguard. This is why no chart in this repo carries one.
|
||||
- **Validate every schema against the real values, not only against chart defaults.** Defaults are valid by construction, so they prove nothing. Render each chart against its bundle in `cluster-config/fleet-cd/` **and** against `helm get values` — the two differ more often than expected (four of ten bundles in one wave, always with the repo file being the worse one). This step caught a schema of mine that would have broken three live paperless releases, because all three write `tikaGotenberg.enabled` as the string `"true"` and the first draft demanded a boolean. Result per chart is a **list of rejected keys**, which is the cluster side's work order before the version is pulled up.
|
||||
|
||||
### 13. Everything else
|
||||
|
||||
@@ -5,7 +5,7 @@ name: calibre-web-automated
|
||||
description: A Helm chart to deploy calibere-web-automated
|
||||
icon: https://raw.githubusercontent.com/crocodilestick/Calibre-Web-Automated/main/README_images/cwa-logo-round-dark.png
|
||||
|
||||
version: 6.1.0+upv4.0.6
|
||||
version: 7.0.0+upv4.0.6
|
||||
appVersion: v4.0.6
|
||||
|
||||
maintainers:
|
||||
|
||||
@@ -61,7 +61,7 @@ THE FIRST START BUILDS A LIBRARY, AND THE STARTUP PROBE IS TIMING IT
|
||||
kubectl -n {{ .Release.Namespace }} logs {{ $pod }} -f
|
||||
|
||||
SECRETS — THE FIELDS THE 1PASSWORD ITEM MUST CARRY
|
||||
{{ if .Values.secrets.cwaSecretRef }}{{ .Values.secrets.cwaSecretRef }}{{ else }}(secrets.cwaSecretRef is unset — see below){{ end }}
|
||||
{{ .Values.secrets.cwaSecretRef }}
|
||||
→ Secret {{ .Release.Name }}-{{ .Chart.Name }}-secret
|
||||
hardcover-api-token becomes the HARDCOVER_TOKEN environment variable
|
||||
calibre-plugins mounted as /config/.config/calibre/customize.py.json,
|
||||
@@ -74,13 +74,10 @@ SECRETS — THE FIELDS THE 1PASSWORD ITEM MUST CARRY
|
||||
hardcover-api-token parks the pod in CreateContainerConfigError; a missing
|
||||
calibre-plugins fails the mount instead ("couldn't find key calibre-plugins"),
|
||||
and the container is never created at all.
|
||||
{{- if not .Values.secrets.cwaSecretRef }}
|
||||
|
||||
secrets.cwaSecretRef IS UNSET. The OnePasswordItem has been created with an
|
||||
empty itemPath, the operator has nothing to resolve, and the Secret above will
|
||||
never appear — the pod cannot start. Set it to the item's op:// path and
|
||||
upgrade.
|
||||
{{- end }}
|
||||
secrets.cwaSecretRef itself is required: the template guards it with
|
||||
required(), so a release without it does not render at all rather than
|
||||
creating a OnePasswordItem with an empty itemPath.
|
||||
|
||||
CHANGING THE ITEM'S CONTENT RESTARTS NOTHING
|
||||
Helm never sees what is inside a OnePasswordItem, so it cannot hash it into the
|
||||
|
||||
@@ -3,4 +3,4 @@ kind: OnePasswordItem
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-secret
|
||||
spec:
|
||||
itemPath: {{ .Values.secrets.cwaSecretRef }}
|
||||
itemPath: {{ required "A 1Password item reference must be provided (secrets.cwaSecretRef)" .Values.secrets.cwaSecretRef }}
|
||||
@@ -17,6 +17,7 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"cwaSecretRef": {
|
||||
"description": "op:// item path carrying \"hardcover-api-token\" and \"calibre-plugins\". Required - the OnePasswordItem, the HARDCOVER_TOKEN env reference and the plugin volume are all rendered unconditionally. Enforced by required() in the template, not here: the null default keeps this type widened, and a schema \"required\" entry could never fire against a key that is present with value null.",
|
||||
"type": ["string", "null"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
scaleDown: false
|
||||
|
||||
secrets:
|
||||
# REQUIRED - op:// item path for the 1Password operator, carrying the fields
|
||||
# "hardcover-api-token" and "calibre-plugins". Both are needed even if you
|
||||
# never use Hardcover: the OnePasswordItem is created unconditionally, and so
|
||||
# are the environment reference and the volume. Without this value the render
|
||||
# aborts - required() in calibre-web-automated.secret.yaml is the whole
|
||||
# enforcement, and values.schema.json cannot help here (README, guideline 12).
|
||||
# Before the guard existed it produced an OnePasswordItem with an empty
|
||||
# itemPath, the operator had nothing to resolve, the Secret never appeared and
|
||||
# the pod could not start.
|
||||
cwaSecretRef: null
|
||||
|
||||
cwa:
|
||||
|
||||
@@ -23,7 +23,7 @@ type: application
|
||||
# continuously, so a pod restart could pull a different image than the last one
|
||||
# without anything being recorded anywhere. The dated tags are immutable, so the
|
||||
# image is now pinned by the chart version like every other chart in this repo.
|
||||
version: 5.0.0+up2026.8.2.java25
|
||||
version: 6.0.0+up2026.8.2.java25
|
||||
appVersion: "2026.8.2-java25"
|
||||
|
||||
maintainers:
|
||||
|
||||
@@ -204,9 +204,11 @@ OPERATORS ARE SYNCHRONIZED FROM VALUES, NOT FROM THE GAME
|
||||
SECRETS — WHICH FIELDS THE 1PASSWORD ITEM MUST CARRY
|
||||
The OnePasswordItem CR {{ $secret }} is rendered unconditionally, so
|
||||
secrets.minecraftServerRef has to be set even when nothing consumes a key from
|
||||
it; it has no default and would otherwise render an itemPath of null.
|
||||
it; it has no default and would otherwise render an itemPath of null. The
|
||||
template guards it with required(), so a release without it does not render at
|
||||
all — this note tells you why the guard is there, not that you got past it.
|
||||
|
||||
secrets.minecraftServerRef → {{ .Values.secrets.minecraftServerRef | default "NOT SET" }}
|
||||
secrets.minecraftServerRef → {{ .Values.secrets.minecraftServerRef }}
|
||||
|
||||
The operator copies the item's FIELDS into the Kubernetes Secret, one key per
|
||||
field name. This release consumes:
|
||||
|
||||
@@ -3,4 +3,4 @@ kind: OnePasswordItem
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-secret
|
||||
spec:
|
||||
itemPath: {{ .Values.secrets.minecraftServerRef }}
|
||||
itemPath: {{ required "A 1Password item reference must be provided (secrets.minecraftServerRef) - the OnePasswordItem is rendered unconditionally, so it is needed even with RCON and CurseForge both off" .Values.secrets.minecraftServerRef }}
|
||||
@@ -28,6 +28,7 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"minecraftServerRef": {
|
||||
"description": "op:// item path for the 1Password operator. Required even when RCON and the CurseForge downloader are both off: the OnePasswordItem is rendered unconditionally. The item's CONTENT may be empty in that case, the reference may not. Enforced by required() in the template, not here: the null default keeps this type widened, and a schema \"required\" entry could never fire against a key that is present with value null.",
|
||||
"type": ["string", "null"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +37,15 @@ image:
|
||||
tagOverride: ""
|
||||
|
||||
secrets:
|
||||
# op:// item path for the 1Password operator. Only needs to carry a
|
||||
# "curseforge-api-key" key when curseforge.enabled is true and an
|
||||
# "rcon-password" key when server.rcon.enabled is true.
|
||||
# REQUIRED - op:// item path for the 1Password operator. The OnePasswordItem
|
||||
# CR is rendered unconditionally, so this reference has to be set even when
|
||||
# nothing consumes a key from it; it has no default and would otherwise render
|
||||
# an itemPath of null. The item's CONTENT may be empty in that case: it only
|
||||
# needs to carry a "curseforge-api-key" key when curseforge.enabled is true
|
||||
# and an "rcon-password" key when server.rcon.enabled is true. Without the
|
||||
# value the render aborts - required() in minecraft-server.secret.yaml is the
|
||||
# whole enforcement, and values.schema.json cannot help here (README,
|
||||
# guideline 12).
|
||||
#
|
||||
# Documented limit (chart 3.0.0): changing this path rolls the pod (the
|
||||
# StatefulSet hashes the rendered OnePasswordItem into checksum/secret-ref),
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ type: application
|
||||
# (2026.8.22-9fea41204) and "latest" moves daily. appVersion is therefore the
|
||||
# exact tag, and the +up suffix normalizes the dash to a dot as the versioning
|
||||
# scheme requires - the same shape rss-bridge and minecraft-server use.
|
||||
version: 1.0.5+up2026.9.13.3b8009065
|
||||
version: 1.0.6+up2026.9.13.3b8009065
|
||||
appVersion: "2026.9.13-3b8009065"
|
||||
|
||||
maintainers:
|
||||
|
||||
@@ -19,9 +19,10 @@ Usage (the values path to the resources dict varies per chart):
|
||||
resources:
|
||||
{{- include "searxng.resources" .Values.<app>.resources | nindent 12 }}
|
||||
|
||||
NOTE: charts in this repo deliberately have no dependencies, so this helper is
|
||||
duplicated into every chart's templates/_helpers.tpl with the chart's name as
|
||||
define prefix. template-chart holds the reference implementation.
|
||||
NOTE: this helper is duplicated into every chart's templates/_helpers.tpl with
|
||||
the chart's name as define prefix, because sharing it would mean a library
|
||||
chart, and a dependency is admissible but expensive (README, guideline 14) -
|
||||
this chart takes none. template-chart holds the reference implementation.
|
||||
*/}}
|
||||
{{- define "searxng.resources" -}}
|
||||
{{- $resources := . | default dict -}}
|
||||
@@ -168,9 +169,9 @@ Rules:
|
||||
- keys only present in the override are passed through unchanged.
|
||||
|
||||
NOTE: like the helpers above, this is duplicated into every chart's
|
||||
templates/_helpers.tpl with the chart's name as define prefix, because charts
|
||||
in this repo deliberately have no dependencies. template-chart holds the
|
||||
reference implementation.
|
||||
templates/_helpers.tpl with the chart's name as define prefix, because sharing
|
||||
it would mean a library chart and this chart takes no dependency (README,
|
||||
guideline 14). template-chart holds the reference implementation.
|
||||
*/}}
|
||||
{{- define "searxng.defaultedDict" -}}
|
||||
{{- $defaults := .defaults | default dict -}}
|
||||
|
||||
@@ -6,6 +6,9 @@ metadata:
|
||||
spec:
|
||||
# Optional, and only meaningful with settings.limiter: true. The item must
|
||||
# carry a "valkey-url" field pointing at an EXTERNAL Valkey/Redis; the chart
|
||||
# deploys none of its own, because charts in this repo have no dependencies.
|
||||
# deploys none of its own. Chart dependencies are admissible since #214
|
||||
# (README, guideline 14), but this chart declares none: an external connection
|
||||
# through a secret is the same shape outline and paperless-ngx use for their
|
||||
# databases.
|
||||
itemPath: {{ .Values.secrets.valkeySecretRef }}
|
||||
{{- end }}
|
||||
+4
-4
@@ -32,10 +32,10 @@ secrets:
|
||||
# unless the bot detection below is switched on.
|
||||
#
|
||||
# Setting it renders a second OnePasswordItem and passes the URL to the
|
||||
# container as SEARXNG_VALKEY_URL. The chart ships NO Valkey of its own -
|
||||
# charts in this repo have no dependencies (README, guideline 13), so an
|
||||
# external connection through a secret is the same shape outline and
|
||||
# paperless-ngx use for their databases.
|
||||
# container as SEARXNG_VALKEY_URL. The chart ships NO Valkey of its own.
|
||||
# Chart dependencies are admissible since #214 (README, guideline 14), but
|
||||
# this chart declares none, so an external connection through a secret is the
|
||||
# same shape outline and paperless-ngx use for their databases.
|
||||
valkeySecretRef: null
|
||||
#
|
||||
# Documented limitation (README, guideline 9): the CONTENT of these items is
|
||||
|
||||
@@ -4,5 +4,5 @@ description: A Helm chart to deploy urlaubsverwaltung on Kubernetes
|
||||
icon: https://raw.githubusercontent.com/urlaubsverwaltung/urlaubsverwaltung/main/src/main/resources/static/favicons/apple-touch-icon.png
|
||||
type: application
|
||||
|
||||
version: 9.0.3+up6.12.1
|
||||
version: 10.0.0+up6.12.1
|
||||
appVersion: 6.12.1
|
||||
@@ -3,4 +3,4 @@ kind: OnePasswordItem
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-db-secret
|
||||
spec:
|
||||
itemPath: {{ .Values.secrets.databaseSecretRef }}
|
||||
itemPath: {{ required "A database Secret Reference must be provided (secrets.databaseSecretRef)" .Values.secrets.databaseSecretRef }}
|
||||
@@ -3,4 +3,4 @@ kind: OnePasswordItem
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret
|
||||
spec:
|
||||
itemPath: {{ .Values.secrets.oidcSecretRef }}
|
||||
itemPath: {{ required "An OIDC Secret Reference must be provided (secrets.oidcSecretRef)" .Values.secrets.oidcSecretRef }}
|
||||
@@ -17,9 +17,11 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"databaseSecretRef": {
|
||||
"description": "op:// item path carrying \"jdbc-url\", \"username\" and \"password\". Required - the chart deploys no database and all state lives in the external one. Enforced by required() in the template, not here: the null default keeps this type widened, and a schema \"required\" entry could never fire against a key that is present with value null.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"oidcSecretRef": {
|
||||
"description": "op:// item path carrying \"client-id\", \"client-secret\", \"issuer-name\", \"issuer-uri\", \"jwt-issuer-uri\" and \"redirect-uri\". Required - the chart offers no non-OIDC login and the app resolves the issuer at boot. Enforced by required() in the template, not here: the null default keeps this type widened, and a schema \"required\" entry could never fire against a key that is present with value null.",
|
||||
"type": ["string", "null"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,21 @@
|
||||
scaleDown: false
|
||||
|
||||
secrets:
|
||||
# REQUIRED - op:// item path carrying "jdbc-url", "username" and "password".
|
||||
# This chart deploys NO database; all state lives in the external one, and
|
||||
# three datasource environment variables read these keys unconditionally.
|
||||
# Without the value the render aborts - required() in
|
||||
# urlaubsverwaltung-db.secret.yaml is the whole enforcement, and
|
||||
# values.schema.json cannot help here (README, guideline 12).
|
||||
databaseSecretRef: null
|
||||
# REQUIRED - op:// item path carrying "client-id", "client-secret",
|
||||
# "issuer-name", "issuer-uri", "jwt-issuer-uri" and "redirect-uri". This chart
|
||||
# offers no login path besides OIDC, and the identity provider is required at
|
||||
# boot, not at login: the application resolves <issuer-uri>/.well-known/
|
||||
# openid-configuration while building its security beans, before the HTTP port
|
||||
# opens, and exits when it cannot. Without the value the render aborts -
|
||||
# required() in urlaubsverwaltung-oidc.secret.yaml is the whole enforcement,
|
||||
# and values.schema.json cannot help here (README, guideline 12).
|
||||
oidcSecretRef: null
|
||||
|
||||
ingress:
|
||||
|
||||
Reference in new issue
Block a user