feat(bulwark): new chart for Bulwark Webmail (1.0.0+up1.12.0)
A JMAP webmail client for the stalwart chart (Gitea #65): StatefulSet, one PVC at /app/data, Service plus headless Service, Ingress at a host root, two OnePasswordItems, three probes, computed limits, replicas plus scaleDown, strict values.schema.json. Everything below was measured against the source at tag 1.12.0 rather than read out of the documentation, which was wrong about three of them. THE DEFINING PROPERTY: THE VOLUME BEATS THE CHART, FOR EVERY VALUE, SILENTLY. configManager.get resolves "admin override > env var > default", the admin dashboard may write any key of CONFIG_ENV_MAP, and nothing reports that it just disconnected the chart - so a helm upgrade can succeed and change nothing. Upstream documents this for the server URL only; it is true of everything. Exactly three values escape it (SESSION_SECRET(_FILE), ADMIN_PASSWORD, BULWARK_TELEMETRY). The value that closes it, bulwark.adminConfigReadOnly, defaults to false because its price is threefold: it freezes the settings policy (and with it the only way to move Web Push off the vendor relay), it freezes an override that ALREADY exists instead of removing it, and on a fresh install it stops admin.json from being written at all - so the admin dashboard never comes up and its login answers HTTP 500 while the pod stays Ready. OIDC-only sign-in, with the real way back out of a lockout: not helm upgrade with OAUTH_ONLY=false (oauthOnly goes through the same precedence chain) but removing the override in the admin dashboard. That is why ADMIN_PASSWORD is set - the dashboard is the door. It generates no random password and logs nothing, so the #65 analogy does not apply. SESSION_SECRET_FILE and OAUTH_CLIENT_SECRET_FILE are both used - the better path garage (#81) and keycloak (#83) did not have - in one projected volume mounted WITHOUT subPath, because both are re-read on every use and a subPath mount is never refreshed, and at mode 0440 because secret files are owned by root and fsGroup only supplies the group. Two backup statements, both at the value: without the session secret the synchronized settings are unreadable out of an intact volume, and if the dashboard's OAuth setup was ever used the client secret sits in config.json on that volume in cleartext. Probes: all three a plain GET on /api/health, with the limit written at the readiness value - it carries process, HTTP acceptance, a free event loop and Next.js routing, and nothing about the reported state or about Stalwart. No ConfigMap, so the checksum/config rule (#82) has nothing to attach to, and values.yaml says so explicitly; the op:// paths are covered by checksum/secret-ref. Renovate: no versioningTemplate, measured rather than assumed. 315 tags in eight shapes (releases, a second v-prefixed family of the same images, an -always flavour, floating minors and names, commit SHAs, betas, attestations) and plain docker versioning excludes all six unwanted ones. Dry runs at 1.12.0, 1.11.0 and 1.10.0 are recorded in the block. Part of #89 - deliberately not "Fixes", because one binding decision of the issue was changed out of necessity and wants ratification rather than an automatic close: the plan specifies HEAD /api/health for all three probes, and a Kubernetes probe cannot send HEAD at all (HTTPGetAction has no method field; the kubelet always issues GET). The alternative, an exec probe, would mean starting a Node process every few seconds in an image that carries no curl and no wget. GET is used instead and is marginally more capable than HEAD, so every limit the issue argues is unchanged - but the decision is the maintainer's to confirm.
This commit was merged in pull request #90.
This commit is contained in:
1 parent
40e29f7f72
commit
b39f36ff5c
17 files changed
+2719
-1
No files matched your search
@@ -326,6 +326,67 @@
|
||||
datasourceTemplate: "docker",
|
||||
depTypeTemplate: "app-version",
|
||||
},
|
||||
{
|
||||
description: [
|
||||
"bulwark: the busiest tag landscape of any chart in this file, and the reason this block",
|
||||
"was measured instead of copied. Counted on 2026-10-05 against the ghcr.io tags API,",
|
||||
"315 tags in EIGHT shapes side by side:",
|
||||
"",
|
||||
" 1. release tags, suffix-free 1.12.0, 1.11.2, 1.11.1, ... <- what we track",
|
||||
" 2. the SAME releases with a 'v' v1.12.0, v1.11.2, ...",
|
||||
" 3. a '-always' build flavour 1.12.0-always, v1.12.0-always",
|
||||
" 4. floating minors and majors 1.12, 1.11, 1, v1.12, v1 - they move",
|
||||
" 5. floating names latest, main, dev, latest-always - they move",
|
||||
" 6. commit-SHA tags 0080d27, main-<sha>, dev-<sha> (the bulk of the",
|
||||
" 315, pushed per commit) plus one typo'd tag, mainfc38427",
|
||||
" 7. PRERELEASES 1.11.0-beta.1, -beta.2, -beta.3 and their",
|
||||
" -always twins",
|
||||
" 8. attestation tags sha256-<64 hex>",
|
||||
"",
|
||||
"Shapes 4-7 are each a way to pin something nobody chose into appVersion and republish",
|
||||
"the chart for it - and shape 2 is the subtler one, because it is the same image under a",
|
||||
"second name, so selecting it would rewrite appVersion and the +up suffix for no change",
|
||||
"at all.",
|
||||
"",
|
||||
"LIKE keycloak AND UNLIKE garage, THE ANSWER IS AN ABSENCE: no versioningTemplate. Plain",
|
||||
"`docker` versioning already excludes every unwanted shape, so a constraint here would be",
|
||||
"a line that does nothing and one more thing to keep correct. It splits a tag at the first",
|
||||
"dash and only ever offers candidates carrying the SAME suffix as the current value -",
|
||||
"ours has none, so shapes 3 and 7 are invisible to it; the SHA and floating-name tags",
|
||||
"parse as no version at all; the floating minors have fewer parts than our value and",
|
||||
"cannot be more precise; and a 'v'-prefixed tag normalizes to the same version as ours,",
|
||||
"so it is never GREATER and never an update. `ignoreUnstable` (a Renovate default, also",
|
||||
"pulled in by config:recommended above) is a second, independent guard on shape 7.",
|
||||
"",
|
||||
"MEASURED, NOT ASSUMED, and written down because a later round will otherwise add a",
|
||||
"constraint 'to be safe'. Renovate 44.138.0, --platform=local --dry-run=lookup against",
|
||||
"the real registry, reading THIS file (so separateMinorPatch and the rest of the config",
|
||||
"above are in effect), 2026-10-05:",
|
||||
" appVersion 1.12.0 -> updates [], warnings []",
|
||||
" appVersion 1.11.0 -> exactly two: 1.11.2 (patch), 1.12.0 (minor)",
|
||||
" appVersion 1.10.0 -> exactly one: 1.12.0 (minor)",
|
||||
"Every offered newValue was the suffix-free form. No run offered a beta, an -always tag, a",
|
||||
"'v' form, a floating tag or a SHA tag. The 1.11.0 and 1.10.0 fixtures are the guard the",
|
||||
"nginx and qbittorrent rules taught this repo to run: they prove real updates still come",
|
||||
"through rather than the filter quietly emptying the list.",
|
||||
"",
|
||||
"ONE CAVEAT ABOUT THAT RUN, stated rather than hidden because it was visible in the log:",
|
||||
"ghcr.io served NO releaseTimestamp anonymously, so Renovate marked both updates",
|
||||
"`pendingChecks: true` under the minimumReleaseAge rule below",
|
||||
"(minimumReleaseAgeBehaviour=timestamp-required). Whether the shared instance sees the",
|
||||
"timestamps is NOT verified here - it authenticates to github.com with GITHUB_COM_TOKEN",
|
||||
"and this run did not. If it does not, the consequence is a held PR rather than a wrong",
|
||||
"one, and it would apply to every ghcr.io-based chart in this file alike (bentopdf,",
|
||||
"calibre-web-automated, cyberchef, matrix-synapse, ytdlp-web-player), so it is not a",
|
||||
"decision about this chart.",
|
||||
],
|
||||
customType: "regex",
|
||||
managerFilePatterns: ["bulwark/Chart.yaml"],
|
||||
matchStrings: ["(?m)^appVersion:\\s*\"?(?<currentValue>[^\"\\s]+)\"?"],
|
||||
depNameTemplate: "ghcr.io/bulwarkmail/webmail",
|
||||
datasourceTemplate: "docker",
|
||||
depTypeTemplate: "app-version",
|
||||
},
|
||||
{
|
||||
customType: "regex",
|
||||
managerFilePatterns: ["calibre-web-automated/Chart.yaml"],
|
||||
|
||||
Reference in new issue
Block a user