Commit Graph
13 Commits
Author SHA1 Message Date
jklein cbddba6972 Replace the obsolete no-dependencies rationale in every chart helper
Validate Helm Charts / Detect changed charts (pull_request) Successful in 4s
Validate Helm Charts / Resource quantities (pull_request) Successful in 8s
Validate Helm Charts / Build ${{ fromJSON(needs.detect-changed-charts.outputs.charts) }} (pull_request) Successful in 32s
Validate Helm Charts / Trivy config ${{ fromJSON(needs.detect-changed-charts.outputs.scan-charts) }} (pull_request) Successful in 1m24s
Validate Helm Charts / Install-test ${{ fromJSON(needs.detect-changed-charts.outputs.install-charts) }} (pull_request) Failing after 16m52s
The doc comments on the resources and defaultedDict helpers justified the
copy-per-chart with "charts in this repo deliberately have no dependencies".
That rule fell with #214: a dependency is admissible now, just expensive, and
it sits in the README as guideline 14, not 13. The justification still holds,
but its reason is a different one - sharing the helper would mean a library
chart, a second artefact to publish, version and pull for something that
changes about once a year. searxng got that wording in PR #38; this carries it
to the remaining 22 charts, 41 occurrences in all.

Comments only: every touched chart renders byte-identical against its
ci/<chart>/test-values.yaml. Each published chart takes a patch bump,
appVersion and +up suffix untouched; template-chart is never published and
takes none, but is corrected because every new chart inherits from it.

Two repo files carried the same claim at no version cost:
validate-charts.yml explained the all-charts quantity render test with it, and
change-app-version.yml still counted nine images for freesailarr - MediathekArr
made it ten.
2026-09-26 21:42:49 +00:00
jklein 6fe729523f gotenberg: render large byte counts without exponential notation (8.0.1+up8.36.0)
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, so a bare byte count like 1048576 turned into
"1.048576e+06" - not a valid Kubernetes quantity. multiplyQuantity then aborted
the render on its own suffix check. The second "%v", the one printing a
non-integer product, never reaches that check and rendered an invalid quantity
silently; only the API server rejects it on apply.

Both call sites now go through a new formatNumber helper that forces plain
decimal notation and passes strings ("512Mi") through untouched. The
fromYaml/toYaml round-trip is not touched: it was just unified across all
charts and it is not the cause.

gotenberg reaches multiplyQuantity from two places - the Deployment's
resources block and NOTES.txt, which reports the effective limits. With the
chart's default values both non-CPU resources carry an explicit limit, so no
limit is computed and neither site was affected in the default configuration.

Teil von #157
2026-08-29 01:05:58 +02:00
jklein 37b76e353c gotenberg: seccompProfile RuntimeDefault in the pod context
Sets seccompProfile.type: RuntimeDefault in the pod security context, so
the container runtime's default syscall filter applies to every container
in the pod.

The value lives in the pod context rather than the container context
because it covers init containers and any container added later without
being repeated; a container that needs a different filter can still
override it under securityContext.container, which wins over the pod
value.

Gotenberg is the chart where a syscall filter was most likely to bite: it
drives headless Chromium and LibreOffice, and browser sandboxes are the
classic casualty of a restrictive seccomp profile. Verified in k3d that
both engines still work under the filter - Chromium HTML->PDF and
LibreOffice document->PDF both return real, non-empty PDFs, and the
kernel reports Seccomp: 2 (filter mode) inside the container.

Major bump: runtime behavior changes.

Refs #84
2026-08-23 23:08:37 +02:00
jklein 0c403b6100 gotenberg: small requests, explicit higher limits
The computed limits (limitFactor 3 x request = 1536Mi memory, 30Mi ephemeral
storage) were too small for real documents: a 12 MB HTML already gets the
container OOM-killed, and the caller sees no HTTP error at all, just a dropped
connection and a rising RESTARTS counter.

Rather than raise the requests and reserve conversion-sized capacity on the
node around the clock, requests and limits are decoupled: the requests stay as
they were, and both limits are now set explicitly. The chart already supported
this - an explicit limit wins over the limitFactor computation.

Measured in a throwaway k3d cluster with the official image (HTML via
Chromium), building on the series in the issue:

  18 MB HTML, 2Gi     -> OOMKilled
  18 MB HTML, 2560Mi  -> OOMKilled
  18 MB HTML, 3Gi     -> HTTP 200 in ~22s, 21 MB PDF
  12 MB HTML, 1536Mi  -> OOMKilled (the old computed limit)
  12 MB HTML, 2Gi     -> HTTP 200 in ~13s

Memory beyond 3Gi buys nothing: gotenberg's own request timeout is 30s and the
chart passes no flags to change it, so a document needing more memory has
already run out of time (a 25 MB HTML misses the 30s even at 4Gi).

The ephemeral-storage limit is raised in the same change, because raising
memory alone only moves the failure. With 3Gi memory and the old 30Mi limit,
/tmp peaked at 40 MB on a single conversion and at ~125 MB over a short
series, and the pod was evicted:

  Pod ephemeral local storage usage exceeds the total limit of containers 30Mi

That failure is worse than the OOM-kill: the pod does not restart, it is
replaced, and the old one is left behind as Evicted.

The defaults in the effectiveResources helper are updated in lockstep with
values.yaml, so an erased "resources:" block (#99) falls back to the new
explicit limits instead of the old computed ones.

NOTES.txt is pulled along. Its numbers came from effectiveResources already,
but the text described a threshold that has moved and advice that no longer
holds: raising the request no longer drags the limit with it now that the
limits are explicit. The warning is kept but no longer claims memory is the
first limit you hit - with these limits, the 30s timeout is.

Major, because the runtime behaviour changes and the pod may occupy more
memory during large conversions than it was allowed to before.

Fixes #106
2026-08-23 22:35:22 +02:00
jklein 8bc673d80d gotenberg: null-safe hardening, probes and resources
Retrofit of #99 for a chart that already carries a values.schema.json,
plus the schema type change that goes with it.

An override written without children is YAML null. Where the chart
defines a default, Helm's coalescing deletes the default before schema
validation runs, so the schema never sees the null and cannot reject it:
the container rendered "securityContext: null" - unhardened, healthy,
silent. Where the chart defines no default (resources.limits), the null
survives into validation and a strict "object" type aborted the render.

The defaultedDict helper from #96 handles the first case; widening the
types of exactly these blocks to ["object", "null"] handles the second.
All other keys stay strict, additionalProperties: false is untouched.

The probes address the container port by name, so a rebuilt default probe
needs no further context.

Rendering with normal values is byte-identical to 5.0.0.
2026-08-23 20:37:12 +02:00
jklein 09d8a94bfc Add NOTES.txt to the gotenberg chart
Gotenberg has no Ingress, so the notes lead with the cluster-internal URL and
point out that the Service listens on 80 while the container listens on 3000
— the mismatch a consumer such as paperless-ngx has to get right — plus the
port-forward command for reaching it by hand.

Three findings from measuring the running chart went in as warnings:

- The chart passes no command-line flags, so Gotenberg's basic auth, OIDC,
  SSRF guards and request timeout cannot be enabled through values at all.
- Memory, not disk, is the first limit to hit: at the default limit a large
  document gets the container OOM-killed, the caller sees the connection
  dropped rather than an HTTP error, and the notes give the exact kubectl
  command that prints OOMKilled.
- Temp space is an emptyDir counted against ephemeral-storage, where running
  out looks different — the pod is evicted and replaced, not restarted.

Both limits are read back through the chart's own resources helper, so the
printed figures follow limitFactor and any override instead of being
hardcoded. Refs #43.
2026-08-23 20:30:22 +02:00
jklein c88ce80750 Conventions batch 4: env blocks, homeassistant className default, strict clusterIssuer
- apache-tika, gotenberg, cyberchef, homeassistant, patchmon: additive env
  value blocks rendered through tpl (value, secretKeyRef and configMapKeyRef
  forms), following the template-chart/outline pattern; patchmon gets separate
  blocks for the server container and the guacd sidecar.
- homeassistant: ingress.className now defaults to nginx; an empty className
  omits ingressClassName from the rendered Ingress, so the flexible upstream
  ingress style stays intact.
- outline, paperless-ngx: remove the ingress.clusterIssuer defaults
  (letsencrypt / letsencrypt-issuer) - the value is now strictly required,
  consistent with the repo-wide ingress standard; CI test-values set it
  explicitly.

Chart bumps: apache-tika 7.2.0, gotenberg 4.2.0, cyberchef 5.2.0,
patchmon 5.2.0, homeassistant 4.2.0 (minor); outline 5.0.0,
paperless-ngx 10.0.0 (major).
2026-08-22 20:10:06 +02:00
jklein a69542383e Conventions batch 1: icons, template file names, cosmetics
- Add icon: to all 17 Chart.yaml (official project icons); removes the
  last helm lint --strict INFO finding across the repo
- Rename template files to the <app>.<kind>.yaml scheme (apache-tika,
  gotenberg, teamspeak-server PVC, paperless-ngx configmap) - pure
  git mv, no content changes
- template-chart: fix missing space in {{ .Chart.Name}} and rename the
  ConfigMap resource -config-map -> -configmap (chart is never published)
- rallly: fix typos in required messages (rallySecret -> ralllySecret,
  databseSecret -> databaseSecret)
- README: document the deliberate PVC-name exception from the naming
  scheme (renames would provision new empty volumes)
- Patch-bump all 16 published charts

Rendered resources are byte-identical for all published charts (only
helm's '# Source:' comments change for the renamed files); the only
render change is the template-chart ConfigMap name.

Part of #32
2026-08-22 15:21:52 +02:00
jklein 6779e49355 Add per-workload replicas values and a chart-global scaleDown flag
Every Deployment/StatefulSet now takes its replica count from a replicas
value (default 1, explicit 0 allowed) via a new per-chart <chart>.replicas
helper; the helper uses a kindIs "invalid" nil check so an explicit 0 is
not swallowed by Helm's default function. A chart-global scaleDown flag
(default false) takes precedence: it renders every workload with
replicas: 0 and suspends the paperless-ngx consume CronJob, stopping the
app without uninstalling it (PVCs, Secrets, Services and Ingress remain).

Defaults leave the rendered manifests byte-identical to main, so all
published charts get a minor version bump; the template-chart carries the
reference helper implementation and stays unversioned.

Fixes #25
2026-08-22 08:12:40 +02:00
jklein 91a2fbcb05 Compute memory/ephemeral-storage limits from requests, drop default CPU limits
Every chart now renders its container resources through a duplicated
_helpers.tpl helper (reference implementation in template-chart): requests
ship as chart defaults, missing memory and ephemeral-storage limits are
computed as resources.limitFactor x the request (default 3, satisfactory
keeps 2 to preserve its previously published 8Gi limit), an explicitly set
limit always wins, and a CPU limit is only rendered when set explicitly.
Fixed limit defaults are removed from all values.yaml files; teamspeak-server
gains a values-driven resources block instead of hardcoded template values.
Major version bump for all published charts.
2026-08-21 23:34:09 +02:00
jklein b5eba4cbf1 Harden pod and container security contexts across all workloads
Add securityContext hardening (runAsNonRoot, readOnlyRootFilesystem,
capabilities drop ALL, allowPrivilegeEscalation false) to the 10 workloads
that lacked it: apache-tika, cyberchef, gotenberg, homeassistant,
matrix-delegation-nginx, paperless-server, paperless-consume cronjob
(plus automountServiceAccountToken false), patchmon-frontend,
urlaubsverwaltung and zipline. All contexts are configurable via
securityContext.pod / securityContext.container in values.yaml; writable
paths are provided as emptyDirs. Image-forced deviations (Home Assistant
root start for s6-overlay + NET_RAW for discovery, paperless root init
container for /run ownership) are documented in the charts' values.yaml.
Major version bump for every changed published chart.
2026-08-21 21:49:05 +02:00
jklein 78d78973c5 Ensure liveness, readiness and startup probes on all workloads
Every container in every Deployment/StatefulSet now defines all three
probes. The paperless-ngx consume CronJob intentionally has none (batch
workload).

- Add probes: apache-tika, calibre-web-automated, cyberchef, gotenberg,
  homeassistant, patchmon-backend, samba (tcp/445), teamspeak-server
  (tcp/30033), zipline (/api/healthcheck)
- Fix voucher-vault null probe values with real defaults
- Fix startup-probe semantics in template-chart and rallly (no
  initialDelaySeconds, generous failureThreshold)
- Switch outline probes to its /_health endpoint
- Add readiness/startup probes to satisfactory
- Add startup probes to matrix-synapse, matrix-delegation-nginx,
  paperless-server, patchmon-frontend, urlaubsverwaltung
- Major version bump for all published charts
2026-08-21 17:36:53 +02:00
jklein 36eced0a3f feat(gotenberg): added initial chart 2026-02-23 16:34:15 +01:00