Zum Hauptinhalt springen

CI mit GitLab

Diese Anleitung richtet CodeGuard für Merge Requests, den Default-Branch und nächtliche Läufe in GitLab CI/CD ein. Sie setzt self-hosted GitLab-Runner auf macOS voraus, die ephemer und isoliert sind, sodass CodeGuard dort bauen und testen darf.

So funktioniert CodeGuard in der CI​

  • Jeder Aufruf bekommt --ci. Das Profil ist nicht interaktiv, lokale Trust-Tickets gelten nicht, trust grant ist verboten.
  • compile und tests starten nur, wenn der Runner eine Attestierung der Organisation trägt (siehe Organisationsrichtlinie). Fehlt sie, laufen nur die statischen Prüfungen und der Lauf endet mit Exit 6.
  • Der Job-Status folgt dem Exit-Code von CodeGuard. Die Berichte werden als Job-Artefakt abgelegt.

Voraussetzungen​

  • GitLab-Runner auf macOS 15 oder neuer, dessen Jobs jeweils in einer frischen, ephemeren Umgebung laufen, die dateisystem- und netzwerkisoliert ist. Nur dann darf die Attestierungsdatei dort liegen.
  • Admin-Zugriff auf das Runner-Image, um Dateien als root abzulegen.
  • Das Projekt liegt im Wurzelverzeichnis des Repositorys. check-diff bricht ab, wenn Projektwurzel und Git-Wurzel verschieden sind.

Schritt 1: Runner-Image vorbereiten​

Die Vorbereitung ist dieselbe wie bei GitHub Actions:

  1. Xcode (xcodebuild >= 26.0.0, < 28.0.0) und die benötigten Simulator-Runtimes installieren.

  2. CodeGuard mit Scripts/install.sh installieren (Repository-URL: Platzhalter <REPOSITORY-URL>).

  3. SwiftLint als root-eigene Kopie nach /usr/local/bin legen.

  4. Organisationsrichtlinie mit trusted_roots und execution_environment nach /Library/Application Support/CodeGuard/policy.yml installieren.

  5. Attestierungsdatei mit exakt diesem Inhalt als root mit Modus 0644 ablegen:

    version: 1
    runner_class: ephemeral
    ephemeral: true
    filesystem_isolated: true
    network_isolated: true
  6. Als Runner-Benutzer prüfen: codeguard version, codeguard --ci config validate, codeguard --ci doctor.

Alle Befehle und Dateien im Detail: CI mit GitHub Actions, Schritt 1.

gefahr

Die Attestierung sichert zu, dass der Runner ephemer und isoliert ist. CodeGuard führt daraufhin Projektcode aus Merge Requests ohne menschliche Freigabe aus. Lege sie nie auf einem dauerhaften oder vernetzten Runner ab.

Weise dem Runner einen Tag zu, z. B. macos-codeguard (Platzhalter), damit nur passende Jobs dort laufen.

Schritt 2: Repository vorbereiten​

  • .codeguard.yml und gegebenenfalls .swift-format und .swiftlint.yml ins Wurzelverzeichnis committen.
  • .gitlab-ci.yml, .codeguard.yml, Package.swift, Package.resolved, *.xcconfig, project.pbxproj und Entitlements sind geschützte Dateien. Ein Merge Request, der eine davon ändert, endet mit Exit 6 (protected_file). Solche Änderungen brauchen bewusst eine menschliche Prüfung.

Schritt 3: Pipeline anlegen​

Datei .gitlab-ci.yml:

stages:
- codeguard

variables:
GIT_DEPTH: "0" # voller Klon, damit die Basis-Revision existiert

.codeguard:
stage: codeguard
tags: [macos-codeguard] # Platzhalter: Tag deiner ephemeren macOS-Runner
timeout: 3h
artifacts:
when: always
expire_in: 30 days
paths:
- codeguard-reports/

codeguard:diff:
extends: .codeguard
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- mkdir -p codeguard-reports
- set +e
- codeguard --ci --format json --output codeguard-reports/codeguard.json check-diff --base "$CI_MERGE_REQUEST_DIFF_BASE_SHA"
- rc=$?
- echo "CodeGuard exit code $rc"
- exit $rc

codeguard:project:
extends: .codeguard
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "schedule"
script:
- mkdir -p codeguard-reports
- set +e
- codeguard --ci --format sarif --output codeguard-reports/codeguard.sarif check-project
- rc=$?
- echo "CodeGuard exit code $rc"
- exit $rc

Erläuterungen:

  • GIT_DEPTH: "0": GitLab klont standardmäßig flach. Ohne die Basis-Revision endet check-diff mit Exit 2 (unbekannte Referenz) bzw. Exit 3 (Commit-Objekt fehlt).
  • CI_MERGE_REQUEST_DIFF_BASE_SHA: Basis des Merge-Request-Diffs. Die Variable gibt es nur in Merge-Request-Pipelines, deshalb die rules mit merge_request_event.
  • set +e und exit $rc: Das Skript läuft bis zum Ende und übernimmt den Exit-Code von CodeGuard als Job-Ergebnis. Diese Form setzt voraus, dass die Skriptzeilen in einer gemeinsamen Shell laufen, wie beim Shell-Executor üblich. Prüfe das in deiner Runner-Konfiguration.
  • artifacts: when: always: Der Bericht wird auch bei Funden abgelegt.
  • Nächtlicher Lauf: Lege dafür im Projekt einen Pipeline-Zeitplan (Pipeline schedules) an. codeguard:project läuft dann mit $CI_PIPELINE_SOURCE == "schedule".
  • timeout: Builds für mehrere Plattformen und Simulator-Tests dauern. CodeGuard hat kein Gesamtzeitlimit über den ganzen Lauf.
Format gitlab-sarif

CodeGuard kennt zusätzlich --format gitlab-sarif. Diese Variante enthält nur sicherheitsbezogene Funde mit Datei und Position, höchstens 5000 Ergebnisse und kürzt Meldungen auf 1024 Zeichen. Eine Anbindung an die GitLab-Sicherheitsberichte ist nicht Teil dieser Anleitung; die Berichte werden hier nur als Artefakt abgelegt.

Ergebnis prüfen​

Mit gültiger Attestierung steht im JSON-Bericht "build_authorization": "operator_attested" unter run, und compile und tests erscheinen unter Completed. Fehlt die Attestierung, meldet der Bericht:

1. ERROR
Rule: codeguard-build-execution-denied
Build and test execution was not authorized: ci-untrusted execution requires an attested isolated runner: no declaration is installed at the organisation's execution-environment path.
Grant project trust, or run inside an attested isolated environment.

Den vollständigen Bericht dazu und die Bedeutung aller Exit-Codes im Pipeline-Kontext findest du unter CI mit GitHub Actions; sie gelten für GitLab genauso.

Simulatoren auf dem Runner​

CodeGuard legt für Tests Wegwerf-Simulatoren im Standard-Device-Set des Runner-Benutzers an und löscht sie danach. Auf einem ephemeren Runner verschwinden die bleibenden Logs mit der Umgebung. Bricht ein Job hart ab, räumt erst der nächste Lauf auf demselben Runner ein zurückgebliebenes Gerät ab. Siehe Trust und Sicherheit.

Siehe auch​