Skip to content

Portal-Profile im CI verwenden

Wie Sie .codecharter/config.yml, das Lockfile und die CLI-Befehle restore/update/verify nutzen, um portalverwaltete Profile in Ihrer CI zu betreiben.

Voraussetzung: Diese Seite setzt voraus, dass Sie bereits Profile und Regeln im Portal angelegt haben. Wenn Sie neu einsteigen, finden Sie den Einstieg unter Profile verwalten.

Profile, die Sie im Portal pflegen, gelangen über zwei Dateien in Ihrem Repository in die CI, beide im Verzeichnis .codecharter/: config.yml (was das Projekt referenziert) und codecharter.lock.json (eingefrorene Versionen und Hashes). Die CLI synct, prüft und verifiziert diese Dateien.

Konzept: .codecharter/config.yml und .codecharter/codecharter.lock.json

.codecharter/config.yml deklariert, welche Profile Ihr Projekt nutzt. Die Datei liegt im Verzeichnis .codecharter/ Ihres Repositories und wird gefunden, indem von der analysierten Datei aus nach oben gewandert wird. Jeder Profil-Eintrag ist ein String der Form [org/][email protected] und pinnt eine exakte Version; Plattform-Profile verwenden das Präfix codecharter/:

# .codecharter/config.yml
version: 1
profiles:
  - [email protected]
  - [email protected]
  - codecharter/[email protected]

Dieselbe Datei unterstützt außerdem einen optionalen Schlüssel overrides, mit dem Sie die severity einer Regel (error, warning, info) anpassen, direkt mit dem Regel-Slug als Schlüssel. Um eine Regel ganz abzuschalten, führen Sie sie stattdessen unter ignore auf. Regel-Slugs sind über alle Profile hinweg eindeutig, daher adressieren beide Abschnitte Regeln direkt:

# .codecharter/config.yml
version: 1
overrides:
  no-async-void:
    severity: warning
ignore:
  - rule: long-method

.codecharter/codecharter.lock.json wird von der CLI erzeugt und committed. Es hält die benötigte Engine-Version und das Portal fest, gegen das aufgelöst wurde, und friert jedes Profil auf eine konkrete Version, einen SHA-256-Hash und eine Download-URL ein:

{
  "lockfileVersion": 1,
  "engineMinVersion": "3.2.0",
  "generatedAt": "2026-06-01T12:00:00Z",
  "portalBaseUrl": "https://codecharter.tools",
  "profiles": [
    {
      "slug": "acme-base",
      "version": "1.4.0",
      "source": "org",
      "contentHash": "sha256:e3b0c44298fc1c149afb...",
      "bundleUrl": "https://codecharter.tools/...",
      "eTag": "\"abc123\"",
      "rules": [
        { "slug": "no-async-void", "version": "2.1.0", "contentHash": "sha256:abc123..." }
      ]
    }
  ]
}

restore lädt Bundles von der im Lockfile hinterlegten bundleUrl herunter. Lassen Sie diese Datei deshalb immer von codecharter update erzeugen, statt sie von Hand zu schreiben.

Authentifizierung: API-Key und Lizenz

Befehle, die direkt mit dem Portal sprechen (update, push und verify --against-portal), erhalten den API-Key über ihr verpflichtendes Flag --api-key. restore braucht keinen API-Key: Es authentifiziert Bundle-Downloads mit Ihrer CodeCharter-Lizenz.

Die Umgebungsvariable CODECHARTER_API_KEY hat einen anderen Zweck: Jeder CLI-Befehl benötigt eine gültige Lizenz (Exit-Code 6, wenn keine gefunden wird). Ist CODECHARTER_API_KEY gesetzt, holt die CLI automatisch eine kurzlebige Lizenz vom Portal (GET /api/v1/cli/license), sobald die gecachte Lizenz fehlt oder bald abläuft. Deshalb setzen Sie das Secret in CI-Steps als Umgebungsvariable, auch wenn der Befehl selbst keinen API-Key entgegennimmt.

CLI-Befehle

restore

codecharter restore [--lockfile <path>] [--cache-dir <path>] [--quiet]

Lädt alle im Lockfile eingetragenen Profile und Regeln vom Portal herunter und legt sie unter .codecharter/cache/ neben dem Lockfile ab. Kein Download, wenn der Hash übereinstimmt (idempotent). Typischer erster Schritt in der CI. Exit-Codes: 0 Erfolg (ein fehlendes Lockfile ist ein No-Op), 1 Bundle-Hash-Drift nach dem Download, 2 Bedien- oder Netzwerkfehler.

update

codecharter update [profile] --portal-url <url> --api-key <key> [--all] [--config <path>] [--lockfile <path>]

Löst die in .codecharter/config.yml deklarierten, exakt versionierten Profil-Referenzen erneut gegen das Portal auf und schreibt .codecharter/codecharter.lock.json mit frischen Hashes und Download-URLs neu. --portal-url zeigt standardmäßig auf das gehostete Portal (nur für eine selbstgehostete Instanz angeben), und die Authentifizierung greift auf die installierte codecharter.license zurück, wenn --api-key fehlt. Ohne das Argument [profile] werden alle Profile aktualisiert; mit einem Profil-Slug nur dieses Profil. Das aktualisierte Lockfile committen Sie manuell und öffnen einen PR. In der CI läuft üblicherweise nur restore, nicht update. Exit-Codes: 0 Erfolg, 1 Resolver- oder Portalfehler, 2 Bedienfehler.

verify

codecharter verify [--lockfile <path>] [--cache-dir <path>] [--against-portal] [--portal-url <url>] [--api-key <key>] [--quiet]

Standardmäßig arbeitet verify offline: Es hasht die lokal gecachten Bundle-Dateien und vergleicht sie mit codecharter.lock.json. Bei jeder Abweichung oder einem fehlenden Bundle schlägt es mit Exit-Code 1 fehl. Mit --against-portal lässt es zusätzlich das Portal die Lockfile-Einträge gegen die gespeicherten Versionen prüfen; in diesem Modus zeigt --portal-url standardmäßig auf das gehostete Portal und die Authentifizierung greift auf die installierte Lizenz zurück, wenn --api-key fehlt, und der Befehl bricht früh ab, wenn das Portal nicht erreichbar ist. Exit-Codes: 0 sauber, 1 Drift, 2 Bedienfehler (zum Beispiel fehlendes Lockfile).

Beachten Sie die unterschiedlichen Cache-Standardpfade: restore schreibt nach .codecharter/cache neben dem Lockfile, verify prüft standardmäßig ~/.codecharter/cache. Übergeben Sie in der CI deshalb --cache-dir .codecharter/cache an verify, damit es den Cache prüft, den restore tatsächlich geschrieben hat.

analyze setzt das Lockfile selbst durch

codecharter analyze prüft das Lockfile selbst, sobald .codecharter/config.yml Profile deklariert: Es beendet sich mit Exit-Code 2, wenn das Lockfile fehlt, führt bei fehlenden Bundles im Cache ein stilles implizites Restore aus, beendet sich mit 3, wenn dieses Restore scheitert, weil das Portal nicht erreichbar ist, und mit 4 bei Hash-Drift. CI-Pipelines können direkt auf diese Exit-Codes reagieren.

GitHub-Actions-Workflow (vollständig)

Die CLI ist auf GitHub-Runnern nicht vorinstalliert. Laden Sie sie vom Portal herunter (GET /api/v1/cli/{platform}/{version}, authentifiziert mit Ihrem API-Key als Bearer-Token; Plattformen: win-x64, linux-x64, osx-x64, osx-arm64; Versionsselektoren: latest, v1, v1.4, v1.4.2).

.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'

      - name: Install CodeCharter CLI
        run: |
          curl -fsSL -H "Authorization: Bearer $CODECHARTER_API_KEY" \
            -o codecharter-cli.tar.gz \
            "https://codecharter.tools/api/v1/cli/linux-x64/latest"
          mkdir -p "$HOME/codecharter-cli"
          tar -xzf codecharter-cli.tar.gz -C "$HOME/codecharter-cli"
          echo "$HOME/codecharter-cli" >> "$GITHUB_PATH"
        env:
          CODECHARTER_API_KEY: ${{ secrets.CODECHARTER_API_KEY }}

      - name: Cache CodeCharter bundles
        uses: actions/cache@v4
        with:
          path: .codecharter/cache
          key: codecharter-${{ hashFiles('.codecharter/codecharter.lock.json') }}
          restore-keys: codecharter-

      - name: Restore portal profiles
        run: codecharter restore
        env:
          CODECHARTER_API_KEY: ${{ secrets.CODECHARTER_API_KEY }}

      - name: Verify lockfile integrity
        run: codecharter verify --cache-dir .codecharter/cache
        env:
          CODECHARTER_API_KEY: ${{ secrets.CODECHARTER_API_KEY }}

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

restore und verify laufen vor dem eigentlichen Analyze-Step: restore stellt sicher, dass alle Bundles lokal vorliegen, verify stellt sicher, dass der Cache zum Lockfile passt. Die Umgebungsvariable CODECHARTER_API_KEY auf diesen Steps erlaubt der CLI, ihre kurzlebige Lizenz automatisch zu beziehen.

Lockfile-Cache-Strategie

Der Cache-Key codecharter-${{ hashFiles('.codecharter/codecharter.lock.json') }} bedeutet: Jedes Mal, wenn Sie das Lockfile aktualisieren, gibt es einen Cache-Miss und einen frischen Download. Bei gleicher Lock-Version ist restore in Sekunden durch.

Den Cache-Pfad .codecharter/cache/ zur .gitignore hinzufügen:

# .gitignore
.codecharter/cache/

Ins Repository committed wird dagegen das Verzeichnis .codecharter:

  • .codecharter/config.yml (Profil-Referenzen)
  • .codecharter/codecharter.lock.json (eingefrorene Versionen und Hashes)

Häufige Fehler

Lockfile fehlt

Deklariert .codecharter/config.yml Profile, aber codecharter.lock.json fehlt, beendet sich codecharter analyze mit Exit-Code 2, und codecharter verify meldet:

error: lockfile not found at '<path>'.

und beendet sich mit Exit-Code 2. codecharter restore behandelt ein fehlendes Lockfile als No-Op (note: no lockfile found, nothing to restore., Exit 0). Das Lockfile wurde nicht committed: Führen Sie lokal codecharter update --portal-url <url> --api-key <key> aus und nehmen Sie .codecharter/codecharter.lock.json in Ihren Commit auf.

Hash-Drift

codecharter verify meldet Drift so und beendet sich mit Exit-Code 1:

DRIFT: 1 entry/entries do not match the lockfile.
  [hash-mismatch] [email protected]
    expected: sha256:e3b0c44...
    actual:   sha256:f7a9d12...

codecharter restore schlägt mit error: bundle hash drift for profile '[email protected]'. Run 'codecharter update' to refresh the lockfile. fehl (Exit 1), und codecharter analyze beendet sich mit Exit-Code 4. Das Profil im Portal wurde geändert, ohne das Lockfile zu aktualisieren, oder das Lockfile wurde manipuliert. Führen Sie lokal codecharter update --portal-url <url> --api-key <key> aus, um das Lockfile zu aktualisieren, und mergen Sie es in einem PR.

Portal nicht erreichbar

codecharter restore meldet fehlgeschlagene Downloads als error: failed to download bundle for '<slug>': <message>, und codecharter verify --against-portal gibt error: portal request failed: <message> aus. Ist der Cache unvollständig und das Portal nicht erreichbar, beendet sich codecharter analyze mit Exit-Code 3.

Prüfen Sie, ob der Runner ausgehenden Internet-Zugriff auf codecharter.tools hat und eine gültige Lizenz verfügbar ist (restore authentifiziert sich mit der Lizenz, nicht mit dem API-Key). Self-Hosted-Runner in isolierten Netzwerken brauchen einen Outbound-Proxy oder eine Firewall-Freigabe.

Profil-Version nicht gefunden

Existiert eine im Lockfile eingetragene Version nicht mehr im Portal (sie wurde gelöscht oder gehört zu einem anderen Org-Scope), schlägt codecharter update mit einem Resolver-Fehler fehl (Exit 1), und codecharter verify --against-portal meldet den Eintrag als portalseitigen Drift. Lokales codecharter update --portal-url <url> --api-key <key> behebt das, wenn eine neuere Version existiert.

Rate-Limit überschritten (429)

Das Portal limitiert API-Anfragen pro Identität (jeder API-Key hat sein eigenes Kontingent): standardmäßig 60 GET-Anfragen und 10 Schreib-Anfragen pro Minute. Über dem Limit schlagen Anfragen mit 429 Too Many Requests fehl; die Antwort enthält einen Retry-After-Header mit den Sekunden bis zum Zurücksetzen des Kontingents und einen JSON-Body mit demselben Wert im Feld retryAfter.

Ein einzelner CI-Lauf bleibt weit unter diesen Limits; die übliche Ursache sind viele parallele Jobs mit demselben Key. Downloads der CLI-Release-Archive sind nicht limitiert, Auflösungs- und Prüf-Aufrufe dagegen schon. Abhilfe: .codecharter/cache/ mit dem Lockfile als Cache-Key cachen (wie im Workflow oben), damit wiederholte Läufe keine Portal-Aufrufe machen, vor dem nächsten Versuch die in Retry-After genannten Sekunden warten, oder unabhängigen Pipelines eigene API-Keys geben, damit sie sich kein Kontingent teilen.

VS Code

Die VS-Code-Extension integriert sich direkt in den Offline-first-Workflow. Sie müssen dafür weder restore noch verify manuell ausführen.

Einrichtung

  1. Öffnen Sie die Einstellungen der Extension (Ctrl+,, suchen Sie nach "CodeCharter").
  2. Liegt die codecharter-CLI nicht auf Ihrem PATH, verweisen Sie die Einstellung codecharter.serverPath auf die Binärdatei. Die Portal-URL lässt sich über codecharter.portalBaseUrl anpassen (Standard: https://codecharter.tools).
  3. Öffnen Sie einen Workspace, der eine .codecharter/config.yml und ein .codecharter/codecharter.lock.json enthält.

Automatisches Restore

Enthält der Workspace eine .codecharter/config.yml, die Profile deklariert, führt die Extension beim Aktivieren einmalig codecharter restore aus und zeigt das aktive Regelset in der Statusleiste an, genauso wie codecharter restore in der CI.

Drift-Warnung

Hat sich das Lockfile seit dem letzten Restore geändert, zeigt die Extension eine Warnmeldung mit der Aktion Run restore. Ein Klick darauf führt codecharter restore erneut aus, damit der lokale Cache wieder zum Lockfile passt.

Offline-Modus

Ohne Internetverbindung arbeitet die Extension mit den zuletzt gecachten Bundles weiter, solange .codecharter/cache/ vorhanden und Ihre Lizenz noch gültig ist.

Integration mit codecharter push

codecharter push lädt ein Verzeichnis mit lokalen .cgr-Regeldateien ins Portal hoch und öffnet dort einen neuen Entwurf zum Prüfen und Veröffentlichen. Ein minimaler Aufruf erfordert --profile und --version; --portal-url zeigt standardmäßig auf das gehostete Portal, und die Authentifizierung nutzt die installierte Lizenz oder einen --api-key mit dem Scope write:rules:

codecharter push ./rules --profile my-team-rules --version 1.0.0 \
  --portal-url https://codecharter.tools \
  --api-key $CODECHARTER_API_KEY

Mit --dry-run lässt sich der Upload validieren, ohne tatsächlich ins Portal zu schreiben. Der VS-Code-Befehl CodeCharter: Push to portal ist damit nicht gleichzusetzen: Er gehört zum Handoff-Workflow des Portals und sendet den Regel-Entwurf, den Sie gerade in VS Code bearbeiten, zurück ans Portal; den CLI-Befehl push ruft er nicht auf.