8 Min. Lesezeit

Können doppelte Gateway-Instanzen Ihre Audit-Historie aufteilen?

Doppelte Gateway-Instanzen können widersprüchliche Zuständigkeiten und verborgene Historie erzeugen. Teste Tresorbesitz, Freigaben, Widerrufe und Audit-Integrität sicher.

Können doppelte Gateway-Instanzen Ihre Audit-Historie aufteilen?

Ein kopiertes App-Bundle ist keine harmlose Möglichkeit, ein zweites lokales Gateway zu erstellen. Es testet, ob die Software eine einzige Zuständigkeit für Zugangsdaten, Freigaben, Widerrufe und Nachweise bewahren kann, wenn macOS ihr zwei plausible Anspruchsteller präsentiert.

Der gefährliche Fehler ist nicht immer ein Absturz. Ein Absturz ist laut. Der leisere Fehler besteht aus zwei Prozessen, die beide gesund wirken, beide Agentenanfragen annehmen und beide genügend Nachweise hinterlassen, um die Person, die sie gestartet hat, zu beruhigen. Dann bringt eine Änderung an den Zugangsdaten, ein Widerruf oder eine Vorfallprüfung die Aufspaltung ans Licht: Ein Prozess wusste etwas, das der andere nicht wusste.

Sallyport ist als eine signierte, dauerhaft laufende macOS-Menüleisten-App mit einem eingebetteten Tresorkern konzipiert. Deshalb sollte das gleichzeitige Starten von Stable-, Beta- und kopierten Bundles als gezielter Test von Parallelität und Identität behandelt werden, nicht als normaler Betrieb. Der Test sollte eine eng gefasste Antwort liefern: Weist das System das Duplikat zurück, koordiniert es die Instanzen sicher oder lässt es sie zu, während ein maßgeblicher Tresor und eine überprüfbare Historie erhalten bleiben?

Zwei Bundles bedeuten nicht automatisch zwei Identitäten

Der im Finder angezeigte Name ist in diesem Experiment das schwächste Identitätssignal. Sallyport.app, Sallyport Beta.app und Sallyport Copy.app können für einen Menschen wie drei unabhängige Anwendungen aussehen und trotzdem dieselbe Bundle-ID und dieselbe Signaturidentität in ihren Bundles tragen.

Apple beschreibt die Bundle-ID als Kennung, die macOS zur Identifikation auf App-Ebene verwendet. Die Dokumentation zur Codesignierung erklärt außerdem, dass eine Designated Requirement dem System ermöglicht, Code über Aktualisierungen hinweg als dieselbe Anwendung zu erkennen. Diese Konzepte sind nützlich, aber keines beantwortet die entscheidende Frage vollständig. Dass macOS eine Identität erkennt, beweist nicht, dass zwei laufende Prozesse ihren Zustand sicher verwalten.

Halte zunächst fest, was du tatsächlich gestartet hast. Tu das, bevor du den Tresor öffnest, einen Agenten verbindest oder etwas freigibst.

APP_A="/Applications/Sallyport.app"
APP_B="$HOME/Desktop/Sallyport Beta.app"

for app in "$APP_A" "$APP_B"; do
  echo "=== $app ==="
  plutil -p "$app/Contents/Info.plist" | grep -E 'CFBundleIdentifier|CFBundleShortVersionString|CFBundleVersion'
  codesign -dvv "$app" 2>&1 | grep -E 'Identifier=|TeamIdentifier=|Authority='
  codesign -d -r- "$app" 2>&1 | grep 'designated =>'
done

Wichtiger als der genaue Text ist die Form der Ausgabe:

=== /Applications/Sallyport.app ===
"CFBundleIdentifier" => "..."
"CFBundleShortVersionString" => "..."
Identifier=...
TeamIdentifier=...
designated => identifier "..." and anchor ...

Bewahre dieses Artefakt zusammen mit dem Testprotokoll auf. Wenn die beiden unveränderten Bundles dieselbe Kennung und dieselbe Designated Requirement melden, bezeichne sie als zwei Kopien derselben Codeidentität. Wenn sie sich unterscheiden, handelt es sich um getrennte Codeidentitäten. Verwende Bezeichnungen wie «Stable» und «Beta» nicht als Ersatz für eine dieser Tatsachen.

Es gibt noch eine zweite Unterscheidung, die Teams oft verwischen: Eine Codeidentität ist keine Speicheridentität. Von zwei Prozessen mit derselben Designated Requirement kann erwartet werden, dass sie auf dasselbe geschützte Material zugreifen. Zwei Prozesse mit unterschiedlichen Requirements können getrennte Systemberechtigungen erhalten. Keine dieser Möglichkeiten sagt aus, ob sie einen verschlüsselten Tresor sicher gemeinsam nutzen oder an eine Audit-Kette anhängen können. Die Zuständigkeit für den Speicher musst du separat testen.

Eine aufgeteilte Audit-Historie ist schlimmer als ein unvollständiges Log

Ein unvollständiges Journal zeigt, dass Nachweise fehlen. Ein aufgeteiltes Journal kann zwei intern konsistente Geschichten erzählen, in denen jeweils die Aufzeichnungen des anderen Prozesses fehlen. Das verlangsamt die Vorfallprüfung und kann dazu führen, dass eine widerrufene Sitzung aus Sicht eines Prozesses weiterhin gültig erscheint.

Für ein Aktions-Gateway muss das Journal im Nachhinein konkrete Fragen beantworten:

  • Welcher Agentenprozess hat die Aktion angefordert?
  • Welcher Gateway-Prozess hat sie freigegeben oder abgelehnt?
  • Welche Zugangsdatenreferenz wurde verwendet, ohne das Geheimnis offenzulegen?
  • Hat ein Mensch die Sitzung oder den einzelnen Aufruf freigegeben?
  • Erfolgte der Widerruf vor oder nach der Aktion?

Wenn Prozess A und Prozess B jeweils eine unabhängige Sequenz schreiben, können beide Sequenzen für sich korrekt geprüft werden. Das genügt nicht. Die Prüfung einer kryptografischen Kette zeigt, dass die Datensätze innerhalb dieser Kette nicht unbemerkt verändert wurden. Sie beweist nicht von selbst, dass ein anderer legitimer Schreiber nicht an anderer Stelle eine separate Kette begonnen hat.

Darum ist die Unterscheidung zwischen Manipulationsnachweis und Vollständigkeit wichtig. Eine Hash-Kette schützt die Beziehung zwischen den Datensätzen, die in dieser Kette vorhanden sind. Vollständigkeit braucht eine klare Zuständigkeitsregel, einen einzigen Anhängepunkt oder dauerhafte Nachweise für jeden akzeptierten Zweig und seine Zusammenführung. Wenn das falsch umgesetzt ist, kann ein Bediener die Prüfung erfolgreich durchführen und trotzdem die Hälfte der Aktionen übersehen.

Das Thema geht über Logs hinaus. Eine aufgeteilte Audit-Historie folgt oft einer aufgeteilten Zuständigkeit:

  • Ein Prozess hält den Tresor für gesperrt, während ein anderer eine entsperrte Sitzung hat.
  • Ein Prozess widerruft einen Agentenlauf, während ein anderer ihn weiterhin akzeptiert.
  • Ein Prozess zeichnet eine Freigabe pro Aufruf auf, während der andere keinen Grund sieht zu fragen.
  • Ein Prozess schreibt das endgültige Aktionsergebnis, während der andere nur die Anfrage erfasst.

Beurteile den Test nicht danach, ob beide Kopien einen HTTP-Aufruf oder SSH-Befehl ausführen können. Ein erfolgreicher Aufruf beweist nur, dass ein Pfad vorhanden ist. Der Test ist bestanden, wenn ein späterer Prüfer die vollständige Aktionshistorie rekonstruieren kann, ohne zu erraten, welche Kopie den fehlenden Zustand besaß.

Lege den Vertrag für die Zuständigkeit fest, bevor du den Wettlauf startest

Ein Test mit doppelten Instanzen ohne erwartete Invarianten liefert nur Anekdoten. Schreibe zuerst den Vertrag auf und versuche dann, ihn zu brechen.

Für lokale Gateway-Kopien gibt es drei vertretbare Verträge.

  1. Exklusive Zuständigkeit. Der erste Prozess besitzt Tresor und Journale. Spätere Kopien verweigern den Betrieb, holen die erste App in den Vordergrund oder beenden sich mit einer klaren Begründung.
  2. Ein aktiver Prozess mit Übergabe. Ein späterer Start erkennt den Besitzer und bittet ihn, die gewünschte Arbeit auszuführen. Der neue Prozess entsperrt, genehmigt oder erweitert nicht unabhängig.
  3. Koordinierte Zuständigkeit mehrerer Prozesse. Mehr als ein Prozess kann laufen, aber alle verwenden ein bewusst entwickeltes Protokoll für den gemeinsamen Zustand, das atomare Tresoränderungen und eine einzige prüfbare Ereignisreihenfolge bewahrt.

Der erste Vertrag ist für eine Desktop-Anwendung mit besonders wichtigen Zuständen meist am einfachsten zu beurteilen. Der dritte kann gültig sein, bringt aber eine deutlich größere Beweislast mit sich. «Beide zeigen auf denselben Ordner» ist kein Koordinationsprotokoll.

Schreibe die erwarteten Ergebnisse vor dem Test in eine Tabelle. Formuliere jedes Ergebnis so, dass es beobachtbar ist.

BedingungErwartetes VerhaltenAufzubewahrender Nachweis
Stable besitzt einen entsperrten TresorDer Beta-Start wird abgelehnt, übergeben oder koordiniertUI-Zustand, Prozessliste, Gateway-Antwort
Stable besitzt einen gesperrten TresorKeine Kopie darf eine Aktion ausführen, bevor die Tresorsperre geöffnet istAufzeichnung der abgelehnten Anfrage und lokaler Zustand
Stable hat eine freigegebene AgentensitzungEin neuer Agentenprozess braucht eine eigene SitzungsentscheidungFreigabeaufzeichnungen mit Prozessidentität
Für eine Zugangsdatenreferenz ist eine Freigabe pro Aufruf eingestelltJede Nutzung fragt nach, unabhängig davon, welche Kopie sie erhältEine Freigabeaufzeichnung pro versuchtem Aufruf
Ein Lauf wird in einem Prozess widerrufenKein Prozess darf diesen Lauf fortsetzenWiderrufsereignis und abgelehnter Folgeaufruf
Beide Kopien fordern gleichzeitig eine harmlose Aktion anDie Historie bleibt vollständig und kann geprüft werdenGeordnete Aktivitätsaufzeichnungen und Audit-Prüfung

Die Formulierung ist wichtig. «Die Kopien sollten sich nicht in die Quere kommen» ist nicht testbar. «Ein kopiertes Bundle kann keine erfolgreiche Aktionsantwort zurückgeben, nachdem ein bestehender Besitzer denselben Agentenlauf widerrufen hat» ist testbar.

Trenne außerdem das Verhalten des Produkts vom Verhalten des Testaufbaus. Dein Shell-Skript kann versehentliche Doppelstarts verhindern, aber das beweist nicht, dass die App sie verhindert. Dein Reverse Proxy kann Anfragen serialisieren, aber das beweist nicht, dass der lokale Tresor gleichzeitige Anfragen korrekt verarbeitet. Lass nicht den Testaufbau den Fehler lösen, den du finden wolltest.

Starte unveränderte Kopien, bevor du veränderte Artefakte testest

Das saubere Experiment beginnt mit unveränderten App-Bundles. Kopiere ein Anwendungs-Bundle, ohne Dateien darin zu ändern, lege die Kopien an getrennten gewöhnlichen Orten ab und halte jeden Pfad fest. Wenn du zuerst eine ausführbare Datei oder die Info.plist veränderst, wird die Codesignatur oft ungültig. Dann testest du nicht mehr doppelte Zuständigkeit, sondern die Signaturprüfung.

Apples TN3127 erklärt, warum diese Grenze wichtig ist: macOS verwendet Designated Requirements, um zu entscheiden, ob Code eine etablierte Identität erfüllt. Wenn du ein Bundle änderst und seine Signatur nicht mehr gültig ist, kann jede Ablehnung korrekt sein, sagt aber nichts über doppelte Zuständigkeit zwischen gültigen Builds aus.

Verwende ein kleines Startprotokoll. Es sollte nur Fakten enthalten, die du beobachten kannst:

Test ID: duplicate-owner-01
Build A path: /Applications/Sallyport.app
Build B path: /Users/tester/Desktop/Sallyport Beta.app
Bundle IDs: [recorded value A] / [recorded value B]
Designated requirements: [recorded value A] / [recorded value B]
Launch order: A first, B second
Vault state before launch: locked
Agent process IDs: [record after start]
Expected contract: exclusive ownership

Starte dann A, warte, bis der Leerlaufzustand erreicht ist, und starte B. Halte das Ergebnis fest, bevor du etwas anderes tust. Eine Ablehnung muss so eindeutig sein, dass der Bediener weiß, welcher bestehende Prozess den Zustand besitzt. Ein stilles Beenden erzeugt Supportanfragen und verleitet dazu, so lange erneut zu starten, bis ein Wettlauf entsteht.

Prüfe die tatsächliche Trennung der Prozesse mit dem Betriebssystem, nicht anhand der App-Fenster. Ein zweites Fenster kann zum selben Prozess gehören, während ein Hintergrundhelfer einen zweiten Prozess erzeugen kann, obwohl nur ein sichtbares Menüleistensymbol vorhanden ist.

pgrep -alf 'Sallyport|sp mcp|sp-ssh'
ps -axo pid,ppid,start,command | grep -E 'Sallyport|sp mcp|sp-ssh' | grep -v grep

Behandle die Ausgabe als Zeitachsen-Artefakt. Speichere sie sofort nach jeder Startphase. Füge nach Möglichkeit die IDs der übergeordneten Prozesse ein. Sie helfen zu erklären, ob die zweite Aktion von einem unabhängigen App-Prozess, einem vom Agenten gestarteten Shim oder einem untergeordneten Helfer kam.

Verwende dafür keine Produktionszugangsdaten. Richte HTTP-Anfragen an einen eigenen Endpunkt, der eine harmlose Methode oder einen kontrollierten Testdienst akzeptiert. Verwende für SSH ein eigenes Konto mit eingeschränkten Befehlen oder einen Host ohne Produktionszugriff. Du testest Prozesszuständigkeit und Audit-Verhalten. Ein schädlicher Endpunkt ist nicht nötig, um herauszufinden, ob eine zweite Kopie handeln kann.

Das Tresortor muss einen sichtbaren Besitzer haben

SSH-Schlüssel außerhalb der Agenten halten
Leite SSH-Befehle über Sallyports gebündelten Helfer sp-ssh, statt SSH-Schlüssel an Agenten weiterzugeben.

Das Tresortor ist nur dann eine absolute Grenze, wenn jeder Aktionspfad dasselbe Tor erreicht. Wenn ein Prozess entsperrt bleiben kann, nachdem ein anderer Prozess sperrt, beendet wird oder den Zugriff verliert, beschreibt «gesperrt» nur ein Fenster und nicht den tatsächlichen Systemzustand.

Teste diese Abfolge zuerst mit einer harmlosen HTTP-Aktion:

  1. Starte Kopie A mit gesperrtem Tresor.
  2. Verbinde einen Agentenprozess über den lokalen MCP-Shim und versuche die harmlose Aktion. Erwarte eine Ablehnung.
  3. Entsperre A über die normale lokale Interaktion und wiederhole die Aktion. Zeichne Ergebnis und Aktivitätseintrag des erfolgreichen Aufrufs auf.
  4. Starte Kopie B, während A verfügbar bleibt. Entsperre B noch nicht.
  5. Lass denselben Agentenprozess und einen neuen Agentenprozess versuchen, dieselbe Aktion über Bs erreichbaren Pfad auszuführen, sofern ein solcher existiert.
  6. Sperre A oder beende A und wiederhole die Anfragen mit beiden Agenten.

Das erwartete Ergebnis hängt vom Vertrag für die Zuständigkeit ab. Das unsichere Ergebnis lässt sich jedoch klar benennen: B führt die Aktion aus, weil es eine Berechtigung behalten oder unabhängig erworben hat, die der Mensch beim Sperren von A nicht sehen konnte.

Hier scheitert eine verbreitete Empfehlung: «Teilt einfach den entsperrten Zustand, damit Beta nicht ständig nachfragt.» Menschen empfehlen das, weil wiederholte lokale Authentifizierung während der Entwicklung lästig ist. Es ist falsch, sofern der gemeinsame Zustand keinen festgelegten Besitzer, keine klare Lebensdauer und keinen Widerrufspfad hat, den jeder Prozess vor dem Handeln beobachtet. Ein bequemes Dialogfenster ist es nicht wert, einen unsichtbaren zweiten Entsperrzustand zu schaffen.

Das hardwaregeschützte Tresormodell schafft eine nützliche Testgrenze. Während der Tresor gesperrt ist, sollte ein Agent eine Ablehnung erhalten, nicht ein Platzhaltergeheimnis, eine teilweise vorbereitete Anfrage oder eine in die Warteschlange gestellte Aktion, die später nach dem Entsperren ausgeführt wird. Ein Aktions-Gateway sollte eine freigegebene Aktion selbst ausführen und ihr Ergebnis zurückgeben. Es sollte dem Agenten keine Zugangsdaten überlassen, während der Mensch noch einen lokalen Zustand klären muss.

Zeichne sowohl die Aktionsantwort als auch die Nachweise im Journal auf. Eine Ablehnung, die aus der Historie verschwindet, erschwert die spätere Fehlersuche unnötig. Ein Erfolg, der ohne vorherige Entsperr- oder Freigabeaufzeichnung erscheint, ist noch problematischer.

Die Sitzungsfreigabe muss an einen Prozess gebunden sein, nicht an ein Etikett

Eine Berechtigung pro Sitzung soll einem Menschen ermöglichen, einen bestimmten Agentenlauf zu beurteilen. Sie verliert ihre Bedeutung, wenn die Berechtigung von einem Prozess auf einen anderen übergeht, weil beide Läufe einen ähnlichen Namen haben, aus demselben Terminal gestartet wurden oder über dasselbe kopierte Bundle verbunden sind.

Die Freigabeaufzeichnung sollte einem Bediener beantworten, welche ausführbare Datei angefragt hat, wer sie signiert hat, wann dieser Prozess begann und wann seine Berechtigung endete. Die Codesignatur des Prozesses ist besonders nützlich, weil ein Terminalbefehl allein den dahinterstehenden Code nicht identifiziert.

Führe diesen Test mit zwei bewusst getrennten Agentenprozessen durch. Verwende nicht denselben Shell-Prozess zweimal und bezeichne ihn dann als zwei Agenten.

# Terminal 1
sp mcp

# Terminal 2
sp mcp

Die Befehle sind absichtlich schlicht. Entscheidend ist, dass sie aus getrennten Agentenprozessen in deinem Testaufbau stammen und jeder anschließend einen harmlosen Aufruf sendet. Gib die erste Sitzung frei und lasse die zweite unbeantwortet. Wenn dein Aufbau Prozessdetails auf der Freigabekarte anzeigt, erfasse die angezeigte Berechtigung und vergleiche sie mit dem gestarteten Prozess.

Teste anschließend diese Übergänge:

  • Beende den freigegebenen Agentenprozess und starte einen Ersatzprozess mit demselben Befehl.
  • Starte oder aktiviere ein kopiertes Gateway, während die erste Sitzung freigegeben bleibt.
  • Widerrufe den ersten Lauf im Sitzungsjournal.
  • Lass beide Prozesse noch eine harmlose Anfrage senden.

Die erwartete Regel ist einfach: Eine Freigabe gehört zu einem Lauf, bis dieser Lauf endet, und ein Widerruf beendet die Berechtigung dieses Laufs überall. Ein Ersatzprozess darf die Freigabe nicht allein deshalb übernehmen, weil er vertraut aussieht. Ein kopiertes Gateway darf dieselbe Agentenverbindung nicht als Erlaubnis verstehen, eine Entscheidung zu umgehen, die der andere Prozess verlangen würde.

Verwechsle die Sitzungsfreigabe nicht mit Schlüsseln pro Aufruf. Eine Sitzungsfreigabe beantwortet, ob dieser Agentenprozess das Gateway während seines Laufs verwenden darf. Ein Schlüssel pro Aufruf beantwortet, ob jede Nutzung dieser bestimmten Zugangsdaten eine neue menschliche Entscheidung braucht. Das eine betrifft die Lebensdauer des Aufrufers, das andere die Sensibilität der Zugangsdaten. Wenn du beides in deinen Testnotizen vermischst, wirst du das Ergebnis falsch lesen.

Eine Freigabe pro Aufruf macht verborgene doppelte Pfade sichtbar

Eine vollständige Audit-Historie bewahren
Sitzungen und einzelne Aufrufe werden aus einem verschlüsselten, hashverketteten Audit-Log dargestellt.

Eine Zugangsdatenreferenz, die bei jeder Nutzung eine Freigabe verlangt, eignet sich gut als Test für doppelte Instanzen, weil die Software dabei jede Aktion einzeln berücksichtigen muss. Verwende eine eigene Testreferenz oder ein eigenes SSH-Ziel, stelle die Freigabe pro Aufruf ein und sende gleichzeitig harmlose Anfragen über die beiden möglichen Pfade.

Die Frage lautet nicht: «Habe ich zwei Dialoge erhalten?» Zwei Dialoge können korrekt sein oder zeigen, dass beide Kopien unabhängige Berechtigungen geschaffen haben. Entscheidend ist, ob jede abgeschlossene Aktion genau eine zugehörige Freigabe hat und keine Kopie die Freigabe der anderen wiederverwenden kann.

Führe während des Tests ein kleines Ereignisprotokoll:

ZeitGateway-ProzessAgenten-PIDAnfrage-IDMenschliche EntscheidungErgebnis
10:03:01A4128req-a1freigegebenerfolgreich
10:03:02B4194req-b1abgelehntabgelehnt
10:03:04A4128req-a2freigegebenerfolgreich

Verwende Anfrage-IDs, die dein Testendpunkt oder dein Testaufbau erzeugt. Verlasse dich nicht auf die Reihenfolge, in der Fenster erschienen sind. Die Desktop-Planung kann sichtbare Dialoge umordnen, und ein HTTP-Ergebnis kann nach einer späteren Anfrage zurückkehren.

Ein schlechter Ausgang wirkt zunächst oft ordentlich: Du gibst Anfrage A in Kopie A frei und stellst dann fest, dass Kopie B Anfrage B ohne eigene Freigabe abschließen kann. Das zeigt, dass der Freigabestatus eine Grenze ohne Entscheidung des Bedieners überschritten hat. Auch der umgekehrte Fehler ist ernst: Du gibst B frei, aber das Ergebnis wird ohne Erklärung im Aktivitätsstrom von A aufgezeichnet.

Wiederhole den Paralleltest nach dem Sperren des Tresors, nach dem Beenden einer Kopie und nach dem Widerruf des ersten Agentenlaufs. Diese Übergänge finden veraltete Zustände im Speicher. Besonders aufschlussreich sind Fehler nach einer Zustandsänderung, wenn ein Prozess seine Sicht aktualisiert hat und der andere nicht.

Die Audit-Prüfung braucht einen Beweis vorher und nachher

Ein Testbericht mit dem Satz «Das Log sah gut aus» ist kein Nachweis. Erfasse eine Ausgangsbasis, führe eine kontrollierte Gruppe von Aktionen aus, prüfe danach und vergleiche erwartete mit beobachteten Datensätzen.

Das für dieses Gateway beschriebene Audit-Design hat einen Vorteil: Dasselbe blind beschreibbare, verschlüsselte und hashverkettete Log wird sowohl im Sitzungsjournal als auch im Aktivitätsjournal dargestellt. Die Journale sollten daher zwei Ansichten einer einzigen Historie sein, nicht zwei unabhängig gepflegte Aufzeichnungen, die einander nur ähneln.

Beginne mit einem leeren oder klar abgegrenzten Testzeitraum. Notiere die Startzeit und erzeuge dann eine bekannte Sequenz: Ablehnung bei gesperrtem Tresor, freigegebene Sitzungsaktion, pro Aufruf freigegebene Aktion, Ablehnung pro Aufruf, Widerruf der Sitzung und abgelehnte Aktion nach dem Widerruf. Halte die Sequenz kurz genug, um jedes Ereignis zuordnen zu können.

Führe danach die Offline-Prüfung aus:

sp audit verify

Bewahre die vollständige Befehlsausgabe auf, einschließlich eines Exit-Status ungleich null, falls die Prüfung fehlschlägt. Der Prüfer sollte keinen Tresorzugriff benötigen, um die Chiffretextkette zu prüfen. So kann ein Ermittler die Integrität prüfen, ohne zuerst den Zugangsdaten-Tresor zu entsperren. Genau das brauchst du, wenn ein Test mit doppelten Prozessen schiefgegangen ist.

Die Prüfung allein ist nur der erste Schritt. Vergleiche drei Ansichten:

  1. Dein externes Testprotokoll mit jeder Anfrage-ID und dem erwarteten Ergebnis.
  2. Das Sitzungsjournal mit Freigaben, Laufenden und Widerrufen.
  3. Das Aktivitätsjournal mit jedem Aktionsversuch und Ergebnis.

Jedes Ereignis im Testprotokoll sollte der passenden Journalansicht zugeordnet werden können. Jedes Journalereignis im abgegrenzten Testzeitraum sollte auf etwas zurückverweisen, das du bewusst erzeugt hast. Untersuche zusätzliche Datensätze, selbst wenn die Kette gültig ist. Eine unerwartet erfolgreiche Aktion kann ein Wiederholungsversuch, eine in der Warteschlange verbliebene Anfrage oder ein Hinweis darauf sein, dass ein zweiter Prozess noch aktiv war, obwohl du dachtest, er sei beendet.

Wenn zwei unabhängige Ketten geprüft werden können, melde das als Fehler der Vollständigkeit der Historie, sofern das dokumentierte Design für mehrere Prozesse keine übergeordnete Beziehung und keine deterministische Zusammenführung erfasst. Löse das nicht, indem du exportierte Logs nach dem Test aneinanderhängst. Eine manuelle Zusammenführung erzeugt einen Bericht, aber keine Audit-Historie.

Das Wiederherstellungsverhalten entscheidet, ob ein Fehler zur Sicherheitsstörung wird

Bei sensiblen Schlüsseln erneut fragen
Markiere einen Schlüssel für die Freigabe pro Aufruf, wenn jede einzelne Nutzung eine menschliche Entscheidung erfordert.

Du solltest unterbrochene Zuständigkeitsversuche erwarten. Menschen beenden Beta-Versionen gewaltsam. Laptops gehen in den Ruhezustand. Ein Testaufbau beendet einen Prozess zwischen einer Freigabe und dem Ergebnis einer Aktion. Die Anwendung muss damit umgehen, ohne dass ein verlassener Besitzer die Arbeit dauerhaft blockiert oder ein neuer Besitzer annimmt, es sei keine Aktion erfolgt.

Teste mindestens vier Unterbrechungspunkte:

  • Beende Kopie A, nachdem sie eine Anfrage erhalten, aber bevor sie eine Freigabe bekommen hat.
  • Beende Kopie A nach der Freigabe, aber bevor die externe Aktion abgeschlossen ist.
  • Beende Kopie A, nachdem die Aktion abgeschlossen ist, aber bevor das Ergebnis für den Agenten sichtbar wird.
  • Starte Kopie B unmittelbar nach jeder Unterbrechung.

Schreibe für jeden Fall die sichere Wiederherstellungsregel auf, bevor du ihn durchführst. Eine vernünftige Regel könnte sein, dass B die Arbeit verweigert, bis festgestellt wurde, dass A beendet ist und der dauerhafte Zustand wiederhergestellt wurde. Eine andere Möglichkeit wäre, dass B nur aus festgeschriebenen Audit-Datensätzen fortsetzt und eine ungewisse Aktion als unbekannt markiert, statt Erfolg oder Misserfolg zu behaupten. Die richtige Regel hängt von der Implementierung ab, aber Raten ist niemals akzeptabel.

Verbirg Ungewissheit nicht. Externe Systeme können eine HTTP-Anfrage oder einen SSH-Befehl abschließen, während der lokale Prozess beendet wird. Wenn das Gateway nicht beweisen kann, ob die Operation abgeschlossen wurde, sollte es diese Unklarheit in den Nachweisen bewahren. Eine Wiederholung eines unbekannten Schreibvorgangs kann eine zweite reale Aktion auslösen. Zu behaupten, die erste habe nie stattgefunden, erzeugt eine falsche Audit-Geschichte.

Auch der sofortige Widerruf muss hier genau geprüft werden. Widerrufe einen Agentenlauf, beende unmittelbar danach den aktuellen Besitzer, starte eine Kopie und versuche mit diesem Agenten dieselbe Aktion. Wenn der Ersatzprozess das Fehlen des Zustands im Speicher als neue Sitzung behandelt, war der Widerruf nicht dauerhaft genug. Ein Widerruf, der nur funktioniert, solange ein Prozess lebt, ist bei einem Ausfall nicht verlässlich.

Halte Stable- und Beta-Tests getrennt, sofern das Teilen nicht bewusst vorgesehen ist

Stable- und Beta-Versionen verleiten Teams zu einem beiläufigen Nebeneinander, weil beide nützlich sind. Stable führt echte Arbeit aus, Beta braucht realistischen Druck. Wenn beide ohne klaren Kompatibilitätsvertrag gegen denselben Tresor und dieselben Journale laufen, erhältst du die Risiken des Betriebs mit der Beobachtbarkeit eines Experiments.

Verwende eine von zwei Anordnungen. Die sicherere Variante gibt Beta einen eigenen Test-Tresor, eigene Testzugangsdaten, eigene Testagenten und einen getrennten Nachweissatz. So kannst du das Verhalten der Beta testen, ohne dass ein experimenteller Prozess Teil der Produktionshistorie wird.

Die schwierigere Variante lässt Stable und Beta bewusst denselben Zustand teilen. Wähle sie nur, wenn die versionsübergreifende Kontinuität selbst Gegenstand des Tests ist. Teste dann Versionsunterschiede in beide Richtungen: Stable besitzt den Zustand und danach startet Beta, Beta besitzt den Zustand und danach startet Stable, ein Prozess führt ein Upgrade durch, während der andere geöffnet bleibt, und ein Prozess führt ein Rollback durch, nachdem der andere neue Historie geschrieben hat. Halte fest, ob jeder Übergang abgelehnt, übergeben oder koordiniert wird.

Für Sallyport bietet die feste Entscheidungskette einen nützlichen Rahmen für die Abnahme: Das Tresortor bleibt absolut, ein neuer Agentenprozess erhält standardmäßig seine eigene Sitzungsfreigabe und Zugangsdatenreferenzen mit Freigabe pro Aufruf fragen bei jeder Nutzung erneut. Die Implementierung kann exklusive Zuständigkeit oder eine sichere Übergabe wählen, darf diese Kontrollen aber nicht stillschweigend abschwächen, damit sich zwei Bundles bequem anfühlen.

Beende den Test mit einer klaren Aussage, die ein anderer Ingenieur hinterfragen kann: Welcher Prozess besaß den Tresor, was geschah beim Auftauchen einer weiteren Kopie, überschritt eine Aktion eine Freigabe- oder Widerrufsgrenze und deckte eine Offline-Prüfung jedes erzeugte Ereignis ab? Wenn die Antwort davon abhängt, welches Fenster du zufällig beobachtet hast, wiederhole den Test. Die Nachweise reichen noch nicht aus.

FAQ

Ist es sicher, zwei Kopien eines lokalen KI-Aktions-Gateways auszuführen?

Betrachte dies als Test der Zuständigkeit für den Zustand, nicht als kosmetischen Test. Starte Kopien nur in einer isolierten Testumgebung, halte ihre Prozessidentitäten und Speicherorte sichtbar und mache jede Aktion harmlos. Der Test ist erst bestanden, wenn du einen maßgeblichen Tresor und eine vollständige, überprüfbare Historie der erzeugten Aktionen nachweisen kannst.

Sollte eine Beta-Version den Tresor der stabilen App teilen?

Ein Beta-Kanal kann Identität und Speicher mit der stabilen Version teilen oder beides bewusst isolieren. Beides kann richtig sein, eine zufällige Mischung jedoch nicht. Wenn eine Beta-Version den Produktions-Tresor entsperren oder in das Produktionsjournal schreiben kann, muss dieser Vertrag dokumentiert sein. Teste daran auch Upgrades, Downgrades und Rollbacks.

Erzeugt das Umbenennen eines macOS-App-Bundles eine separate App-Instanz?

Das Umbenennen des äußeren .app-Ordners erzeugt nicht unbedingt eine andere macOS-App-Identität. Prüfe Bundle-ID, Signaturdetails, Pfad zur ausführbaren Datei, laufende Prozess-ID und alle Speicherorte, bevor du Schlussfolgerungen ziehst. Eine kopierte Bundle-Datei kann weiterhin als dieselbe signierte App erkannt werden oder abgelehnt werden, weil die Signatur nicht mehr gültig ist.

Kann Codesignierung einen aufgeteilten Tresorzustand verhindern?

Nein. Ein signiertes Bundle teilt macOS mit, wer den Code erstellt und identifiziert hat. Es beweist jedoch nicht, dass zwei laufende Prozesse ihre Schreibvorgänge korrekt koordinieren. Du brauchst weiterhin eine klare Zuständigkeit, Sperren, ein Wiederherstellungsverhalten und einen Audit-Test, der eine Aufspaltung erkennt, nicht nur einen Absturz.

Welche Nachweise sollte ein Test mit doppelten Instanzen sammeln?

Ein brauchbarer Test braucht eine präzise Ereignisfolge: Prozessstart, Versuch, den Tresor zu entsperren, Sitzungsfreigabe, Aktionsanfrage, Ergebnis, Widerruf und Beendigung. Zeichne Zeitstempel, Prozess-IDs, Pfade zu den ausführbaren Dateien und das Ergebnis der Audit-Prüfung nach jeder Phase auf. Wenn du nicht rekonstruieren kannst, welcher Prozess für welches Ereignis zuständig war, fehlen dem Test die nötigen Belege.

Kann ich doppelte Gateways mit Produktions-API-Schlüsseln testen?

Verwende keinen aktiven Zugang nur deshalb, weil die App Geheimnisse vom Agenten fernhält. Nutze einen eigenen Test-Endpunkt oder ein SSH-Ziel, das eine schreibgeschützte, unkritische Anfrage ausführen kann. Du willst das Verhalten des Gateways beobachten, nicht testen, ob eine versehentliche Kopie etwas Wichtiges erreicht.

Was passiert, wenn zwei Gateway-Prozesse gleichzeitig Audit-Ereignisse schreiben?

Ein gleichzeitiger Audit-Schreibvorgang bedeutet nicht automatisch eine Beschädigung, ist aber ein Warnsignal, bis das System Reihenfolge und Integrität nachweist. Eine hashverkettete Historie braucht für jeden akzeptierten Datensatz einen eindeutigen Vorgänger oder einen festgelegten Mechanismus, der mehrere Schreiber erfasst, ohne einen Zweig zu verbergen. Führe nach dem Paralleltest eine Offline-Prüfung durch und untersuche anschließend die Ereignisreihenfolge, statt einer erfolgreichen Aktionsantwort zu vertrauen.

Sollten zwei Agentenprozesse eine Freigabe teilen?

Eine Sitzungsfreigabe muss an einen konkreten Agentenprozess gebunden sein, nicht nur an einen App-Namen, ein Terminalfenster oder eine ungenaue Benutzerabsicht. Zeichne die bei der Freigabe angezeigte Prozessidentität auf und prüfe, ob ein zweiter Agentenprozess seine eigene Berechtigungsentscheidung erhält. Andernfalls kann eine Freigabe auf Arbeit übergreifen, die der Mensch nie geprüft hat.

Sollte ich das App-Bundle verändern, um doppelte Instanzen zu testen?

Beginne mit kopierten, nicht veränderten Bundles. Änderungen innerhalb einer App können ihre Codesignatur ungültig machen und die Fragestellung von der Ausführung doppelter Instanzen auf den Umgang mit unsigniertem Code verschieben. Ermittle zuerst das Verhalten mit unveränderten Artefakten. Falls diese Grenze für deinen Release-Prozess wichtig ist, kannst du anschließend einen separaten Test für eine fehlgeschlagene Signatur durchführen.

Wie sieht ein bestandener Test mit doppelten Gateways aus?

Das korrekte Ergebnis ist eine ausdrückliche Ablehnung, eine Übergabe an einen einzigen Prozess oder ein koordiniertes Design mit gemeinsamem Zustand, das Tresor und Audit-Historie konsistent hält. Falsch ist ein Szenario, in dem zwei Prozesse gesund wirken, aber jeweils eine andere Sicht auf Berechtigungen oder Historie haben. Bequemlichkeit spielt keine Rolle, wenn ein Bediener später nicht nachweisen kann, welcher Prozess eine Aktion ausgeführt hat.

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