CI CD
Justin Klein edited this page 2026-10-15 17:51:52 +00:00
Clone

Wiki Page Revisions

31 Commits

Author SHA1 Message Date
jklein 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.
2026-10-15 17:51:52 +00:00
jklein 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.
2026-10-14 14:57:00 +00:00
jklein 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.
2026-10-13 19:17:12 +00:00
jklein 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.
2026-10-13 18:48:54 +00:00
jklein b90df5f07d CI-CD: cash in the delta rule - 64 over 22, the first run holding all three rounds
All three parallel rounds have now merged, and this page had three deltas
on it (+2 rss-bridge, +4 realm hostnames, +2 MTA-STS) each of which
deferred the running total to "the first run on main that holds all of
them". The MTA-STS round was the last of the three, so its own run IS that
run: 64 assertions over 22 charts, 0 failed, stalwart contributing 4.

Replaces my own 60/22, which was measured before #122 landed and was
already the second figure this paragraph had to correct.

The intermediate numbers are kept legible on purpose rather than tidied
away - 58/22, 60/21, 60/22 were each correct for the substructure they were
read on, and none of them is a total. And 62 + 2 = 64 is named as a CHECK
rather than as the source: the figure above was read from a run, and the
arithmetic only agrees because nothing else moved in between. A round that
changes an existing chart's routes instead of adding a chart would not add
up that way at all, which is the whole reason the convention says to read
the total rather than sum the deltas.
2026-10-13 10:43:10 +00:00
jklein af20995c9e CI-CD: the MTA-STS delta is 2, measured at 60 over 22 on top of rss-bridge
Three rounds were in flight at once and this page already carries the rule
they settled on - a round's figure is its DELTA, because none of the three
branches contained the others. My own paragraph still read "takes it to 58
over 21", which was a running total from before rss-bridge landed and is
now simply wrong.

Restated as a delta of 2, with the figure re-measured after rebasing onto
the landed rss-bridge round: 60 over 22. Named against the 62 over 22 this
page records for rss-bridge plus #122, so the three deltas (+2, +4, +2) are
visible side by side, and the total once all three land is left to be read
off the first run on main that holds them rather than added up here.

Also kept the point that is this round's own: it is the first entry in this
history where the figure grew because a chart ALREADY in the list gained an
object instead of because a chart joined - so the chart count does not move,
and an overlay that was not extended would have left the new route
unrendered.
2026-10-13 10:33:17 +00:00
jklein 48e555443b CI-CD: the running total both rounds deferred is 62 over 22, measured
The rss-bridge round and the realm-hostname round were measured on branches
that did not contain each other (58/22 and 60/21), so both left the running
total to the first branch holding both. That branch exists now - the
realm-hostname branch with main merged into it - and the figure is 62
assertions over 22 charts, 0 failed, keycloak contributing 8.

Read off ci/run-httproute-match-test.sh rather than added up, which is the
rule both rounds wrote down.
2026-10-13 10:31:03 +00:00
jklein 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.
2026-10-13 10:29:41 +00:00
jklein 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;
2026-10-13 10:21:46 +00:00
jklein 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.
2026-10-13 10:19:11 +00:00
jklein 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.
2026-10-13 10:13:44 +00:00
jklein 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.
2026-10-13 10:11:19 +00:00
jklein 56ef01d057 CI-CD: the HTTPRoute test after group 3 - 56 assertions over 21 charts
Up from 37 over 15, with the per-chart breakdown: keycloak 4 and
matrix-synapse 4 (two routes each), homeassistant 5 (two routes, three rules),
bulwark/stalwart/ytdlp-web-player 2 each.

Corrected the forward-looking claim about bulwark. This page said bulwark was
the second rewrite-target chart and would meet the #118 prefix/redirect
pairing when group 3 landed. It does not: bulwark has one Ingress, no
rewrite-target, and cannot have one, because NEXT_PUBLIC_BASE_PATH is compiled
into its bundle. The run-httproute-match-test.sh header carried the identical
claim and was corrected in the same round - noted here, because that is where
the next reader will look.

Three additions to "what an overlay has to do", all from group 3:

  - a multi-OBJECT overlay has to enter every object, not just a multi-app
    one - keycloak covers public and admin, matrix-synapse covers homeserver
    and delegation, and the latter is the only overlay in the repo whose two
    backendRefs resolve to different Services;
  - one overlay has to SUPPLY hostnames (homeassistant, which has no
    ingress.domain), and for that chart the overlay ADDS coverage rather than
    trading it, because ingress.enabled defaults to false there and the
    install-test never exercised a routing object at all;
  - a render-FAILURE path cannot live in this test, and two of group 3's
    guards are exactly that (homeassistant's ImplementationSpecific abort,
    ytdlp-web-player's same-host refusal) - exercised by hand, recorded in the
    PR, enforced by the chart's own fail.
2026-10-12 21:40:51 +00:00
jklein 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.
2026-10-12 20:11:38 +00:00
jklein 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.
2026-10-12 18:28:32 +00:00
jklein d51fb49b93 CI-CD: the HTTPRoute test's figure from the CI run
The local run was missing the three charts with a Helm dependency, so it
counted 27. CI run 719 renders all 30 for the same 4 assertions.
2026-10-12 15:25:31 +00:00
jklein 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.
2026-10-12 15:23:46 +00:00
jklein 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.
2026-10-07 11:39:25 +00:00
jklein 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.
2026-10-04 17:09:56 +00:00
jklein 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.
2026-10-02 00:21:18 +00:00
jklein 069d4e3aaa CI-CD: was der erste Sonar-Lauf gemessen hat, und der richtige Schluessel
Der Projektschluessel ist JLab-Helm-Charts, gelesen am Projekt auf dem Server.
Der bisherige war geraten und hat die Meldung erzeugt, die ein nicht
vorhandenes Projekt und ein Token ohne Recht gleichermassen erzeugen - dass der
Server die zwei Faelle nicht unterscheidet, steht jetzt dabei. Dazu, warum kein
sonar.projectName gesetzt wird.

Die Analysator-Tabelle stand aus einer Sprachliste und versprach mehr, als die
Instanz liefert. Gemessen in Lauf 375: zwei Qualitaetsprofile, json und yaml;
gearbeitet haben der IaC-Kubernetes-Sensor und die Geheimnis-Erkennung ueber
391 Dateien. Shell und GitHub Actions liefen nicht, und nichts in diesem
Repository kann das aendern - Analysatoren sind server-seitige Plugins. Die
Folge ist benannt: Die fuenf ci/-Skripte und die dreissig Workflow-Dateien
werden nicht analysiert.

Die Liste der drei offenen Fragen ist eine Liste der drei Antworten geworden,
alle positiv. Die dritte beantwortet dieselbe Frage fuer OP_CONNECT_HOST, und
damit sind an der Publish-Strecke zwei der drei genannten Punkte belegt - offen
bleibt der Upload, der nie stattgefunden hat.
2026-10-02 00:16:08 +00:00
jklein eef939472e CI-CD: die SonarQube-Analyse, und warum sie kein Torwaechter ist
Neuer Abschnitt auf CI-CD: der Aufruf, die Analysatoren und was sie hier
abdecken, die fehlenden Ausschluesse mit Begruendung, die Voraussetzungen und
wie ein fehlender aussieht, dazu die drei Punkte, die der erste Lauf beantwortet.

Die Einleitung der Seite stimmte nicht mehr: Sie nannte zwei Pipelines und
einen manuell ausgeloesten Lauf. Jetzt sind es vier Laeufe, und die
Unterscheidung, die man mitnehmen muss, steht dort - nur die PR-Pipeline kann
einen Merge aufhalten. Die Analyse meldet einen Zustand, der schon gemergt ist.

Der Abschnitt zum Nachweis des Publish-Wegs nennt eine der drei offenen Fragen
nicht mehr als diesem Weg allein gehoerend: Ob eine Repository-Variable in
einem aus einem fremden Repository aufgerufenen Workflow ankommt, beantwortet
der erste Sonar-Lauf fuer beide.

Was auf der Seite des Bausteins steht - warum fetch-depth: 0 nicht optional
ist, warum kein Docker-Runner noetig ist, was der Scanner zur Laufzeit holt -
ist bewusst nicht wiederholt, sondern verlinkt. Zwei Kopien einer Begruendung
heisst, dass eine davon irgendwann falsch ist, und die Datei gehoert uns nicht.

Zum SONAR_TOKEN festgehalten, dass es vorhanden ist und dass "vorhanden" hier
die Bestaetigung des Betreuers meint und keine Pruefung durch ein Werkzeug:
Secrets und Variablen sind von aussen nicht lesbar, tea antwortet mit
"user should be the owner of the repo".
2026-10-01 23:50:05 +00:00
jklein 18796c709a CI/CD: publish-helm-chart liegt jetzt in workflow-util/pipelines
Die Seite beschrieb den Publish-Workflow als Workflow dieses Repositories. Er
liegt seit Gitea #66 in workflow-util/pipelines und wird an einen Tag gebunden
aufgerufen.

Neu ist ein Abschnitt, was ein Aufrufer hier beisteuert: registry-owner als
Pflichteingabe mit github.repository_owner, secrets: inherit, die
Repository-Variable OP_CONNECT_HOST, und ci/helm-dependencies.sh - das bleibt
unser Skript und laeuft aus unserem Checkout, womit es Teil des Vertrags ueber
die Repository-Grenze wird.

Die Begruendungen des Upload-Schritts stehen nicht mehr hier, sondern im Wiki
von pipelines, mit Verweis. Zwei Kopien einer Erklaerung heisst, dass eine von
beiden irgendwann falsch ist - und die Datei, die diese Saetze beschreiben, ist
nicht mehr unsere. Was hier bleibt, ist das Repository-Eigene: die erwartete
Form des Tresor-Felds, der zweite Eigentuemer auf derselben Instanz, der
Spiegel ohne Actions und der erneute Upload derselben Version.

Der Abschnitt zum Nachweis ist umgeschrieben: Ein manueller Dispatch einer
Huelle ist nach dem Umzug der einzige Weg, einen Publish von Hand zu starten,
und er ist das Einzige, was die drei offenen Punkte beweisen kann -
cross-repo-uses, eine Variable in einem fremd aufgerufenen Workflow, und der
Upload selbst.

Dazu nachgezogen: die Huellenzahl (25, nicht 26 oder 24), der Hinweis bei
helm-dependencies.sh, und in New-Chart der Schritt 1 - eine Huelle wird kopiert
und nicht aus dem Gedaechtnis geschrieben, weil eine fehlende Owner-Eingabe
erst beim echten Publish auffaellt.
2026-10-01 23:04:06 +00:00
jklein d7ce2055a0 CI-CD: the publish target is composed from a base and the repository owner
charts-url in the registry vault item held the full registry URL and the
workflow appended /api/charts. It now holds only the base up to
/api/packages, and the owner segment comes from github.repository_owner,
which this Gitea instance does populate (measured).

Records what the composition buys, the guards that make a mismatch
between vault item and workflow a named error instead of a 404 against a
masked URL, the order of the hard cut, and why proving the new path
takes a manual dispatch.
2026-09-30 18:51:41 +00:00
jklein 0f631e747f convertx, CI-CD: the measured install-test time
The chart's first green install-test leg took 2m35s including cluster
creation (Gitea PR #61), against an estimate of roughly five minutes for the
pull alone. Recorded in both places the estimate had been reasoned about.

The general point belongs on the CI-CD page rather than only on the chart
page: a large image moves the all-charts figure less than it looks, because
the legs run concurrently and that figure tracks the slowest leg plus
scheduling, never the sum of the pulls.
2026-09-30 15:32:57 +00:00
jklein 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.
2026-09-30 15:31:06 +00:00
jklein fb1be28644 CI/CD: compare the runtime figure against the run's own chart count 2026-09-27 14:30:30 +00:00
jklein 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".
2026-09-27 14:29:00 +00:00
jklein e434810e33 sure: chart page for the new we-promise Sure chart
Adds the chart page following the outline reference (same sections, same
table shapes, the complete values reference), a row in the chart index and
the sidebar entry, and pulls the two publish-workflow counts up by one
where the new chart changes them.
2026-09-22 19:53:48 +00:00
jklein 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".
2026-09-22 19:45:59 +00:00
jklein 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.
2026-09-18 08:48:01 +00:00