Skip to content

ADR-0033: Consolidate dependency automation on Renovate

Field Value
Status Accepted
Date 2026-06-14
Authors Roman Mednitzer

Context

Two bots were raising dependency PRs against this repository. Renovate ran from a bare renovate.json (extends: ["config:recommended"]) and GitHub's repo-level Dependabot security updates raised their own PRs for the same advisories. There was no .github/dependabot.yml — Dependabot version updates were never configured — so the overlap was confined to security updates, but it was real: the cryptography v46 advisory produced a duplicate pair (Renovate #55 and Dependabot #54) for one fix.

The bare Renovate config also did not maintain the uv-compiled, hashed requirements-dev.txt lock the way this repository needs. The lock's autogenerated header recorded the short -o output flag, which Renovate's pip-compile manager option allowlist rejects, so Renovate skipped the lock; #55's bump landed incomplete in the dev extra and needed the #57 follow-up. Separately, the container-image build work (ADR-0032) added a Dockerfile with a digest-pinned base image, a new ecosystem that should be kept current by the same single tool.

The rest of the fleet standardised on a single dependency-automation tool. This repository was the lone two-bot configuration for security updates and carried an unconfigured Renovate.

Decision

  1. Renovate is the single dependency-automation tool. renovate.json is replaced by a curated renovate.json5 extending config:best-practices, with semantic commits, the Europe/Vienna timezone, a dependencies label, and rmednitzer as reviewer. enabledManagers is restricted to the three ecosystems in use: github-actions, dockerfile, and pip-compile. The list is load-bearing — a manager that overlapped a re-introduced dependabot.yml would resurrect duplicate PRs.

  2. The hashed-lock invariant is preserved and made Renovate-maintainable. requirements-dev.txt is a uv pip compile pyproject.toml --extra dev --generate-hashes --universal lock. Its header is normalised from the short -o to the long-form --output-file requirements-dev.txt, because Renovate's uv option allowlist rejects -o and would otherwise skip the lock. Renovate's pip-compile manager replays the recorded command, regenerating a universal, fully-hashed lock on each update. A make lock target records the canonical command so local regenerations keep the long form. The locked pins and hashes are unchanged by this ADR. pip-compile updates require uv in the Renovate runtime (present in the Mend-hosted app; ensure it on any self-hosted runner).

  3. Action and base-image digest pinning are preserved. pinDigests: true with config:best-practices keeps GitHub Actions and the Dockerfile base image digest-pinned (ADR-0032's posture, maintained by Renovate). Minor/patch/digest action updates are grouped, majors stay individual; Actions are scheduled Monday, the Dockerfile and the pip lock Wednesday (Europe/Vienna).

  4. Dependabot security updates are turned off; alerts stay on. GitHub's repo-level Dependabot security updates (the auto-PRs) are disabled, ending the duplicate security PRs. Dependabot vulnerability alerts (detection, surfaced in the Security tab) remain enabled: Renovate reads them and raises the fix PRs through its own vulnerability handling, so security coverage is unchanged and single-sourced.

Consequences

Positive

  • One tool, one config (renovate.json5), one PR-author identity for version and security updates across Actions, the Dockerfile, and the Python lock. The #54/#55-class duplicate is removed at the source.
  • The dev lock is maintained by Renovate with the hash-regeneration discipline the repository already documents, rather than by a second bot — and the -o skip that left #55 incomplete is fixed.
  • The dependency-automation story matches the rest of the fleet.

Negative / accepted trade-offs

  • Renovate's pip-compile manager depends on uv in the runtime; a self-hosted Renovate without uv would silently stop maintaining the lock. Mitigation: documented here, in renovate.json5, and in the make lock target; the Mend-hosted app ships uv.
  • Security-fix PRs now come only from Renovate. The GitHub-native Dependabot security update path is no longer a redundant second source; the Dependabot alert feed is kept, so detection is unchanged and only the duplicate PR creation is removed.

Neutral

  • The repository's own image (deploy/helm/praxis/values.yaml) is set at deploy time, not a third-party dependency, so no helm-values manager is enabled; the Dockerfile base image it builds from is covered by the dockerfile manager.

Alternatives considered and rejected

  • Keep both bots (mirror only the version-update retirement). Rejected: it leaves the security-update overlap that produced #54/#55 in place.
  • Disable Renovate's vulnerability handling and keep Dependabot for security. Rejected: it splits the automation across two tools and two configs again — the cost this ADR removes — when Renovate already maintains the lock and can raise the security PR.
  • Leave Renovate on the bare config:recommended. Rejected: it skips the -o lock (the #55/#57 cause) and carries none of the grouping, scheduling, labelling, or digest discipline the rest of the fleet uses.

Revisit triggers

  • A new ecosystem enters the repository (e.g. a runtime lock or Helm chart dependencies): add the matching Renovate manager rather than a second bot.
  • Renovate's uv/pip-compile option allowlist changes such that the recorded command form must change again.
  • A published ghcr.io/rmednitzer/praxis image with a tracked digest would justify a scoped helm-values manager.