fix(renovate): stop the docker datasource stalling in Pending Status Checks #91

Sammanfogat
supernaut sammanfogade 1 incheckning från fix/renovate-docker-release-timestamp in i main 2026-08-18 09:04:03 +00:00
Ägare

The defect

minimumReleaseAgeBehaviour defaults to timestamp-required (Renovate's own schema: enum
timestamp-required / timestamp-optional, default timestamp-required). Renovate's docker
datasource often returns no releaseTimestamp
, and a check that needs a timestamp can never pass
without one. So the update is deferred on every run and the branch is never created.

The Dependency Dashboard lists it under "Pending Status Checks" with an approvePr-branch
action, which reads as though a branch already exists. Nothing logs an error at info.

Three things made this hard to see:

  • "Pending Status Checks" implies external CI. With prCreation at its immediate default the
    section can only mean an unmet internal check.
  • The internal-checks gate runs before PR-limit accounting, so a held update never reaches
    prHourlyLimit and never appears under "Rate-Limited". Two updates rate-limited and seven pending
    were two separate gates, not one phenomenon.
  • Release age being satisfied proves nothing. Renovate never compares ages when the timestamp is
    absent, so checking the registry's own dates and finding them old is not evidence the update will
    ever be offered.

Measured

On bitborg-infra, 2026-08-17, seven image updates were held this way:

Update Registry release age
codeberg.org/forgejo/forgejo 16.0.2-rootless 18.2 d
docker.io/grafana/loki 3.7.6 12.2 d
docker.io/victoriametrics/victoria-metrics v1.149.0 17.4 d
docker.io/victoriametrics/vmagent v1.149.0 17.4 d
docker.io/victoriametrics/vmalert v1.149.0 17.4 d
docker.io/library/postgres 17.11-trixie 4.1 d
quay.io/prometheus/alertmanager v0.34.0 1.2 d

Every one satisfies the 3-day quarantine except alertmanager, and that one is held for the same
reason as the rest, not for its age. docker.io/grafana/alloy opened a PR in the same run from the
same defaults file as the held vmagent, which is what rules out the manager, the file, the
datasource and the update type.

Renovate names the cause itself at debug:

DEBUG: Marking 1 release(s) as pending, as they do not have a releaseTimestamp
and we're running with minimumReleaseAgeBehaviour=timestamp-required
       "depName": "codeberg.org/forgejo/forgejo"
       "versions": ["16.0.2-rootless"]
       "check": "minimumReleaseAge"

The change

One packageRule, scoped to matchDatasources: ["docker"]. Datasources that do supply timestamps
keep failing closed, so the quarantine still applies wherever it can actually be evaluated.

The trade-off is deliberate and worth stating plainly: for images whose timestamp never arrives, the
3-day supply-chain quarantine stops applying. It was not protecting those images before, it was
permanently blocking them, which is the worse of the two failures for the git server and the
database. Image-tag bumps are never automerged, so a human still reviews every one. The bypass is
also not silent: Renovate logs a WARN at info naming the releases it proceeded on, so a skipped
quarantine is visible in the logs without raising the log level.

Verified

Reproduced with platform=local, RENOVATE_DRY_RUN=full and LOG_LEVEL=debug on renovate
43.288.0, the version production runs. No production access, no token, no Ansible apply.

  • Before: 8 Marking N release(s) as pending ... timestamp-required decisions, naming exactly
    the seven dashboard entries and nothing else.
  • After (scoped rule): 0 holds, and branch intents for all seven, plus the dashboard-approval
    gated postgres major.
  • renovate-config-validator accepts the option inside packageRules, and rejects a
    deliberately typo'd option name, so that check was shown able to fail.
  • pnpm format:check and pnpm mdlint clean.

Reviewer note: the validator checks option names but not enum values. A bogus
minimumReleaseAgeBehaviour: "totally-bogus-value" passes it with
Config validated successfully. The behavioural run above is what proves the value is honoured.

Deployment

None needed. Renovate resolves this preset from main at run time, so merging is the whole
deployment and it takes effect on the next run. The debug-logging apply planned in
bitborg/bitborg-infra#430 is no longer required.

Refs bitborg/bitborg-infra#430, bitborg/bitborg-infra#332

## The defect `minimumReleaseAgeBehaviour` defaults to `timestamp-required` (Renovate's own schema: enum `timestamp-required` / `timestamp-optional`, default `timestamp-required`). Renovate's **docker datasource often returns no `releaseTimestamp`**, and a check that needs a timestamp can never pass without one. So the update is deferred on every run and **the branch is never created**. The Dependency Dashboard lists it under **"Pending Status Checks"** with an `approvePr-branch` action, which reads as though a branch already exists. Nothing logs an error at `info`. Three things made this hard to see: - "Pending Status Checks" implies external CI. With `prCreation` at its `immediate` default the section can **only** mean an unmet *internal* check. - The internal-checks gate runs **before** PR-limit accounting, so a held update never reaches `prHourlyLimit` and never appears under "Rate-Limited". Two updates rate-limited and seven pending were two separate gates, not one phenomenon. - Release age being satisfied proves nothing. Renovate never compares ages when the timestamp is absent, so checking the registry's own dates and finding them old is not evidence the update will ever be offered. ## Measured On `bitborg-infra`, 2026-08-17, seven image updates were held this way: | Update | Registry release age | | --- | --- | | `codeberg.org/forgejo/forgejo` 16.0.2-rootless | 18.2 d | | `docker.io/grafana/loki` 3.7.6 | 12.2 d | | `docker.io/victoriametrics/victoria-metrics` v1.149.0 | 17.4 d | | `docker.io/victoriametrics/vmagent` v1.149.0 | 17.4 d | | `docker.io/victoriametrics/vmalert` v1.149.0 | 17.4 d | | `docker.io/library/postgres` 17.11-trixie | 4.1 d | | `quay.io/prometheus/alertmanager` v0.34.0 | 1.2 d | Every one satisfies the 3-day quarantine except `alertmanager`, and that one is held for the same reason as the rest, not for its age. `docker.io/grafana/alloy` opened a PR in the same run from the **same defaults file** as the held `vmagent`, which is what rules out the manager, the file, the datasource and the update type. Renovate names the cause itself at `debug`: ``` DEBUG: Marking 1 release(s) as pending, as they do not have a releaseTimestamp and we're running with minimumReleaseAgeBehaviour=timestamp-required "depName": "codeberg.org/forgejo/forgejo" "versions": ["16.0.2-rootless"] "check": "minimumReleaseAge" ``` ## The change One `packageRule`, scoped to `matchDatasources: ["docker"]`. Datasources that do supply timestamps keep failing closed, so the quarantine still applies wherever it can actually be evaluated. The trade-off is deliberate and worth stating plainly: for images whose timestamp never arrives, the 3-day supply-chain quarantine stops applying. It was not protecting those images before, it was permanently blocking them, which is the worse of the two failures for the git server and the database. Image-tag bumps are never automerged, so a human still reviews every one. The bypass is also not silent: Renovate logs a WARN at `info` naming the releases it proceeded on, so a skipped quarantine is visible in the logs without raising the log level. ## Verified Reproduced with `platform=local`, `RENOVATE_DRY_RUN=full` and `LOG_LEVEL=debug` on renovate **43.288.0**, the version production runs. No production access, no token, no Ansible apply. - Before: **8** `Marking N release(s) as pending ... timestamp-required` decisions, naming exactly the seven dashboard entries and nothing else. - After (scoped rule): **0** holds, and branch intents for all seven, plus the dashboard-approval gated `postgres` major. - `renovate-config-validator` accepts the option inside `packageRules`, and **rejects** a deliberately typo'd option name, so that check was shown able to fail. - `pnpm format:check` and `pnpm mdlint` clean. **Reviewer note:** the validator checks option *names* but **not** enum *values*. A bogus `minimumReleaseAgeBehaviour: "totally-bogus-value"` passes it with `Config validated successfully`. The behavioural run above is what proves the value is honoured. ## Deployment None needed. Renovate resolves this preset from `main` at run time, so merging is the whole deployment and it takes effect on the next run. The debug-logging apply planned in bitborg/bitborg-infra#430 is no longer required. Refs bitborg/bitborg-infra#430, bitborg/bitborg-infra#332
supernaut lade till 1 incheckning 2026-08-18 05:07:22 +00:00
fix(renovate): stop the docker datasource stalling in Pending Status Checks
Alla kontroller lyckades
ci / ci (pull_request) Successful in 12s
bcca7f296b
`minimumReleaseAgeBehaviour` defaults to `timestamp-required`. Renovate's docker datasource often
returns no `releaseTimestamp`, and a check that needs a timestamp can never pass without one, so the
update is deferred on every run and the branch is never created. The Dependency Dashboard lists it
under "Pending Status Checks" with an `approvePr-branch` action, which reads as though a branch
already exists. Nothing logs an error at `info`.

Measured on bitborg-infra 2026-08-17: seven image updates held this way, including the git server
(16.0.2, released 18 days earlier) and the database. Release age was satisfied for all seven by the
registries' own dates. Renovate never compares ages when the timestamp is absent, so "the quarantine
is satisfied" was not evidence the update would ever be offered.

Scoped to the docker datasource. Datasources that do supply timestamps keep failing closed, so the
quarantine still applies wherever it can be evaluated. The bypass is not silent: Renovate logs a
WARN at `info` naming the releases it proceeded on.

Verified by reproducing the decision with `platform=local`, `dry-run=full` and `LOG_LEVEL=debug` on
renovate 43.288.0, the version production runs:

- before: 8 `Marking N release(s) as pending ... minimumReleaseAgeBehaviour=timestamp-required`
- after: 0 holds, and branch intents for all seven held updates
- `renovate-config-validator` accepts the option name, and rejects a deliberately typo'd one

Note for reviewers: the validator checks option names but NOT enum values, so a bogus value passes
it silently. The behavioural run above is what proves the value is honoured.

Refs bitborg/bitborg-infra#430, bitborg/bitborg-infra#332
supernaut sammanfogade incheckning a11e0dd0c5 till main 2026-08-18 09:04:03 +00:00
supernaut tog bort grenen fix/renovate-docker-release-timestamp 2026-08-18 09:04:03 +00:00
Logga in för att delta i denna konversation.
Inga granskare
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-docs!91
Ingen beskrivning angiven.