Wiki Page Revisions
39 Commits
39 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
42e5f416f0
|
paperless-ngx, CI/CD, style guide, lessons: an egress rule names the pod port
Gitea #136. The paperless-ngx page said an egress rule names the port on the destination as the client dials it, and that paperless dials the Tika and Gotenberg Services on 80. The chart acted on it and the release cut Paperless off from both services on 2026-10-15. kube-proxy does a ClusterIP Service's destination NAT before the egress policy is evaluated at the pod's interface, so the policy sees podIP:targetPort - the rule names the pod port, 9998 and 3000 here. The old sentence is quoted as refuted rather than removed, together with the symptom that identifies it: a timeout, not connection refused. - paperless-ngx: the rule's ports and the quick repair for 14.0.0, the new networkPolicy.egress.mailImport (993, off), extraPorts as pod ports inside the cluster, and the install-test's Tika gate being off, so a green install-test is not cover for the corrected path. - CI-CD: the cross-chart assertion as a fifth row, why it needs two charts, the gate-on/gate-off pair, and 210 assertions over 30 charts. - Chart-Style-Guide: pod ports also in egress, and the bar for a named egress switch - no second switch for a port another value already decides. - Lessons-Learned: the lesson, plus how the wrong sentence passed every check while the correct mechanism stood two days older in the style guide. |
||
|
|
81980279c4
|
NetworkPolicies in every chart (Gitea #5): the convention, the gate, and what it does not do
29 chart pages plus Chart-Style-Guide, CI-CD, Charts and Lessons-Learned. Chart-Style-Guide gains section 15, and its core is the FOUR PORT CLASSES - the part that is actually hard to get right. A port a network probe addresses stays open until probeSources is set, because the kubelet probes from the worker node's IP and no chart can know it. A NodePort-published port stays open because the source is already masqueraded. Everything else can be and is restricted by source, which is why the charts with a real inbound restriction are exactly those whose probes use a different port. A replica-to-replica bus gets a bare podSelector - and, since policyTypes lists Egress, its outbound side needs a rule of its own or the cluster never forms while every node looks healthy. The exec-probe distinction is written down as load-bearing rather than pedantic: it is the whole reason valkey and minecraft-server are the tightest policies in the repository and every HTTP-probed web app is looser. CI-CD gains the networkpolicy job as section 8 (the later two renumbered), and it ends with the measurement rather than a claim. Two experiments ran on the PR and were reverted: cyberchef's probe port restricted to an address no probe can come from stayed GREEN at 1m9s, and outline with its DNS egress rule removed went RED at 5m59s. Together those say k3s exempts the kubelet's probe traffic while enforcing everything else - so the install-test's net is an EGRESS net, and a wrong ingress port is caught by the render assertion or not at all. Every chart page gets a networkPolicy values table and an operating note naming that chart's own trap, not a boilerplate one: - keycloak carries the blast radius: it is the cluster's identity provider, its http rule is the only source-restricted inbound rule in the repo, and nothing in CI can catch a wrong controller - so the page asks for a real login and a look at consumers' issuer URLs after the first upgrade. - garage asks the reader to check their S3 consumers, because anything in another namespace is blocked until it is in allowedNamespaces. - bulwark names the quietest failure in the sweep: its probes test its own port, so a jmapServerUrl on a blocked port yields a Ready pod serving an empty webmail. - gotenberg explains what its DNS-only cap COSTS - HTML conversion silently loses remote assets - rather than only what it buys. - satisfactory and homeassistant each argue their own Ingress-only policy; satisfactory's deciding half is that it is the one chart with no install-test at all, so an egress cap there would be the only one with no empirical check behind it. - paperless-ngx names the two pods of its release that the object does NOT cover, including the consume CronJob whose pod template carries no labels. - freesailarr explains why ten containers behind a VPN need only three egress rules, and that extraPorts cannot help with an alternative WireGuard port because it is TCP-only. valkey and stalwart are corrected rather than extended. valkey's page now says why having no probeSources is what makes it the tightest policy here and not an incomplete one. stalwart's carries a dated correction: this page and the chart both advised putting the ingress controller's namespace into allowedNamespaces with ["ingress-nginx"] as the example, and both halves are wrong - ingress-nginx is gone from the cluster entirely, and allowedNamespaces would have opened http to every pod in that namespace anyway. Charts drops the claim that valkey is "the first chart with a NetworkPolicy on by default" and says instead that every chart has one, with the two shapes a reader needs before opening any chart page. Lessons-Learned gains four, all transferable: - the net that existed for a different failure than the one it was built for, and why both experiments were needed before either could be read; - a comment that could not describe its own syntax (a template comment must not spell out its own closing delimiter; the render then fails pointing at the template, not at the sentence); - three values that reached no rule and would have read as controls - a convention about value NAMES is not a convention about which values exist; - the subchart whose comments the parent could not fix, and the rule it produced: before making a check a gate, ask which failures the author of this diff can actually fix. |
||
|
|
1caabc1a37
|
paperless-ngx 13.0.0: quoted scalars, the pinned mover, and oidcSecretRef gone (Gitea #11/#101/#112)
paperless-ngx: the removed secrets.oidcSecretRef and why it is not coming back (one json env var, no _FILE variant; Keycloak marks a client public per client), tokenAuthMethod restricted to "none" and why client_secret_basic could never work beside a chart that configures no secret, the new smbConnection.cron keys, and the env block's quoting with PAPERLESS_LOGGING_DIR as the worked example - cross-referenced to jk-cluster-config #360, which it does NOT close. Two notes were wrong rather than incomplete and are replaced, not appended: "A schedule may not start with *" documented the bug as a workaround ("use an equivalent that starts with a digit"), and the probes-exception section said paperless.replicas: 0 keeps moving PDFs off the share - with the required podAffinity it no longer can, and what the operator gets instead is a failing job per schedule. CI-CD: the new yaml-scalar job as 7 (trivy-config 7->8, install-test 8->9, following the renumbering the #128 round started), required podAffinity added to the selector-match job's scope, and the two render-only overlay kinds in the fixtures table. Chart-Style-Guide: the | quote half of the env convention, which was never written down here although template-chart has carried it all along - together with the six charts that do not follow it, because template-chart's own comment claimed all of them did while seven did not. Lessons-Learned: the genus. A value the operator quotes correctly that still lands bare in the manifest; its quiet half, where the render succeeds and the API server rejects the object; the defect that survived because no fixture rendered the object carrying it; and the issue that was wrong about the defect while being right about the pain. |
||
|
|
6c1c01453e
|
The chart bump follows the app bump (Gitea #128)
The decision from issue #128: app major -> chart major, app minor -> chart MINOR, patch/digest -> chart patch, as a maximum against the chart's own classification rather than a replacement. The level comes from Renovate's update type, since an appVersion comparison is blind to the update that prompted it - freesailarr's appVersion never moves. Versioning carries the rule, Renovate the hook and its measurements, Workflow the wiki exception where "plain" is now mechanically defined, CI-CD the new bump-level job, and Lessons-Learned the decision together with its limit: the reading duty was rejected, so the incident that lesson is about stays repeatable and the honest number is the whole of the remedy. Chart-Style-Guide, ytdlp-web-player, bulwark and stalwart each carried a sentence calling the hook's result a chart patch, which it no longer always is. |
||
|
|
7159e15564
|
Style guide: repair the index-naming rule's reason, and align stalwart on index
The rule read "acceptable only because a route holds no state and no certificate". That was true of homeassistant, the chart it was written for, and false of every chart it was later applied to: keycloak's realm Ingresses (#122) and stalwart's MTA-STS Ingresses (#123) both own cert-manager Certificates, so the rule's own precondition excluded the cases it was being cited for. It surfaced only because the two rounds ran in parallel and answered the same sentence differently - keycloak by index citing the rule, stalwart by issuer citing the rule's precondition. The maintainer settled it on index (keycloak was already published) and the REASON is what gets corrected here, not the naming of two charts. The reason that holds, in three steps kept apart because their standing differs: cert-manager here runs without --enable-certificate-owner-ref (MEASURED - absent from the Deployment args and from the ControllerConfiguration, which carries only kind and enableGatewayAPI); by that default the Certificate is collected with its Ingress but the SECRET IS NOT (DOCUMENTED behaviour); and no rename was ever performed (NOT APPLIED). So a rename recreates the Certificate against a surviving secret and issues nothing - and the promise hangs on a cluster flag this repository does not control. Also: stalwart added to that rule's examples; the per-entry-issuer paragraph corrected from "name after the issuer" to "name by index" with the obligation that follows (NOTES.txt must print index -> issuer -> hosts, since the name no longer carries it); the sharper reorder hazard recorded (the index runs over groups derived from the list, so a reorder can renumber objects that did not move); and the note that the index question only arises where a mode renders one object per entry - stalwart's Gateway mode renders a single route, so it has the question on the Ingress side only. homeassistant stays named as the certificate-free original case. Lessons learned: my own point 3 said the opposite and is replaced by what the round actually taught - a rule can be right while its written reason is wrong, a justification is load-bearing because it is what someone reaches for when the rule meets an unforeseen case, and parallel rounds are a conformance test nobody wrote (sequentially the second would have followed the first and the broken reason would have survived). stalwart: one half-sentence that was missing from "TLS belongs to the platform" - cert-manager runs here with enableGatewayAPI: true, so the listener certificates can be issued by it from an annotation on the Gateway. The work moves to the Gateway object rather than disappearing. |
||
|
|
57cf169203
|
freesailarr, Lessons learned: the release runs in the jellyfin namespace - correcting a limit I invented
A correction to my own measurement round, and it runs in the direction of understating the evidence rather than overstating it. The freesailarr page claimed, as the second of three limits, that there is no freesailarr namespace in jk-cluster and no pods of it visible, and concluded that where the backend runs is not determinable. The first clause is literally true; the conclusion does not follow. THE RELEASE RUNS IN NAMESPACE jellyfin. Verified: pod freesailarr-freesailarr-sfs-0, 10/10 Running, 0 restarts, on jk-worker-2; the StatefulSet's Helm annotations name release freesailarr in namespace jellyfin; all ten containers readable (gluetun, qbittorrent, prowlarr, flaresolverr, radarr, recyclarr, sonarr, seerr, bazarr, mediathekarr). How the error was produced: by searching over namespace NAMES - for freesailarr, and for anything containing "sail" or "arr". None matched, because the release lives beside its neighbouring service rather than in a namespace named after its chart. An empty result that read like a fact. What this strengthens, and it is the point of the correction: the freesailarr.published helper is now proven AT THE SOURCE rather than deduced from a redirect through a proxy. RADARR__SERVER__URLBASE=/radarr is set in the running container (with PROWLARR__ and SONARR__ likewise) while kubectl get ingress -n jellyfin returns NO resources at all - not this chart's object and not jellyfin's own. That combination is exactly what the helper exists for: read from ingress.enabled alone the variable would be empty in Gateway mode, and the UI would be broken behind a Ready pod. The two genuine limits stay, and are now scoped: the implementation cannot be named (httproutes and gatewayclasses are RBAC-forbidden to the read-only identity), and every HTTP measurement passed through the front proxy at proxy.jk-dev.de - which applies to the HTTP rows and not to the rows read from the API server. The lesson is recorded with it: a release does not have to live in a namespace named after its chart, and a query over namespace names does not answer "is this running". Same genus as the #118 finding one level over - a search that answers a different question than the one asked - and the mirror image of the rewrite-target grep that counted bulwark's refutations as occurrences. Treat an empty result as a question about the query before accepting it as a finding. No chart change and no version step: this is a wiki-only correction. |
||
|
|
1b9dd9de5b
|
rss-bridge, CI-CD, Lessons learned: #51 was closed, and the cause was never identified
PR #124 merged and the maintainer closed Gitea #51 one second later, on the strength of that round's green install-test. Three wiki passages written minutes earlier say the opposite - that the issue stays open, and that the standing instruction is to close it only after checking the cause. Corrected, with the emphasis moved to the part that outlives the colour: the chart was ruled out by a byte-identical render, the runner is the implicated layer, and THE CAUSE WAS NEVER IDENTIFIED. The diagnostic programme in #51's body - docker info for userns and the dind configuration, the same image in a local k3d without remapping - was not executed. Which produces the sentence that now matters most and that a closed issue cannot carry: if this chart's install-test goes red again, that is a fresh finding and not a known quirk. It is recorded on the chart page and in the repository's overlay comment, i.e. in the two places whoever sees the red will be reading, rather than only in a tracker nobody reopens. Also drops the pinned run count in favour of "every run of that branch after the first" - a third green had arrived with the push after the commit that said "two", so each commit recording the number invalidated it. Repo side: PR #127, a patch bump to 2.1.1+up2026.09.30, since a comment in a chart directory is still a change to that chart. |
||
|
|
28db5e2ba4
|
stalwart: MTA-STS routes as a maintainable list, in both routing modes
Gitea #123. The policy route for mta-sts.<domain> moves out of jk-cluster-config into the chart as mtaSts.hosts. stalwart: a new mtaSts values section - the entry form, the two object shapes and why they differ, the hardwired RFC 8461 path, the rejected certificate.extraDnsNames alternative, and the migration order. Three new traps: the chart registers a route and does not create a domain (404 at a correctly routed endpoint, silent on the sender's side); a parent wildcard does not cover mta-sts.sub.<domain>; and why one Ingress per cluster issuer cannot be one object. CI section: 2 -> 4 assertions, plus the install-test covering the Ingress half the overlay cannot reach. CI-CD: 58 assertions over 21 charts, why the chart count does not move, and the note that an overlay never covers the Ingress half of a both-modes feature. Chart-Style-Guide: section 4 gains the rule for a host list with a per-entry secret AND a per-entry issuer, and the rule that a both-modes feature must render in both - inert and documented where one mode cannot carry a part of it, never required. Lessons-Learned: the two fields cert-manager reads at different scopes. The annotation is object-scoped and the secret is tls-entry-scoped, so a per-entry optional issuer cannot live on one object - and ingress-shim names the Certificate after the secret and owns it from the Ingress, so a shared secret must sit in exactly one object. Generalises past this chart; |
||
|
|
3b9293706e
|
rss-bridge, CI-CD, Lessons learned: the green install-test reproduced, so "twice" rather than "one run"
The previous wiki commit recorded rss-bridge's install-test going green after months of failing on the Gitea runner, and hedged it with "it is one run". A second run on a second commit of the same PR came back green too - run 792 job 2623 and run 794 job 2638, both with the chart genuinely in the matrix, a k3d cluster built and the pod Ready. So the result is not a fluke, and the real caution is a different one: nobody has identified what changed on the runner. A green test does not explain itself, and the diagnostic programme in Gitea #51's body - docker info on the runner for userns and the dind configuration, the same image in a local k3d without remapping - remains unexecuted. That, and not the run count, is why the issue stays open. "Close an issue on a cause, not on a colour" is unaffected by the count. |
||
|
|
20d504722e
|
keycloak: one hostname per realm, in both routing modes (#122)
The chart gains keycloak.realmHosts: a list rendering one routing object per entry - an Ingress with app-root, or an HTTPRoute whose Exact match on / carries a RequestRedirect filter to /realms/<realm>/account/. Empty by default, so nothing renders and no installation changes. keycloak: the new Configurable-values row, and the section 'Four more Ingress objects in this namespace, and they are not this chart's' is replaced by 'One hostname per realm' - the four objects are still named there, but now as the thing a migration would adopt rather than as a permanent neighbour. With the per-mode object table, the two required deviations (per-entry tlsSecretName, optional per-entry issuer), the six render aborts and what each prevents, the proxy-buffer loss in Gateway mode phrased for account-console traffic, and the migration order with its one unchecked question. Chart-Style-Guide: the third admissible Ingress shape, with both deviations stated as required rather than tolerated, and keycloak added to the index-naming rule beside homeassistant. CI-CD: 56 assertions over 21 charts becomes 60, keycloak 4 -> 8 plus two 'not checked' lines; and why the overlay does not repeat the entries that the install-test fixture already carries. Charts: the Ingress cell for keycloak. Lessons-Learned: 'The precise message that hid the structural one' - a per-entry check that fired before the mode-conflict abort and answered the wrong diagnosis, plus the note that a strict schema can make a template guard unreachable. |
||
|
|
3fd7e65d5e
|
rss-bridge on the Gateway API, the production proof of the Gateway mode, and the red check that went green
Three rounds of knowledge in one commit, all of it measured rather than relayed. rss-bridge: the last chart of the Gateway-API sweep (Gitea #114). New Routing row and prerequisites per mode, a Gateway-mode install example, the httpRoute values table, and four operating-notes sections: the mode guards, why httpRoute.hostnames is this chart's own mandatory value (the third hostname shape in the repo - no ingress.domain to fall back to, and ingress.hosts deliberately not reused because its tlsSecretName entries address nothing once TLS sits on the listener), that rss-bridge.tlsGroups is therefore inert in that mode, and that nothing is lost on the switch - measured on the live Ingress, which carries no nginx annotation at all, so this is the one chart of the sweep whose Gateway branch has no loss to explain. Also records the ingress.enabled-derived-value screen coming back CLEAN for this chart, because an unrecorded clean screen is indistinguishable from one nobody ran. The install-test section is new and was rewritten once while being written: the chart's test had been red on the Gitea runner since the move (#51) and went GREEN on 2026-10-13, pod Ready in 22s with 0 restarts. The chart is ruled out as the cause by a diff, not an argument - the PR's rendered defaults are byte-identical to origin/main, so the spec that succeeded is the spec that had been failing. One run, no identified change on the runner, so #51 stays open: close on a cause, not on a colour. freesailarr: the Gateway mode is in production, which is the claim all four PRs of the sweep refused to make. No freesailarr Ingress objects in any namespace while the host answers; /radarr answers 302 from Kestrel with returnUrl=%2Fradarr, so the freesailarr.published helper works in production; /qbittorrent 301s to the slashed form from the chart's own rule; and the query string survives the redirect. The query-string answer is written as a measured data point and NOT as a promise - the specification still has no query field, so a different implementation may legitimately drop it. Three limits recorded with it: httproutes and gatewayclasses are RBAC-forbidden so the implementation cannot be named, there is no freesailarr namespace in the cluster at all, and every HTTP measurement passed through a front proxy. The attribution of the 301 to the chart's rule is inference from the snippet's carrier being gone plus the changed response signature, and says so. CI-CD: the httproute render test goes to 58 assertions over 22 charts, two overlays now have to supply hostnames rather than one, and the all-charts install-test note is corrected - rss-bridge's last green run is no longer a GitHub one. Lessons learned: three entries. The claim four PRs refused to make and where the measurement that reached it actually stopped; a screen that finds nothing is still a result worth writing down; and the red check that was kept red so it could say something, and then said it - an excluded test is not a quiet test but a blind one, because you also lose the moment the fault stops existing. |
||
|
|
1e684ca6ce
|
freesailarr, Renovate, Lessons learned: the grouped stack PR and the security default a patch bump switched off
The chart's trustedNetworks value for prowlarr, radarr and sonarr, with the consequence written as it is: the default is empty, so the chart does not restore the forwarded-header trust that prowlarr 2.6.3 and radarr 6.4.3 removed, and sonarr has been without it since before 4.0.19. Renovate: the first grouped chart, the two rules it takes because matchUpdateTypes and separateMinorPatch are rejected in one rule, and the measured branch split without the second rule. Lessons learned: a plain app-version bump switched off a security default, and that is the one update class the wiki obligation exempts. |
||
|
|
b4afbd4e99
|
Lessons learned: four of six charts leaned on an annotation the chart never set
The generalisation of the #118 entry, and the reason that one is recorded as a method rather than as a qBittorrent bug. At #118 the discovery was singular and late - one chart, one annotation, found after shipping while migrating a host. Group 3 asked the same question BEFORE writing any Gateway branch, with read-only kubectl against the live cluster, and found it was not singular: keycloak (proxy buffers, on both its Ingress objects), matrix-synapse (body size, the nginx.org twin, a snippet), stalwart (the whole enable-cors block), bulwark (body size). None of it is findable from inside the repository - a git grep over those six chart directories hits documentation only. So the measurement at the live object is part of the procedure. Three qualifications, because the measurement is only the first step: - READ THE DIRECTIVE before calling an annotation load-bearing. matrix-synapse's snippet is the entry that would frighten a reviewer most and is not load-bearing at all: more_set_headers is the headers-more module's output-header directive, so those headers reach the client and never Synapse. Had it gone the other way, the sweep would have shipped a scary paragraph about a non-problem. - "NO COUNTERPART" IS A CLAIM TO CHECK against the pinned CRDs, and once it was false: HTTPRoute filters do carry a cors field, and responseHeaderModifier beside it - both Extended, neither Core. stalwart still renders neither, and the three reasons are the transferable part: no values to render from, Extended is not promisable, and half a feature is worse than none when the expressible half is the useless one (Authorization in the allowed headers makes every request preflighted). - A GUARD CAN MATTER MORE IN THE NEW MODE. ytdlp-web-player's find was a render guard, not an env var, and in Gateway mode the admission webhook that made it merely tidy cannot fire at all - leaving it the only thing between a values file and an authentication bypass that depends on DNS. Ask what a derived value protects, not only what it computes. Plus: a shape read off an issue's summary table is a hypothesis. Three of #114's four descriptions of the group-3 shapes were wrong, two had already been copied into README and a CI script header, and the bulwark one came from a grep counting the chart's own refutations as occurrences. Also updated the group-1 note: the ingress.enabled-derived screen is closed at three finds. |
||
|
|
52588f0d74
|
freesailarr: the trailing slash on qBittorrent's prefix (#118)
freesailarr: a new section on the bare, slashless prefix - why qBittorrent answers it 200 while the page's relative links are served by seerr, that the Gateway mode now renders the 301 itself (Exact match, RequestRedirect, statusCode 301 written out because it defaults to 302, and 301 rather than an Extended value that would fail the whole route), the query-string asymmetry, and the Ingress-mode remedy with its price: a configuration-snippet annotation is honoured only where allow-snippet-annotations is on, which has been off by default since ingress-nginx 1.9 and means accepting risk level Critical. Also why a third Ingress object with pathType: Exact is not a substitute, with the controller-v1.14.5 source citation and the note that the ordering consequence is inferred, not observed. CI-CD: the third finding of the HTTPRoute render test, its per-object scope and the precedence reasoning, the two new "not checked" entries, and the corrected figures - 37 assertions over 15 charts, the first check added since the pilot rather than a chart. Lessons-Learned: both halves. The chart left a gap that an operator had closed silently from another repository with an annotation of risk level Critical, so the chart looked correct, the running system worked, and the migration appeared to break something the chart had never provided. And the method half, which generalises further: a search over the chart answers what the chart does, while what the running system does is a separate measurement - at the live object or in the cluster repository's values. Where a chart finding is meant to carry a claim about behaviour, that second measurement is mandatory. |
||
|
|
353fb7d6de
|
Gateway-API mode for group 2 of #114: the five annotation charts
PR #117. calibre-web-automated, outline, paperless-ngx, zipline (proxy-body-size) and freesailarr (rewrite-target) each gain an httpRoute block, off by default. Per chart page: a Routing row instead of the Ingress row, a Gateway-mode install snippet, an httpRoute values table, and a "Routing: Ingress or Gateway API" operating note. The upload-limit disclosure is written in each chart's own terms rather than copied: an e-book library (calibre), an upload service (zipline), the web-UI half while the consume directory keeps no limit (paperless), and the open #12 pair (outline). freesailarr sets no body-size annotation and needs none, but ingress.annotations is its operator's only lever for one. outline: #12 now says what Gateway mode does to it. The ingress half of the pair disappears, so the effective ceiling is the Gateway's and neither documented number necessarily decides. That moves the defect; it does not fix it. paperless-ngx: it was the last chart rendering its Ingress unconditionally and now has ingress.enabled, default true. Recorded with the reason, because the page previously stated the absence of that switch as a property. freesailarr: the page gains the finding and the improvement. Its shared-host app list was gated on ingress.enabled and also feeds the <APP>__SERVER__URLBASE variables, so Gateway mode would have served radarr/sonarr/prowlarr under their prefixes with no base path set - broken UI, Ready pod. And its rewrite-target crutch is gone: a URLRewrite filter is per rule, so qBittorrent needs no second routing object, no repeated TLS secret, no conditional cert-manager annotation and no regex path. Chart-Style-Guide §4: the "needs one, not sets one" screen, the rewrite-target asymmetry as the one place this mode is less machinery, the ingress.enabled-first rule for a chart without that switch, the freesailarr hostnames exception, and the group status. §12.1 gains the two addenda the sweep produced. CI-CD: the HTTPRoute test figure (4 over 2 at the pilot, 20 over 10 after group 1, 36 over 15 now), the multi-app overlay rule, and the honest note that the Gateway branch of NOTES.txt is executed by that test but printed by no stage. Lessons-Learned: the freesailarr case in full, next to sure's. Same helper shape, different symptom - which is the point: ingress.enabled is almost never asked "does an Ingress exist", and the property it stands in for does not flip with the object. |
||
|
|
e559776af6
|
docs: Gateway-API routing mode on the eight group-1 chart pages (#114)
bentopdf, garage, patchmon, rallly, searxng, sure, urlaubsverwaltung and voucher-vault now offer the Gateway-API HTTPRoute as an alternative to the Ingress (Gitea PR #116, group 1 of the #114 sweep). Per page: the summary table's "Ingress" row becomes a "Routing" row naming both modes, an installation example in Gateway mode, an httpRoute values table, a "Routing: Ingress or Gateway API" section with the three hard rules and what each chart in particular loses in that mode, and a CI note explaining why the install-test stays in Ingress mode while the route is held by the httproute-match render test through ci/httproute/<chart>.yaml. Corrections rather than additions, where a page said something the second routing template makes false: garage claimed nothing outside the Ingress template reads ingress.domain, so that switching the Ingress off freed domain as well as clusterIssuer. The HTTPRoute reads it as its hostname, so that now holds only while BOTH modes are off. bentopdf and urlaubsverwaltung carried the same claim in weaker form. sure's ingress.enabled row said it decides RAILS_ASSUME_SSL/RAILS_FORCE_SSL. Those now follow ingress.enabled OR httpRoute.enabled, because Gateway mode sets ingress.enabled false by construction while TLS is terminated at the Gateway - the old reading would have meant insecure cookies and http:// links with a green pod. garage additionally gets the upload-limit regression spelled out: proxy-body- size has no Gateway-API counterpart, so an S3 endpoint published through an HTTPRoute inherits whatever limit the Gateway carries. #114 counted five charts affected by this, measured on charts that hardcode the annotation; garage depends on one without setting it and is a sixth. Lessons-Learned gains "The switch that stopped meaning what it was read for" - the sure finding in general form, with the grep that finds the remaining cases (freesailarr and ytdlp-web-player both read .Values.ingress.enabled outside their Ingress templates) - plus two lines in "The recurring shape". No new Charts row and no _Sidebar entry: the charts already exist. Chart-Style-Guide section 4 is unchanged - the convention was applied, not altered. |
||
|
|
63e18d4527
|
Gateway API as the second routing mode (pilot on cyberchef)
Documents Gitea #114's pilot, which is in helm-charts PR #115. Chart-Style-Guide §4 becomes "Ingress and Gateway API" and carries the binding form: HTTPRoute with parentRefs only - no Gateway, no gatewayClassName, no certificate, no implementation-specific policy object, because that subset is identical on nginx-gateway-fabric, Cilium, Envoy Gateway and Istio. Plus the four guards (a value instead of auto-detection, mutual exclusion with ingress.enabled, mandatory parentRefs, one source of truth for the hostname) and what has no counterpart at all: proxy-body-size and auth annotations. The §4 anchor changed, so the reference on the homeassistant page moved with it. CI-CD gains the httproute-match job as #5 (install-test renumbered to #7) and a section on the Gateway-API CRD fixture - why it is real rather than a stub, why --server-side (the CRD is 244792 bytes as JSON against a 262144 byte annotation limit), and why it is not in ci/common/. cyberchef gains the httpRoute values, a "Routing modes" section, the attachment check, and the honest version of its CI section: its install-test now runs in Gateway mode, which gives up installing the Ingress and buys a route validated against a real schema. What stays unprovable is named - nothing routes in k3d. template-chart carries the reference implementation; New-Chart gains the overlay obligation; Renovate replaces the blanket "ci/** is not managed" with the distinction that was always meant - a fixture image stays unmanaged, a pinned tool is tracked wherever it lives. Lessons-Learned: the stub CRD that would have proved nothing. |
||
|
|
aa25dced2b
|
stalwart: per-group distribution and PDB, and the selector-match CI assurance
stalwart: the six new per-group values in the nodes table, a "High availability, per group" section, and four traps - distribution is a promise and the price is a Pending pod (including the delete-the-Node-object inversion and the ceiling as a rule rather than a number), the opposite defaults of the two node-inclusion policies, nodeAffinityPolicy being pruned silently below Kubernetes 1.26, and the collision abort. Also: the install-test renders neither object, and the render-only overlay that covers them instead. CI-CD: the new selector-match job as step 4, install-test renumbered to 6, and helm-dependencies.sh now in six places - with the 503 that took both render tests red while this was written. Chart-Style-Guide: §11 gains the per-group PDB, the distribution-rule convention, the chart-filled labelSelector, the explicit nodeAffinityPolicy with its two separately-argued consequences, the collision abort, and the reminder not to add updateStrategy or podManagementPolicy for this. Lessons-Learned: two sections - the two defaults that pointed in opposite directions (where a review's own authoritative table was the thing that was wrong), and the duplicate the API rejected while the apply path merged it silently - plus four entries in the recurring shape. |
||
|
|
1f9ce77762
|
keycloak: the A/B that exonerated the theme mount, and the lesson from it | ||
|
|
eed0689a43
|
keycloak: extraVolumes/extraVolumeMounts, the theme route and its trap (Gitea #88) | ||
|
|
996f8c0dde
|
bulwark: new chart page, index, sidebar, stalwart cross-reference, and four rules it bought
The chart page leads with the two things that are not visible from outside and that govern everything else: Bulwark is a pure CLIENT, so with the mail server gone the release is Ready and green and nothing in it can tell; and the VOLUME BEATS THE CHART for every value, silently, because the application resolves "admin override > env var > default" and its admin dashboard may write any key. Upstream documents the second only for the server URL, which is what makes it a trap rather than a footnote. Also on the page, each measured against the source at tag 1.12.0 rather than taken from the documentation: the real way out of an OIDC lockout (remove the override in the dashboard - a helm upgrade with OAUTH_ONLY=false goes through the same precedence chain and can do nothing), the three-part price of adminConfigReadOnly, the redirect URI that carries the UI language across 27 locales, the two-part backup statement (the volume alone is not a backup, and it may hold the OAuth secret in cleartext), why rotation needs no restart and which mount detail that depends on, and what the probes do and do not carry. Charts: new row, and the counter is now measured against */Chart.yaml instead of carried forward - it had drifted. The table also still lists convertx, for which there is no chart directory in the repository; flagged in a note rather than deleted, because removing it is a decision about that chart and not a documentation fix. Lessons learned, four entries, all of them transferable beyond this chart: a recovery instruction that ran through the fault it was meant to repair; a read-only switch whose write barrier also blocked the one-time bootstrap write that creates the admin password; a probe method the platform does not offer at all (an HTTP probe is always GET); and a 0400 secret file that only works because the kubelet silently widens it. |
||
|
|
c983ae10cd
|
keycloak: the readiness check that is gated behind the metrics option
Found while verifying the CI result rather than from the plan, and it changes a default: Keycloak's DATABASE health check is the one row of upstream's check table whose "Requires Metrics" column says yes. With metrics-enabled=false - the chart's default in its first draft - /health/ready answers 200 with the database gone, and the pod keeps taking logins it cannot serve. That is the urlaubsverwaltung shape a second time, and the generalisation is worth more than the fix: the dependency was not missing from a health GROUP this time, it was conditional on an option named for observability, which is a place nobody looks when reviewing a probe. So the rule grows past health groups - find the list of checks the endpoint performs, and find out what each one is conditional on. "This path includes the database" is a claim about configuration, not about the path. keycloak.md: metrics default is now true with that reasoning, a new trap section for it, and the measured install-test figure (71.8s from helm install to both pods Ready, 0 restarts, Gitea PR #87). Also corrected an overclaim of my own in the same page: two replicas both reaching Ready does NOT prove that jdbc-ping found the peer. Readiness reports one node's own health, so two nodes that never met are both Ready and both alone. The install-test rules out the louder half (a replica that cannot start or cannot share the database); the Infinispan view still has to be read out of the log, which is what step 2 of the first-install checklist is for. |
||
|
|
0852b72ee2
|
keycloak: new chart page, index, sidebar, and three rules it bought
The chart page carries the values table, the vault fields, the first-install checklist with the permanent administrator as a mandatory step, the minor-upgrade procedure, and the traps - of which two are the point of the page: hostname-admin is not an access control, and a shared database merges two clusters. Chart index counter: 30 directories / 29 installable. That follows the index TABLE, which already lists convertx - its page landed before its PR, and convertx/ does not exist on origin/main yet. So the number is one ahead of the repository on purpose, as it was before this change. Renovate: the counter-case to garage, measured rather than assumed - four tag shapes on quay.io/keycloak/keycloak and plain docker versioning already excludes the three unwanted ones, so that block carries no versioningTemplate. Written down because an unnecessary constraint is not free: it reads as load-bearing to the next person and has to stay correct as upstream's tagging changes. Plus a section on the automerge decision: switching it off for minor and major was proposed and declined, so the upgrade procedure is documented instead of prevented, with the obligation that puts on whoever reviews an app-version PR. Chart style guide section 11: a chart defaulting to more than one replica ships a PodDisruptionBudget, and it is rendered only while the computed replica count is >= 2 - minAvailable 1 with a single replica blocks every drain forever with a message that names the PDB rather than the replica count. CI/CD: the trusted-registry list for AVD-KSV-0125 is a separate file from the ignore file on purpose, so a new registry is an entry there rather than a suppression. quay.io joined it with this chart. Lessons learned, two entries and three lines in the recurring shape: - "The application that rewrites its own installation at start" - three correct requirements that cannot start a pod together, and why the obvious repair (an empty volume over the directory) breaks the command meant to fill it. - "The upgrade procedure the automerge did not know about" - the general form, which applies to any clustered application whose versions must not be mixed: a constraint living in documentation is invisible to the machinery that performs upgrades, and the better the pipeline, the less likely anybody is standing in the path to notice. |
||
|
|
c9c99757c1
|
garage: new chart page, index row, sidebar entry, two lessons
The page carries the values table, the first-install checklist for both paths (self-configuring with --single-node, and the manual layout sequence) and a traps section: the metadata gap in a volume backup, metadata_fsync being off upstream, the two-snapshot restore window, the non-idempotency of layout apply and why single-node mode does not have it, replication factor 1 applying to the metadata, the scratch image that rules out exec probes for good, and why the RPC secret has to be an environment variable. Two Lessons-Learned entries, both in their general form rather than as garage notes: "the snapshot that was not a restore point" repeats at every embedded database on a volume with snapshots, and "a permission check that assumes it owns the filesystem" at every application offering a *_secret_file with a 0o077 mode test. Chart index count 28 -> 29 directories. |
||
|
|
43aef80b2e
|
paperless-ngx: the optional valkey subchart, and two findings it produced
paperless-ngx (Gitea #78) takes our own valkey chart as an optional subchart, off by default. Its page gets the two new value blocks, the five Redis consumers that argue the queue-vs-cache choice, the three operator traps and the CI section, which now describes the first real installation of the valkey-subchart path anywhere here. Two findings are general enough to leave the chart page: - A rule about the relationship between a parent's and a subchart's values cannot live in a template. Helm renders a subchart's templates first, so the subchart's own required() always wins and reports the path as the subchart sees it. Schema validation runs before any rendering, so that is where such a rule goes. The first draft was a fail() in the parent that could never fire. - Erasing a dependency switch turns the subchart ON: a null override deletes the key, an unresolvable condition counts as enabled. The one block in a chart that must not be null-safe, and the opposite of the rule for every other block. Both in Chart-Style-Guide section 14 and Lessons-Learned; valkey's page names its second consumer and the queue/cache pair of worked examples; Charts gets the row. |
||
|
|
1eb6831a58
|
stalwart: the subchart is our own valkey chart, from the published index
Follows the decision on #65 to depend on our published valkey chart rather than upstream's. Four pages, and the choice of pages is deliberate. stalwart.md: the subchart section rewritten - our chart, not upstream's, so "consumed as it comes" no longer applies; the condition is valkeySubchart.enabled with the subchart's own error message quoted and the reason it only appears once the dependency is switched on; the auth-conf field is a complete "requirepass <pw>" line, not a password; and the cache-vs-queue choice argued with its cost (allkeys-lru makes the rate limiters and the auto-ban fail open under memory pressure - size memory, do not switch to noeviction). Plus a section on the PR-ordering rule. valkey.md: the same rule, stated FROM THIS SIDE. This is the page someone editing valkey/ will actually be reading, and this repo's own lesson is to put the warning where the next change will be made. It also warns against the tempting repair of adding an "enabled" property here for a key this chart does not read. Chart-Style-Guide.md, section 14: two charts carry a dependency now, and point 2 ("we consume their chart as it comes") explicitly does not apply when the subchart is ours. Adds the PR-ordering rule, the condition-key trap, and the two measurements that back the published-version form. Lessons-Learned.md: two entries - the green check that tested the wrong artifact, and the condition key the subchart rejected (including the part that makes it dangerous: Helm skips a disabled subchart's validation, so CI stays green and the error waits for the first operator who enables it). Three lines in "The recurring shape". |
||
|
|
079639225c
|
stalwart: new chart page, index, sidebar and four lessons
The chart page carries the full values reference, the eight-step first install (eight, not seven: the bootstrap wizard appears only when config.json is ABSENT, and the chart always renders one, so a first install goes through recovery mode) and a Traps section. Four entries on Lessons-Learned, because none of them is specific to mail: - The source address every NodePort quietly replaces. externalTrafficPolicy Cluster masquerades the client address onto the node IP, and every application that evaluates the client address meets this - bans, rate limits, geo rules, audit logs. Includes the three traps of the PROXY header remedy and the reason the trusted set and the probe set have to be disjoint in Kubernetes. - The rate limit that counted a node instead of a client. A per-IP limit in an application is a per-node limit for probes; the arithmetic that picks the probe intervals, and why a tcpSocket probe is the wrong escape. - The hardening that stopped the container from starting. setcap +ep makes the binary capability-dumb, so drop: [ALL] fails the execve itself. The lesson is that a deviation has to be documented with its mechanism, or the next hardening pass removes it as unused. - The missing file that opened a database nobody meant to use. An absent config.json opens an ephemeral in-memory store with green probes; an unparsable one aborts. The lenient path is the one a broken mount takes. Also on the fail-open: it covers the TASKS as well as the listeners, with all ten enabled by default, and the error is logged after the listeners are already bound. |
||
|
|
f8c4ea123e
|
Lauf 399 festhalten, und die Lehre aus der Analysator-Tabelle
Die Analyse laeuft durch (44 s, ANALYSIS SUCCESSFUL). Was sie gefunden hat, ist von hier aus nicht lesbar: die API antwortet anonym mit 401, was die richtige Einstellung ist - die Zahlen kommen also von einem Konto auf dem Server, nicht aus einem Protokoll. Dazu der Eintrag zur Tabelle, die ich aus einer Produktdokumentation gebaut und als Zusage ueber diese Instanz verwendet habe. Shell und GitHub Actions laufen hier nicht, weil Analysatoren server-seitige Plugins sind. |
||
|
|
cf31f0e2c5
|
Zwei gemessene Befunde festhalten: leichtgewichtige Tags und verwaiste Verweise
Der Umzug von publish-helm-chart nach workflow-util/pipelines hat beides geliefert. Erstens: tag.gpgsign erzwingt hier die annotierte Form, git tag kann keinen leichtgewichtigen Tag erzeugen - update-ref ist der Weg, und cat-file -t ist die Prufung. Zweitens: Ein ausgezogener Dateiname macht seine Verweise nicht veraltet, sondern falsch; ein Kommentar, der eine verschwundene Nachbardatei als ausfuhrliche Begrundung zitiert, liest sich weiterhin vollstandig. |
||
|
|
cb89a6476c
|
convertx: new chart page, index row, sidebar entry, two lessons
The chart page follows outline.md: prerequisites, installation walkthrough, the required 1Password field, the complete values reference and the operating notes. No version rows, as on every chart page. The notes it carries are the ones that cannot be read off the values: - the chart bypasses the image entrypoint, which is what keeps the hardening baseline intact on an image that carries no USER - together with the obligation that creates, namely re-reading the upstream entrypoint at every app-version bump - uid 1000 rather than the repo's 20000, because the image owns /home/convertx with it and the uid owns data on a PersistentVolume - what has to be writable and why: /home/convertx is HOME, and LibreOffice is invoked without -env:UserInstallation, so its profile can only go there - the probes use /healthcheck; "/" is never a 200 - whoever opens the page first becomes the administrator, and accountRegistration does not gate that - the ingress annotation is the only upload ceiling, because the application enforces none - WEBROOT, PUID/PGID/UMASK and PORT do not belong in the env block Two entries in Lessons learned, both preventive rather than post-mortem, in the shape the valkey entries already use: - the probe that would have passed on a redirect and meant something else a week later - a 3xx makes an httpGet pass, so a redirecting path hides the question instead of answering it, and the answer has to hold for every state the application can be in - the entrypoint we skipped, and the obligation that created - an override forks the entrypoint silently, and a fork with no diff is a fork nobody reviews, so the warning belongs at the line the next change will touch Also corrected in CI-CD: the per-chart publish workflow count, which read 24 and was already one behind before this chart made it 26. |
||
|
|
6fbc6d5776
|
The instructions block is a snapshot from session start
Forge-and-Tooling: correct the mechanism. The block is not a live read of the spawning session's working directory but a snapshot taken when that session started, so fetching mid-session does not refresh it — the file on disk can be correct while every agent started afterwards still gets the superseded rules. Records the measurement that shows it: a directory fast-forwarded and verified beforehand, an agent worktree identical to origin/main (0 0), and a block from before Gitea #47 regardless. States the two consequences that hold, separately from the ones that do not. Lessons-Learned: a new entry, because the failure form is the one this page collects — a stale instructions block looks exactly as authoritative as a current one, like the probe that cannot fail and the required array that never fires. Both measurements included, and the point that it went well only because someone checked. One bullet added to "The recurring shape". |
||
|
|
cd49460ed9
|
CI/CD: the all-charts install-test, and where the install-test job now lives
The install-test job moved into the reusable install-test.yml with two callers - the PR pipeline with the charts a pull request changed, the new install-test-all-charts.yml with every installable chart, on demand (Gitea #52). CI-CD: a section on the all-charts run - why it exists (the accidental first one, Gitea PR #48: 19 of 20 charts Ready in 12m41s, rss-bridge not), when to run it, what it records, the 20-charts-in-12m41s expectation, and that it runs the same job with a different matrix. Plus the runtime row, the shared-job note under the install-test stage, and select-charts next to detect-changed-charts where the exclusion list is read. Forge-and-Tooling: the quoted required-check name predates the move of the job into a called workflow - read the current one off a real run. Lessons-Learned: the green history from another machine, and one line in the recurring shape about making an accidental answer repeatable. Home: a row for "does every chart still come up on the current runner". |
||
|
|
d91927d2d0
|
valkey: chart page, index row, sidebar entry, two lessons
The new valkey chart (helm-charts #53, issue #46): one instance per application instead of the shared cluster-redis, whose separation rested on a single ACL file in a single 1Password field. The page carries what an operator cannot read off the templates: that the 1Password field auth-conf holds a finished "requirepass <password>" line rather than a password, that uid 999 / gid 1000 are the image's own user and why fsGroup has to match them, that maxmemory is derived from the computed memory limit and a value above it aborts the render, and that persistence and the eviction policy are a pair rather than two switches. Also what the install-test does not cover: one variant per chart, and fsGroup itself is unproven on k3d's node-directory volumes. Two Lessons-Learned entries, both from this chart's review rather than from an outage, because both generalize: a CLI that prints an error and exits 0 (valkey-cli without -e, so the natural ping probe cannot fail), and a secret whose FORMAT is load-bearing - a present-but-malformed field yields a running server with its protection off. |
||
|
|
e53493b99e
|
sure: the three failures the install-test found, and what they changed
The chart page now describes what was measured rather than only what was read from source: readiness runs through curl because the kubelet's HTTP prober follows the app's own redirect into https, /tmp as an emptyDir is not a temporary directory Ruby accepts, and ephemeral-storage at the scaffold's 10Mi evicts the pod within two minutes. Each of the three also has an entry on the lessons page, since none of them is specific to this chart. |
||
|
|
72fdda3bbf
|
satisfactory: server.storage stays the documented exception (#39)
Walks back the part of the previous commit that described storage as null-safe. It is not: an erased size still renders a PVC without one and fails at apply time, which is the decision values.schema.json has always documented. Overturning it belonged in its own issue, #39, not in the null-safety bugfix - so the chart page now marks it as an exception and names where the trade is argued, including the part that is easy to miss: the difference only matters on a new install, because an existing release cannot shrink its PVC either. The erased-key table stays and gains a "now" column, so the one key that did not change is visible rather than implied. Style guide 2 and the lessons entry lose the claim that the exception did not hold and gain the rule that replaced it: an exception is allowed, an unmarked one is not, and a bugfix that settles an open design question has stopped being a bugfix. |
||
|
|
d19d0bd89f
|
required() for the four mandatory OnePasswordItem references (#18)
Chart pages: calibre-web-automated 7.0.0, minecraft-server 6.0.0 and urlaubsverwaltung 10.0.0 now guard their secret references, so the values tables no longer say "not guarded by a required in the template". searxng 1.0.6 is a version snapshot only - its valkey reference was already correctly optional and stays that way. Style guide 12: the bullet on how null reaches the schema was wrong in the case it was being applied to. A null chart default is NOT coalesced away; only a user null over a non-null default is. Added the rule that follows from it - a value with no valid default cannot be enforced by values-schema at all while helm lint --strict has to pass on the defaults, so required() is the whole enforcement and a required array would be a guard that cannot fire. Lessons learned: both halves of that, since a safeguard that looks like one and never fires is the same failure shape as the missing guard it replaced. |
||
|
|
313ec47607
|
satisfactory: dev and server are null-safe as of 7.0.1
Chart page: version snapshot, the dev and server blocks documented as erasable, a table of what a single nulled key used to render (empty Service ports, a sizeless PVC), and why server.resources is the one key without its own default there. CI section: the notes are rendered by no stage of this chart's pipeline, and how to render them without a cluster. Style guide 2: the rule is about the shape, not about probes, security contexts and resources specifically - it covers every chart-owned block a template dereferences, and a half-protected chart is worse than an unprotected one. Lessons learned: new entry for the half-protected chart and for NOTES.txt as template code the pipeline is blind to. |
||
|
|
1f9b27e76f
|
Renovate: the PR policy after the alignment with cluster-config
The config now matches cluster-config's: global automerge with platformAutomerge, no PR caps, separateMinorPatch, config:best-practices. Two statements on these pages had become false and are rewritten rather than left standing: that Renovate merges its own PRs because main has no required status checks, and that majors are merged by hand. Both are active on main now - a review requirement and validate-charts as the single status context the matrix reports under - which is precisely why platformAutomerge could be turned on and why automerging majors is not unattended: the review is the gate. Touches Renovate (PR policy), Forge-and-Tooling (auto-merge, required check), Versioning (the order of a stepwise major jump is kept at the review now), CI-CD (required check, why the install-test blocks), and the two pages quoting the searxng downgrade as something that happened "unattended". |
||
|
|
f62f2e5871
|
Fill the wiki as the repository's knowledge base
One page per chart - prerequisites, installation walkthrough, the required 1Password fields, the complete values reference and the chart's operating traps - plus the long form of the workflow, the forge and its measured differences, the pipelines, versioning, Renovate, the chart style guide, the procedure for a new chart, local development, and the incidents each rule was bought with. Chart pages quote versions as snapshots; Chart.yaml stays authoritative, because Renovate moves app versions continuously and never edits the wiki. |