Commit Graph
7 Commits
Author SHA1 Message Date
jklein 50f683776e feat(cyberchef): Gateway-API as an alternative to the Ingress (pilot)
Validate Helm Charts / Detect changed charts (pull_request) Successful in 4s
Validate Helm Charts / Resource quantities (pull_request) Successful in 14s
Validate Helm Charts / Selector match (pull_request) Successful in 12s
Validate Helm Charts / HTTPRoute match (pull_request) Successful in 13s
Validate Helm Charts / Build cyberchef (pull_request) Successful in 6s
Validate Helm Charts / Trivy config cyberchef (pull_request) Successful in 18s
Validate Helm Charts / Build template-chart (pull_request) Successful in 7s
Validate Helm Charts / Trivy config template-chart (pull_request) Successful in 17s
Install-test / Install-test cyberchef (pull_request) Successful in 1m0s
Validate Helm Charts / Install-test (pull_request) Successful in 1m0s
The Gateway-API pilot of Gitea #114: one chart, the convention, the CI that
holds it. The remaining 20 charts follow in their own PRs.

The form, additive and off by default:

    httpRoute:
      enabled: false     # counterpart to ingress.enabled
      parentRefs: []     # the Gateway - a platform object
      hostnames: []      # empty = [ingress.domain]

Only HTTPRoute with parentRefs is rendered: no Gateway, no gatewayClassName,
no Certificate, and no implementation-specific policy object. That subset is
identical on nginx-gateway-fabric, Cilium, Envoy Gateway and Istio, which is
what lets the implementation be chosen later without touching the charts
again. Class and certificate move to the platform.

Four guards, all against silent failures:

  - mutually exclusive with ingress.enabled, with a render abort naming BOTH
    value paths. A migration runs over a second hostname, not in parallel.
  - parentRefs mandatory in Gateway mode, render abort on the empty list: a
    route without a parent is created, is schema-valid, and routes nothing.
  - hostnames empty means [ingress.domain], so the hostname has one source.
  - the mode is a VALUE, not auto-detection: .Capabilities.APIVersions is
    unreliable at template time and a missing CRD fails at install time.

ingress.clusterIssuer was already only read inside the Ingress template, so
the "conditionally required" half of #114 needed no change in this chart -
checked rather than assumed, and it has to be re-checked per chart in the
sweep.

CI, both halves, because neither covers the other:

  - the install-test installs cyberchef in GATEWAY mode against the REAL
    Gateway-API CRDs (standard channel v1.6.3, pinned and Renovate-tracked,
    applied --server-side). A schema-less stub would accept a malformed route
    and prove only that something was created. The Ingress path of this one
    chart is no longer installed; it is a built-in type that never routed in
    k3d anyway, and helm lint renders this chart's defaults - Ingress mode -
    on every PR.
  - ci/run-httproute-match-test.sh, over every chart on every PR: every
    backendRefs entry must name a Service, on a port, that the SAME render
    creates, and parentRefs must not be empty. The CRDs accept both of those
    mistakes, so the schema cannot catch them, and the only report would be a
    route status no controller writes in CI.

What stays unprovable, and is written down instead of implied: that traffic
flows. No Gateway controller runs in k3d.

Minor: additive with unchanged defaults, proven by an empty helm template
diff against origin/main for the default values.

Part of #114
2026-10-12 15:16:26 +00:00
jklein 0217422179 template-chart: NOTES.txt and the naked-integer render fix (4.1.0+upxxx)
Two changes to the reference implementation, both of which every chart copied from it inherits.

Render fix (part of #157): multiplyQuantity turned its input into a string with printf "%v". The null-safe fallback helpers pass values through fromYaml, which parses every number as float64, and Go's "%v" switches float64 to exponential notation from about 1e6 upwards - so a bare byte count like 1048576 arrived as "1.048576e+06" and the suffix check aborted the render. A new xxx.formatNumber helper forces plain decimal notation on both the input and the non-integer product; strings like "512Mi" pass through untouched. This is the canonical fix agreed for the issue, taken over verbatim, because multiplyQuantity is the same copy in every chart and a private variant would create drift instead of a solution. The toYaml/fromYaml round-trip is deliberately not touched: it is not the cause.

NOTES.txt (part of #43): the scaffold now carries the reference NOTES.txt - a placeholder-carrying template, not finished prose. It renders the access URL from ingress.domain (no real domain anywhere), names which fields the 1Password item must carry, and prints the chart's traps: the placeholder image, the fact that both a Deployment and a StatefulSet render, and that no checksum/secret-ref means a secret change restarts nothing here. Output is conditional on the values actually set.

appVersion unchanged; minor bump because both changes are additive.
2026-08-28 23:59:38 +02:00
jklein 00ea301e33 template-chart: seccomp profile, unprivileged port, and two placeholder fixes
Five changes to the scaffold every future chart is copied from:

1. seccompProfile.type: RuntimeDefault in the pod security context, in
   line with the rest of the seccomp series (#84). Pod context, because
   from there it also covers init containers and any container added
   later without being repeated.

2. containerPort 80 -> 8080, clearing AVD-KSV-0117. Note that the usual
   justification for this does not hold: a non-root container CAN bind
   port 80 on current Kubernetes, because the kubelet sets
   net.ipv4.ip_unprivileged_port_start=0 in the pod network namespace.
   Measured, not assumed - see the values.yaml comment. The reason to
   stay above 1024 is that this is a runtime default rather than a
   guarantee, and that every real chart here already does.

3. The ConfigMap placeholder key is renamed from the literal "key" to
   "example-setting", clearing AVD-KSV-01010 (secret-scanner patterns
   match any key named "key").

4. The image placeholder is fully qualified as ghcr.io/ORG/IMAGE, so the
   template stops teaching the unqualified form that produced the
   repo's unqualified Docker Hub images.

5. env values are rendered through "quote". Without it a value like
   "8080" renders as a YAML number and the API server rejects the whole
   manifest ("cannot unmarshal number into Go struct field
   EnvVar.value of type string"). Every real chart in the repo already
   quotes here; only the template did not. Found by instantiating the
   template and installing it, not by rendering it.

Verified by instantiating the scaffold into a working chart per the
README procedure and installing it in k3d: the workload becomes Ready,
the Service routes to the app on 8080 and an ephemeral container added
to the running pod inherits Seccomp: 2 from the pod context.

Refs #84
2026-08-23 23:29:51 +02:00
jklein b218f64eac template-chart + README: values.schema.json, gate and null-safe helpers
Closes out the schema programme (#68) by moving what the 18 charts taught
into the reference implementation and the binding guidelines.

template-chart:
- values.schema.json as the reference schema: additionalProperties false
  on every chart-owned level, pod-spec passthrough left open, and the
  reasoning inline in the descriptions so a copy carries it along.
- defaultedDict and subBlock plus the per-block fallbacks for both
  security contexts, the three probes and resources, wired into both the
  Deployment and the StatefulSet.
- the reference itself violated guideline 1: its env block reads
  ingress.domain, so with the Ingress gated off it rendered an empty
  value. That read is now required(), and the comment says why - the
  template is what people copy, so it has to teach the guard, not the
  hole.

README, new section "Values that must not lie" with the five rules:
1. a value read outside its obvious template needs its own guard
   (matrix-synapse published '{"m.server": ":443"}' to federation without
   it, rendering cleanly and reporting healthy)
2. probes, contexts and resources through the null-safe helper, never
   behind an "if" - a guard removes the probe instead of showing a null
3. no liveness on an external dependency where a dependency-free path
   exists, otherwise document why on the helper
4. a fallback reproduces THIS chart's defaults, not the repo standard -
   calibre's readOnlyRootFilesystem: false is what keeps the runtime uid
   at 1000 instead of 911 and existing volume data readable
5. a probe default carries its context - port name, Host header, exec
   command - or the probe vanishes (teamspeak) or gets 403 (patchmon)

Plus the two mechanics that are easiest to lose: null reaches schema
validation only for keys WITHOUT a chart default (which is why the helper
and the ["object","null"] types each cover a case the other cannot), and
schemas must be validated against real bundle values - that step caught a
draft of mine that would have broken three live paperless releases.

CLAUDE.md: the new-chart checklist now names the schema and the
adaptation step, since the copied file is chart-specific and wrong until
it is adapted.

freesailarr is not covered: it is not on main yet (#59).
2026-08-23 22:35:03 +02:00
jklein 1bca98b9ef Add checksum/config annotation to template-chart and make it binding
A changed ConfigMap did not restart any pod in this repo: no chart carries
a checksum/config annotation, so the pod template stays identical and the
running container keeps its old config. With subPath mounts (the usual form
here) the kubelet never refreshes the file either, so the change is silently
ineffective - see #82, where this caused a real outage while every bundle was
green and the pod Ready.

template-chart is the reference implementation, so it gets the annotation on
both pod templates (Deployment and StatefulSet), and the README style guide
gets a new binding section 9 covering the rule, the reason, and the limit for
1Password-backed Secrets.

Major bump: runtime behavior changes - a config change now costs a restart.
2026-08-23 18:49:10 +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 bf0642fe78 feat(charts): added simple template chart 2026-03-19 12:09:30 +01:00