8 Min. Lesezeit

Agentenfreigaben unter macOS müssen jeden Build unterscheiden

Eine Agentenfreigabe unter macOS muss stabile, Beta-, Paketmanager- und lokale Builds unterscheiden, bevor ein vertrauenswürdiger Prozess einen anderen abdeckt.

Agentenfreigaben unter macOS müssen jeden Build unterscheiden

Einen KI-Agenten anhand eines freundlichen Befehlsnamens freizugeben bedeutet, möglicherweise die falsche ausführbare Datei freizugeben. Auf einem Mac sammeln sich schnell ein Release des Anbieters, eine Beta, eine Kopie aus dem Paketmanager und ein selbst erstellter Build an, die alle auf denselben Namen hören. Wenn deine Freigabegrenze diese Varianten nicht unterscheiden kann, kann eine Entscheidung für einen geprüften Build unbemerkt auf einen anderen übergreifen.

Die Lösung ist keine längere Allowlist. Du musst festlegen, welche Eigenschaften einen Agentenlauf in deiner Umgebung identifizieren, nachweisen, dass jede installierte Kopie diese Eigenschaften besitzt, und anschließend das Freigabeverhalten mit gleichzeitig vorhandenen Kopien testen. Pfade, Signaturen, Designated Requirements und Hashes beantworten unterschiedliche Fragen. Wer sie verwechselt, setzt sein Team Risiken aus.

Ein Befehlsname kann auf mehrere ausführbare Dateien zeigen

Ein Shell-Befehl ist eine Suche, keine Identität. Wenn du claude, agent oder einen Wrapper-Namen eingibst, kann deine Shell einen Alias, eine Funktion, einen Shim, einen symbolischen Link, ein Paketmanager-Verzeichnis oder eine Datei auflösen, die in PATH vor der eigentlich gemeinten Kopie steht.

Beginne in dem Terminal, Editor, Startdienst oder Automatisierungs-Runner, der den Agenten tatsächlich startet. Untersuche keine bequeme interaktive Shell und gehe davon aus, dass das Ergebnis übertragbar ist. Login-Shells, grafische Anwendungen und CI-Runner erhalten oft unterschiedliche Umgebungsvariablen.

Führe zuerst Folgendes aus:

type -a agent-name
command -v agent-name

Ein nützliches Ergebnis könnte so aussehen:

agent-name is /Users/me/bin/agent-name
agent-name is /opt/homebrew/bin/agent-name
agent-name is /usr/local/bin/agent-name
/Users/me/bin/agent-name

Die Ausgabe sagt, dass in dieser Shell der erste Pfad gewinnt. Sie sagt nicht, ob /Users/me/bin/agent-name eine direkte Binärdatei, ein symbolischer Link, ein Skript, das eine andere Binärdatei startet, oder ein Wrapper ist, der vor der Übergabe die Umgebungsvariablen ändert.

Löse die Datei auf, bevor du sie untersuchst:

BIN="$(command -v agent-name)"
python3 - <<'PY' "$BIN"
import os, sys
print(os.path.realpath(sys.argv[1]))
PY
file "$BIN"

Wenn file ein Shellskript meldet, lies es. Bei einem symbolischen Link prüfe das Ziel. Bei einer universellen Mach-O-Datei untersuche die ausführbare Datei. Ein Wrapper kann dafür sorgen, dass eine Freigabeoberfläche korrekt aussieht, obwohl später ein anderer untergeordneter Prozess gestartet wird.

Höre nicht auf, sobald du den aktuellen Gewinner gefunden hast. Erfasse jedes Ergebnis von type -a sowie Kopien im Applications-Ordner des Anbieters, im Downloads-Ordner, im ausgecheckten Quellcode und in den Verzeichnissen des Paketmanagers. Die heute bevorzugte Kopie kann morgen nach einem Paketmanager-Update oder einer kleinen PATH-Änderung verlieren.

Ein Pfad belegt den Ort, nicht die Identität

Teams beginnen oft mit einer Pfadregel, weil Pfade leicht zu lesen sind. /Applications/Agent.app wirkt bewusst gewählt. /Users/me/dev/agent/bin/agent wirkt experimentell. Das sind hilfreiche Hinweise, aber ein Pfad allein beweist nicht, welcher Code sich aktuell dort befindet.

Ein Paketmanager kann die Datei hinter einem stabilen symbolischen Link ersetzen. Ein direkter Installer kann ein App-Bundle an Ort und Stelle überschreiben. Ein lokaler Build kann jedes Mal denselben Ausgabeort verwenden. Ein Angreifer mit ausreichenden Schreibrechten kann eine Datei an einem freigegebenen Pfad ersetzen. Der Pfad zeigt nur, wo der Loader die Datei gefunden hat.

Verwende in deinem Inventar vier getrennte Felder:

FeldWas es aussagtWas es nicht aussagt
Aufgelöster PfadWo dieser Start die Datei gefunden hatWer sie erstellt hat oder ob sie verändert wurde
SignaturinformationenWelche Signaturidentität dem Code zugeordnet istOb ein anderer Build desselben Signierers identisches Verhalten zeigt
Designated RequirementWelche Kontinuitätsregel macOS mit dem Code verknüpftOb die Regel für deinen Freigabezweck eng genug ist
SHA-256-HashDie exakten Bytes, die du untersucht hastOb ein zukünftiges Update das Vertrauen erben sollte

Diese Unterscheidung ist wichtig, weil sich die Felder unterschiedlich schnell ändern. Ein Anbieter-Update kann Pfad und Designated Requirement beibehalten und trotzdem den Hash ändern. Eine Beta kann die Signaturautorität behalten, aber eine andere Bundle-ID verwenden. Ein lokaler Build kann denselben Quellstand wie ein Release haben, aber eine Ad-hoc-Signatur oder gar keine Signatur tragen.

Apples Technical Note TN2206 erklärt die vorgesehene Rolle des Designated Requirement: Es soll legitime Updates eines Programms erkennen und fremden Code ausschließen. Damit ist es ein Mechanismus für Kontinuität. Es beantwortet aber nicht allgemein die Frage: «Habe ich genau diese Binärdatei gemeint?» Apple weist außerdem darauf hin, dass die Standardanforderung aus der Signaturkonfiguration erzeugt wird. Ihre Reichweite hängt daher davon ab, wie der Entwickler den Build signiert hat.

Freigabesysteme brauchen dieselbe Trennung. Die Entscheidung, die nächste kompatible Version eines Anbieters zu vertrauen, ist etwas anderes als die Entscheidung, genau ein Release-Artefakt zu vertrauen. Wer beides gleich behandelt, kann später nicht erklären, was der Benutzer freigegeben hat.

Prüfe die Signatur, bevor du eine Freigaberegel erstellst

Erfasse für jede mögliche ausführbare Datei die Signaturdetails und ihren Hash. Die folgenden Befehle verwenden nur integrierte macOS-Werkzeuge und shasum:

inspect_agent() {
  target="$1"
  echo "=== $target ==="
  echo "Resolved path: $(python3 - <<'PY' "$target"
import os, sys
print(os.path.realpath(sys.argv[1]))
PY
)"
  shasum -a 256 "$target"
  codesign --display --verbose=4 "$target" 2>&1 \
    | grep -E '^(Executable|Identifier|TeamIdentifier|Authority|CDHash)='
  codesign --display -r- "$target" 2>&1 \
    | sed -n '/designated/,$p'
  codesign --verify --strict --verbose=2 "$target" 2>&1
}

inspect_agent "$(command -v agent-name)"

Wichtiger als eine bestimmte Zeichenfolge des Anbieters ist die Form der Ausgabe:

=== /opt/homebrew/bin/agent-name ===
Resolved path: /opt/homebrew/Cellar/agent-name/2.4.1/bin/agent-name
3b1f...  /opt/homebrew/bin/agent-name
Executable=/opt/homebrew/bin/agent-name
Identifier=com.example.agent
TeamIdentifier=AB12CDE345
Authority=Developer ID Application: Example, Inc. (AB12CDE345)
CDHash=9c1a...
designated => anchor apple generic and identifier "com.example.agent" and certificate leaf[subject.OU] = "AB12CDE345"
/opt/homebrew/bin/agent-name: valid on disk
/opt/homebrew/bin/agent-name: satisfies its Designated Requirement

Behandle den angezeigten CDHash nicht als Ersatz für deinen SHA-256-Eintrag. Der CodeDirectory-Hash gehört zur Codesignatur und kann sich durch die Struktur der Signatur ändern. shasum -a 256 liefert einen vertrauten exakten Fingerabdruck der Datei für einen Testeintrag. Wenn du eine Kollision untersuchst, erfasse beide Werte.

Bei einem App-Bundle solltest du die tatsächliche ausführbare Datei untersuchen, nicht nur das Bundle-Verzeichnis. Finde sie so:

APP="/Applications/Agent.app"
EXEC="$APP/Contents/MacOS/$(defaults read "$APP/Contents/Info" CFBundleExecutable)"
inspect_agent "$EXEC"

Wenn der Agent einen Helferprozess startet, untersuche auch diesen. Die ausführbare Datei, die ein Terminalfenster öffnet, ist nicht immer der Prozess, der HTTP-Aufrufe ausführt oder SSH startet. Ein Freigabesystem sollte den Prozess identifizieren, der die sensible Aktion anfordert. Dein Test sollte trotzdem die gesamte Startkette prüfen.

Apples neuere TN3127 geht über den älteren Signaturleitfaden hinaus. Sie zeigt, wie sich Standardanforderungen je nach Signaturtyp unterscheiden und warum getrennt verteilte Varianten nicht zwingend miteinander kompatibel sind. Das ist eine Warnung vor Annahmen. Vergleiche den tatsächlichen Requirement-Text deiner installierten Dateien.

Stabile, Beta-, Paketmanager- und lokale Builds brauchen eine Testmatrix

Mach dein Inventar konkret. Wähle die Kopien aus, die auf deinem Mac plausibel vorhanden sein können, gib jeder ein kurzes Label und notiere, was sie deiner Erwartung nach mit den anderen gemeinsam haben oder nicht gemeinsam haben soll.

LabelTypische QuelleErwarteter SignaturstatusErwartung an die Freigabe
StabilInstaller des Anbieters oder App-BundleRelease-SignaturidentitätAusgangskandidat
BetaBeta-Kanal des AnbietersKann dieselbe Release-Identität verwendenMuss separat getestet werden
PaketmanagerFormula, Cask, npm-ähnlicher Shim oder ÄhnlichesHängt von der Paketierung abDas gestartete Ziel muss aufgelöst werden
LokalQuellcode-Checkout oder Build-AusgabeEntwicklung, Ad hoc oder nicht signiertStandardmäßig eigene Prüfung

Diese Tabelle schreibt nicht die richtige Entscheidung vor. Sie verhindert die bequeme Entscheidung, bei der ein Kanalname als ausreichende Information gilt. Eine Beta kann genauso signiert sein wie die stabile Version. Eine Paketmanager-Kopie kann ein unverändertes Artefakt des Anbieters, ein neu verpacktes Artefakt oder ein Skript sein, das eine andere ausführbare Datei herunterlädt. Ein lokaler Build kann eine gültige Entwicklungssignatur tragen und dadurch offizieller wirken, als er ist.

Erstelle für jede installierte Kopie eine Zeile in einer Textdatei, die zusammen mit deinen Notizen zum Agenten-Setup gespeichert wird:

label: stable
launch path: /Applications/Agent.app/Contents/MacOS/agent-name
resolved path: /Applications/Agent.app/Contents/MacOS/agent-name
version: 2.4.1
identifier: com.example.agent
team or authority: AB12CDE345
sha256: 3b1f...
designated requirement: anchor apple generic and identifier "com.example.agent" ...
expected approval group: release

label: local
launch path: ~/src/agent/build/agent-name
resolved path: /Users/me/src/agent/build/agent-name
version: git revision recorded separately
identifier: ad hoc or absent
team or authority: none
sha256: 8e52...
designated requirement: unavailable or different
expected approval group: local only

Notiere die Version, aber lasse die Versionsnummer nicht die Entscheidung bestimmen. Versionsangaben sind Anwendungsmetadaten. Eine Datei kann eine Versionsnummer behaupten, die nicht zu dem Release passt, das du herunterzuladen glaubtest. Signatur und Hash liefern unabhängige Fakten.

Der schwierige Fall sind zwei Zeilen mit derselben Kennung, demselben Team und demselben Designated Requirement, aber unterschiedlichen Hashes. Das ist nicht unbedingt ein Fehler. Es bedeutet, dass der Anbieter zwei Builds erstellt hat, die macOS als Varianten desselben Programms betrachten kann. Wenn die Freigabe dem Release-Kanal des Anbieters folgen soll, kann das akzeptabel sein. Wenn sie nur ein bestimmtes Release-Artefakt abdecken darf, ist die Regel zu weit gefasst.

Der falsche Test gibt jede Kopie einzeln frei

Jeden Agentenlauf verfolgen
Das Sitzungsprotokoll erfasst Agentenläufe und unterstützt den sofortigen Widerruf von Sitzungen.

Wenn du den stabilen Build am Montag und die Beta am Dienstag testest, sagt das fast nichts über eine gegenseitige Abdeckung aus. Jeder Test kann eine Nachfrage anzeigen, weil bisher noch keine aktive Freigabe besteht. Du brauchst beide Kopien installiert und eine Sitzung der einen Kopie, die noch läuft, während die andere Zugriff anfordert.

Führe diese Reihenfolge in einem Wegwerfkonto oder mit Zugangsdaten aus, die keine Produktionssysteme verändern können:

  1. Lege die stabile, Beta-, Paketmanager- und lokale Kopie bereit. Bestätige ihre aufgelösten Pfade und speichere die Prüfausgabe.
  2. Lösche oder widerrufe die bestehende Agentensitzung über das von dir verwendete Freigabewerkzeug. Bestätige, dass der nächste sensible Aufruf eine neue Entscheidung erfordert.
  3. Starte die stabile Kopie und führe einen harmlosen Aufruf an einen Testendpunkt aus. Gib nur diesen Lauf frei. Lass den Prozess weiterlaufen.
  4. Starte die Beta-Kopie, während der stabile Prozess weiterläuft, und führe denselben harmlosen Aufruf aus. Beobachte, ob sie eine Freigabe verlangt, und prüfe die auf der Karte angezeigte Prozessidentität.
  5. Wiederhole den Test mit der Paketmanager- und der lokalen Kopie. Ändere anschließend die PATH-Reihenfolge und wiederhole den Paketmanager-Test.

Das gewünschte Ergebnis hängt von deiner Regel ab. Wenn stabile und Beta getrennt sein sollen, muss die Beta eine Freigabe verlangen, während die stabile Kopie bereits freigegeben ist. Wenn sie absichtlich dieselbe Freigabegruppe teilen, müssen Karte und Auditspur die Gruppierung für einen Prüfer ausreichend deutlich machen.

Rufe für diesen Test keine Produktions-API auf. Verwende einen Testendpunkt mit fester Antwort, der in seinen eigenen Logs eine sichtbare, harmlose Markierung hinterlässt. Für SSH kannst du ein Testkonto verwenden, dessen Befehl nur Identitätsinformationen ausgibt:

ssh [email protected] 'id; hostname; date -u +%FT%TZ'

Der Test liefert zwei Beobachtungen: Was die Freigabeoberfläche sagt und was das Zielsystem protokolliert. Speichere Zeitstempel, Hash der ausführbaren Datei, Prozess-ID und zurückgegebene Markierung. Wenn ein Wrapper die tatsächlich ausgeführte Datei verändert hat, zeigt sich die Abweichung dann, statt erst in einer späteren Untersuchung.

Ein typischer Fehler sieht so aus: Ein Entwickler gibt die stabile App frei und installiert anschließend eine Beta, die durch eine Änderung der Shell-Konfiguration /Users/me/bin vor /Applications setzt. Der Befehlsname bleibt gleich. Die Beta führt einen Aufruf ohne neue Nachfrage aus, weil die Autorisierungsprüfung eine gemeinsame Signaturidentität oder eine zu breite Prozessgruppe erkennt. Niemand bemerkt es, weil der ursprüngliche stabile Prozess noch läuft und der Audit-Eintrag nur agent-name nennt. Du verhinderst diesen Fehler durch den Überlappungstest, nicht durch das Lesen von Versionshinweisen.

Prozessidentität und exakte Bytes beantworten unterschiedliche Freigabefragen

Eine Freigabe kann sinnvoll an eine signierte Prozessidentität gebunden sein, die bei Aktualisierungen stabil bleibt. Sie kann ebenso an exakt definierte Bytes gebunden sein. Keine der beiden Entscheidungen ist immer richtig.

Verwende die Prozessidentität, wenn du einer gepflegten Release-Linie eines bekannten Signierers vertrauen willst. So muss der Benutzer nicht jedes Patch-Release erneut freigeben, nur weil sich der Hash der ausführbaren Datei geändert hat. Eine stabile Prozessidentität kann außerdem einen normalen Updateweg überstehen.

Verwende exakte Bytes, wenn der Build experimentell, lokal erstellt, unabhängig gepatcht oder aus einem Kanal stammt, den du nicht mit dem stabilen Kanal zusammenlegen willst. Eine Hashbindung eignet sich besonders für eine kurze Untersuchung oder Reproduktion, bei der die Freigabe mit einer Änderung der Datei verfallen soll.

Gefährlich ist die Annahme, eine Signaturkennung allein sei eine Identität. Apple dokumentiert, dass mehrere Signierer dieselbe Signaturkennung beanspruchen können. Apple empfiehlt, sie bei der Codeprüfung mit passenden Validierungs- und Teambeschränkungen zu kombinieren. Praktisch bedeutet das: Identifier=com.example.agent ohne Autorität oder Team ist nur ein Label, das jemand anderes wiederverwenden kann.

Ein Designated Requirement ist im Allgemeinen stärker, weil es die Kennung mit Einschränkungen für die Signaturautorität verbinden kann. Es kann trotzdem weiter gefasst sein als deine Absicht. Eine Anforderung, die jeden gültigen Build eines Teams mit einer bestimmten Kennung akzeptiert, kann korrekt einen stabilen Build, eine Beta und einen vom Anbieter erzeugten lokalen Test-Build abdecken. Das ist nur dann gut, wenn alle drei tatsächlich dieselbe Freigabegruppe bilden sollen.

Schreibe die Gruppenentscheidung in einfacher Sprache neben den Inventareintrag. Zum Beispiel:

Release group: accept future vendor-signed builds with the release identifier.
Beta group: separate, even when signed by the same vendor identity.
Local group: exact SHA-256 only; rebuild requires another approval.

So steht die Entscheidung fest, bevor die Oberfläche nach einem Klick fragt. Außerdem zeigt sich, ob dein Werkzeug die gewünschte Unterscheidung ausdrücken kann. Falls nicht, verwende eine engere operative Grenze, etwa eine Freigabe pro Aufruf für Beta- und lokale Builds, bis das Werkzeug diese Möglichkeit bietet.

Eine Sitzungsfreigabe ersetzt keine Freigabe pro Aufruf

Eine Sitzungsfreigabe beantwortet die Frage: «Darf dieser Agentenprozess während dieses Laufs mit Zugriff ausgeführt werden?» Eine Freigabe pro Aufruf beantwortet: «Darf diese bestimmte Zugangsdaten jetzt für diese bestimmte Aktion verwendet werden?» Die erste Kontrolle begrenzt, welcher Prozess eine Sitzung erhält. Die zweite begrenzt die Folgen dieser Sitzung.

Sallyport verwendet eine feste Entscheidungskette: Ein gesperrter Tresor verweigert jede Aktion, ein neuer Agentenprozess benötigt normalerweise eine Sitzungsfreigabe, und für ausgewählte Zugangsdaten kann bei jeder Verwendung eine neue Bestätigung verlangt werden. Die Freigabekarte stellt die Codesignatur-Autorität des Prozesses an den Anfang. Das ist ein hilfreicher Hinweis, aber sobald mehrere Builds existieren, solltest du trotzdem den Überlappungstest ausführen.

Verwende die häufigere Prüfung für Zugangsdaten, die unumkehrbare oder nach außen sichtbare Änderungen verursachen können. Zugangsdaten für Produktionsbereitstellungen, destruktive Verwaltungs-APIs und SSH-Zugriff auf gemeinsam genutzte Infrastruktur sollten nicht allein deshalb Vertrauen erben, weil ein Agentenprozess zu Beginn eines langen Laufs akzeptabel war.

Löse eine Binärkollision nicht dadurch, dass du dauerhaft für jede Zugangsdaten eine Bestätigung bei jedem Aufruf verlangst. Das verwandelt ein Designproblem in Bestätigungsmüdigkeit. Menschen bestätigen wiederholte, erwartbare Abfragen, ohne sie zu lesen. Trenne stattdessen die Builds, die keinen gemeinsamen Zugriff haben sollen, und verwende eine Freigabe pro Aufruf für Aktionen, bei denen ein Mensch den konkreten Nutzungszeitpunkt sehen muss.

Teste für ein Aktions-Gateway dieselbe Matrix an der Aktionsgrenze. Starte jede Binärdatei, führe jeweils eine Test-HTTP-Anfrage und einen Test-SSH-Befehl aus, falls beide Kanäle verwendet werden, und vergleiche dann Sitzungs- und Einzelaufruf-Eintrag. Die Aufzeichnungen sollten beantworten können, welche ausführbare Datei die Anfrage ausgelöst hat, welche Freigabe sie abdeckte und ob die Zugangsdaten eine weitere Bestätigung verlangten.

Paketmanager und Shims verbergen die ausführbare Datei

Alle Builds aussperren
Wenn der Tresor mit Secure Enclave und Touch ID gesperrt ist, wird jede Aktion abgelehnt.

Paketmanager installieren häufig stabile Einstiegspfade, die auf andere Orte zeigen. Ein Befehl unter /opt/homebrew/bin/agent-name kann ein symbolischer Link in ein versioniertes Cellar-Verzeichnis sein. Ein anderes Werkzeug kann einen JavaScript-, Python- oder Shell-Shim installieren, der eine Laufzeit auswählt und anschließend ein Paket aus einem Cache-Verzeichnis lädt.

Folge der Kette, bis du den Prozess erreichst, der die sensible Anfrage stellt. Diese Befehle helfen bei häufigen Fällen:

ls -l "$(command -v agent-name)"
readlink "$(command -v agent-name)" || true
head -n 40 "$(command -v agent-name)" 2>/dev/null || true

Unter macOS zeigt readlink möglicherweise nur eine Ebene. Der kleine Python-Auflöser aus dem ersten Abschnitt ist für das endgültige Ziel zuverlässiger. Wenn die Einstiegsdatei ein Skript ist, suche nach exec, Aufrufen von Laufzeiten, Pfaden heruntergeladener Binärdateien und Umgebungsvariablen, die den Release-Kanal auswählen.

Gehe nicht davon aus, dass eine Paketmanager-Version der gleichnamigen Version des Anbieters entspricht. Das Paket kann Patches anwenden, eine Binärdatei neu verpacken, aus dem Quellcode kompilieren oder eine andere Laufzeit starten. Behandle die installierte ausführbare Datei als das Objekt, das du freigibst, und bewahre die Paketinformationen nur als zusätzlichen Kontext auf.

Dieselbe Warnung gilt für IDE-Erweiterungen und Terminal-Integrationen. Ein grafischer Starter kann eine Kopie bündeln, während deine Shell eine andere verwendet. Teste jeden Einstiegspunkt, der einen Agenten starten kann. «Im Terminal wird korrekt nachgefragt» sagt nichts über eine Hintergrundaufgabe aus, die ein Editor gestartet hat.

Lokale Builds müssen als lokal erkennbar sein

Ein lokaler Build ist gerade deshalb nützlich, weil er sich von einem Release unterscheiden kann. Vielleicht enthält er einen Patch, ein ungeprüftes Dependency-Update, eine Compileränderung, ein Debug-Flag oder eine generierte Datei, die nie in das Artefakt des Anbieters gelangt ist. Er sollte nicht unbemerkt den Ruf des Release-Builds bei der Freigabe übernehmen.

Prüfe zuerst seinen Signaturstatus:

LOCAL="$HOME/src/agent/build/agent-name"
codesign --display --verbose=4 "$LOCAL" 2>&1 | sed -n '1,25p'
codesign --verify --strict --verbose=2 "$LOCAL" 2>&1
shasum -a 256 "$LOCAL"

Eine nicht signierte Ausgabe, eine Ad-hoc-Signatur und eine Entwicklungssignatur sind nicht dasselbe. Eine nicht signierte ausführbare Datei liefert einer Freigabeschicht weniger dauerhafte Identitätsnachweise. Eine Ad-hoc-Signatur kann eine Datei signiert erscheinen lassen, ohne sie mit einer Entwickleridentität zu verbinden. Eine Entwicklungssignatur weist auf einen Entwicklungskontext hin, macht die Datei aber nicht zu einem Release-Artefakt.

Die sicherste Standardeinstellung ist einfach: Lege lokale Binärdateien in ein eigenes Verzeichnis, gib ihnen einen sichtbar anderen Befehlsnamen, wenn du den Build kontrollierst, und verlange nach jeder Hashänderung eine neue Freigabe. Wenn du den Befehl nicht umbenennen kannst, mache den aufgelösten Pfad und den Status als lokaler Build in Runbook und Testausgabe deutlich.

Vermeide den verbreiteten Rat, jeden lokalen Build nur zur Verringerung der Abfragen mit demselben Zertifikat wie die Releases zu signieren. Dieser Rat ist beliebt, weil er die Entwicklung angenehmer macht. Er ist falsch, wenn deine Freigabemodell die Signaturautorität als sinnvolle Grenze verwendet. Du erweiterst damit die Release-Identität auf jede Maschine und jedes Skript, die auf dieses Zertifikat zugreifen können. Halte Release-Signaturmaterial aus beiläufigen lokalen Builds heraus, sofern dein Releaseprozess diese Aussage nicht aufrechterhalten kann.

Audit-Einträge müssen die spätere Rekonstruktion ermöglichen

Neue Prozesse genehmigen
Ein neuer Agentenprozess benötigt normalerweise bei seinem ersten Aufruf eine einmalige Sitzungsfreigabe.

Ein Freigabeeintrag, der nur «Agent freigegeben» sagt, ist schwacher Nachweis. Sechs Wochen später kannst du nicht erkennen, ob das freigegebene Programm aus dem stabilen Installer, dem Beta-Ordner, einem Paketmanager-Link oder einem lokalen Checkout stammte.

Bewahre für jeden Test und jede wichtige betriebliche Änderung folgende Fakten auf:

  • Startpfad und endgültig aufgelöster Pfad
  • Signaturkennung, Autorität oder Team sowie der Text des Designated Requirement
  • SHA-256-Hash und Anwendungsversion
  • Prozess-ID, Startzeit und Ergebnis der Sitzung
  • Ziel der Aktion und Ergebnis des einzelnen Aufrufs

Sallyport führt Agentenläufe in seinem Sitzungsprotokoll und einzelne Aktionen in seinem Aktivitätsprotokoll. Beide werden aus einem verschlüsselten, hashverketteten Auditprotokoll erzeugt. Die Offline-Prüfung sp audit verify kann feststellen, ob diese verschlüsselte Protokollkette noch gültig ist. Sie ergänzt aber keine Identitätsfelder, die du nie erfasst hast. Mache die Informationen zur ausführbaren Datei zum Ereigniskontext, solange du die Maschine noch untersuchen kannst.

Führe nach einer Änderung der Buildmatrix, dem Widerruf einer Sitzung und der Wiederholung des Überlappungstests eine Auditprüfung aus. Du willst zwei Dinge bestätigen: Das System hat die erwarteten getrennten Läufe aufgezeichnet, und die Protokollspur lässt sich weiterhin unabhängig prüfen. Eine intakte Kette beweist die Kontinuität der Aufzeichnung, nicht die Klugheit deiner ursprünglichen Gruppierungsentscheidung.

Mach daraus einen Regressionstest statt einer einmaligen Bereinigung

Mehrere Kopien kehren zurück. Jemand installiert eine Beta, um einen Fehler zu testen. Ein Paketmanager aktualisiert sich über Nacht. Ein Teammitglied teilt einen lokalen Build. Die stabile App aktualisiert sich an Ort und Stelle. Wenn du erst nach einem Vorfall testest, entdeckst du die Kollision möglicherweise erst, nachdem der Agent bereits Zugriff hat.

Bewahre ein kurzes Testskript auf, das für jeden möglichen Pfad einen Bericht mit Zeitstempel schreibt. Führe es nach Installationsänderungen, vor der Freigabe neuer Zugangsdaten mit hoher Wirkung und nach Änderungen an Shell-Startdateien oder Agenteneinstellungen des Editors aus.

#!/bin/zsh
set -eu

for candidate in \
  "/Applications/Agent.app/Contents/MacOS/agent-name" \
  "/opt/homebrew/bin/agent-name" \
  "$HOME/src/agent/build/agent-name"; do
  [[ -e "$candidate" ]] || continue
  echo "### $candidate"
  echo "resolved: $(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$candidate")"
  shasum -a 256 "$candidate"
  codesign --display --verbose=4 "$candidate" 2>&1 \
    | grep -E '^(Identifier|TeamIdentifier|Authority|CDHash)=' || true
  codesign --display -r- "$candidate" 2>&1 \
    | grep 'designated' || true
  echo
 done

Vergleiche den Bericht mit der zuletzt geprüften Kopie. Ein geänderter Hash ist nach einem Update erwartbar. Eine geänderte Signaturautorität, Kennung oder ein geändertes Designated Requirement verlangt eine ausdrückliche Entscheidung, bevor du die Änderung als normales Update behandelst. Ein neuer Pfad, der in type -a vor dem Release-Pfad erscheint, verdient dieselbe Aufmerksamkeit.

Der praktische Maßstab ist klar: Eine Freigabe sollte für die ausführbare Gruppe gelten, die du beabsichtigt hast, und deine Nachweise sollten zeigen, warum diese Gruppe einen Build einschließt und einen anderen ausschließt. Lege stabile, Beta-, Paketmanager- und lokale Kopien auf denselben Mac, lass einen Prozess freigegeben laufen und zwinge jede andere Kopie zu einer Anfrage. Wenn dich das Ergebnis überrascht, ist die Freigabegrenze zu ungenau.

FAQ

Kann ich einer Agentenfreigabe vertrauen, die nur den Prozessnamen anzeigt?

Nein. Ein Prozessname sagt kaum etwas darüber aus, wer die ausführbare Datei erstellt hat oder ob sie dem Programm entspricht, das du freigeben wolltest. Behandle den Namen als menschliche Bezeichnung und prüfe anschließend Pfad, Signatur, Designated Requirement und Hash der ausführbaren Datei.

Sollten stabile und Beta-Versionen eines Agenten unter macOS dieselbe Freigabe teilen?

Normalerweise nicht. Stabile und Beta-Builds können dieselbe Bundle-ID, denselben Befehlsnamen und dieselbe Signaturautorität verwenden, besonders wenn beide vom gleichen Anbieter stammen. Teste sie als getrennte Kandidaten, bevor du entscheidest, dass eine Freigabe für beide gelten soll.

Gilt eine Installation über einen Paketmanager als eigene Agentenidentität?

Eine Homebrew-Installation ist nicht automatisch sicherer oder klarer getrennt als ein direkter Download. Entscheidend ist, welche ausführbare Datei deine Shell startet und welche Codesignatur und welchen Hash sie nach der Installation besitzt.

Sollte ich eine lokal erstellte Agenten-Binärdatei freigeben?

Ein lokaler Build sollte normalerweise eine eigene Prüfung auslösen, sofern du seiner Signaturidentität und seinem Buildprozess nicht bewusst vertraust. Eine Ad-hoc-Signatur, eine Entwicklungssignatur oder eine nicht signierte ausführbare Datei bietet eine ganz andere Sicherheit als ein veröffentlichter Build.

Wie finde ich jede Kopie eines Agentenbefehls auf meinem Mac?

Beginne mit type -a agent-name und prüfe anschließend jeden gefundenen Pfad mit codesign und shasum. Führe das in genau der Terminalumgebung aus, die den Agenten startet, denn PATH-Reihenfolge und Shell-Funktionen können das Ergebnis verändern.

Was ist ein Designated Requirement bei der Codesignierung unter macOS?

Ein Designated Requirement beschreibt die Bedingungen, anhand derer macOS signierten Code bei Aktualisierungen als dasselbe Programm erkennt. Es enthält häufig eine Signaturkennung und eine Signaturautorität. Damit eignet es sich für Kontinuität, kann aber zu weit gefasst sein, wenn du Release-Kanäle voneinander trennen willst.

Reicht die Codesignatur-Autorität aus, um eine ausführbare Datei zu identifizieren?

Eine Codesignatur-Autorität zeigt, wer die ausführbare Datei signiert hat. Sie beweist nicht, dass zwei Dateien Byte für Byte identisch sind. Wenn du Builds desselben Signierers unterscheiden musst, kombiniere sie daher mit dem Hash der ausführbaren Datei.

Wie teste ich, ob eine Freigabe die falsche ausführbare Datei abdeckt?

Der praktische Test ist einfach: Lass eine freigegebene Kopie laufen, starte die andere und prüfe, ob die Freigabegrenze wie vorgesehen reagiert. Wiederhole den Test nach dem Widerruf der ersten Sitzung und nach einer Änderung der PATH-Reihenfolge.

Wann sollte ich für jeden Agentenaufruf eine Freigabe verlangen?

Verwende eine Bestätigung pro Aufruf für Zugangsdaten, die Produktionsdaten ändern, Kundendaten offenlegen oder Systeme außerhalb deiner normalen Entwicklungsumgebung erreichen können. Eine Sitzungsfreigabe passt besser zu einem geprüften Agentenlauf, dessen erlaubte Aktionen trotzdem einen begrenzten Schaden verursachen können.

Was sollte ich für jeden freigegebenen Agenten-Build dokumentieren?

Führe für jeden freigegebenen Build ein kleines Inventar mit Pfad der ausführbaren Datei, Installationsquelle, Version, Signaturkennung, Team oder Autorität, Designated Requirement und SHA-256-Hash. Aktualisiere es nach der Installation einer Beta, einem Paketmanager-Update oder einem neuen Build aus dem Quellcode.

Sallyport

Sallyport führt API-Aufrufe und SSH-Befehle für Ihren KI-Agenten aus. Die Schlüssel bleiben in einem lokalen Tresor auf Ihrem Mac; Sie geben jeden Lauf frei, und jede Aktion landet in einem versiegelten Journal.

© 2026 Sallyport · Open Source unter Apache-2.0 · Oleg Sotnikov