Nach dem Umzug eines iOS-Projekts auf einen Cloud-Mac bedeutet ein erfolgreicher Build noch nicht, dass alle Datenschutzangaben vollständig sind. Ein Abhängigkeitsupdate kann eine neue PrivacyInfo.xcprivacy einführen, während eine fehlerhafte Konfiguration der Ressourcen-Kopierphase verhindern kann, dass das Manifest des Hauptprojekts in die fertige App gelangt. Zuverlässiger ist es, Datenschutzmanifeste als Bestandteil des Build-Artefakts zu behandeln: zuerst den Quellbaum prüfen, anschließend das erzeugte Produkt untersuchen und schließlich ungeprüfte Änderungen über eine versionierte Baseline blockieren.
Umfang des Prüfgates festlegen
Ein praktikables Prüfgate sollte mindestens vier Ebenen abdecken: Lassen sich die Manifeste als plist parsen, haben die Felder auf oberster Ebene die richtigen Typen, werden sämtliche Manifeste aus Abhängigkeiten erfasst und sind die erwarteten Manifeste in der fertigen App vorhanden? Es reicht nicht, lediglich im Repository-Stammverzeichnis nach einer einzelnen Datei zu suchen. Quellcodeabhängigkeiten, vorkompilierte Frameworks und von Paketmanagern ausgecheckte Komponenten können jeweils eigene Erklärungen mitbringen.
Erstellen Sie zunächst in einem sauberen Arbeitsverzeichnis einen Manifestindex:
find . \
-path './.git' -prune -o \
-path './DerivedData' -prune -o \
-name PrivacyInfo.xcprivacy -print \
| LC_ALL=C sort > privacy-manifests.current
Tragen Sie die vom Projekt ausdrücklich verwalteten Pfade in privacy-manifests.baseline ein. Die Pipeline vergleicht beide Dateien und schlägt fehl, sobald ein Pfad hinzugefügt, entfernt oder geändert wurde. Erst nach der Prüfung durch die Codeverantwortlichen wird die Baseline aktualisiert. So werden Änderungen an Erklärungen, die durch Abhängigkeitsupdates entstehen, nicht unbemerkt übernommen.
Eine Baseline ist kein Nachweis der Konformität. Sie belegt lediglich, dass die aktuelle Änderung ausdrücklich geprüft wurde, und ersetzt keine Beurteilung des tatsächlichen Codeverhaltens.
Plist und Struktur auf oberster Ebene validieren
plutil -lint erkennt beschädigte XML- oder Binär-plists, prüft jedoch nicht, ob die Felder den richtigen Typ haben. Mit der Python-Standardbibliothek lässt sich ohne zusätzliche Abhängigkeiten eine schlanke Strukturprüfung ergänzen:
import pathlib
import plistlib
import sys
allowed = {
"NSPrivacyTracking": bool,
"NSPrivacyTrackingDomains": list,
"NSPrivacyCollectedDataTypes": list,
"NSPrivacyAccessedAPITypes": list,
}
failed = False
files = sorted(pathlib.Path(".").rglob("PrivacyInfo.xcprivacy"))
if not files:
print("No privacy manifest found")
sys.exit(1)
for path in files:
try:
with path.open("rb") as stream:
data = plistlib.load(stream)
if not isinstance(data, dict):
raise TypeError("Root must be a dictionary")
for key, value in data.items():
expected = allowed.get(key)
if expected is None:
raise KeyError(f"Unknown top-level key: {key}")
if not isinstance(value, expected):
raise TypeError(f"{key} must be {expected.__name__}")
print(path)
except Exception as error:
failed = True
print(f"{path}: {error}")
sys.exit(1 if failed else 0)
Speichern Sie das Skript als Scripts/validate_privacy_manifests.py und führen Sie es vor dem Build aus. Verwendet das Projekt organisationsinterne Erweiterungsfelder, sollten nicht pauschal alle unbekannten Schlüssel zugelassen werden. Nehmen Sie jedes Feld einzeln in die Positivliste auf und dokumentieren Sie seinen Zweck.
Prüftabelle für Required-Reason-APIs anlegen
Eine korrekte Struktur bedeutet noch nicht, dass die angegebenen Gründe korrekt sind. Zugriffe auf Dateizeitstempel, Systemlaufzeit, freien Speicherplatz, Einstellungen und ähnliche APIs müssen in die Codeprüfung einbezogen werden. Automatische Scans liefern zwar Anhaltspunkte, doch Makros, Abstraktionsschichten und binäre Abhängigkeiten können Fehlalarme oder übersehene Treffer verursachen. Daher darf eine einzelne Textsuche nicht unmittelbar über den Grundcode entscheiden.
Führen Sie für jede Erklärung einen prüfbaren Datensatz:
| Prüfpunkt | Zu dokumentierende Angaben | Fehlerbedingung |
|---|---|---|
| API-Kategorie | Kategoriekennung aus dem Manifest | Kein entsprechender Codepfad für die Kategorie |
| Verwendungsort | Modul, Datei und verantwortliche Person | Ursprung des Aufrufs nicht auffindbar |
| Verwendungszweck | Tatsächliche, nutzerseitige Funktion | Angegebener Grund stimmt nicht mit dem Verhalten überein |
| Herkunft der Abhängigkeit | Eigener Code oder konkrete Komponente | Herkunft der Binärdatei ist unklar |
| Auslöser für erneute Prüfung | Änderung am Code oder an der Abhängigkeitsversion | Nach der Änderung nicht erneut bestätigt |
Dokumentieren Sie bei Closed-Source-Binärkomponenten mindestens die Komponentenversion, den Manifest-Hash und die Produktfunktion, für die die Komponente eingebunden wurde. Lässt sich die Herkunft einer Erklärung nicht nachvollziehen, sollten fehlende Angaben nicht durch Vermutungen ergänzt werden. Klären Sie sie stattdessen mit den Verantwortlichen für die Abhängigkeit.
Fertige App erneut prüfen
Eine im Quellbaum vorhandene Datei wird möglicherweise nicht kopiert, wenn die Target-Zugehörigkeit oder die Ressourcenphase falsch konfiguriert ist. Die Pipeline sollte deshalb einen unsignierten Release-Build erstellen und anschließend das tatsächliche Produkt prüfen:
rm -rf .build/privacy
xcodebuild \
-scheme "$SCHEME" \
-configuration Release \
-sdk iphoneos \
-derivedDataPath .build/privacy \
CODE_SIGNING_ALLOWED=NO \
build
APP_PATH="$(find .build/privacy/Build/Products -type d -name '*.app' -print -quit)"
test -n "$APP_PATH"
find "$APP_PATH" -name PrivacyInfo.xcprivacy -print | LC_ALL=C sort
Haupt-App, eingebettete Frameworks und Erweiterungen sollten jeweils so enthalten sein, wie es für das Projekt vorgesehen ist. Der zufällig erzeugte DerivedData-Pfad darf nicht fest einprogrammiert werden. Ebenso wenig genügt es, lediglich die Anzahl der Manifeste im Quellbaum zu prüfen, da mehrere Quellmanifeste während des Builds zusammengeführt, ersetzt oder ausgelassen werden können.
Artefaktinventar speichern
Speichern Sie den relativen Pfad und den SHA-256-Hash jedes im Artefakt enthaltenen Manifests als Pipeline-Anhang:
find "$APP_PATH" -name PrivacyInfo.xcprivacy -print0 |
while IFS= read -r -d '' file; do
relative="${file#"$APP_PATH"/}"
digest="$(shasum -a 256 "$file" | awk '{print $1}')"
printf '%s %s
' "$digest" "$relative"
done | LC_ALL=C sort > privacy-artifact.sha256
Tritt später ein Prüfproblem auf, beantwortet dieser Datensatz die Frage: „Was war in diesem konkreten Build tatsächlich enthalten?“ Das ist zuverlässiger, als lediglich den aktuellen Branch zu untersuchen.
Fehlerbedingungen in den Arbeitsalltag integrieren
Teilen Sie die Prüfungen in eine schnelle und eine vollständige Stufe auf. Bei Merge Requests werden zunächst Manifestsuche, plist-Parsing, Feldtypprüfung und Baseline-Vergleich ausgeführt. Auf dem Hauptbranch kommen der Release-Build und die Prüfung des App-Artefakts hinzu. Schnelle Prüfungen liefern den betroffenen Pfad üblicherweise innerhalb weniger Sekunden; die vollständigen Prüfungen erkennen zusätzlich Probleme in Ressourcenphasen und eingebetteten Frameworks.
Vor der Veröffentlichung sollten folgende Prüfpunkte bestehen bleiben:
- Der Manifestindex stimmt mit der freigegebenen Baseline überein.
- Jede Datei besteht sowohl
plutil -lintals auch das Skript zur Strukturprüfung. - Jede neue API-Kategorie ist mit einer Codestelle, einer verantwortlichen Person und dem tatsächlichen Zweck verknüpft.
- Manifeständerungen nach Abhängigkeitsupdates wurden manuell geprüft.
- Die Manifeste in der fertigen App, in Erweiterungen und in eingebetteten Frameworks entsprechen den Erwartungen.
- Artefaktpfade und Hashes wurden zusammen mit dem Build archiviert.
Dieses Prüfgate soll dem Team die Konformitätsentscheidung nicht automatisch abnehmen. Sein Zweck besteht darin, Auslassungen in eindeutige Build-Fehler zu verwandeln und jede Änderung an einer Erklärung bis zum Code, zu den Abhängigkeiten und zu den Prüfprotokollen zurückverfolgbar zu machen.
Häufig gestellte Fragen
Reicht eine PrivacyInfo.xcprivacy-Datei im Repository aus?
Nein. Sie muss fehlerfrei lesbar sein, korrekte Feldtypen verwenden und im erzeugten App- oder Framework-Artefakt enthalten sein.
Kann ein Skript die Begründung jeder Required Reason API vollständig bewerten?
Nein. Es erkennt fehlende Dateien, Strukturfehler und ungeprüfte Änderungen. Ob eine Begründung zum tatsächlichen Codepfad passt, muss fachlich geprüft werden.
Warum ist nach einem Abhängigkeitsupdate eine neue Baseline nötig?
Abhängigkeiten können eigene Manifeste ergänzen oder verändern. Die Baseline sollte erst nach Prüfung des Diffs aktualisiert werden.
Wählen Sie für Ihren nächsten Build einen exklusiven Cloud-Mac
Wählen Sie Mac-mini-Modell, Mietdauer und Region passend zu Ihrer Workload. Jede Bestellung entspricht einem eigenen physischen Knoten. Die tatsächliche Verfügbarkeit wird in Echtzeit über die Konsole angezeigt.