Zum Inhalt springen

CodeCharter in GitHub-Actions-Workflows ausführen

CodeCharter in Ihrem GitHub-Workflow mit der offiziellen Action bochmann-software/codecharter.

Die offizielle Action bochmann-software/codecharter@v1 ist der schnellste Weg, CodeCharter in einen GitHub-Workflow einzubinden. Sie kümmert sich um den CLI-Download, das Caching und das Veröffentlichen der Findings als PR-Annotations.

Empfohlen: Installieren Sie zusätzlich die CodeCharter GitHub App. Die Action veröffentlicht dann einen gebrandeten CodeCharter-Check-Run und PR-Kommentar über die App, ohne pull-requests: write und ohne GitHub-Token auf dem Runner. Ohne die App läuft die Action weiter und fällt auf einen Workflow-Token-Kommentar zurück.

Minimal-Setup

.github/workflows/codecharter.yml:

name: CodeCharter

on:
  pull_request:
  push:
    branches: [main]

jobs:
  analyze:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '9.0.x'
      - uses: bochmann-software/codecharter@v1
        with:
          solution: Acme.Web.sln
          api-key: ${{ secrets.CODECHARTER_API_KEY }}

Fertig. Findings tauchen automatisch im PR als Inline-Annotations auf.

API-Key beschaffen

  1. Im Portal unter API Keys einen Key erzeugen.
  2. Im GitHub-Repo unter Settings → Secrets → Actions als CODECHARTER_API_KEY hinterlegen.

Die Action liest den Key, authentifiziert gegen das Portal und lädt die über den version-Input gewählte CLI-Version (Standard latest).

Ausführungsmodell

Die Action führt die CLI nativ auf dem Runner aus. Sie nutzt kein Docker und zieht kein Container-Image. Bei jedem Lauf passiert Folgendes:

  1. Sie lädt das self-contained CLI-Archiv für die Plattform des Runners (win-x64, linux-x64, osx-x64, osx-arm64) aus dem Portal, authentifiziert mit dem API-Key.
  2. Sie prüft das Archiv gegen die vom Portal mitgelieferte SHA-256-Prüfsumme.
  3. Sie führt die CLI direkt auf Ihrer ausgecheckten Solution aus.

Das heruntergeladene Binary wird zwischen den Runs gecached (siehe Caching). Da kein Container im Spiel ist, funktionieren Linux-x64-, Windows-x64- und macOS-Runner (x64 und arm64) gleichermaßen, GitHub-hosted wie self-hosted. Andere Plattformen (etwa Linux arm64) schlagen mit einer expliziten Fehlermeldung fehl.

Inputs

Input Default Beschreibung
api-key Pflicht. API-Key aus dem Portal.
solution erste .sln / .slnx Welche Solution analysiert wird. Ohne Angabe nimmt die Action die erste gefundene .sln/.slnx (alphabetisch sortiert). Wird keine gefunden, bricht sie mit einem Fehler ab; bei mehreren Treffern gibt sie eine Warnung aus.
fail-on error Schwelle für Build-Fehler (info, warn, error, never). warning wird ebenfalls als Synonym für warn akzeptiert.
severity-threshold info Minimale Severity, die gemeldet und annotiert wird (info, warn, error).
rules (leer) Pfad zu einem Regelverzeichnis in Ihrem Repository (z. B. .codecharter/rules). Leer lassen, um die eingebauten Standardregeln zu verwenden.
diff false Beschränkt auf Pull-Requests sowohl die gemeldeten Findings als auch die fail-on-Schwelle auf die im PR geänderten Zeilen. Der Base-Commit des PR muss auf dem Runner erreichbar sein; verwenden Sie actions/checkout mit fetch-depth: 0. Hat außerhalb von pull_request-Events keine Wirkung.
version latest Welche CLI-Version heruntergeladen wird. Empfehlung: pinnen. Gültige Werte: latest, v1, v1.4 oder ein exakter Pin wie v1.4.2.
sarif-output Wenn gesetzt, wird zusätzlich SARIF in diese Datei geschrieben.
cache true Das heruntergeladene CLI-Binary zwischen Workflow-Runs cachen.
portal-base-url Überschreibt den Portal-Endpunkt, etwa für ein selbst gehostetes oder Staging-Portal. Standard ist das öffentliche Portal.
require-rules false Schlägt fehl statt stillschweigend gebündelte Beispielregeln zu verwenden, wenn kein Regelverzeichnis vorhanden ist.
baseline Pfad zu einer Baseline-Datei; nur Findings, die darin nicht enthalten sind, schlagen den Build fehl. Baseline generieren mit dem CLI-Flag --write-baseline.
telemetry false Opt-in für ein Nutzungsereignis. Es enthält aggregierte Finding-Zähler pro Regel (Regel-ID, Severity, Anzahl) sowie Ihre Konto- und Installations-Kennung. Kein Quellcode, keine Dateipfade, keine Fundstellen werden übermittelt.
badge false Meldet Coverage, Findings und Testzahlen des Laufs an das Portal, damit es README-Badges für dieses Repository ausliefern kann. Gespeichert werden nur Läufe auf dem Standardbranch, und öffentlich ausgeliefert wird nichts, solange Sie die Veröffentlichung im Portal nicht einschalten. Siehe Badges.
comment true Fixierten PR-Zusammenfassungskommentar veröffentlichen oder aktualisieren. Benötigt permissions: pull-requests: write, wenn die CodeCharter-App nicht installiert ist.
comment-key Unterscheidungsstring, damit mehrere CodeCharter-Schritte in einem Workflow getrennte Kommentare führen.
github-token ${{ github.token }} Token für die Veröffentlichung des PR-Kommentars.

Outputs

Output Beschreibung
findings-total Gesamtzahl Findings
findings-error Anzahl error-Findings
findings-warn Anzahl warn-Findings
findings-info Anzahl info-Findings
sarif-path Pfad zur SARIF-Datei, falls erzeugt

Badges

Das Portal kann Badges zu Coverage, Findings und Tests für ein Repository ausliefern und rendert die Bilder selbst. Ihre README hängt damit an keinem fremden Badge-Dienst.

  1. Setzen Sie badge: 'true' an der Action. Läufe auf dem Standardbranch melden ihre Zahlen dann an das Portal, Läufe auf anderen Branches melden nichts.
  2. Öffnen Sie im Portal die Seite GitHub App. Dort steht jedes Repository, das Badge-Daten gemeldet hat, mit einem Schalter Badges veröffentlichen.
  3. Schalten Sie ihn ein. Das Portal erzeugt einen nicht erratbaren Token für dieses Repository und zeigt das fertige Markdown für alle drei Badges.
- uses: bochmann-software/codecharter@v1
  with:
    api-key: ${{ secrets.CODECHARTER_API_KEY }}
    badge: 'true'
![coverage](https://codecharter.tools/badge/<token>/coverage.svg)
![codecharter](https://codecharter.tools/badge/<token>/findings.svg)
![tests](https://codecharter.tools/badge/<token>/tests.svg)

Warum ein Token und nicht /badge/owner/repo.svg? GitHub lädt Bilder in einer README über den eigenen Camo-Bildproxy. Der entfernt den Referer-Header und hält eine gemeinsame Kopie für alle Betrachter vor. Eine aus dem Repository-Namen abgeleitete URL wäre deshalb erratbar und würde die Zahlen eines privaten Repositories an jeden herausgeben, der es versucht, ohne dass eine Referrer- oder Cookie-Prüfung das verhindern könnte. Die Veröffentlichung ist deshalb standardmäßig aus, der Token ist der einzige Schlüssel, und wer sie wieder ausschaltet, bekommt auf den URLs erneut 404, während die gespeicherten Zahlen erhalten bleiben.

Ein Badge ohne Daten liefert ebenfalls 404, etwa das Test-Badge, solange kein Lauf Testzahlen gemeldet hat, und das Findings-Badge, solange kein Analyse-Lauf Befundzahlen gemeldet hat. Das Portal zeigt nur die Snippets der Badges an, für die Ihr Repository tatsächlich Zahlen gemeldet hat, damit das kopierte Markdown immer funktioniert.

Coverage-Verlauf

Neben dem aktuellen Wert hält das Portal die Messreihe hinter dem Coverage-Badge fest: jeder Coverage-Lauf auf dem Standardbranch hängt einen Punkt an. Über den Link Coverage-Verlauf an einem Repository auf der Seite GitHub App sehen Sie den aktuellen Wert, die Veränderung gegenüber dem Stand vor 30 Tagen, den Verlauf als Diagramm und die letzten Messungen mit abgedeckten und messbaren Zeilen. Der Verlauf ist nur für Sie sichtbar und hängt nicht an der Badge-Veröffentlichung. Gespeichert bleiben die neuesten 400 Punkte pro Repository, ältere fallen automatisch heraus.

Komplett-Setup: SARIF + Code Scanning

Wenn Sie die Findings im Security-Tab Ihres GitHub-Repos sehen möchten:

- uses: bochmann-software/codecharter@v1
  id: codecharter
  with:
    solution: Acme.Web.sln
    api-key: ${{ secrets.CODECHARTER_API_KEY }}
    sarif-output: codecharter.sarif

- name: Upload SARIF
  if: always()
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: codecharter.sarif

if: always() sorgt dafür, dass der Upload-Schritt auch dann ausgeführt wird, wenn ein vorheriger Schritt fehlgeschlagen ist, zum Beispiel wenn CodeCharter wegen überschrittener fail-on-Schwelle einen Fehler-Exit-Code zurückgibt. Ohne diese Bedingung würde GitHub Actions den Upload überspringen, sobald ein früherer Schritt nicht erfolgreich war.

Matrix-Builds

Wenn Ihre Solution auf mehreren OS gebaut wird, aber CodeCharter deterministisch ist, läuft die Analyse nur einmal:

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - run: dotnet build

  codecharter:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/checkout@v4
      - uses: bochmann-software/codecharter@v1
        with:
          api-key: ${{ secrets.CODECHARTER_API_KEY }}

Self-Hosted Runner

Funktioniert ohne Anpassungen, solange der Runner diese Voraussetzungen erfüllt:

  • Netzwerkzugriff auf codecharter.tools. Die Action lädt die CLI bei jedem Lauf aus dem Portal, und die CLI bezieht bei jedem Lauf mit dem API-Key eine kurzlebige Lizenz vom Portal.
  • Ein .NET-SDK, das Ihre Solution bauen kann. Die Action gibt eine Warnung aus, wenn kein dotnet auf dem Runner gefunden wird.
  • zstd oder gzip im PATH, wenn das CLI-Binary zwischen den Runs gecached werden soll. Fehlt beides, überspringt die Action den Cache mit einer Warnung und lädt die CLI bei jedem Lauf neu; mit cache: 'false' unterdrücken Sie die Warnung.

Auf Runnern ohne Portal-Zugriff installieren Sie das CLI-Binary manuell, hinterlegen Sie eine vollständige codecharter.license und rufen Sie codecharter direkt in einem run:-Step auf, siehe Offline- oder Dauer-Runner.

Versions-Pinning

Empfehlung: die Action auf eine konkrete Minor-Version pinnen und selten upgraden.

- uses: bochmann-software/codecharter@v1   # Major-pinning, kriegt v1.x.y Updates
- uses: bochmann-software/codecharter@v1.4 # Minor-pinning, statisch
- uses: bochmann-software/codecharter@<sha> # SHA-pinning, am konservativsten

Wir folgen SemVer (siehe Versionierung) und brechen innerhalb einer Major-Version keine Verträge.

Caching

Die Action cached automatisch das heruntergeladene CLI-Binary zwischen Workflow-Runs, geschlüsselt nach Runner-Plattform und CLI-Version. Exakte Pins (z. B. v1.4.2) bleiben unbegrenzt im Cache; bewegliche Selektoren (latest, v1, v1.4) werden täglich neu aufgelöst, damit ein Cache-Treffer nicht lange einen veralteten Build liefert. Der Cache umfasst das CLI-Binary; die Analyse selbst läuft bei jedem Aufruf vollständig.

Auf einer mittleren Solution ist ein warmer Run typisch in 5-15 Sekunden durch.

Deaktivieren Sie das Caching manuell, wenn Sie unerklärliche Cache-Effekte debuggen:

- uses: bochmann-software/codecharter@v1
  with:
    cache: 'false'
    api-key: ${{ secrets.CODECHARTER_API_KEY }}

Wenn keine PR-Annotations auftauchen

GitHub zeigt Inline-Annotations in der Ansicht Files changed nur bei Pull-Requests. Bei direkten push-Runs erscheinen die Annotations trotzdem in der Workflow-Run-Zusammenfassung, nur nicht inline im Code. Wenn Sie Inline-PR-Annotations erwarten, stellen Sie sicher, dass der Workflow auf pull_request triggert.

Werden die Ergebnisse über die CodeCharter-App veröffentlicht, zeigt der Check-Run maximal 50 Inline-Annotations pro Run; bei mehr Findings erscheinen nur die ersten 50 als Annotations.

Permissions

Mit installierter CodeCharter GitHub App veröffentlicht die Action die Ergebnisse über die App, und der Workflow braucht nur contents: read.

Ohne die App fällt die Action auf einen Workflow-Token-Kommentar zurück, der zusätzlich pull-requests: write benötigt:

permissions:
  contents: read
  pull-requests: write   # nur ohne die CodeCharter-App nötig

Wenn Sie außerdem SARIF zu GitHub Code Scanning hochladen, kommt security-events: write hinzu:

permissions:
  contents: read
  security-events: write
  pull-requests: write   # nur ohne die CodeCharter-App nötig