Rust: Crates und Continuous Integration – eine perfekte Mischung

Seite 3: Format-Check automatisieren

Inhaltsverzeichnis

Das Formatieren von Code, um einen einheitlich lesbaren Text zu erhalten, ist meistens eine langweilige, weil rein mechanische Aufgabe, die sowohl Zeit als auch geistige Anstrengung erfordert. Es ist dennoch sinnvoll, da es das Begutachten von Code erleichtert und beschleunigt. Automatische Formatierungswerkzeuge entlasten Entwicklerinnen und Entwickler von dieser Aufgabe, sodass sie sich auf wichtigere Aufgaben konzentrieren können.

Rust bietet Formatierungswerkzeuge wie cargo fmt, die den Prozess vereinfachen. Das Tool formatiert Sourcecode automatisch nach den gültigen Coding Guidelines. Rust definiert zwar einen eigenen Coding Style, der sich aber über die Konfigurationsdatei .rustfmt.toml an die Bedürfnisse des Projekts anpassen lässt. Durch Einfügen von hard_tabs = true lässt sich beispielsweise das Verwenden von Tabs anstelle von Leerzeichen erzwingen.

Da jede Formatänderungen auf ihre Übereinstimmung mit den Coding Style Guidelines von Rust zu überprüfen ist, empfiehlt sich auch dafür automatisiertes Vorgehen über CI. Bei Missachtung der Guidelines unterbricht das System den Prozess dann mit einer Fehlermeldung. Bei GitHub Actions sind dazu in der Konfigurationsdatei der CI folgende Zeilen zu ergänzen:

      - uses: actions-rs/cargo@v1
        with:
          command: fmt
          args: --all -- --check

Ein weiteres wichtiges Testkriterium kann die Performance beziehungsweise die vom Code verursachte CPU-Last sein. Um sie zu überwachen, bietet Rust verschiedene Möglichkeiten, Performancetests für Funktionen eines Crate zu schreiben. Eine der bekanntesten ist Criterion.rs. Ein einfaches anschauliches Beispiel für einen Benchmark findet sich auf GitHub.

Läuft der Benchmark beispielsweise mit dem aktuellen master-Branch und einem anschließenden Pull Request, zeigt Criterion an, ob der Pull Request die Performance der Crates verändert. Leider ist das Ausführen von Benchmarks mit Hilfe von GitHub Actions nicht ohne weiteres möglich, da die Performance stark von der verwendeten Hardware abhängt, auf der die Benchmarks laufen. Auch andere Aufgaben, die parallel zum Benchmark auf der Hardware laufen, haben Einfluss auf die Performance. Es ist bei GitHub aber möglich, sogenannte Runner einzufügen und sie für das Ausführen der Benchmarks zu nutzen.

Obwohl sich Rust als sichere Programmiersprache empfiehlt, finden sich auch bei in Rust geschriebener Software sicherheitsrelevante Fehler. Um zu prüfen, ob für die verwendeten Crates bekannte Fehler existieren, lässt sich mit dem Tool cargo-audit die RustSec Advisory Database abfragen. Ein solcher Check ist immer dann sinnvoll, sobald es Änderungen der Abhängigkeiten (in der Datei Cargo.toml) gegeben hat. Darüber hinaus ist es empfehlenswert, diese Sicherheitstests regelmäßig zu wiederholen, da in die RustSec Advisory Database kontinuierlich Aktualisierungen einfließen. Die folgende Action führt cargo-audit bei jeder Änderung an einer Cargo-Konfigurationsdatei sowie regelmäßig alle 24 Stunden aus. Erkannte Fehler lösen automatisch einen Issue auf GitHub aus (vgl. Beispiel).

name: Security audit
on:
  push:
    paths:
      - '**/Cargo.toml'
      - '**/Cargo.lock'
  schedule:
    - cron: '0 0 * * *'

jobs:
  security_audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - uses: actions-rs/audit-check@v1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

In der Datei Cargo.toml finden sich alle Abhängigkeiten des eigenes Crate mit Namen und Versionsnummer. Sollte es ein Update eines anderen Crate geben, von dem das eigene abhängt, empfiehlt es sich in der Regel, die Versionsnummer in der Cargo-Konfiguration anzupassen. Nicht immer erfahren Entwickler aber direkt, wenn es Updates der Abhängigkeiten gegeben hat. In solchen Fällen hilft der sogenannte Dependabot. Diese von GitHub gekaufte Software überprüft regelmäßig, ob neuere Versionen der Abhängigkeiten vorliegen und erstellt automatisch einen Pull Request, der die Cargo-Konfiguration aktualisiert. Ist die CI wie oben beschrieben konfiguriert, löst sie daraufhin automatisiert das Kompilieren und Testen des Crate auf allen relevanten Systemen aus.