Only the newest Java line is maintained from now on. Publishing the chart once
per line out of one directory is what made the lines drift apart (#158): a
change reached whichever line happened to lie in the directory. java8 and java17
stay published as frozen artifacts at 4.0.0, java21 at 4.1.0, and none of them
gets another chart change.
Running an older JVM is now a decision at rollout time instead of a chart
version: image.tagOverride replaces the tag that otherwise comes from
appVersion. It is not called image.tag because it decouples the running image
from the chart version, and it is deliberately outside Renovate's reach -
renovate.json5 keeps tracking appVersion only.
The pairing of tag and minecraft.version is now checked at render time and fails
with both values named, the line each one belongs to, and where the tag came
from. Until now nothing checked it: a mismatch installed silently and only the
container failed afterwards. The boundaries are Mojang's, swept over all 102
releases of the piston-meta manifest (javaVersion.majorVersion): up to 1.16.5
Java 8, 1.17-1.17.1 Java 16, 1.18-1.20.4 Java 17, 1.20.5-1.21.11 Java 21, 26.1
and later Java 25. The 1.17 line was the one gap the chart's own notes did not
cover.
Two cases pass unchecked on purpose, documented in values.yaml and NOTES.txt: a
tag without a recognizable java<N> part, and a minecraft.version that is not a
plain numeric x[.y[.z]]. A guard that rejects what it does not understand gets
worked around instead of respected.
Major, because an installation that already runs a mismatched pair stops
rendering. It does not run today either - it now fails earlier and visibly.
game.seasonalEvents was handed to the container unchanged, into the image's
DISABLESEASONALEVENTS. Its default true therefore wrote
DISABLESEASONALEVENTS=true: the seasonal events were OFF in every install
this chart has ever produced, while values.schema.json described the very
same key as "true means events are enabled" (#215).
Of the two ways out, this is the loud one. Inverting the template under the
old key would have flipped the behaviour of every existing release in
silence - the same class of mistake that created the issue. Renaming the key
cannot be missed: game.seasonalEvents no longer exists, additionalProperties
is false on the game block, and a values file that still carries it fails
schema validation on upgrade instead of quietly meaning the opposite.
The new key is positive (enableSeasonalEvents) to avoid a double negative,
so the chart negates it on the way into the env var. Go's "not" cannot do
that: it reads every non-empty string as true, and the schema deliberately
accepts the string form of booleans, so "false" would have flipped the wrong
way. The helper compares explicitly and fails on anything that is neither
true nor false rather than filing it under "off".
The default is enableSeasonalEvents: false, which renders the
DISABLESEASONALEVENTS this chart has always rendered. At chart defaults the
6.1.0 and 7.0.0 manifests are identical, so upgrading alone moves no server;
switching the events on is now a deliberate act with a key that means it.
Separate finding from the same issue, fixed here because it lives in the
block being touched: "--set game=null" - or a leftover "game:" whose
sub-keys were deleted - aborted the render with a nil pointer at
.Values.game.maxPlayers. The game block never got the null-safe treatment of
#99 that probes, security contexts and resources have. It now falls back to
the documented defaults, and the schema accepts the null accordingly. The
same gap remains in the dev and server blocks; it is reported, not fixed
here.
Major bump: a values key is removed, and the schema rejects it.
The chart told operators that adding a duplicate env name to an installed
release makes the next upgrade fail in the API server, quoting "The order in
patch list ... doesn't match $setElementOrder list". Measured against helm
3.19.0 and Kubernetes 1.35, it does not fail: the upgrade succeeds, helm prints
"Release has been upgraded", and Kubernetes merges the env list by name, so the
duplicate pair collapses to the chart's own entry and the operator's override is
discarded without a word. At install time the same values behave differently -
both entries reach the pod, the later one wins, and the API server says so with
"hides previous definition of ..., which may be dropped when using apply".
The advice that followed from the old claim survives - such a switch only takes
at install time - but the stated reason was wrong in the dangerous direction. A
reader who expects a loud failure treats a green upgrade as proof the override
took effect, and green is exactly what a silently dropped override looks like.
The text now names the real failure mode and tells the reader to read the value
back off the Deployment. README carries the same correction, because every chart
in this repo offers the same additive env block.
Also records what the earlier measurement left open. With the database scaled
back up the pod returns to Ready on its own after about five seconds, restart
count still 0, so leaving the liveness group untouched costs no manual recovery.
And the limit of that signal belongs next to it: the db indicator validates a
connection, not the schema, so a database that came back empty still put the pod
back to Ready with /actuator/health at 200.
MANAGEMENT_ENDPOINT_HEALTH_GROUP_READINESS_INCLUDE=readinessState,db puts the datasource into Spring Boot's readiness group, which shipped with readinessState alone: a total database outage left the pod 1/1 Ready while every request failed. Naming the members replaces the default, so readinessState is repeated. The liveness group stays untouched on purpose, because an outage has to keep traffic away rather than add a crash loop to it.
MANAGEMENT_HEALTH_MAIL_ENABLED=false removes the mail indicator, which pinned the aggregate /actuator/health at 503 for the whole life of a healthy release, because the chart's mail wiring points at localhost:1025 where nothing listens. values.yaml and NOTES.txt document what that costs and when it has to be switched back on.
The publish step no longer speaks OCI. "helm registry login", "helm push"
and "helm registry logout" are replaced by a single HTTP POST of the
packaged .tgz to <charts-url>/api/charts, with Basic auth per request.
Credentials and the target URL come from a new 1Password item
op://GitHub-Actions/jlab-registry-access (username, password, charts-url).
The old item is left untouched, so a revert of this commit restores the
previous pipeline without any further work. No registry address enters
the repository.
The three properties of the old step survive:
- values are read via steps.<id>.outputs.* into the step's own env block
and used as quoted shell variables, each guarded with ":?"
- credentials stay out of argv: "curl --config -" instead of "--user"
- a failed upload fails the job: "--fail-with-body", because curl exits 0
on HTTP 401/403/409 without it and the publish would go green with
nothing uploaded
The "<chart>-*.tgz" glob is replaced by the file name built from the
chart name and the version already read from Chart.yaml; --upload-file
takes exactly one file. Two small additions fall out of measuring the
new step: the registry host is masked, because a curl connection error
prints only "<host>:<port>" and the mask on the full URL does not cover
that, and whitespace in the credentials is rejected up front, because an
unquoted curl config value ends at the first space.
No chart is touched and no chart version is bumped.
Minecraft 26.2 requires Java 25, so the chart's default minecraft.version can
only be raised on a java25 image. appVersion becomes 2026.8.2-java25 - the same
dated upstream release the java21 line ships, so the only variables that change
are the JVM and the Minecraft version.
The chart version stays at 4.1.0: the Java lines are siblings of one chart
generation, not successors, and are told apart by the +up suffix.
The Java boundaries in the values.yaml / NOTES.txt comments are read off
Mojang's version manifest (javaVersion.majorVersion per release), not
estimated: 1.21.11 is the last release asking for Java 21, every release from
26.1 on asks for Java 25.
Deploys matszwe02/ytdlp_web_player, a Flask app that fetches videos with
yt-dlp, transcodes them with ffmpeg and serves them as HLS. It ships no
authentication of any kind, so the chart carries a preconfigured oauth2-proxy
as an optional subchart, in the data path in front of the app.
This is the first chart in the repo with a dependency, so the rule "charts
have no dependencies" falls here. It is replaced in CLAUDE.md and README.md by
a bar: a dependency has to be optional and off by default, upstream's chart is
consumed as it comes (documented where it falls short of our conventions,
never patched), and the price is written down - above all that a subchart is
invisible to everything downstream watching Helm release versions, so a new
proxy release only reaches a cluster when this chart is republished.
CI learns the dependency in five places, not the three the plan expected:
helm lint, package, template and install all exit 1 while charts/ is unfilled,
so ci/helm-dependencies.sh runs before lint and package in validate-charts.yml,
before package in publish-helm-chart.yml, and inside run-install-test.sh,
run-trivy-config.sh and run-quantity-render-test.sh - the last of which renders
every chart on every PR and would have gone red first.
Notable chart decisions, each measured rather than assumed:
- The image has no USER and runs as root by default, but not by necessity: it
runs under an arbitrary uid with readOnlyRootFilesystem and the full
hardening baseline. Only the pinned uid is a deviation, and it is documented.
- Two emptyDirs, each justified separately. /data holds the video cache
(DATA_PATH). /tmp is NOT mounted - measured across metadata extraction, HLS
transcoding, sprite generation and audio extraction, the image never writes
there. What it does write is $HOME/.cache, so /cache is mounted with HOME and
XDG_CACHE_HOME pointed at it; without it yt-dlp re-downloads its JavaScript
challenge-solver from github.com on every extraction.
- The proxy is wired through config.configFile, the only value the subchart
passes through tpl - config.upstreams is emitted with toJson and would carry
a literal {{ .Release.Name }} into the manifest.
- Rendering aborts when this chart's Ingress and the proxy's claim the same
host: ingress-nginx rejects the second one and a Fleet bundle then sits in
ErrApplied until forceSyncGeneration is bumped.
Fixes#214
The NOTES.txt bullet still said the file was "planned (#43)" and named nine
charts as the ones shipping one. Both halves are now wrong: 23 of 23 charts
carry a templates/NOTES.txt, template-chart included. The count was also
wrong when it was written — the very commit that raised it to "nine" added
template-chart/templates/NOTES.txt, making it ten, and the enumeration was
never maintained. Replaced with a statement and no list, so the next new
chart cannot make it stale again; the quality bar the programme settled on
(rendered URL, which fields the 1Password item must carry, the options
actually active, the chart's traps — conditional on the values really set)
is kept and now reads as a requirement for new charts.
Two further statements corrected against origin/main:
- The chart table listed 22 of 23 charts; `bentopdf` was missing entirely
although it ships (bentopdf/Chart.yaml, 1.0.1+up2.8.7) and has CI fixtures.
- The homeassistant row advertised "has NOTES.txt and Helm tests". The
NOTES.txt half stopped being a distinguishing property once every chart
got one. The Helm tests half holds and is now stated as what it is:
homeassistant/templates/tests/test-connection.yaml is the only such file
in the repo.
Documentation only — no chart directory, no version bump, no publish.
Part of #43.
Adds ci/run-quantity-render-test.sh and a validate-charts job that runs it
over every chart on every PR.
The bug behind #157 has a loud and a silent half. Loud: a bare integer request
of 1048576 is reformatted by printf "%v" to "1.048576e+06", the helper rejects
the suffix it produced itself and the render aborts. Silent: with a fractional
limitFactor the *product* is reformatted after the suffix check, the render
succeeds, and the manifest carries memory: "1.4999985e+06" - rejected by
nothing until the API server sees it at apply time.
So the test renders each chart twice and, for the silent case, searches the
rendered text rather than the exit code. It runs over all charts, not the
changed ones: the resources helper is copied into every chart's _helpers.tpl,
so the regression arrives by copy, in a PR whose diff shows a new chart and not
the bug inside it. The resources paths come from values.schema.json (JSON, so
python3 reads it without pyyaml), which also means a new chart is enrolled
automatically and there is no list to maintain.
Charts that pin every computable limit in their fallback defaults never reach
the helper (gotenberg, rss-bridge). They are reported as "not exercised"
instead of counted as passing.
Part of #43. This chart was cited throughout that issue as the one that already has a NOTES.txt and therefore serves as the style reference for the whole programme. The file contained the single line "Hello :)". It is replaced here by the real thing, built on the pattern the later charts (zipline, voucher-vault, urlaubsverwaltung) established in the meantime.
It prints what an operator would otherwise have to read out of the templates: the access URL assembled from the chart's upstream-style ingress block (hosts x tls, so the scheme is derived per host rather than assumed) or the port-forward command; the three fields the 1Password item must carry (config, http-config, recorder-config) and how configuration.yaml has to include the other two itself; and the traps of this particular chart - onboarding hands the instance to the first visitor, use_x_forwarded_for/trusted_proxies decides between 400 Bad Request and one client IP for everyone, the three config files are read-only subPath mounts that the kubelet never refreshes, safe mode lets a broken configuration pass the probes, and helm uninstall deletes the PVC that holds all of the state.
Conditional sections cover scaleDown/replicas 0, replicas > 1 on a single ReadWriteOnce claim, a NET_RAW override that silently kills device discovery, a non-empty env block, the chart placeholder host chart-example.local, and the case where ingress.tls names a Secret while no cert-manager annotation is set - this chart adds none by itself, unlike the rest of the repo.
No domain appears in the file: hosts come from the values, examples use example.com. Minor bump, appVersion unchanged; a NOTES.txt changes no rendered object, verified by diffing helm template before and after.
Part of #157. The null-safe fallback helpers from #99 pass values through fromYaml, which parses every number as float64; Go's "%v" switches float64 to exponential notation from about 1e6 upwards. A bare byte count like 1048576 therefore reached multiplyQuantity as "1.048576e+06" and the render aborted on the suffix check.
This is the canonical correction already merged into the other charts, adopted verbatim with this chart's define prefix: multiplyQuantity formats its input and its non-integer product through a new formatNumber helper. The fromYaml round-trip itself is not touched - it is not the cause, and it has just been unified across all charts.
Measured against ci/homeassistant/test-values.yaml: resources.requests.memory=1048576 aborted before and now yields request 1048576 / limit "3145728"; 65536 still yields 196608. The silent variant matters here too - values.schema.json types resources.limitFactor as "number" with exclusiveMinimum 0, so a fractional factor is allowed and rendered an invalid quantity without any error (limitFactor 1.5 with memory 999999 produced memory: "1.4999985e+06"); it now produces 1499998.5.
Teil von #157.
The null-safe fallback helpers from #99 pass values through fromYaml, which
goes over JSON and therefore parses every number as float64. Go's "%v"
switches float64 to exponential notation from about 1e6 upwards, so a bare
byte count like 1048576 turned into "1.048576e+06" - not a valid Kubernetes
quantity. The suffix check in multiplyQuantity then aborted the render with
unsupported resource quantity suffix "e+06" in "1.048576e+06"
The second "%v" - the one printing a non-integer product - never reaches that
check and failed silently instead: with a fractional limitFactor it rendered
"1.4999985e+06" into the manifest, which only the API server rejects on apply.
Both call sites now go through a new rss-bridge.formatNumber helper that
forces decimal notation via printf "%.10f" and trims the padding zeros again;
the leading dot in the regex protects "100.0000000000" from collapsing to
"1". Strings such as "512Mi" pass through untouched.
This is the canonical fix from #157, applied verbatim with this chart's
prefix; the round-trip itself is not touched.
Note on this chart specifically: rss-bridge sets explicit memory and
ephemeral-storage limits as chart defaults, and an explicit limit always
wins, so multiplyQuantity is not reachable through this chart's values at
all - the bug was reproduced and the fix verified on a throwaway copy with
those default limits removed. The rendered output for the chart defaults and
for ci/rss-bridge/test-values.yaml is byte-identical to main.
Patch bump: no behavior and no values-schema change.
multiplyQuantity turned its input into a string with printf "%v". The
null-safe fallback helpers from #99 pass values through fromYaml, which
parses every number as float64, and Go's "%v" switches float64 to
exponential notation from about 1e6 upwards. A bare byte count like
1048576 therefore arrived as "1.048576e+06", the suffix check rejected
"e+06" and the render aborted.
The same printf sat on the second output path, for a non-integer product
(a fractional limitFactor - typed "number", not "integer", in this
chart's values.schema.json, so ordinary values reach it). That one never
passes the suffix check, so it produced an invalid quantity silently and
only the API server would have rejected the manifest on apply.
Both are now routed through a formatNumber helper that forces decimal
notation and trims the padding zeros. Strings ("512Mi") pass through
untouched, so the default render is unchanged - including the
checksum/config annotation over the settings.yml ConfigMap, which stays
at 619e1ac4 for the CI values and 25bd1479 for the chart defaults, so no
pod is rolled without reason.
Part of #157. The helper is a verbatim copy of the fix already merged for
template-chart, zipline, cyberchef and bentopdf - multiplyQuantity is the
same duplicated code in every chart.