Commit Graph
14 Commits
Author SHA1 Message Date
jlab-renovate[bot] 9f1c776672 Update l4rm4nd/vouchervault Docker tag to v1.30.2 2026-09-03 22:01:42 +00:00
jklein e0541a0352 voucher-vault: add a NOTES.txt worth reading twice (6.1.0+up1.30.1)
The notes print what an operator would otherwise have to dig out of the
templates or out of the image, not a restatement of the values.

The centrepiece is the secret inventory: the three OnePasswordItem CRs
carry item paths only, so the field names each item must contain are
decided in this chart and appear nowhere in 1Password. A missing field
does not fail the install - the operator writes a Secret without that key
and the pod stays in CreateContainerConfigError.

The warnings are the ones this chart earns, all read out of the running
image rather than assumed:

- The first start against an empty database creates the superuser "admin"
  with a random password and prints it to stdout exactly once. With OIDC
  on, the app drops its password-change pages and the login form redirects
  to the provider by itself, so /admin/ is the documented way back in.
- The probes send Host: 127.0.0.1, which is always in ALLOWED_HOSTS. A
  wrong ingress.domain is therefore invisible: probes pass, the rollout
  goes green, and every real request gets 400.
- The entrypoint waits for Postgres in an nc loop with no timeout before
  opening the HTTP port, so a wrong database host produces no error at all
  - just a log that stops, until the startup probe budget runs out.
- Celery worker and beat are started detached from the same entrypoint;
  uwsgi answers whether or not they survived, so a wrong redis-url costs
  the expiry notifications silently.
- Every start runs makemigrations and migrate, and helm rollback does not
  reverse them.
- Expiry notifications need a per-user Apprise URL, and the beat schedule
  is created only while an empty database is initialized.

Conditional blocks cover the ingress and no-ingress access paths, the
scaled-down state, the storage class, and the case where voucherVault.env
has replaced the chart's full env list instead of extending it. The
startup budget and the replica state are read through the chart's own
helpers. No real domain appears anywhere; the one place an example is
needed uses example.com.

Minor bump, purely additive: a NOTES.txt changes no rendered object.

Part of #43
2026-08-29 00:03:06 +02:00
jklein 6c73ef874b Eight charts: seccompProfile RuntimeDefault and qualified images
Sets seccompProfile.type: RuntimeDefault in the pod security context of
minecraft-router, outline, urlaubsverwaltung, zipline, voucher-vault,
satisfactory, patchmon and calibre-web-automated, 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.

Five of the eight also get the docker.io/ prefix on their previously
unqualified image references, so the pull no longer depends on the
runtime's default-registry setting: itzg/mc-router,
outlinewiki/outline, urlaubsverwaltung/urlaubsverwaltung,
l4rm4nd/vouchervault (twice, app and init container) and
guacamole/guacd:1.6.0. zipline, satisfactory and calibre-web-automated
were already qualified with ghcr.io.

Verified in a throwaway k3d cluster against real application work, not
just a Running pod, and with Seccomp: 2 (filter mode) read from
/proc/<pid>/status inside each container:

- minecraft-router: a Minecraft handshake for a mapped domain travels
  through the router to a backend and the backend's status payload comes
  back to the client.
- outline: all migrations apply (45 tables), OIDC discovery succeeds and
  the server-rendered page answers 200 with <title>Outline</title>.
- urlaubsverwaltung: Liquibase applies 79 changesets (35 tables), the app
  seeds its settings and vacation types, /login answers 200.
- zipline: 27 migrations applied, then a full round trip - first user
  created, login, token, upload, and the file downloaded back byte-exact
  from the PVC.
- voucher-vault: the init container's collectstatic output is served
  (200, 22 KB), Django has its 22 tables and uWSGI answers 200 with
  <title>VoucherVault</title>.
- satisfactory: application behavior is NOT proven - the image is
  multiple GB and pulls 10 GB+ of game files on first start, which is why
  the chart sits in ci/excluded-charts.txt. What is proven is that the
  rendered pod securityContext is accepted server-side and yields
  Seccomp: 2 with uid/gid 1000 on a substitute image.
- patchmon: both containers run under the pod profile and both report
  Seccomp: 2. The server applies 47 migrations (44 tables), connects to
  Postgres and Redis and serves its dashboard; guacd answers a real
  Guacamole "select rdp" instruction with its full args list, over the
  same 127.0.0.1:4822 path the chart wires up.
- calibre-web-automated: the readOnlyRootFilesystem: false deviation is
  unaffected - id abc is still uid 1000 (not the 911 the image falls back
  to in read-only mode), /config and the Calibre metadata.db are owned by
  1000, and both the root s6 init and the uid-1000 application report
  Seccomp: 2. calibredb 9.1 runs and adds a book. Its IPC worker prints a
  traceback while doing so, but an unconfined control pod on the same
  image prints the same class of traceback, so it is not the filter.

trivy config now reports "0 to act on" for all eight; the untouched
samba still shows KSV-0104 and KSV-0030, which confirms these charts are
what closed the findings.

No values.schema.json needed changing: in all eight schemas
securityContext.pod is type ["object", "null"] with no property
restrictions, so the new key validates as it stands. The #99 null paths
still hold - nulling securityContext or securityContext.pod falls back to
the defaults including the new one.

Renovate resolves the prefixed guacd reference: a local dry-run lookup
(renovate 44.40.1, --platform=local --dry-run=lookup) reports depName
docker.io/guacamole/guacd against registryUrl https://index.docker.io
with lookupName guacamole/guacd, currentVersion 1.6.0 and its real
release timestamp, with no warnings. The other four prefixed references
live in templates, which Renovate never reads - they are tracked by the
customManagers via appVersion in Chart.yaml with a depName hardcoded in
renovate.json5, so they are unaffected.

Major bump for all eight: runtime behavior changes.

Refs #84
2026-08-24 13:17:14 +02:00
jklein f2fc18c6ae voucher-vault: strict values.schema.json and null-safe hardening
No ingress gate: this chart already gates its Ingress correctly. Two
changes plus one guard that the existing gate turned out to need.

1. values.schema.json (#68): additionalProperties: false on every
   chart-owned object level. Lists that go verbatim into the pod spec
   (ports, storage.volumes, storage.volumeMounts) stay open.

2. Null-safety for hardening, probes and resources (#99). Two specifics
   of this chart:

   - The probes were wrapped in "if" guards, so an erased probe block did
     not render "livenessProbe: null" - it removed the probe entirely and
     silently. The guards are gone; an empty block now means chart
     defaults, so the workload keeps its probes.
   - The rebuilt probes keep the Host: 127.0.0.1 header. Django's
     ALLOWED_HOSTS only accepts 127.0.0.1 and the configured DOMAIN, so a
     probe without it would get 400 and the pod would never be ready.

3. ingress.domain is required() where it is read. The dependency lives in
   values.yaml, not in a template: the DOMAIN env entry is a tpl string
   feeding Django's ALLOWED_HOSTS. With the existing gate and no domain
   the app rendered DOMAIN: "" and answered 400 to every real request -
   silently, and already before this change. It now fails loudly.

Apart from an added comment, the rendered manifest is unchanged.
2026-08-23 21:14:01 +02:00
jklein 6320709cbc VoucherVault chart: complete security hardening, flexible ingress
Enable readOnlyRootFilesystem and drop all capabilities by default. The
paths the image writes at runtime are covered by emptyDirs (/tmp,
/opt/app/logs and STATIC_ROOT /opt/app/myapp/static); an init container
seeds the static volume with the assets shipped in the image because the
directory doubles as the app's static source. The ephemeral-storage
request covers the ~90Mi static emptyDir.

Move the Ingress to the repo-standard flexible style: ingress.className
value (default nginx) instead of a hardcoded ingressClassName, and
ingress.annotations merged with the cert-manager annotation. domain and
clusterIssuer stay required; the TLS secret name was already standard.

Major bump 3.1.2+up1.30.1 -> 4.0.0+up1.30.1 (hardening changes runtime
behavior). App version unchanged. Part of #32.
2026-08-22 18:24:53 +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 ea68a69a3e Update app versions (batch): tika, gotenberg, synapse, rallly, samba, urlaubsverwaltung, voucher-vault, zipline, teamspeak
Nine non-critical app-version bumps, each with a chart patch bump:

- apache-tika 3.2.3.0-full -> 3.3.1.0-full
- gotenberg 8.26.0 -> 8.36.0
- matrix-synapse v1.149.1 -> v1.159.0
- rallly 4.8.1 -> 4.12.3
- samba 4.23.5 -> 4.23.10
- urlaubsverwaltung 6.5.0 -> 6.7.0
- voucher-vault 1.27.4 -> 1.30.1
- zipline 4.6.4 -> 4.7.0
- teamspeak-server v6.0.0-beta8 -> 6.0.0-beta12.1 (new tag format has no v prefix)

Release notes of every chart were checked for environment-variable
changes; none of the charts needs an env adjustment.

The teamspeak-server install-test is reactivated: beta12.1 ships a
valid default license, so the exclusion is removed, CI fixtures are
added under ci/teamspeak-server/, and the install-test was verified
in a local k3d cluster. README list of excluded charts updated.
2026-08-22 08:44:00 +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 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 78df9dce6a feat(voucher-vault): fixed security-policies 2026-04-13 21:28:41 +02:00
jklein d66092d9e5 feat(voucher-vault): fixed db-secret naming 2026-04-13 20:52:07 +02:00
jklein 6c5f568529 feat(voucher-vault): fixed env naming 2026-04-13 20:48:54 +02:00
jklein 787228edf4 feat(voucher-vault): added initial chart 2026-04-13 20:16:10 +02:00