OpenShell-Policies in Bromure und die Begründung hinter jeder Verbindung
NVIDIAs OpenShell beschreibt in einer einzigen Policy-Datei, worauf ein Coding-Agent zugreifen darf. Bromure Agentic Coding 5.4 setzt diese Policies in der VM des Agenten durch, mit Landlock und seccomp im Inneren und den Netzwerkregeln auf Ihrem Mac, und überwacht den Gast-Kernel mit einem Sentry-Modul. Anschließend verknüpft es jede Netzwerkverbindung mit den Prozessen, die sie geöffnet haben, dem Tool-Aufruf, der diese gestartet hat, und der Begründung, die der Agent für diesen Aufruf gegeben hat.
Ein Coding-Agent braucht echten Zugriff, um nützlich zu sein, und eine Policy legt fest, wie viel. Am besten funktioniert sie als ein einziges Dokument, das man lesen, prüfen und durchsetzen kann, statt als Einstellungen, verstreut über eine Firewall, Mount-Optionen und die Konfiguration des Agenten selbst.
NVIDIAs OpenShell
OpenShell ist NVIDIAs Open-Source-Laufzeit für Agenten, veröffentlicht unter der Apache-2.0-Lizenz. Wir haben auf ihrem Policy-Format aufgebaut, bei dem ein einziges YAML-Dokument vier Bereiche abdeckt:
filesystem_policyundlandlock: welche Pfade der Agent lesen und schreiben darf, durchgesetzt vom Sicherheitsmodul Landlock im Linux-Kernel.process: als welcher Benutzer und welche Gruppe der Agent läuft.network_policies: welche Ziele jedes Programm erreichen darf und welche Anfragen es dorthin senden darf, bis hinunter zu HTTP-Methode und Pfad. Was nicht erlaubt ist, wird verweigert: „OpenShell denies every outbound connection from a sandbox unless a rule in network_policies allows it.“
OpenShell bringt außerdem einen Prover mit, der mit einem SMT-Solver prüft, ob eine Policy irgendetwas über eine andere hinaus erlaubt. Eine Organisation kann eine Grenze festlegen und bekommt zu jeder Änderung ein Ja oder Nein, statt Diffs lesen zu müssen.
Das ist ein sorgfältiges Design von Leuten, die sich erkennbar damit beschäftigt haben, wie Agenten scheitern, und es ist offen, also haben wir darauf aufgebaut.
OpenShell in Bromure
In Bromure Agentic Coding 5.4 kann ein Workspace statt Bromures eigener
Firewall-Regeln eine OpenShell-Policy verwenden. Übernommen haben wir das
Policy-Format und seine Semantik, nicht den Code: Die Engine ist unsere eigene,
auf dem Mac, dazu kommen eigene Komponenten im Linux-Gast. Um sicherzugehen,
dass beide übereinstimmen, haben wir unsere Engine und OpenShells
Referenz-Engine auf 125.666 generierte Fälle angesetzt, quer durch
Netzwerkregeln, HTTP-Regeln, MCP, GraphQL, WebSocket und Prüfungen der
Zieladresse. In keinem Fall waren sie sich uneinig. Diese Tests brachten
Pfad-Tricks wie ..%3b und doppelt kodierte Schrägstriche (%252F) zutage,
die wir jetzt genauso behandeln wie OpenShell.
Bromure unterscheidet sich von OpenShell darin, wo die Durchsetzung läuft. OpenShell startet Sandboxen über ein Gateway und eine Container-Laufzeit. Bromure führt jeden Workspace in einer eigenen Linux-Wegwerf-VM auf Ihrem Mac aus, also teilt sich die Policy auf beide Seiten auf:
- In der VM: Landlock für das Dateisystem, seccomp,
no_new_privsund der Wechsel zum Benutzer aus der Policy. Wie das funktioniert, beschreibt der nächste Abschnitt. - Auf dem Mac: die Netzwerkregeln. Jede Verbindung verlässt die VM über
Bromures virtuellen Switch, der Ziel und Port prüft, und über seinen
TLS-Proxy, der HTTP-Methoden und -Pfade sowie MCP-, GraphQL- und
WebSocket-Nachrichten prüft. Der Mac löst die Adressen auf und pinnt sie,
sodass sich eine
allowed_ips-Regel nicht per DNS umgehen lässt. Root in der VM kann keine Regel ändern, die außerhalb von ihr liegt.
Die Policy kann auch das Programm benennen, das eine Verbindung aufbauen darf.
Im strikten Modus prüft Bromure anhand des Hashs, welches Binary die
Verbindung geöffnet hat: curl darf api.github.com erreichen, ein
Python-Skript nicht. Zusammen mit einer HTTP-Regel wie „nur GET auf
api.github.com/repos/**“ wird ein DELETE am Proxy abgewiesen. Landlock
kann nichts davon leisten: Es schränkt nur Dateien ein.
Legt eine Organisation über bromure.io eine Grenze fest, prüft Bromure jede
Workspace-Policy dagegen, mit NVIDIAs openshell-prover, wenn er installiert
ist, und andernfalls mit einer strengeren eingebauten Prüfung. Eine Policy,
die die Grenze überschreitet, lässt sich nicht speichern.
Eine Änderung haben wir bewusst vorgenommen: Jeder Abschnitt gilt nur, wenn
er vorhanden ist. Eine Policy ohne filesystem_policy lässt Landlock aus,
eine ohne process wechselt keinen Benutzer. OpenShell füllt Standardwerte
ein, weil seine Treiber immer ein vollständiges Dokument senden. In Bromure
macht die Umstellung auf OpenShell einen Workspace nie stillschweigend kaputt.
Daraus ergeben sich drei Stufen:
| Die Policy enthält | Angewendet in der VM | Was garantiert ist |
|---|---|---|
| Nur Netzwerkregeln | Nichts; der Agent behält sudo | Die Netzwerk-Policy und die Beobachtung durch den Kernel-Sentry |
filesystem_policy | Landlock, angewendet noch mit root-Rechten | Eine Einschränkung des Dateisystems, die selbst gegen root hält |
Einen process-Abschnitt oder den strikten Modus | Landlock, seccomp, no_new_privs, ein Benutzer ohne root-Rechte; sudo und docker entzogen | Alles oben Genannte, kein Weg zu root und keine Möglichkeit, Bromures eigene Prozesse zu stoppen |
Einige Felder werden akzeptiert, aber nicht durchgesetzt. Die wichtigsten sind die Felder zum Umschreiben und Signieren von Zugangsdaten: Bromure hält echte Zugangsdaten ohnehin auf dem Mac und setzt sie erst auf dem Weg nach draußen ein, sodass der Agent immer nur Platzhalter in der Hand hat.
In der VM: Landlock, seccomp und das Ablegen von Rechten
Die Gast-Hälfte ist eine Neuimplementierung des Durchsetzungscodes aus
OpenShells Crate sandbox-linux. Sie ist in Python mit ctypes geschrieben,
weil sie beim Booten in der VM laufen muss, wo es keine Rust-Toolchain gibt.
Sie macht dieselben Systemaufrufe wie die Rust-Crates landlock und
seccompiler, und ein differenzielles Test-Harness baut OpenShells echte
Crates und vergleicht beide Pfad für Pfad und Systemaufruf für Systemaufruf.
Ein Supervisor mit root-Rechten, bromure-sandboxd, startet jede
Agent-Sitzung. Er verschiebt die Sitzung in eine eigene cgroup, die
Sandbox-cgroup, und schränkt sie dann in drei Schritten ein.
Landlock. Landlock erlaubt einem Prozess ohne Privilegien, sich selbst und jeden Prozess, den er startet, auf eine Liste von Pfaden zu beschränken. Der Supervisor:
- ruft
landlock_create_rulesetmit den Rechten auf, die der Regelsatz regelt. Auf dem 6.8-Kernel des Gasts (Landlock-ABI 4) sind das Ausführen, Lesen und Schreiben von Dateien, das Auflisten von Verzeichnissen, das Anlegen und Entfernen jeder Dateiart, das Umbenennen über Verzeichnisgrenzen hinweg (REFER) und das Kürzen; - öffnet jeden Pfad in
read_onlyundread_writemitO_PATHund fügt ihn mitlandlock_add_rulealsPATH_BENEATH-Regel hinzu, die die Leserechte oder alle Rechte trägt; - ruft
landlock_restrict_selfauf.
Ab dann schlägt jeder Zugriff, den der Regelsatz regelt und den keine Regel
gewährt, mit EACCES fehl, ganz gleich, wer ihn versucht. Landlock prüft den
Task, nicht den Benutzer, also erweitert sudo die Einschränkung nicht. Ein
Prozess kann weitere Regelsätze stapeln, aber nie einen entfernen; deshalb
braucht eine Änderung am Dateisystem einen Neustart der VM, während
Netzwerkregeln sofort gelten. landlock.compatibility entscheidet, was auf
einem Kernel ohne diese ABI geschieht: best_effort macht mit dem weiter, was
der Kernel bietet, und hard_requirement verweigert den Start der Sitzung.
seccomp. Im strikten Modus oder wenn die Policy einen process-Abschnitt
hat, setzt der Supervisor no_new_privs und installiert OpenShells drei
seccomp-Filter:
- Der Hauptfilter erlaubt standardmäßig und blockiert, was die Sandbox umgehen
kann. Dazu gehören
ptrace,bpf,io_uring_setup,userfaultfd,perf_event_open,process_vm_readvundprocess_vm_writev, die gesamte Mount-Familie undsetns. Er blockiertmemfd_createundexecveatmitAT_EMPTY_PATH, weil Code, der aus einer anonymen Datei ausgeführt wird, Landlock umgeht. Er blockiertunshareundclonemitCLONE_NEWUSER, weil ein neuer User-Namespace Capabilities verteilt. Und er blockiert Sockets der Familien Packet, Bluetooth und vsock sowie Netlink außer für Routing. - Ein Kompatibilitätsfilter beantwortet
clone3mitENOSYS. Ein seccomp-Filter kann Registerwerte lesen, aber keinen Zeigern folgen, undclone3übergibt seine Flags über einen Zeiger.ENOSYSbringt glibc dazu, aufcloneauszuweichen, dessen Flags der Hauptfilter prüfen kann. - Ein Härtungsfilter hindert die Sitzung daran, ihren Supervisor zu erreichen,
der als derselbe Benutzer läuft: kein
ptrace,process_vm_*,pidfd_getfdoderkcmpund keine Signale an den Prozess oder die Prozessgruppe des Supervisors.
Wir weichen an zwei Stellen von OpenShell ab, und nur darin, was gemeldet wird
und wohin Signale zielen. Unsere Filter tragen SECCOMP_FILTER_FLAG_LOG,
sodass ein verweigerter Systemaufruf den Audit-Hook des Kernels erreicht, wo
der Sentry ihn sieht. Und die Signalregel ist so eingeengt, dass die
Jobsteuerung der Shell (kill %1) in einem interaktiven Terminal weiter
funktioniert.
Das Ablegen von Rechten. run_as_user wechselt die Sitzung zum Benutzer
aus der Policy, ohne eine der Gruppen des Standardbenutzers, also kein sudo
und kein docker. Das Home-Verzeichnis des Benutzers wird über einen
idmapped Mount in die Sitzung eingehängt, sodass Dateien, die die Sitzung
anlegt, auf der Platte weiterhin dem Standardbenutzer gehören und die
Konfiguration des Agenten weiterhin gilt.
Ein Sentry im Gast-Kernel
Um festzuhalten, was ein Agent tatsächlich getan hat, lädt Bromure ein eigenes Kernel-Modul in die VM, den Sentry. Sein Design geht davon aus, dass der Agent in der VM root werden kann. Deshalb zählt nichts als Beweis, was root stoppen könnte: Erfassung, Pufferung und Transport laufen alle im Kernel.
Erfassung. Der Sentry registriert kprobes aus dem Kernel-Space:
- Programmstarts, bei
security_bprm_committed_creds, mit der Befehlszeile und der Startzeit des Prozesses; - Änderungen an Anmeldedaten: die Familien
setuidundsetgid,capsetundcommit_creds; ptrace, das Laden und Entladen von Modulen,bpf,kexec_load,mount,unshareundsetns;- neue Netzwerk-Datenflüsse: TCP, sobald das erste SYN hinausgeht
(
tcp_connect), UDP beim ersten Senden an ein Ziel sowie ICMP und Raw-Sockets, jeweils mit der Kette von bis zu acht Prozessen dahinter; - verweigerte Systemaufrufe, bei
audit_seccomp; - verweigerte Dateioperationen, über kretprobes auf den
Datei-Sicherheits-Hooks des Kernels:
security_file_openund diesecurity_path_*-Hooks für mkdir, rmdir, unlink, symlink, link, rename und truncate. Gibt ein Hook für einen Prozess in der Sandbox-cgroupEACCESoderEPERMzurück, ist das eine Verweigerung. Das Ausführen einer Datei, die Landlock nicht erlaubt, erscheint als verweigertes Öffnen mitFMODE_EXEC.
Der Supervisor übergibt dem Sentry die ID der Sandbox-cgroup ein einziges Mal, über einen Modulparameter, der sich setzen, aber nie ändern lässt. Root kann ihn nicht auf etwas anderes richten und so die Aktivität des Agenten als Bromures eigene ausweisen lassen.
Transport. Ein Kernel-Thread öffnet mit sock_create_kern einen
AF_VSOCK-Socket zum Mac. Der Socket hat keinen Dateideskriptor, erscheint
also unter keinem Prozess in /proc, und nichts im User-Space kann ihn
schließen. Ereignisse laufen durch einen Ringpuffer mit 256 Plätzen, und jede
Ereignisart ist auf 64 pro Sekunde begrenzt, mit Spitzen von bis zu 256. Jeder
Frame besteht aus einer 4-Byte-Länge, gefolgt von JSON.
Geladen bleiben. Das Modul hat keine Exit-Funktion, daher weigert sich der
Kernel, es zu entladen, und obendrein hält es eine Referenz auf sich selbst.
Direkt nach dem Laden hebt der Loader den Lockdown des Kernels auf integrity
an, oder auf confidentiality, wenn der Workspace den Sentry verlangt. Ab dann
kann root kein unsigniertes Modul laden, nicht über /dev/mem in den
Kernelspeicher schreiben und nicht per kexec in einen Kernel ohne den Sentry
wechseln.
Nachweisen, dass er lebt. Jede Sekunde sendet der Sentry einen Heartbeat mit einer Sequenznummer, der Zahl verworfener und gedrosselter Ereignisse und der Zahl scharf geschalteter Probes. Schaltet root über debugfs alle kprobes auf einmal ab, verrät diese Zahl das nicht: Die eigenen Flags jeder Probe bleiben dabei unberührt, die Zahl sieht also weiter gesund aus. Um das zu erkennen, hält der Sentry eine kprobe auf einer eigenen, leeren Funktion und ruft diese einmal pro Heartbeat auf. Bewegt sich der Trefferzähler nicht, feuern die Probes nicht, aus welchem Grund auch immer, und der Heartbeat meldet das.
Nachweisen, dass er der Sentry ist. Bei jedem Laden entsteht ein
32-Byte-Geheimnis. Das erste Hello enthält es, und der Mac pinnt es für diesen
Boot. Eine erneute Verbindung wiederholt das Geheimnis nie. Sie sendet
stattdessen sha256(secret, boot_id, connection number), sodass ein Prozess,
der das Geheimnis nach dem ersten Hello aus dem Speicher gelesen hat, sich
trotzdem nicht als das Modul ausgeben kann. Ein zweiter Sentry, ein falsches
Geheimnis, eine wiederverwendete Verbindungsnummer, eine Lücke in der Sequenz
oder 15 Sekunden Schweigen gelten allesamt als Manipulation. Als letzter Zug
bleibt root, die VM abstürzen zu lassen oder auszuschalten, was der Mac als
Schweigen sieht.
Verteilung. Module werden nicht in der VM gebaut. Die CI baut für jedes der 20 Kernel-Releases von Ubuntu 24.04 ein Modul, und zwar zweimal, und die beiden Builds müssen Byte für Byte übereinstimmen. Jedes Modul und der Katalog, der sie auflistet, werden mit einem ed25519-Schlüssel signiert, und die App lehnt ein Modul ab, dessen Signatur oder Hash nicht stimmt.
Eine Lehre aus der Entwicklung: Eine Zeit lang verglich die Probe für
Dateiverweigerungen einen vorzeichenlosen Rückgabewert mit -EACCES und schlug
kein einziges Mal an. Die Tests prüften nur, ob die Probe registriert war, und
das war sie immer. Jetzt prüfen sie, dass eine Verweigerung ein Ereignis
erzeugt.
Die Ereignisse beurteilen. Auf dem Mac werden Ereignisse danach beurteilt, was sie bedeuten, nicht danach, welcher Systemaufruf ausgelöst wurde. Jedes erhöht eine Punktzahl um sein Gewicht, und 20 Punkte innerhalb von 60 Sekunden lösen den Alarm aus:
| Ereignis | Gewicht |
|---|---|
| Eine Manipulation am Sentry oder root-Rechte, erlangt aus einer strikten Sandbox heraus | 20 |
Ein unsigniertes Modul, das Laden von BPF, ein kexec, ein Versuch, den Lockdown abzusenken; ein Programm, das in einer Minute 20-mal abgewiesen wird | 10 |
Ein ptrace oder ein von seccomp verweigerter Systemaufruf | 3 |
| Ein Mount oder ein Namespace-Wechsel; verworfene Ereignisse | 2 |
| Eine von der Sandbox verweigerte Dateioperation | 1 |
Ein sudo in einem Workspace, der sudo erlaubt | 0, angezeigt in der Zeitleiste |
Ein Alarm, der schon in der ersten Minute anschlägt, bringt Menschen bei, die echten zu ignorieren. Deshalb laufen Bromures eigene Verwaltungsaufgaben außerhalb der Sandbox und tauchen nie als Verweigerung auf, und Ereignisse, die entstehen, während Bromure die VM beim Booten zusammensetzt, werden innerhalb eines festen Boot-Zeitfensters gezählt, lösen aber keinen Alarm aus. Schlägt der Alarm an, kann Bromure den Workspace unter Quarantäne stellen: Es trennt die VM vom Netzwerk und hält sie an.
Abstammung: die Begründung hinter jeder Verbindung
Ein Netzwerkprotokoll zeigt, dass sich etwas in der VM mit einem Host verbunden hat, aber nicht, warum. Wenn ein Agent die Arbeit erledigt, ist das Warum genau das, was Sie wissen müssen.
Bromure kann es Ihnen sagen, weil es beide Enden sieht. Sein KI-Proxy sitzt zwischen dem Agenten und dem Modellanbieter und liest jede Antwort, bevor der Agent handelt. Er kennt also jeden Tool-Aufruf, den Befehl, den er ausführen wird, und das, was das Modell unmittelbar davor geschrieben hat. Der Sentry meldet jedes Programm, das in der VM startet, mit seiner Befehlszeile, und jede neue Verbindung mit der Kette der Prozesse dahinter. Bromure führt beides zusammen.
Angenommen, Sie bitten den Agenten, einen Health-Check hinzuzufügen, der Ihre
Zahlungs-API erneut abfragt. Er kommt zu dem Schluss, dass er einen
HTTP-Client braucht, und führt npm install axios aus. npm holt das Paket von
registry.npmjs.org, was die Policy erlaubt. Dann startet ein
postinstall-Skript aus dem Download und versucht, telemetry.example.net zu
erreichen, was keine Regel erlaubt. Die Verbindung wird am Proxy auf dem Mac
abgewiesen, und die Abstammung zeigt, wie es dazu kam:


Der Agent hat nie einen Befehl eingegeben, der telemetry.example.net erreicht
hätte. Ein einfaches Netzwerkprotokoll würde einen Node-Prozess zeigen, der
mit einem unbekannten Host spricht; die Abstammung zeigt, dass es das
Installationsskript einer Abhängigkeit war, unter dem npm install, das der
Agent aus einem erklärten Grund ausgeführt hat.
Die Zuordnung erfolgt in drei Schritten:
- Tool-Aufruf. Der KI-Proxy hält jeden Tool-Aufruf aus der Antwort des
Modells zehn Minuten lang fest: seine ID (
tool_use_idoder bei OpenAIcall_id), den Befehl und bis zu 2.000 Zeichen dessen, was das Modell im selben Zug davor geschrieben hat. - Shell. Aus den Programmstarts des Sentry führt der Mac für jede VM eine
Prozesstabelle, mit PID und Startzeit als Schlüssel, sodass eine
wiederverwendete PID nicht die Vorgeschichte eines anderen Prozesses erben
kann. Eine Shell, die innerhalb von 30 Sekunden nach der Antwort unter dem
Agenten startet, wird dem Tool-Aufruf zugeordnet, wenn der Befehl in ihrer
Befehlszeile vorkommt, nachdem das Quoting des Agenten rückgängig gemacht
wurde. Claude Code zum Beispiel führt Befehle als
bash -c '… eval '"'"'<command>'"'"' …'aus. Das ist eine exakte Übereinstimmung. Hat der Agent den Befehl umgeschrieben, greift Bromure auf das erste Wort, den Zeitpunkt und die Abstammung zurück und kennzeichnet die Zuordnung als unscharf. - Entscheidung. Ein Datenfluss wird anhand von Protokoll, Ziel, Port und Quellport innerhalb von 5 Sekunden dem Erlauben oder Verweigern des Switches zugeordnet und, wenn der Proxy die Anfrage geprüft hat, auch der Entscheidung des Proxys.
Jede Verbindung unterhalb der Shell erbt die Verknüpfung. Das gilt auch für Datenverkehr über Bromures Proxy-Bridge, der sonst komplett wie Verbindungen zu localhost aussähe. Die Bridge beginnt jeden Stream zum Mac mit einer Zeile, die den Quellport des Clients nennt, sodass der Mac die lokale Verbindung dem echten Ziel zuordnen kann.
Im Fenster „Sicherheit“ öffnet Show the Whole Chain auf einer Netzwerkzeile diese Ansicht.
Manche Modelle gehen direkt zum Tool-Aufruf über, ohne vorher etwas zu schreiben. Dann zeigt die Ansicht stattdessen den Prompt und das erklärte Vorhaben des Aufrufs. Hintergrunddienste und alles, was außerhalb eines Tool-Aufrufs gestartet wurde, werden als keinem Agenten zugeordnet gekennzeichnet.
Die Abstammung verändert auch, was nach einer Blockierung passiert. Ein Agent, der nur einen Verbindungsabbruch oder einen Berechtigungsfehler sieht, hält das für eine Störung und probiert einen anderen Host, Port oder ein anderes Tool, was von außen wie ein außer Kontrolle geratener Agent aussieht. Bromure teilt dem Agenten in seiner eigenen Sitzung mit, dass die Policy die Anfrage abgewiesen hat und warum, und dass er Sie fragen soll, statt das zu umgehen. Die Sandbox-Leiste eines laufenden Workspace listet auf, was blockiert wurde, mit einer Schaltfläche Erlauben für jeden Eintrag, und der Policy-Berater entwirft aus den Verweigerungen Regeln, die Sie annehmen können oder nicht.


Die Überlegungen des Agenten werden in Ihrer eigenen Sicherheits-Zeitleiste immer angezeigt. An die Konsole einer Organisation auf bromure.io werden sie nur gesendet, wenn diese Organisation das einschaltet, was standardmäßig nicht der Fall ist, und für private Profile nie. Tokens in Befehlszeilen werden geschwärzt, bevor irgendetwas den Mac verlässt.
So schalten Sie es ein
OpenShell-Policies, der Kernel-Sentry und die Abstammung kommen mit Bromure Agentic Coding 5.4. Standardmäßig sind sie ausgeschaltet. Um sie für einen Workspace einzuschalten, öffnen Sie Einstellungen, dann die Sandbox-Richtlinie des Workspace, und setzen Sandbox engine auf OpenShell + Sentry. Dort können Sie die Policy schreiben oder eine vorhandene OpenShell-YAML-Datei importieren.


- Netzwerkregeln gelten sofort. Änderungen am Dateisystem greifen beim nächsten Start der VM, weil Landlock nur einschränken kann, was ein laufender Prozess darf.
- Der Sentry läuft standardmäßig im Best-Effort-Modus. Stellen Sie ihn auf Required, hebt Bromure den Lockdown des Kernels auf die strengste Stufe an und wertet einen Sentry, der sich nie verbindet, als Manipulation.
- Mit verpflichtendem Sentry ist die Shell eines Workspace nach 4 Sekunden bereit, wenn das Modul für seinen Kernel im Cache liegt, und nach 6 Sekunden, wenn Bromure es erst holen muss.
Um es in Aktion zu sehen, schauen Sie sich Claudias drei Folgen an: Sie schreibt eine Policy, justiert sie nach, während ein Agent arbeitet, und verfolgt einen Lieferkettenangriff um 2 Uhr nachts bis zu den Überlegungen des Agenten zurück.
Wir danken dem OpenShell-Team bei NVIDIA dafür, dass es das Policy-Format, die Referenz-Engine und den Prover offen veröffentlicht hat. Wir haben auf allen dreien aufgebaut.