Changelog — Jarvis Helm Chart
All notable changes to the Jarvis Helm chart (oci://ghcr.io/kj187/charts/jarvis) are documented in this file. The format is based on Keep a Changelog, and the chart follows Semantic Versioning. The chart version is decoupled from the Jarvis app version; appVersion is the image tag the chart deploys by default. The app changelog lives in the repository root.
Every chart version lists a Breaking Changes section, even when there are none. A breaking change is anything that can make helm install/helm upgrade fail or change the behavior of an existing release without the user changing their values: removed or renamed values, changed defaults, new validations that reject previously accepted values, new resources that need extra permissions, or changed selector labels. A breaking change always bumps the chart's major version.
Entries up to and including 1.7.6 were reconstructed from the git history when this file was introduced; their breaking-change classification was assessed retroactively.
Unreleased
2.2.0 - 2026-10-10
Breaking Changes
- No breaking changes.
Changed
appVersionbumped to2.1.0.- The readiness probe now sets
timeoutSeconds: 3(the Kubernetes default of 1 s is shorter than the app's 2 s database ping, so a slow ping could fail the probe and pull the pod out of the Service endpoints). Together with the app no longer caching a failed ping when a client aborts the request, a healthy pod stays ready. Values are unchanged — not breaking. database.maxOpenConns: 1with a PostgreSQL DSN is now raised to2by the app, with a warning in the log, instead of running a single-connection pool, which the app never supported. The default (10) and every value from2up are unchanged; SQLite ignores the value. Nothing has to change in existing values — not breaking.- Custom cluster headers (
clusters[].auth.headers) are now stored in the chart's Secret (cluster-<n>-header-<name>) and read by the Deployment throughsecretKeyRef, instead of being rendered into the ConfigMap, so a header such asAuthorizationno longer sits in a readable ConfigMap. The environment the app sees is identical (JARVIS_CLUSTER_<n>_HEADER_<name>), and the chart Secret is rendered whenever a header is set, also whendatabase.existingSecretis used. Values stay as they were; nothing has to change in existing values — not breaking. - The liveness probe now calls
/health/live(process only) and the readiness probe/health/ready(database ping), instead of both calling/health. A database outage now takes the pod out of the Service endpoints, while an Alertmanager outage does not. The new paths exist from the app version that ships with this chart, so animage.tagoverride pointing at an older Jarvis release fails its probes — not breaking for a release that keeps the chart's default tag.
Added
image.digestvalue (sha256:<64 hex>): when set, the pod pulls<repository>:<tag>@<digest>. Empty by default, so an existing release renders unchanged; a malformed digest fails the render instead of failing at image-pull time — not breaking.networkPolicy.*values: an optionalNetworkPolicythat restricts ingress (port 8080, optionally fromnetworkPolicy.ingress.from) and egress (DNS vianetworkPolicy.egress.allowDnsplusnetworkPolicy.egress.rules). Off by default, so an existing release renders unchanged and no new resource appears — not breaking. Enabling it denies every connection that is not listed: add egress rules for Alertmanager, the database and the OIDC issuer (see docs/deploy-kubernetes.md).config.wsMaxConnectionsvalue (JARVIS_WS_MAX_CONNECTIONS), empty by default and rendered into the ConfigMap only when set (0is rendered and means no cap). The app itself now caps WebSocket connections per pod at 500 and answers503beyond that; the value tunes or lifts that cap. With the chart's default tag an existing release gets the app default without changing values — not breaking for any realistic deployment, since 500 simultaneous browser tabs per pod is far above the intended use.metrics.token(stored in the chart Secret) ormetrics.existingSecret/metrics.existingSecretKey(defaultmetrics-token) value: setsJARVIS_METRICS_TOKEN, so/metricsrequiresAuthorization: Bearer <token>. The ServiceMonitor then scrapes with anauthorizationblock pointing at the same Secret key; annotation-based scraping and other scrapers have to send the header themselves. Empty by default, so an existing release renders unchanged and keeps/metricsopen — not breaking.config.allowedHosts(JARVIS_ALLOWED_HOSTS) andconfig.trustedProxies(JARVIS_TRUSTED_PROXIES) values, both empty by default and rendered into the ConfigMap only when set.allowedHostsmakes the app answer421to aHostheader outside the list (probe and metrics paths exempt);trustedProxiesnames the proxies whoseX-Forwarded-Foris believed when logging the client IP. Empty renders unchanged and keeps the checks off — not breaking. An invalidtrustedProxiesentry makes the app refuse to start, so it surfaces on rollout.config.cookieSecurevalue (default empty), rendered asJARVIS_COOKIE_SECUREonly when set.truemakes the session cookie alwaysSecure, for a TLS-terminating proxy that does not sendX-Forwarded-Proto; empty keeps the automatic behavior, so an existing release renders unchanged — not breaking.auth.setupTokenvalue (andauth.existingSecretKeys.setupToken, defaultsetup-token), rendered asJARVIS_SETUP_TOKENfrom the chart's Secret whenauth.providerisinternal. When set, creating the first admin through/setuprequires the token. Empty by default, so an existing release renders unchanged and keeps the open wizard; withauth.existingSecretthe Secret key is optional (optional: true), so a Secret without it does not block the rollout — not breaking.config.resolvedBufferTTLvalue, rendered asJARVIS_RESOLVED_BUFFER_TTLin the ConfigMap only when set. It sets how long a resolved alert stays in the live snapshot (Go duration, 1m–24h; an invalid value makes the app refuse to start, so it surfaces on rollout). Empty by default, so an existing release renders unchanged and keeps the 20-minute default — not breaking.auth.oidc.adminValuenow accepts several comma-separated groups (e.g.admin_a,admin_b); membership in any one grants the admin role. A single group behaves exactly as before and the value is passed through unchanged, so an existing release renders unchanged — not breaking.
2.1.0 - 2026-09-28
Breaking Changes
- No breaking changes.
Added
config.silenceDurationsvalue, rendered asJARVIS_SILENCE_DURATIONSin the ConfigMap only when set. It defines the instance-wide default durations of the Fast-Silence and Extend-silence menus (comma-separatedm/h/d/w/ydurations, up to 12, each 1m–365d); an invalid value makes the app refuse to start, so it surfaces on rollout rather than silently. Empty by default, so an existing release renders unchanged and keeps the built-in durations — not breaking.clusters[].auth.*values for per-cluster upstream Alertmanager authentication: OAuth2 client credentials, bearer token, basic auth, and custom headers — rendered as the existingJARVIS_CLUSTER_<n>_*variables the backend already reads.oauth2.clientSecret,bearerTokenandbasicAuth.passwordare stored in the chart's Secret, never the ConfigMap;clusters[].auth.existingSecretsources them from an externally managed Secret instead, consistent withdatabase.existingSecretandauth.existingSecret. Settingoauth2.clientIdwithoutoauth2.tokenUrlfails the render, mirroring the backend's own startup validation instead of failing silently at runtime.auth.oidc.groupsClaimandauth.oidc.adminValuevalues, rendered asJARVIS_OIDC_GROUPS_CLAIMandJARVIS_OIDC_ADMIN_VALUEin the ConfigMap, each only when set. They let SSO group membership (e.g.cognito:groups) grant the admin role without editingextraEnv. Empty by default, so an existing release renders unchanged.config.retention.*values (days,eventsDays,claimsDays,silenceEventsDays,commentsDays,sweepInterval), rendered as the correspondingJARVIS_RETENTION_*variables, each only when set. Controls the data-retention sweep; empty by default, matching the backend's own opt-in default of keeping history forever, so an existing release renders unchanged.
Changed
appVersionbumped to2.0.0.- The chart README now keeps only chart values and chart-specific examples; release verification, upgrade/rollback, and authentication procedures link to their canonical guides instead of duplicating them. Documentation only, no rendered change.
- The Kubernetes section of docs/authentication-alertmanager.md and the chart README now document
clusters[].auth.*directly instead of theextraEnvworkaround;extraEnvis kept as a documented fallback for chart versions before this one. - The ingress section points at the new reverse-proxy guide and states that
config.allowedOriginsmust name the URL the browser uses — the WebSocket annotations alone are not enough. Documentation only, no rendered change. artifacthub.io/links's Documentation entry now points at the published docs site (https://kj187.github.io/jarvis/) instead of thedocs/tree on GitHub, following the docs restructure into a reader-intent site. Metadata only, no rendered change.- Comments in
values.yamland the template files pointing atdocs/persistence.mdnow point atdocs/postgres-ha.md, following the same restructure. Comments and a test suite name only, no rendered change.
Fixed
- The Deployment now rolls when the configuration changes. The pod template carries
checksum/config(the rendered ConfigMap) and, when the chart creates a Secret,checksum/secret, so ahelm upgradethat changesauth.mode,config.pollInterval,config.allowedOrigins, a cluster entry or a chart-managed secret replaces the pods instead of leaving them on the old environment until a manualkubectl rollout restart. A Secret referenced through anexistingSecretvalue is not rendered by the chart and is not covered — restart the Deployment after rotating it (see docs/deploy-kubernetes.md). The twochecksum/*keys belong to the chart: apodAnnotationsentry with the same name is ignored instead of rendering a duplicate key. Not breaking: nothing has to change in existing values, and the upgrade rolls the pods just as every chart version upgrade already does, because the pod labels carry the chart version (helm.sh/chart); re-running the same chart version with unchanged values does not roll them. Refs #264. - The values table in the chart README documents six values that existed but were listed nowhere:
podLabels,persistence.annotations,updateStrategy.type,autoscaling.minReplicas,autoscaling.maxReplicasandautoscaling.targetCPUUtilizationPercentage.updateStrategy.typematters most — its auto-selection (Recreatewith a PVC,RollingUpdateotherwise) was explained only in avalues.yamlcomment and therefore reached neither the website nor Artifact Hub. Documentation only, no rendered change.
2.0.0 - 2026-09-15
Breaking Changes
- SQLite (
database.dsnis a file path) combined withreplicaCount > 1orautoscaling.enablednow fails the render regardless ofpersistence.enabled. Previously the guard only fired with a PVC, so the default emptyDir setup rendered fine — while every pod polled Alertmanager independently and kept its own divergent history. Migration: setreplicaCount: 1or switch to PostgreSQL (database.dsn: postgres://..., see docs/persistence.md). (#194) auth.providerother thannonenow fails the render unlessauth.secretKeyorauth.existingSecretis set, andauth.provider: oidcadditionally requiresauth.oidc.issuer,auth.oidc.clientIdandauth.oidc.redirectUrl. Such releases previously rendered, but the pod never started (CreateContainerConfigError). Migration: set the missing values. (#193)
Changed
appVersionbumped to1.12.0.- The chart now ships its own
CHANGELOG.md; the Artifact Hub links point to both the chart and the app changelog. - The chart is published only after the image for its
appVersionexists — as part of an app release, or on its own for chart-only releases. The README documents the versioning rules (breaking change → major). Chart.yamlcomments point to the release process at its new location (.agents/skills/release/SKILL.md); comment-only, no rendered change.
Fixed
- The generated Secret renders
dsn,secret-keyandoidc-client-secretindependently. Settingdatabase.existingSecretno longer suppresses the auth secret key the Deployment references. (#192)
1.7.6 - 2026-09-09
Breaking Changes
No breaking changes.
Changed
appVersionbumped to1.11.0.
1.7.5 - 2026-09-05
Breaking Changes
No breaking changes.
Changed
appVersionbumped to1.10.1.
1.7.4 - 2026-09-05
Breaking Changes
No breaking changes.
Changed
appVersionbumped to1.10.0.
1.7.3 - 2026-08-17
Breaking Changes
No breaking changes.
Changed
appVersionbumped to1.9.3.
1.7.2 - 2026-07-17
Breaking Changes
No breaking changes.
Changed
appVersionbumped to1.9.2.
1.7.1 - 2026-07-16
Breaking Changes
No breaking changes.
Added
database.maxOpenConns(default10) →JARVIS_DB_MAX_OPEN_CONNS, caps the PostgreSQL connection pool per pod. Ignored for SQLite. (#120)
Changed
appVersionbumped to1.9.1.
1.7.0 - 2026-07-15
Breaking Changes
leaderElection.podLabel.enableddefaults totrue: the chart now renders aRole(pods:get,patch) and aRoleBinding, and the pod mounts its ServiceAccount token (automountServiceAccountToken: trueat pod level) so the leader can label itself. Installations whose Helm user may not create RBAC resources, or that rely on the token not being mounted, must setleaderElection.podLabel.enabled: false. (#112)
Added
- Leader pod label
jarvis.kj187.de/role=leader(PostgreSQL multi-replica), withPOD_NAME/POD_NAMESPACEinjected via the Downward API. (#112) podDisruptionBudget.enabled/podDisruptionBudget.minAvailableand atopologySpreadConstraintspassthrough for HA deployments. (#113)metrics.serviceMonitor.relabelings,metricRelabelings,annotationsandhonorLabels. (#117)
Changed
appVersionbumped to1.9.0.
1.6.2 - 2026-07-13
Breaking Changes
No breaking changes.
Changed
appVersionbumped to1.8.0.
1.6.1 - 2026-07-09
Breaking Changes
No breaking changes.
Changed
appVersionbumped to1.7.0.
1.6.0 - 2026-07-04
Breaking Changes
No breaking changes.
Added
- Prometheus scraping for
/metrics: an opt-inServiceMonitor(metrics.serviceMonitor.enabled) andprometheus.io/*pod annotations (metrics.podAnnotations). - Artifact Hub annotations (category, license, links) in
Chart.yaml.
Changed
- Chart versioning is decoupled from the app version: the chart is published by its own workflow on changes under
charts/and signed keylessly with cosign. Previous chart versions were identical to the app version. appVersionbumped to1.6.0.
1.5.0 - 2026-06-26
Breaking Changes
No breaking changes.
Changed
- Chart README recommends PostgreSQL for Kubernetes deployments.
appVersionbumped to1.5.0. Chart versions 1.5.1–1.5.3 only bumpedappVersionto the matching app release.
1.4.0 - 2026-06-22
Breaking Changes
No breaking changes.
Changed
authvalues point to the split user-authentication docs (docs/authentication-user.md).appVersionbumped to1.4.0.
1.3.1 - 2026-06-19
Breaking Changes
- SQLite with
persistence.enabled: truecombined withreplicaCount > 1orautoscaling.enablednow fails the render. This was released as a patch at the time.
Added
updateStrategy.type; when empty, the Deployment strategy is auto-selected:Recreatewithpersistence.enabled,RollingUpdateotherwise.
Fixed
- Rolling updates with an RWO volume (e.g. EBS) no longer force a volume detach that caused
SQLITE_IOERR_READ.
Changed
appVersionbumped to1.3.1. Chart version 1.3.0 only bumpedappVersion.
1.2.0 - 2026-06-18
Breaking Changes
No breaking changes.
Added
extraEnv,extraVolumes,extraVolumeMountsandserviceAccountTokenProjection(projected, audience-scoped ServiceAccount token, e.g. for Vault/JWT). All disabled by default.
Changed
appVersionbumped to1.2.0. Chart version 1.1.0 only bumpedappVersion.
1.0.2 - 2026-06-16
Breaking Changes
No breaking changes (first published chart version).
Added
- Initial chart: Deployment, Service, ConfigMap, Secret, PVC, HPA, ServiceAccount and Ingress (nginx and Traefik WebSocket examples).
- User authentication values:
auth.provider(none/internal/oidc),auth.mode(write_protect/full_protect),auth.secretKey/auth.existingSecret, OIDC settings. - helm-unittest suite.
Chart versions 1.0.3–1.0.5 only bumped appVersion to the matching app release.
