Skip to content

charts/authentik: gate the migrations rules behind a value - #521

Closed
Pirat83 wants to merge 1 commit into
goauthentik:mainfrom
Pirat83:gate-migrations-rules
Closed

Pirat83 wants to merge 1 commit into
goauthentik:mainfrom
Pirat83:gate-migrations-rules

Conversation

@Pirat83

@Pirat83 Pirat83 commented Sep 9, 2026

Copy link
Copy Markdown

The chart ships a PendingMigrations alert at severity: critical, plus two recording rules in the authentik Aggregate migrations group, all keyed on django_migrations_unapplied_total. The default authentik deployment never exports that metric, so on a stock install those rules are silent by construction.

This is goauthentik/authentik#9941, open since 2024-06. I added a confirmation there reproducing it on 2026.8.1 via this chart.

Why gate rather than make the metric work

Three things must be true for the metric to appear, and none of them is. Traced through the source at version/2026.8.1:

  1. django-prometheus only exports it when PROMETHEUS_EXPORT_MIGRATIONS is set (DjangoPrometheusConfig.ready()), and authentik does not set it.
  2. Even set, it would not surface. preload_app = True loads Django's app registry — and so ExportMigrations() — in the gunicorn master, while post_fork only installs MultiProcessValue after the fork. The gauge lands in the master's plain in-process storage, which the multiprocess collector never reads. This is the part the issue reporter flagged as unexplained in 2024.
  3. It would measure nothing anyway. run_migrations() runs at module level in lifecycle/gunicorn.conf.py, so migrations are already applied before anything observes them — the gauge would read 0 on every successful boot.

Point 3 is the reason for gating instead of fixing. PendingMigrations is an alert for deployments where migrations are a separate step and the app can serve against an un-migrated database. That setup is real and those users are exactly who the alert was written for — so the rules stay, behind an opt-in.

The change

One new value, prometheus.rules.migrations.enabled, defaulting to false, gating both the alert and the recording-rule group — the latter reads the same dead metric, so gating only the alert would leave it behind.

Defaulting to false cannot regress anyone, because the rules it disables cannot currently fire.

Verified

Rendered three ways with helm template:

values result
defaults no PrometheusRule (unchanged — prometheus.rules.enabled is already false)
prometheus.rules.enabled=true rule renders without the migrations group and without PendingMigrations; the other 3 alerts and 4 recording groups intact
both enabled=true parsed objects identical to main — 10 objects, all 6 groups, all 4 alerts. The only textual delta is 3 blank lines absorbed by {{- chomping

That third case is the one that matters: the gate is purely additive for anyone who opts in.

Also run: helm lint clean with the gate both off and on; yamllint -c .github/configs/lintconf.yaml clean on values.yaml and Chart.yaml; ./scripts/helm-docs.sh regenerated README.md (one row added) and is idempotent on a repeat run. No chart version bump — check-version-increment is false and the chart version tracks appVersion on release bumps.

Happy to change the approach

If you would rather simply delete these rules than carry a flag for them, say so and I will amend — I chose the flag only to preserve the split-migration-step use case, and it is your call which is the better trade.

The chart ships a `PendingMigrations` alert at severity critical, plus two
recording rules, all keyed on `django_migrations_unapplied_total`. The default
authentik deployment never exports that metric, so on a stock install these are
silent by construction -- see goauthentik/authentik#9941, open since 2024-06.

Three things have to be true for the metric to appear, and none of them is:

1. django-prometheus only exports it when PROMETHEUS_EXPORT_MIGRATIONS is set
   (DjangoPrometheusConfig.ready()), and authentik does not set it.
2. Even set, it would not surface. preload_app = True loads Django's app
   registry -- and so ExportMigrations() -- in the gunicorn master, while
   post_fork only installs MultiProcessValue after the fork. The gauge lands in
   the master's plain in-process storage, which the multiprocess collector never
   reads.
3. It would measure nothing anyway: run_migrations() runs at module level in
   lifecycle/gunicorn.conf.py, so migrations are already applied before anything
   observes them. The gauge would read 0 on every successful boot.

Point 3 is why this gates rather than fixes. PendingMigrations is an alert for
deployments where migrations are a separate step and the app can serve against
an un-migrated database. That configuration is real, and those users are exactly
who the alert was written for -- so the rules stay, behind an opt-in.

Both blocks are gated, not just the alert: the "authentik Aggregate migrations"
recording group reads the same dead metric.

Defaulting to false cannot regress anyone, because the rules it disables cannot
currently fire.

Signed-off-by: Pirat83 <Pirat83@users.noreply.github.com>
@Pirat83
Pirat83 requested a review from a team as a code owner September 9, 2026 19:51
@rissson

rissson commented Sep 22, 2026

Copy link
Copy Markdown
Member

closing in favour of goauthentik/authentik#26352

@rissson rissson closed this Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants