Zum Inhalt

Renovate for Automated Dependency Updates

Einordnung ins Overtime-Projekt

Die Overtime-Codebasis hat mehrere Abhängigkeits-Oberflächen – Python-Pakete, Container-Base-Images und in CI-Pipelines gepinnte Tool-Versionen. Dieses ADR beschreibt, wie Renovate diese automatisiert aktuell hält, ohne dass Updates unbeobachtet einfließen.


1. Kontext & Problemstellung (Deutsch)

Das fiktive B2B-Kollaborations-Projekt Overtime basiert auf einem Python/Django-Backend und verschiedenen Microservices, die in gehärteten K3s-Clustern betrieben werden. Die Plattform hat drei unterschiedliche Abhängigkeits-Oberflächen, die regelmäßig aktualisiert werden müssen:

  1. Python-Pakete – definiert in pyproject.toml bzw. uv.lock (z. B. Django, Gunicorn, structlog).
  2. Container-Base-Images – definiert über ARG-Direktiven in den Dockerfiles (z. B. [registry.suse.com/bci/python:3.14-micro](https://registry.suse.com/bci/python:3.14-micro)).
  3. CI-Tool-Versionen – inline gepinnt in den YAML-Dateien der Pipelines (z. B. Trivy, Buildah, Semgrep, uv, Kustomize).

Ohne Automatisierung veralten diese Abhängigkeiten unbemerkt ("Configuration Drift"). Eine einzelne, nicht gepatchte Abhängigkeit ist eine häufige Ursache für Supply-Chain-Vorfälle. Manuelle Update-Zyklen über mehrere Repositories hinweg sind zudem langsam und fehleranfällig.


2. Architecture Decision Record (English)

ADR-007: Renovate for Automated Dependency Updates

Status

Accepted

Context and Problem Statement

The stack relies on three distinct dependency surfaces that require regular updates: Python packages, container base images, and CI tool versions. Without automation, these drift silently, and manual update rounds are slow and error-prone across multiple repositories. A reliable system is needed to track and remediate vulnerabilities in a timely manner.

Decision Drivers

  • Observability: Updates must be proposed as Merge Requests (MRs) so they are observable and reviewable, rather than being silently applied.
  • Urgency for Vulnerabilities: Vulnerability-flagged updates must arrive immediately (0-day stability wait).
  • Controlled Automation: Major version bumps (e.g., Django, Python) require human review, while minor and patch updates can automerge if CI tests pass.
  • Custom Parsing: CI tool version pins reside in non-standard YAML variables, requiring custom regex manager support.

Considered Options

  • Dependabot — Native GitHub integration, but lacks cross-repo configuration sharing and has limited support for custom package managers.
  • Manual update process — Ad-hoc, lacks an audit trail, and is highly unreliable at scale.
  • Renovate — Highly configurable, natively supports regex custom managers, is self-hostable, and provides strong GitLab support.

Decision Outcome

Chosen: Renovate. Renovate seemed the most configurable and versatile. I implement Renovate using specific renovate.json configurations per repository. The configuration extends standard best practices and explicitly pins Docker digests (config:best-practices, docker:pinDigests). Renovate also created a nice dashboard in the repositories where one can see the state of things.

I did not check Dependabot in depth so it might be a viable option especially if on GitHub, where it has native integration.

Consequences & Trade-offs

Positive Consequences
  • Automated Quality Gating: Every dependency update generates an MR accompanied by a CI pipeline run, ensuring no change is applied without tests passing.
  • Rapid Security Patching: Vulnerability patches arrive within hours (0-day stability) and automerge once CI passes.
  • Cooldown Periods Many Supply-Chain attacks were discovered within the first week, so I want to introduce a cooldown period for non-critical updates. See this Datadog blog post for more info.
  • Supply Chain Hardening: The docker:pinDigests preset locks Docker images to SHA-256 digests in addition to tags, preventing malicious tag mutation attacks.
Negative Consequences / Trade-offs
  • Token Management: Renovate requires a GitLab token with API and write permissions to repositories, which introduces a secret that must be securely rotated.
  • Immediate Downstream Impact: Because Renovate acts on the overtime-ci-templates repository, automerged changes to CI templates immediately affect all consuming service pipelines. This mandates highly reliable CI tests in the template repository.

3. Pipeline Implementation & Code Snippet (English)

The implementation consists of two parts: the CI runner job executing Renovate (housed in the central templates repository) and the specific renovate.json rules defined in the downstream service (e.g., the Django backend).

CI/CD Pipeline Template (.gitlab-ci.yml)

The following job definition resides in overtime-ci-templates/.gitlab-ci.yml. It ensures Renovate runs securely within an ephemeral container via schedule or manual web triggers.

renovate:
  stage: renovate
  image: renovate/renovate:42@sha256:55257c9f54eff5382abacb0a119ba2357566cb01cdbf0a35f152e24729ab8e64
  variables:
    LOG_LEVEL: info
    RENOVATE_CONFIG_FILE: renovate/config.js
    # Required CI/CD variables (set in GitLab project Settings → CI/CD → Variables):
    #   RENOVATE_TOKEN  — GitLab token with api + write_repository scopes
    #   GITHUB_COM_TOKEN — GitHub PAT (read-only) to avoid rate limits on changelog fetching
  script:
    - renovate
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
    - if: '$CI_PIPELINE_SOURCE == "web"'

Dependency Configuration (renovate.json)

The following configuration is deployed in /overtime-django-backend/renovate.json. It translates the decision drivers into actionable rules: pinning digests, automerging minor/patch updates, and strictly requiring human approval for major upgrades.

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:best-practices",
    "docker:pinDigests"
  ],
  "minimumReleaseAge": "14 days",
  "vulnerabilityAlerts": {
    "enabled": true,
    "minimumReleaseAge": null,
    "automerge": true
  },
  "packageRules": [
    {
      "description": "DHI images maintain exact semantic versioning rules",
      "matchPackageNames": [
        "dhi.io/**"
      ],
      "versioning": "docker"
    },
    {
      "description": "Automerge minor and patch updates for app code & base images",
      "matchUpdateTypes": [
        "minor",
        "patch"
      ],
      "automerge": true,
      "automergeType": "branch"
    },
    {
      "description": "Strictly require manual review for major updates (e.g. Django/Python upgrades)",
      "matchUpdateTypes": [
        "major"
      ],
      "automerge": false
    },
    {
      "description": "Never pin digests for the CI templates repo, rely on tags.",
      "matchPackageNames": [
        "alexb-overtime/overtime-ci-templates"
      ],
      "pinDigests": false
    }
  ]
}

4. Compliance Einordnung (Deutsch)

Das detaillierte Mapping auf BSI IT-Grundschutz, CRA und CIS Benchmarks wird in später ergänzt.