Prüfungen und Regeln
Diese Seite erklärt, welche Prüfungen in welchem Kommando laufen, welche Regeln es gibt und wann ein Fund den Lauf blockiert.
Ablauf eines Prüflaufs
Die Phasen laufen in dieser Reihenfolge:
- Pfadregeln (
security): Liegt jede angefragte oder geänderte Datei im erlaubten Bereich? Ist eine geschützte Datei betroffen? Ein Verstoß beendet den Lauf sofort mit Exit 6. Danach läuft nichts mehr. - Inhaltsregeln (
security): Swift-Konstrukte, Secrets, sensible Daten im Log, Netzwerkziele, eigene Regeln. - Plattform-Checks (
platform): statische Prüfung von Xcode-Targets und Paket-Targets mit Privacy Manifest. - Externe statische Werkzeuge:
format,swiftlintundswiftlint_metrics. Ihre Prozesse starten parallel, der Bericht ordnet sie fest in dieser Reihenfolge. compile: Build für jede Plattform, nacheinander.tests: nur wenn der Build auf allen gebauten Plattformen erfolgreich war.
Ein blockierender Fund aus den Schritten 2 bis 6 ergibt Exit 1. Die Schritte danach laufen trotzdem, mit einer Ausnahme: tests startet nicht nach einem fehlgeschlagenen Build.
Welche Prüfung in welchem Kommando läuft
| Prüfung | check-file | check-diff | check-project | Standard | Abschaltbar durch Projekt? |
|---|---|---|---|---|---|
security | ja | ja | ja | an, verpflichtend | nein |
platform | ja | ja | ja | an, nicht verpflichtend | ja |
format | ja | ja | ja | an, verpflichtend | nur über scopes |
swiftlint | ja | ja | ja | an, verpflichtend | nur über scopes |
swiftlint_metrics | ja | ja | ja | aus, bis Metrikregeln konfiguriert sind | über rules.metrics |
compile | nie | ja | ja | an, verpflichtend | nur über scopes |
tests | nie | ja | ja | an, verpflichtend | nur über scopes |
„Verpflichtend“ (required: true) heißt: Fehlt das Werkzeug oder bleibt die Prüfung unvollständig, endet der Lauf mit Exit 3. Eine nicht verpflichtende Prüfung erzeugt in diesem Fall nur eine Warnung. Wie man das konfiguriert, steht unter Projektkonfiguration.
compile und tests werden nur angefordert, wenn im Projektwurzelverzeichnis ein Package.swift oder ein .xcodeproj/.xcworkspace liegt.
Pfadregeln
| Regel-ID | Schwere | Auslöser | Exit |
|---|---|---|---|
path-outside-allowed-scope | error | Datei liegt außerhalb von paths.include oder in paths.exclude | 6 (scope_violation) |
protected-file-change | critical | Eine geänderte Datei passt auf protected_files | 6 (protected_file) |
Beide sind nie waivebar: Der Waiver stünde in der .codeguard.yml des Projekts, die derselbe Diff ändern könnte.
Standardmäßig geschützt sind:
.codeguard.yml, .codeguard.yaml, Package.swift, Package.resolved,
**/*.entitlements, **/*.xcodeproj/project.pbxproj, .github/workflows/**,
.gitlab-ci.yml, **/*.xcconfig, .claude/settings.json, .claude/settings.local.json,
.claude/hooks/**, .opencode/package.json, .opencode/plugins/**, opencode.json,
opencode.jsonc, Tools/CodeGuard/**, .codeguard/baselines/**
check-diffÄndert ein Diff eine geschützte Datei, etwa Package.swift, die .codeguard.yml oder eine CI-Datei, endet check-diff mit Exit 6. Das gilt auch in Merge Requests. Solche Änderungen brauchen bewusst eine menschliche Prüfung.
Echte Ausgabe nach einer Änderung an Package.swift:
CODEGUARD_BLOCKED
1 blocking violations found in 2 changed files.
Validation: file (complete)
Exit: 6 (protected_file)
Requested: security
Completed: security
Skipped:
Konfiguration: .codeguard.yml (auto, sha256 5967f32a…)
Run: cg_3cd7b976-4cc7-498d-b1fe-da50c5fab091
1. CRITICAL Package.swift
Rule: protected-file-change
The operation targets a protected project path.
Do not change protected files without an explicit policy review.
Next action: Request human review for the reported findings.
Inhaltsregeln
Die Inhaltsregeln laufen in der Phase security. Sie lesen jede Datei genau einmal, starten keinen Prozess und brauchen kein Trust-Ticket. Die Swift-Regeln arbeiten auf Lexer-Tokens: Kommentare und String-Inhalte zählen nicht als Code, eine Interpolation \(…) schon. Es gibt keine Unterdrückung per Kommentar und keinen Autofix.
| ID | Standard | Was gefunden wird |
|---|---|---|
forbidden-fatal-error | error, in Testpfaden aus | Aufruf fatalError( oder Swift.fatalError( |
forbidden-force-try | error, in Testpfaden aus | try! |
forbidden-force-cast | error, in Testpfaden aus | as! |
sensitive-data-in-log | critical, auch in Tests | Logger-Aufruf mit sensiblem Bezeichner in den Argumenten |
hardcoded-secret | critical bzw. warning | Secret-Formate, Passwort in einer URL, sensible Zuweisung |
unauthorized-network-destination | error, in Testpfaden warning | Netzwerkziel außerhalb der Allowlist (nur aktiv, wenn eine Allowlist gesetzt ist) |
Testpfade sind Tests/**, **/*Tests/** und **/*UITests/**. Sie sind als Standard-path_overrides hinterlegt und lassen sich überschreiben.
forbidden-fatal-error, forbidden-force-try, forbidden-force-cast
- Alle
#if-Zweige werden geprüft, auch inaktive. Makroexpansionen sind nicht sichtbar. x.fatalError(mit anderem Empfänger zählt nicht. Deklariert die Datei selbstfunc fatalError, ist der Fund nurprobable.try !xist kein Treffer fürforbidden-force-try.- Unbalancierte Klammern in einer
.swift-Datei ergebencodeguard-content-scan-incompletestatt eines stillen Passes.
sensitive-data-in-log
- Logger sind freie Funktionen aus
logger_symbols.functions(Standard:print,debugPrint,dump,NSLog,os_log) oder Methoden auslogger_symbols.methods(Standard:debug,info,notice,log,trace,warning,error,fault,critical). Eine Methode zählt nur, wenn das letzte Glied der Empfängerkettelogenthält (z. B.logger.info(…)). - Sensible Bezeichner (
sensitive_identifiers, Standard:token,accessToken,refreshToken,password,passwd,secret,apiKey,authorization,cookie,sessionID,privateKey):- Bezeichner gleich einem Eintrag (ohne Groß-/Kleinschreibung):
certain, Schwere wie konfiguriert. - Nur ein camelCase-Bestandteil passt (z. B.
userPasswordHash):possible, höchstenswarning.
- Bezeichner gleich einem Eintrag (ohne Groß-/Kleinschreibung):
privacy: .privatemacht einen Aufruf nicht sicher.- Der Bericht enthält nie den Argumenttext, nur die Kategorie:
Possible password is written to a log.
hardcoded-secret
| Stufe | Dateien | Treffer | Schwere |
|---|---|---|---|
| Format | alle Textdateien | 15 Detektoren: AWS Access Key ID, GitHub-Tokens (classic, fine-grained), GitLab PAT, Slack, Stripe Secret Key, OpenAI (zwei Formate), Anthropic, Twilio API Key, SendGrid, npm, PEM-Private-Key-Header, JWT, Google API Key | critical; Google API Key warning |
| URL-Userinfo | alle Textdateien | scheme://user:passwort@host mit nicht leerem Passwort | critical |
| Sensible Zuweisung | Swift/ObjC, Plist, JSON, YAML, .xcconfig, .env | sensibler Bezeichner mit einem Literal von mindestens 8 Zeichen, das kein Platzhalter ist | warning |
Kein Treffer sind Platzhalter (<…>, YOUR_…, xxx…, changeme, $(…), ${…}, %@, $VAR), UUIDs, Hex-Digests, offizielle Beispielwerte (z. B. der AWS-Beispielschlüssel) und Swift-enum-Rohwerte. In Package.resolved, *.lock und *.xcassets/**/Contents.json läuft nur die Formatstufe.
Der gefundene Wert erscheint nie im Bericht, im Audit-Log oder im Fingerprint. Die Meldung lautet immer A hard-coded credential was detected. Einen bekannten, harmlosen Wert gibst du dauerhaft über rules.hardcoded-secret.allowlist_sha256 frei (siehe Projektkonfiguration).
Schon der Kopf eines PEM-Private-Keys in Doku, Kommentar oder String ist ein critical-Fund.
unauthorized-network-destination
- Nur aktiv, wenn
security.network.allowed_destinationsnicht leer ist. Diese Liste kann nur die Organisationsrichtlinie setzen (siehe Organisationsrichtlinie). - Format der Einträge:
scheme://host[:port], auchscheme://*.host[:port]für Subdomains beliebiger Tiefe (nicht die Domain selbst). Ohne Port gilt der Standardport. - Geprüft werden String-Literale in
.swiftund String-Werte in Plist und JSON, die mithttp://,https://,ws://oderwss://beginnen. - Ziel außerhalb der Liste:
error. Interpolation im Schema- oder Host-Teil oder nicht parsebare URL:warning/possible. - Ignoriert werden reservierte Namen (
example.com/.org/.net,*.example,*.test,*.invalid,localhost,*.localhost) und Apples Plist-DTD-URL.
Eigene Regeln (custom_rules)
| Engine | Verhalten |
|---|---|
regex | Muster läuft zeilenweise auf dem Rohtext, ein Fund pro Zeile. Kommentare und Strings werden mit durchsucht. Zeilen über 4 KiB werden übersprungen. |
file | Jede erfasste Datei ist ein Fund (auch Binärdateien). pattern ist verboten. |
dependency, architecture | Nicht umgesetzt. Erzeugt die Warnung codeguard-custom-rule-unsupported. |
Eigene Regeln sind nie waivebar, aber über ihre paths steuerbar. Konfiguration siehe Projektkonfiguration.
Was die Inhaltsregeln durchsuchen
| Scope | Dateien |
|---|---|
check-file | die angefragten Dateien |
check-diff | hinzugefügte, geänderte, umbenannte, kopierte und (mit --include-untracked) unversionierte Dateien, jeweils ganz |
check-project | alle nicht ausgeschlossenen Textdateien |
Nie durchsucht werden .git/, .build/, DerivedData/ und *.xcresult in jeder Tiefe.
Wann ein Inhaltsfund in check-diff blockiert
Jeder Fund bekommt eine scope_relation:
| Wert | Bedeutung | Blockiert? |
|---|---|---|
introduced | Fund in einer hinzugefügten Zeile (neue und unversionierte Dateien: immer) | ja, wenn die Regel blockiert |
touched | Fund in einem geänderten Bereich ohne hinzugefügte Startzeile | ja, wenn die Regel blockiert |
pre_existing | Fund in unverändertem Code einer geänderten Datei | nur bei critical |
Damit blockiert Altcode in einer angefassten Datei nicht, außer bei kritischen Funden wie Secrets.
Plattform-Checks
Die Phase platform prüft rein statisch, ohne xcodebuild und ohne Trust-Ticket.
| Target-Art | Erkennung | Regeln |
|---|---|---|
| App-artig | Application, Watch-App, App Clip, App Extension, ExtensionKit Extension | alle |
| Framework | Framework-Target | nur Privacy |
| Swift-Paket-Target | Ordner Sources/<Target>/ mit PrivacyInfo.xcprivacy | nur Privacy, nie privacy-manifest-missing |
| alles andere | CLI-Tool, Test-Bundle, statische Bibliothek, Paket-Target ohne Manifest | keine |
| Regel-ID | Standard | Auslöser |
|---|---|---|
privacy-manifest-invalid | error | .xcprivacy nicht parsebar, falscher Typ oder unvollständiger Eintrag in NSPrivacyAccessedAPITypes |
privacy-manifest-missing | error | App- oder Framework-Target nutzt eine Required-Reason-API, hat aber kein PrivacyInfo.xcprivacy |
privacy-required-reason-undeclared | error | API-Kategorie genutzt, aber nicht in NSPrivacyAccessedAPITypes deklariert |
privacy-reason-code-invalid | error | Reason-Code ist für die Kategorie nicht zugelassen |
privacy-tracking-domains-missing | warning | NSPrivacyTracking: true ohne NSPrivacyTrackingDomains |
purpose-string-missing | error | Geschützte API genutzt, Schlüssel fehlt in Info.plist und INFOPLIST_KEY_* (in mindestens einer Konfiguration) |
purpose-string-empty | error | Schlüssel vorhanden, aber leer |
ats-arbitrary-loads | warning | NSAllowsArbitraryLoads, …InWebContent oder …ForMedia ist true |
ats-insecure-exception-domain | warning | Ausnahme-Domain mit NSExceptionAllowsInsecureHTTPLoads: true oder TLS unter 1.2 |
entitlements-file-missing | error | CODE_SIGN_ENTITLEMENTS zeigt auf eine fehlende Datei |
entitlement-weakens-hardened-runtime | warning | z. B. com.apple.security.cs.disable-library-validation: true |
entitlement-get-task-allow-release | warning | get-task-allow: true in einer Konfiguration namens Release |
macos-app-sandbox-missing | warning | App-artiges macOS-Target ohne com.apple.security.app-sandbox: true |
Jedes Target wird für alle seine Build-Konfigurationen geprüft. Die Analyse darf dafür Dateien außerhalb von paths.include lesen (Projektdatei, Info.plist, Entitlements), paths.exclude gilt aber weiter. Lässt sich ein Setting oder eine Datei nicht sicher auflösen, entsteht codeguard-platform-check-incomplete statt eines geratenen Ergebnisses.
Echter Ausschnitt aus einem macOS-Projekt ohne App Sandbox:
2. WARNING App.entitlements
Rule: entitlement-weakens-hardened-runtime
Entitlement com.apple.security.cs.disable-library-validation is true, weakening the hardened runtime.
Remove com.apple.security.cs.disable-library-validation unless the target has a specific, documented need for it.
3. WARNING App.entitlements
Rule: macos-app-sandbox-missing
Target "App" configuration "Debug" does not set com.apple.security.app-sandbox = true.
Set com.apple.security.app-sandbox to true, or waive this rule for non-App-Store distribution.
Format: swift-format
- Regel-ID
swift-format, immererrorund blockierend. Die Kategorie von swift-format steht in eckigen Klammern vor der Meldung, z. B.[Indentation] unindent by 2 spaces. - Geprüft wird immer die ganze Datei.
- Ohne Projektdatei gelten die swift-format-Standards (unter anderem 2 Leerzeichen Einrückung, 100 Zeichen Zeilenlänge).
- Eine
.swift-formatim Projektwurzelverzeichnis wird beachtet. Sie muss eine reguläre Datei (kein Symlink) von höchstens 64 KiB sein und darf nur Schlüssel enthalten, die das swift-format aus Xcode 27 kennt. Unbekannte Schlüssel, falsche Typen oder leere verschachtelte Objekte ergeben Exit 2, eine nicht reguläre Datei Exit 6.
rules-MapEnthält rules in der .swift-format nur einen Teil der Regeln, schaltet swift-format alle nicht genannten Regeln ab. Willst du die Standardwerte der übrigen behalten, nenne sie ausdrücklich (swift-format dump-configuration zeigt alle).
Beispiel einer .swift-format, mit der die Beispielprojekte dieser Hilfe geprüft wurden:
{
"version": 1,
"indentation": { "spaces": 4 },
"lineLength": 120
}
Lint: swiftlint
- Regel-IDs
swiftlint.<regel>, z. B.swiftlint.force_try. Die SwiftLint-Schwere bleibt erhalten:errorblockiert,warningnicht. - Beachtet wird höchstens
<Projektwurzel>/.swiftlint.yml. Abgelehnt (Exit 6) werdenparent_config,child_config,plugins, Remote-URLs in diesen Schlüsseln sowie absolute Pfade und..inincluded/excluded. included/excludedder.swiftlint.ymlwirken unter CodeGuard nicht, weil SwiftLint auf einer privaten Kopie der Dateien läuft. Steuere den Umfang überpaths.include/paths.excludevon CodeGuard.// swiftlint:disablewirkt weiterhin, auch für die verwalteten Metrikregeln.
Inhaltsregeln und SwiftLint können dieselbe Stelle melden, zum Beispiel forbidden-force-try und swiftlint.force_try. Es sind zwei getrennte Funde.
Metriken: swiftlint_metrics
Ein zweiter, von CodeGuard erzeugter swiftlint-Lauf setzt Metrikregeln aus rules.metrics durch, unabhängig von der .swiftlint.yml des Projekts. Er läuft nur, wenn checks.swiftlint aktiv ist und mindestens eine Metrikregel einen Schwellenwert hat. Es gibt keine eingebauten Standardschwellen.
Schlüssel in rules.metrics | Regel-ID |
|---|---|
line_length | codeguard-metric-line-length |
file_length | codeguard-metric-file-length |
type_body_length | codeguard-metric-type-body-length |
function_body_length | codeguard-metric-function-body-length |
closure_body_length | codeguard-metric-closure-body-length |
cyclomatic_complexity | codeguard-metric-cyclomatic-complexity |
nesting | codeguard-metric-nesting |
function_parameter_count | codeguard-metric-function-parameter-count |
large_tuple | codeguard-metric-large-tuple |
enum_case_associated_values_count | codeguard-metric-enum-case-associated-values-count |
Überschreitet Code die error-Schwelle, erhält der Fund die Schwere aus rules.metrics.severity (error oder critical) und blockiert. Eine warning-Überschreitung blockiert nicht. Parameter siehe Projektkonfiguration.
Build: compile
| Projektart | macOS | iOS, watchOS, tvOS, visionOS |
|---|---|---|
| Swift Package | swift build | xcodebuild build auf einer Kopie des Pakets mit dem Paket-Scheme |
| Xcode-Projekt | xcodebuild build | xcodebuild build mit generischem Simulator-Ziel |
- CodeGuard erkennt die Plattformen selbst (Xcode:
-showdestinations; Pakete:platformsim Manifest, ohne Angabe nur macOS) und baut die Schnittmenge aus erkannt, konfiguriert (project.platforms) und lokal verfügbar (-showsdks). - Die Plattformen werden nacheinander gebaut. Ein Compile-Fehler auf einer Plattform stoppt die übrigen nicht. Timeout, Abbruch oder Werkzeugfehler stoppen die Matrix.
- Builds laufen offline, ohne Code-Signing, mit einem Job (
-jobs 1bzw.--jobs 1), in einem Arbeitsverzeichnis außerhalb des Projekts. Xcode-Builds laufen auf einer Kopie des Projekts (höchstens 50 000 Einträge, 2 GiB, Tiefe 100; ohne.git,.build,DerivedData,xcuserdata,*.xcresult). - Regel-IDs:
swift-compiler-error,swift-compiler-warning,swift-compiler-note(SwiftPM) bzw.xcodebuild-compiler-error,xcodebuild-compiler-warning(Xcode).
Echter Compile-Fehler aus einem Swift Package:
1. ERROR Sources/SwiftPMClean/SwiftPMClean.swift:2:17
Rule: swift-compiler-error
[swift-compiler-error] cannot find 'missingValue' in scope
Tests: tests
- macOS wird nativ getestet (
swift testbzw.xcodebuild test). - Für iOS, watchOS, tvOS und visionOS legt CodeGuard Wegwerf-Simulatoren an, bootet sie, testet und löscht sie wieder. Ziele:
ios-phone,ios-pad(nur bei iPad-fähigem Xcode-Target,TARGETED_DEVICE_FAMILYenthält 2),watchos,tvos,visionos. Pakete bekommen keinen iPad-Lauf. - Runtime: die neueste verfügbare mit Version ≥ Deployment-Target. Gerätetyp: der erste passende Eintrag einer festen Präferenzliste (neuestes iPhone, iPad Pro 13", größte Watch, Apple TV 4K, Vision Pro). Beides lässt sich mit
project.test_destinationsüberschreiben. - Regel-ID
swift-test-failure. Schlägt derselbe Test auf mehreren Zielen fehl, ist es ein Fund mit allen Zielen.
Echter Fund aus einer iOS-App mit iPad-Unterstützung:
1. [iOS/iPhone, iOS/iPad] ERROR Tests/AppTests.swift:8:1
Rule: swift-test-failure
Expectation failed: 1 == 2
Fehlt für eine erkannte Plattform eine Runtime, wird das Ziel übersprungen (simulatorUnavailable) und es gibt eine Warnung. Bleibt dadurch kein ausführbares Testziel und ist macOS nicht unter den gebauten Plattformen, endet der Lauf mit Exit 3, weil tests verpflichtend ist. Echte Ausgabe einer watchOS-App auf einem Rechner ohne watchOS-Runtime:
1. ERROR
Rule: codeguard-simulator-selection-failed
checks.tests.required is set, but no test target can run on this host; no test ran.
Install a simulator runtime for a detected platform, or set checks.tests.required: false.
2. WARNING
Rule: codeguard-simulator-unavailable
No usable watchOS simulator runtime or device type with deployment target 10.0; its tests were skipped. There are no installed watchOS simulator runtimes.
checks.tests.required: false kann nur die Organisationsrichtlinie setzen. Das Projekt kann tests lediglich über scopes: [] herausnehmen. Siehe Projektkonfiguration.
Laufdiagnosen
Laufdiagnosen beschreiben den Zustand des Laufs, keine Code-Regel. Sie sind nicht waivebar, und severity_floors wirken nicht auf sie.
| Regel-ID | Schwere | Bedeutung |
|---|---|---|
codeguard-build-execution-denied | error | Build/Test nicht autorisiert (kein Trust-Ticket bzw. keine CI-Attestierung). Führt zu Exit 6. |
codeguard-tool-output-unparseable | error | Werkzeugausgabe nicht sicher lesbar. Führt zu Exit 4, nie zu einem Pass. |
codeguard-dependency-unavailable | error/warning | Werkzeug fehlt, oder SwiftPM konnte Remote-Abhängigkeiten nicht laden (offline) |
codeguard-workspace-copy-failed | error | Die Projektkopie für Xcode überschritt ein festes Limit (Exit 4) |
codeguard-content-scan-incomplete | warning | Eine Datei war nicht sicher auswertbar (Größe, Kodierung, Lexer, Zeitbudget, unparsebares JSON/Plist …). Bei checks.security.required: true Exit 3. |
codeguard-custom-rule-unsupported | warning | Custom Rule mit Engine dependency oder architecture |
codeguard-tool-configuration-rejected | warning | Projekt-.swift-format oder .swiftlint.yml abgelehnt |
codeguard-project-config-ignored | warning | --no-project-config, obwohl eine .codeguard.yml existiert |
codeguard-platform-check-incomplete | warning | Plattform-Check konnte ein Target nicht sicher auswerten |
codeguard-platform-unavailable | warning | Erkannte Plattform ohne lokales SDK übersprungen |
codeguard-platform-not-built | info | Plattform im Manifest, die CodeGuard nicht baut (z. B. maccatalyst, linux) |
codeguard-platform-resolution-failed | error | Plattformauflösung beendet den Lauf vor dem ersten Build |
codeguard-simulator-unavailable | warning | Keine passende Runtime/Gerätetyp oder kein simctl |
codeguard-simulator-selection-failed | error | Erzwungenes Ziel nicht erfüllbar oder kein Testziel ausführbar |
codeguard-simulator-failed | error | Ein simctl-Schritt ist gescheitert (Exit 4/5) |
codeguard-simulator-cleanup-failed | warning | Ein Simulator ließ sich nicht aufräumen. Ändert den Exit-Code nicht. |
codeguard-simulator-sweep-incomplete | warning | Verwaiste Geräte konnten nicht vollständig aufgeräumt werden |