Abhängigkeiten bändigen – Wie Bots dabei helfen können

In der Softwareentwicklung gibt es viele verschiedene Abhängigkeiten – auf vielen verschiedenen Ebenen. In diesem Artikel soll es darum gehen, wie mit geringem Aufwand die Versionen seiner Abhängigkeiten aktuell gehalten werden kann.

Warum sollte ich meine Abhängigkeiten überhaupt aktuell halten?

“Never touch a running System” lautet doch die Devise, oder nicht? Vor 30 Jahren, als Systeme noch kaum vernetzt waren, mag der Spruch vielleicht noch sinnvoll gewesen sein. Heutzutage ist es eher fahrlässig sich daran zu orientieren.

  • Security / Vulnerability: Aktualisiere ich meine Abhängigkeiten nicht kontinuierlich, erhöht sich Tag für Tag die Wahrscheinlichkeit, dass eine aktuell bereits geschlossene Sicherheitslücken in meiner alten Software weiterhin existiert. Kommt es deswegen zu einer Datenpanne, ist das nicht nur ein Imageschaden, sondern kann schnell auch an die Substanz eines Unternehmens gehen: DSGVO Bußgelder bis zu 20 Millionen Euro oder aber bis 4 Prozent des weltweiten Jahresumsatzes.
  • Viele kleine Schritte sind einfacher als wenige große: Früher oder später werde ich dazu gezwungen, Versionen zu aktualisieren. Sei es, weil ich ein neues Feature einer Library brauche oder eine neue Library einführen muss, die aus Kompatibilitätsgründen nicht mehr mit meinen alten Versionen funktioniert. In so einem Fall muss ich unter Umständen große Versionssprünge, vielleicht über mehrere Major-Versionen, machen. Das kann die Umsetzung eines Features extrem verzögern, da solche Aktualisierungen meist schwierig sind und oft Aktualisierungen vieler anderer Abhängigkeiten erfordern, also eine ganze Kaskade auslösen können.

Tooling

Wie der Titel schon verraten hat, gibt es Tools in Form von Bots, die uns dabei helfen können, unsere Abhängigkeiten komfortabel und mit geringem Aufwand aktuell zu halten.

Dafür gibt es aber wichtige Voraussetzungen:

  1. Man braucht automatisierte Tests, am besten auf allen Ebenen: Unit, Integration und End-To-End
  2. Eine Verlässliche CI/CD Pipeline

Wie aber funktionieren diese Bots?

Prinzipiell sehr einfach. Die Bots integrieren sich in das Source Code Management System wie GitHub oder GitLab und können ein Source Repository scannen. Wird eine veraltete Abhängigkeit entdeckt, erstellen sie einen Pull Request mit der neuen Version. Jetzt kommen die CI/CD Pipeline und die automatisierten Tests ins Spiel: Durch den Commit mit der aktualisierten Version und/oder durch das Erstellen des Pull Requests muss jetzt die CI/CD Pipeline loslaufen und die automatisierten Tests ausführen.

Jetzt hat man einen fertigen Pull Request mit der aktuellen Version, welcher durch die CI/CD Pipeline mit ihren automatisierten Tests Qualitätsgesichert ist. Was nun mit dem Pull Request gemacht wird, ist einem selbst überlassen. Im besten Fall wird der Pull Request automatisch gemerged, wenn die Pipeline erfolgreich war.

Battle of the Bots – Welche Bots sind für den produktiven Einsatz empfehlenswert?

Dependabot

Dependabot creates pull requests to keep your dependencies secure and up-to-date.

Dependabot ist vermutlich der bekannteste unter seiner Art. Er ist 2017 angetreten und wurde 2019 von GitHub übernommen und ist tief in GitHub integriert. Er hat also mit GitHub und Microsoft einen starken Partner hinter sich. Mittlerweile wurde in GitHub auf basis von Dependabot auch ein Sicherheits-Feature eingebaut, dass den Besitzer eines Repositories unter security/dependabot bzw. über entsprechende Mails über Sicherheitslücken informiert.

Dependabot kann aber auch außerhalb von GitHub eingesetzt werden. Dies ist im dependabot-script Projekt beschrieben, Beispielsweise für GitLab. Hier müssen leider einige Abstriche in der Integration und bei den Features hingenommen werden.

Die Integration in ein selbst gehostetes GitLab ist nicht kompliziert. Dependabot ist ein eigenes Repository in GitLab, dort wird er als Scheduled Pipeline betrieben. Pro Repository, das er scannen soll, wird jeweils ein Scheduled-Job angelegt, der als Parameter das zu scannende Repository und den Package Manager wie Maven, Gradle oder npm, enthält. Damit Dependabot die GitLab API ansprechen kann, muss in den GitLab CI/CD Einstellungen noch eine Umgebungsvariable mit einem GitLab Access Token hinterlegt werden. Im besten Fall gehört das Token einem dedizierten GitLab Nutzer, welcher z. B. Dependabot heist. Weitere Details zur GitLab Integration siehe [4] und [5]

Weitere Informationen

Renovate

Save time and reduce risk by automating dependency updates in software projects. Fully customizable with a setting to suit every workflow

Renovate ist ein erstklassiker OpenSource Bot, der von der Firma WhiteSource entwickelt wird. Er ist der Underdog, da er nicht so einen großen Partner hinter sich hat bzw. nicht so große Aufmerksamkeit erfährt. Er muss sich aber keineswegs hinter Dependabot verstecken. Renovate hat mehr als doppelt so viele Sterne auf GitHub und verrichtet seinen Dienst mindestens genauso gut, wenn nicht sogar besser.

Da Renovate nicht so nahe an einer bestimmten Plattform ist wie Dependabot, gibt es auch eine breitere Integration in andere Plattformen wie GitLab.com oder Azure DevOps.

Die Integration in ein selbst gehostetes GitLab läuft prinzipiell genau wie bei Dependabot. Allerdings muss bei Renovate etwas mehr Zeit in die Konfiguration und die dazugehörige Dokumentation investiert werden – dafür kann man Renovate aber auch individueller an seine Bedürfnisse anpassen. Weitere Details zur GitLab Integration siehe [8].

Weitere Informationen

Dependabot vs. Renovate

Hier ein kleiner Vergleich, der aber keinen Anspruch auf Vollständigkeit erhebt:

Dependabot Renovate
Unterstützte Package Manager o (15) ++ (59)
Konfigurierbarkeit o ++
GitHub Integration ++ +
GitLab Integration + +
Kosten / Preis keine keine
Lizens Prosperity Public License 2.0.0 AGPL-3.0

Und welchen Bot soll ich jetzt nehmen?

Wie so oft lautet die Antwort: “Es kommt darauf an.”

Beide erledigen ihre Aufgabe gut und unterstützen die meisten gängigen Package Manager. Es lohnt sich aber einen Blick in die unterstützen Package Manager zu werfen. Renovate hat dort deutlich die Nase vor Dependabot.

Auf GitHub würde ich Dependabot bevorzugen, außer man verwendet einen Package Manager, welcher von Dependabot nicht, oder nicht zufriedenstellend, unterstützt wird.

Auf anderen Plattformen wie GitLab.com oder Azure DevOps lässt sich Renovate leichter integrieren und ist dann dort vermutlich die bessere Wahl. Ebenso wenn der Bot individuell angepasst werden soll.

Am besten man probiert beide aus und entscheidet dann.

Wie verwenden wir bei Proxora die Bots?

Wir haben Dependabot vor ca. einem Jahr in unser selbst betriebenes GitLab integriert. Er ist bei einem mittelgroßen und drei kleineren Repositories aktiv. Wir haben insgesamt gute Erfahrungen damit gemacht. Aber leider unterstützt Dependabot keine Gradle Projekte mit Kotlin DSL, daher musste unser großes Haupt-Repository (Monorepo) außen vor bleiben. Seit etwa zwei Monaten ist nun auch Renovate aktiv, da er mit unserem Haupt-Repository bzw. Gradle mit Kotlin DSL gut funktioniert. Auch die fein granulare Konfigurierbarkeit ist ein großer Vorteil für uns gegenüber Dependabot. Daher wird Dependabot mittelfristig bei uns verschwinden und durch Renovate ersetzt.

Aktuell aktualisiert Renovate bei uns wöchentlich Abhängigkeiten in vier Repositories mit diesen Package Managern:

  • Gradle (Groovy/Kotlin DSL)
  • Gradle Wrapper
  • Maven
  • GitLab Pipeline Images

Über eine im Repository abgelegte renovate.json können wir sehr feingranular Renovate sagen, was er machen soll, beispielsweise:

  • Wenn für Abhängigkeit X die Minor- oder Patch-Version erhöht wurde, dann merge automatisch bei erfolgreicher Pipeline.
  • Ignoriere Abhängigkeiten, wenn sie einem bestimmten regulären Ausdruck entsprechen.
  • Gruppiere Abhängigkeiten zu einem Pull Request, wenn sie einem bestimmten regulären Ausdruck entsprechen, z.B. für org.testcontainers.

So können wir Abhängigkeiten, die durch unsere Pipeline bzw. Tests gut abgedeckt sind, guten Gewissens automatisch aktualisieren lassen. Die übrigen Abhängigkeiten werden im Pull Request derzeit manuell begutachtet und wenn möglich durch Tests abgesichert und zu der Auto-Merge Liste hinzugefügt.

Was wollen wir zukünftig damit noch alles machen?

Renovate ist für uns noch nicht ausgereizt. Zukünftig soll er uns auch mit unseren JavaScript (npm), Docker und Infrastructure-as-code (Terraform-Module, Helm Charts und Helmfile) Abhängigkeiten helfen. Und natürlich soll die Liste der automatisch mergebaren Abhängigkeiten kontinuierlich vergrößert werden.

So bleiben wir mit wenig Aufwand auf dem aktuellen Stand, verringern die Anfälligkeit für Sicherheitslücken und halten unsere Software langfristig wartbar!