# SSH-Startup-Dateien: Warum Remote-Befehle Agents täuschen

Ein SSH-Befehl ist nicht automatisch das Programm, das du eingegeben hast. Bevor der Remote-Rechner `git`, `python` oder ein Deployment-Skript ausführt, wählt der SSH-Daemon ein Konto aus, startet dessen Shell und übergibt ihr eine Befehlszeichenkette. Startup-Dateien und Serverregeln können die Umgebung verändern, den Befehl ersetzen oder einen Aufruf interaktiv machen, während ein anderer nicht interaktiv bleibt.

Das wird noch wichtiger, wenn ein Agent das Ergebnis meldet. Ein Mensch, der ein unerwartetes Banner, einen Alias oder eine farbige Eingabeaufforderung sieht, hält an und prüft die Ursache. Ein Agent kann den Exit-Code 0 und eine vertraut wirkende Ausgabe als Beweis lesen, dass das gewünschte Programm gelaufen ist. Ich habe erlebt, wie aus einer harmlosen Statusprüfung der Aufruf eines Wrapper-Skripts wurde und eine Deployment-Prüfung das Ergebnis der falschen ausführbaren Datei zurückgab.

Die Lösung besteht nicht darin, jede Profildatei zu löschen. Menschen brauchen brauchbare interaktive Shells. Entscheidend ist, den Ausführungspfad zu kennen, Komfort für Menschen von Automatisierung zu trennen und den Vertrag für Remote-Befehle eindeutig festzulegen.

## Ein Remote-Befehl läuft zuerst durch die Shell des Kontos

OpenSSH führt die Wörter nach `ssh host` normalerweise nicht als direkten `execve`-Aufruf der Ziel-Binärdatei aus. Im Handbuch von `sshd` steht, dass sshd nach der Anmeldung den gewünschten Befehl über die Shell des Benutzers mit der Option `-c` startet. Der Pfad der Login-Shell stammt aus der Kontodatenbank des Remote-Hosts, nicht vom Rechner, der die SSH-Verbindung geöffnet hat.

Das erklärt viele verwirrende Berichte. Angenommen, ein Agent sendet:

```text
ssh deploy@buildbox git -C /srv/app rev-parse HEAD
```

Das Remote-Konto kann Bash, zsh, fish, eine eingeschränkte Shell oder einen Wrapper des Unternehmens verwenden. Die ausgewählte Shell erhält einen Befehl, der `git -C /srv/app rev-parse HEAD` entspricht. Zuvor kann sie sich selbst initialisieren. Außerdem kann sshd einen Ersatzbefehl vorgeben, bevor die Shell so weit kommt.

Das ist etwas anderes als die Shell, die der Agent lokal verwendet. Ein Agent kann aus einem sauberen Prozess auf einem Mac laufen, während das entfernte Konto `deploy` zehn Jahre persönlicher Shell-Anpassungen besitzt. Eine saubere lokale Eingabeaufforderung macht die andere Seite nicht sauber.

Verwechsle die Befehlsanalyse der Shell auch nicht mit dem SSH-Transport. SSH verschlüsselt die Verbindung und authentifiziert das Konto. Es garantiert nicht, dass `python` die erwartete Binärdatei bezeichnet, dass der PATH unverändert bleibt oder dass ein Profil keine Ausgabe nach stdout schreibt.

Die erste praktische Frage lautet deshalb nicht «Hat SSH eine Verbindung hergestellt?», sondern «Welches Programm hat den Remote-Befehl unter welchem Konto und mit welchen Initialisierungsregeln interpretiert?»

## Der Shell-Modus entscheidet, welche Dateien mitreden

Das Startup-Verhalten hängt von Shell-Familie und Aufrufmodus ab. Die Bezeichnungen «eine SSH-Shell» oder «eine Bash-Shell» sind zu ungenau, um das Verhalten vorherzusagen.

Für Bash unterscheidet das GNU-Bash-Referenzhandbuch zwischen Login-, interaktivem und nicht interaktivem Aufruf. Eine Login-Bash-Shell liest `/etc/profile` und anschließend die erste lesbare persönliche Datei aus `~/.bash_profile`, `~/.bash_login` und `~/.profile`. Eine interaktive Shell, die keine Login-Shell ist, liest `~/.bashrc`.

Ein normaler Remote-Befehl läuft meistens unter einer nicht interaktiven Shell. Das bedeutet nicht, dass sie nichts lädt. Bash liest die Datei aus `BASH_ENV`, wenn diese Umgebungsvariable gesetzt ist, bevor sie einen nicht interaktiven Befehl ausführt. Das Bash-Handbuch beschreibt außerdem ein Sonderverhalten, wenn Bash erkennt, dass sshd sie mit einer netzwerkverbundenen Standardeingabe gestartet hat: Sie kann `~/.bashrc` lesen. Automatisierung sollte daher nicht auf der Faustregel beruhen, dass `.bashrc` nur interaktive Nutzung betrifft.

zsh hat eine andere Struktur. `/etc/zshenv` und `~/.zshenv` gelten für jeden zsh-Aufruf. Eine laute oder zustandsbehaftete `.zshenv` ist deshalb besonders gefährlich. zsh liest `.zprofile` für Login-Shells und `.zshrc` für interaktive Shells. Wer PATH-Änderungen und Statusausgaben in `.zshenv` ablegt, verändert damit auch Remote-Befehle, Skripte und oft den Start grafischer Anwendungen.

POSIX-`sh` bietet keinen universellen Ausweg. Die Implementierungen unterscheiden sich. Die POSIX-Spezifikation beschreibt die Datei `ENV` für interaktive Shells, aber `/bin/sh` kann auf einem System dash, Bash im Kompatibilitätsmodus oder eine andere Implementierung mit eigenen Details sein. Teste den tatsächlichen Host, statt anzunehmen, dass ein Dateiname überall dasselbe bedeutet.

Diese Unterscheidung hat eine direkte praktische Folge. Ein Befehl, der in einer interaktiven Fehlersuche funktioniert, kann für einen Agent fehlschlagen, weil die interaktive Sitzung ein Profil lädt, das die Befehlssitzung überspringt. Das Gegenteil kommt ebenfalls vor: Ein Automatisierungs-Hook beeinflusst Befehlssitzungen, während er im Terminal eines Menschen fehlt.

Lege Einstellungen für die interaktive Nutzung in Dateien ab, die nur interaktive Shells lesen. Eingabeaufforderungen, Completion, Fenstertitel, Farbstandardwerte und Begrüßungen gehören dorthin. Anforderungen der Automatisierungsumgebung gehören in eine kleine, dokumentierte Datei, die ein kontrollierter Launcher bewusst lädt. Ein Agent sollte seine Laufzeit nicht aus den Dotfiles eines Entwicklers ableiten.

## PATH-Änderungen verändern Identität, nicht nur Komfort

PATH gilt oft als reine Komforteinstellung. Bei unbeaufsichtigter Ausführung bestimmt er jedoch, welches Programm tatsächlich läuft. Wenn ein Profil `/opt/team/bin` an den Anfang setzt, können `curl`, `git`, `ssh` oder `python` auf einen Wrapper statt auf das Systemprogramm verweisen.

Dieser Wrapper kann beabsichtigt sein. Teams nutzen Wrapper, um Cloud-Zugangsdaten auszuwählen, Repository-Prüfungen zu erzwingen, Telemetrie hinzuzufügen oder Sprachlaufzeiten festzulegen. Der Fehler besteht darin, dass ein Agent daraus ableitet, ein unqualifizierter Befehl müsse das Programm des Herstellers bedeuten. Tatsächlich bedeutet er nur «die erste passende ausführbare Datei im PATH, den diese Shell gerade besitzt».

Aliase und Funktionen erzeugen eine ähnliche Mehrdeutigkeit, wobei ihr Verhalten vom Shell-Modus abhängt. Bash erweitert Aliase in einer nicht interaktiven Shell normalerweise nicht, solange `expand_aliases` nicht aktiviert ist. Das macht Aliase bei normalen SSH-Befehlen weniger häufig, aber nicht unmöglich. Eine geladene Datei kann die Erweiterung aktivieren. Funktionen benötigen keine Alias-Erweiterung. Ein Profil kann eine Funktion namens `git` definieren, Umgebungswerte exportieren und dafür sorgen, dass jeder spätere Befehl in dieser Shell die Funktion aufruft.

Frage zunächst die Shell, behandle die Antwort aber als Hinweis aus genau der untersuchten Umgebung und nicht als universellen Beweis:

```sh
ssh -T deploy@buildbox '
printf "shell argv0: %s\n" "$0"
printf "shell flags: %s\n" "$-"
printf "PATH: %s\n" "$PATH"
command -V git
command -V python
command -V curl
'
```

Ein typisches Ergebnis könnte so aussehen:

```text
shell argv0: -bash
shell flags: hBc
PATH: /opt/team/bin:/usr/local/bin:/usr/bin:/bin
git is /opt/team/bin/git
python is /usr/local/bin/python
curl is /usr/bin/curl
```

Das Builtin `command -V` kann einen Alias, eine Funktion, ein Builtin oder einen Pfad melden. In Shells, die dies unterstützen, zeigt `type -a git` mehrere passende Pfade. In Bash gibt `declare -f git` den Funktionskörper aus, wenn `git` eine Funktion bezeichnet. Diese Prüfungen machen einen häufigen Fehler sichtbar: Ein Profil definiert eine `git()`-Funktion, die einen echten Git-Befehl ausführt und danach unauffällig ein Statusereignis sendet. Die Ausgabe sieht weiterhin wie Git-Ausgabe aus. Die Nebenwirkung liegt an anderer Stelle.

Auch die Befehlszwischenspeicherung kann eine Rolle spielen. Einige Shells merken sich, wo sie einen Befehl gefunden haben. Wenn ein Profil den PATH ändert, nachdem die Shell einen Namen aufgelöst hat, verwendet sie möglicherweise weiter den gespeicherten Ort, bis `hash -r` oder das entsprechende Gegenstück den Cache leert. Das passiert vor allem in langlebigen interaktiven Shells, kann aber auch Agents betreffen, die einen Shell-Prozess offen halten.

Verwende für Befehle, deren Identität eine Sicherheitsentscheidung oder ein Deployment-Ergebnis beeinflusst, absolute Pfade. Schreibe nicht einfach `/usr/bin/git`, nur weil diese Datei auf deinem Laptop existiert. Prüfe den erwarteten Pfad auf dem Zielbetriebssystem, dokumentiere ihn und teste ihn unter dem Konto, das die Arbeit ausführt. Wenn das Deployment bewusst einen Versionsmanager oder Wrapper verwendet, benenne diesen Wrapper ausdrücklich und mache seinen Vertrag zum Bestandteil des Jobs.

## Ein Pseudo-Terminal verändert mehr als die Formatierung

`ssh host command` weist normalerweise kein Pseudo-Terminal zu. `ssh -t host command` erzwingt eines. Diese eine Option kann andere Startup-Zweige aktivieren, die Pufferung beeinflussen, Farben einschalten und Eingaben anfordern, nach denen ein Lauf ohne TTY nie fragt.

Viele Shell-Konfigurationsdateien beginnen mit einer Prüfung wie dieser:

```sh
case $- in
  *i*) ;;
  *) return ;;
esac
```

Diese Prüfung beendet den Rest der Datei, sofern die Shell sich nicht als interaktiv erkennt. Ein Pseudo-Terminal kann eine Shell unter Umständen interaktiv machen, unter denen eine normale Befehlsverbindung es nicht wäre. Der Befehl erhält dann Aliase, Completion, Eingabeaufforderungs-Helfer, PATH-Änderungen und terminalbezogene Exporte, die im Agent-Lauf fehlten.

Programme reagieren ebenfalls direkt auf das Terminal. Ein Befehl kann eine Fortschrittsanzeige ausgeben, die Ausgabe paginieren, ein anderes Diagnoseformat wählen oder eine Bestätigung einlesen. Ein Parser, der ein einzelnes JSON-Objekt erwartet, kann scheitern, weil ein Profil vor dem Programm eine Begrüßung ausgibt oder das Programm ein TTY erkennt und Steuerzeichen sendet.

Teste bei einer Abweichung beide Modi:

```sh
ssh -T deploy@buildbox 'printf "flags=%s tty=" "$-"; test -t 1 && echo yes || echo no'
ssh -tt deploy@buildbox 'printf "flags=%s tty=" "$-"; test -t 1 && echo yes || echo no'
```

Der erste Befehl weist SSH an, kein Terminal zu vergeben. Der zweite erzwingt eines, selbst wenn die lokale Standardeingabe kein Terminal ist. Vergleiche die Ausgaben und anschließend Befehlsauflösung und PATH in beiden Modi. Wenn sich die Ergebnisse unterscheiden, passe nicht zuerst den Parser an. Finde den Startup-Zweig, der den Unterschied verursacht.

Automatisierung sollte standardmäßig `-T` verwenden. Weise nur dann ein Terminal zu, wenn ein Befehl es wirklich benötigt, etwa bei einer kontrollierten interaktiven Wiederherstellung. Ein Agent, der für eine normale Statusabfrage ein Terminal braucht, läuft bereits in einer weniger vorhersehbaren Umgebung.

## Serverregeln können den gewünschten Befehl ersetzen

Startup-Dateien sind nur eine Ebene. Der Server kann einen Befehl ersetzen oder einschränken, bevor die Shell des Kontos ihn sieht. Wer `.bashrc` prüft und dort aufhört, kann die Regel übersehen, die das Ergebnis tatsächlich verändert.

Das Handbuch zu `sshd_config` beschreibt `ForceCommand`. Ein Administrator kann diese Einstellung global oder in einem `Match`-Block für einen Benutzer, eine Gruppe, eine Adresse oder eine andere Bedingung anwenden. Mit `ForceCommand internal-sftp` ignoriert der Server beispielsweise gewöhnliche Shell-Befehle und startet den internen SFTP-Dienst. Bei einem eigenen Wrapper erhält dieser den Kontext des angeforderten Befehls und entscheidet, was geschieht.

Ein SSH-Public-Key-Eintrag kann im `authorized_keys`-File des Kontos ebenfalls eine Einschränkung wie `command="..."` enthalten. Das ist bei Backup-Konten, Repository-Zugriff, Dateiübertragung und eng begrenzter Automatisierung üblich. Es kann eine gute Sicherheitsmaßnahme sein. Zum Debugging wird es, wenn ein Agent ein eingeschränktes Zugangsmittel erhält, aber beliebige Befehle ausführen soll.

Auch Umgebungsregeln gehören in diese Prüfung. `AcceptEnv` legt fest, welche vom Client gesendeten Variablen sshd akzeptiert. `SetEnv` kann Variablen serverseitig setzen. `PermitUserEnvironment` kann erlauben, dass die SSH-Umgebungsdatei eines Kontos oder Optionen in autorisierten Schlüsseln Werte setzen. Diese Einstellungen können PATH, Locale, das Verhalten einer Laufzeit und Hooks wie `BASH_ENV` beeinflussen.

Verwende `ssh -G` auf dem Client, kenne aber seine Grenze:

```sh
ssh -G buildbox | grep -E '^(hostname|user|port|requesttty|remotecommand|sendenv|setenv) '
```

OpenSSH gibt die Client-Konfiguration aus, nachdem lokale `Host`-Blöcke und Standardwerte angewendet wurden. Die Ausgabe kann einen unerwarteten `RemoteCommand`, eine erzwungene Terminaleinstellung, eine Regel zur Umgebungsweitergabe oder einen anderen Zielhost sichtbar machen. Serverseitiges `ForceCommand`, die Login-Shell des Remote-Kontos oder Einschränkungen in `authorized_keys` werden dadurch nicht sichtbar.

Bitte den Serververantwortlichen um die relevanten Teile von `sshd_config` und um die Kontoeinschränkungen, wenn das Konto für Automatisierung vorgesehen ist. Wenn du den Host nicht verwaltest, bitte um eine dokumentierte Ausführungsschnittstelle, statt das Verhalten persönlicher Shells durch Testläufe zu rekonstruieren. Ein Konto mit einem undurchsichtigen erzwungenen Wrapper ist kein allgemeiner SSH-Endpunkt, selbst wenn es die Authentifizierung akzeptiert.

## Den Ausführungspfad prüfen, ohne einer einzelnen Probe zu vertrauen

Ein Diagnosebefehl läuft genau in der Umgebung, die unter Verdacht steht. Das macht die Diagnose nicht unmöglich. Es bedeutet, dass du mehrere unabhängige Fakten sammeln und genau benennen solltest, was jeder davon beweist.

Prüfe zuerst die lokale Client-Konfiguration mit `ssh -G`. Ermittle dann die konfigurierte Shell des Remote-Kontos aus der Kontodatenbank des Hosts. Auf vielen Linux-Systemen liefert `getent passwd deploy` einen durch Doppelpunkte getrennten Datensatz, dessen letztes Feld der Shell-Pfad ist. Auf macOS kann ein Administrator das Konto mit Directory-Service-Werkzeugen prüfen. Nutze dafür nach Möglichkeit einen vertrauenswürdigen Administrationsweg und nicht die möglicherweise angepasste Shell des Kontos.

Rufe als Nächstes die Startup-Dateien der tatsächlich verwendeten Shell ab und prüfe sie: globale Dateien, persönliche Dateien und alle Dateien, die sie laden. Suche nach folgenden Arten von Verhalten:

- `PATH=`-Zuweisungen, Initialisierung von Versionsmanagern und `hash`-Befehle
- `alias`, Funktionsdefinitionen und Shell-Optionen wie `expand_aliases`
- Ausgabebefehle wie `echo`, `printf` und Helfer für Terminalsteuerung
- `BASH_ENV`, `ENV`, Locale-Variablen und sprachspezifische Umgebungs-Hooks
- bedingte Zweige, die `-t`, `$-`, `$SSH_TTY` oder `$TERM` prüfen

Suche nicht nur nach dem Wort `alias`. Eine Zeile wie `. ~/.local/share/tool/init.sh` kann die Datei laden, in der die relevante Funktion definiert wird. Verfolge die Kette der eingebundenen Dateien bis zu ihrem Ende. Profil-Dateien wachsen leicht zu einer Sammlung bedingter Includes, wodurch das Verhalten für Automatisierung schwer prüfbar wird.

Führe anschließend mit einem harmlosen Befehl einen kleinen Fingerabdruck-Lauf aus. Zeichne Shell-Flags, aktuelles Verzeichnis, PATH, relevante Umgebungsvariablen und die Auflösung der tatsächlich verwendeten Tools auf. Gib nicht einfach jede Umgebungsvariable in die Logs aus. Dort liegen häufig Tokens und Cloud-Zugangsdaten. Ein Diagnoseprotokoll soll die Ausführungsbedingungen belegen, nicht zu einem neuen Geheimnisspeicher werden.

Teste zuletzt den exakten Produktionsbefehl im exakten Modus des Agents: dasselbe Konto, kein Terminal sofern nicht erforderlich, derselbe Eingabetransport und dasselbe Arbeitsverzeichnis. Ein Ergebnis aus einer interaktiven Anmeldung als Administrator ist kein Ersatz. Es beantwortet eine andere Frage.

Bewahre die Nachweise zusammen mit der Deployment- oder Automatisierungsdefinition auf. Der nützliche Nachweis ist kein Screenshot eines funktionierenden Terminals. Es ist ein kurzes Dokument mit Shell des Kontos, Startup-Dateien, die den Lauf beeinflussen dürfen, benötigten Pfaden, erwarteter Umgebung, Terminalrichtlinie und serverseitigen Befehlsbeschränkungen.

## Die Automatisierungs-Shell bewusst langweilig machen

Eine zuverlässige Remote-Aktion sollte in eine bekannte Shell mit einer kleinen Umgebung gelangen und anschließend benannte Binärdateien ausführen. Die erste Shell, die sshd verwendet, wird dadurch nicht entfernt. Aber der Zustand, der das eigentliche Programm erreicht, wird begrenzt.

Für ein kleines, festes Skript kannst du das Skript über die Standardeingabe senden und eine bekannte Shell mit leerer Umgebung starten. Die Remote-Befehlszeichenkette bleibt unverändert, wodurch außerdem eine fragile Verschachtelung aus lokalen und entfernten Anführungszeichen vermieden wird.

```sh
ssh -T deploy@buildbox '/usr/bin/env -i PATH=/usr/bin:/bin /bin/sh -s' <<'REMOTE'
set -eu
PATH=/usr/bin:/bin
export PATH

/usr/bin/git -C /srv/app rev-parse HEAD
REMOTE
```

Das hat mehrere Vorteile. `-T` vermeidet ein Terminal. `/usr/bin/env -i` löscht geerbte Variablen. `/bin/sh -s` liest das unveränderte Skript aus der Standardeingabe, und das quotierte Here-Dokument verhindert, dass die lokale Shell `$PATH` oder anderen Text vor der Übertragung erweitert. `set -eu` beendet den Lauf bei einem nicht gesetzten Parameter oder einem fehlgeschlagenen einfachen Befehl, unter den normalen Regeln der Shell.

Auch das hat Grenzen. `/usr/bin/env`, `/bin/sh` und `/usr/bin/git` sind Beispiele und nicht Pfade, die du blind auf jeden Host kopieren solltest. Prüfe die Pfade für jede Zielklasse. Eine leere Umgebung kann Variablen entfernen, die ein Programm tatsächlich benötigt, etwa Home-Verzeichnis, Locale, Proxy-Konfiguration oder den Ort einer Laufzeit. Füge nur ausdrücklich benötigte Variablen wieder hinzu und dokumentiere den Grund für jede einzelne.

Verwende `env -i` nicht, um eine fehlerhafte Kontokonfiguration zu verbergen. Wenn eine Startup-Datei die anfängliche Shell so stark verändert, dass der feste Launcher nicht starten kann, eignet sich das Konto nicht für unbeaufsichtigte Arbeit. Verwende ein eigenes Konto mit kontrollierter Login-Shell und minimalen Startup-Dateien.

Vermeide es, beliebigen Agent-Text in eine entfernte `sh -c`-Zeichenkette einzusetzen. Fehler beim Quoting können Daten in Shell-Syntax verwandeln, bevor das vorgesehene Skript sie sieht. Übertrage Daten über einen begrenzten Kanal, nutze ein festes Remote-Skript mit validierten Argumenten oder ein Protokoll für strukturierte Anfragen. Shell ist mächtig, weil sie Text als Code interpretiert. Ein Agent sollte diese Grenze nicht versehentlich verwischen können.

## Interaktive Konten von Agent-Konten trennen

Das sauberste Design verwendet unterschiedliche Identitäten für Menschen und Automatisierung. Ein Entwicklerkonto kann Eingabeaufforderung, Completion, Sprachmanager und persönliche Helfer behalten. Ein Automatisierungskonto sollte eine deklarierte Shell, ein kleines Home-Verzeichnis und Startup-Dateien besitzen, die bei Befehlssitzungen nichts tun oder nur eine eng geprüfte Einrichtung laden.

Diese Trennung ist keine Bürokratie. Sie ermöglicht klare Antworten auf alltägliche, aber wichtige Fragen: Welche Git-Binärdatei führt das Deployment aus? Welches Verzeichnis ist das Startverzeichnis? Akzeptiert das Konto ein Terminal? Welche Umgebungsvariablen können einen Release beeinflussen? Wer darf den Wrapper ändern, der die Befehle ausführt?

Ein eigenes Konto macht auch Befehlsbeschränkungen verständlicher. Du kannst einen erzwungenen Wrapper für die wenigen vorgesehenen Aktionen verwenden und alles andere ablehnen. Das macht den Wrapper jedoch nicht zu einer Policy-Sprache. Halte ihn so einfach, dass er geprüft werden kann: Argumente validieren, die dokumentierte Umgebung setzen, einen absoluten Programmpfad aufrufen und einen Audit-Eintrag schreiben.

Löse das nicht mit einer großen `case`-Anweisung und Dutzenden Ausnahmen in `.bashrc`. Dieser Ansatz ist beliebt, weil jedes Konto bereits eine Profildatei besitzt und keine Deployment-Änderung nötig ist. Er scheitert, weil sich Profilregeln je nach Shell-Modus unterscheiden, die Reihenfolge der eingebundenen Dateien unübersichtlich wird und eine harmlose interaktive Änderung unbeaufsichtigtes Verhalten verändern kann. Lege die Automatisierungseinrichtung in den Launcher oder ein eigenes Skript, das den Vertrag der Automatisierung besitzt.

Sallyport kann SSH-Zugangsdaten aus einem Agent-Prozess heraushalten und SSH-Aktionen über den enthaltenen Helfer `sp-ssh` ausführen. Es kann ein unkontrolliertes Remote-Konto jedoch nicht deterministisch machen. Prüfe das Remote-Konto als Teil des Aktionsdesigns und nutze anschließend den Aktivitätsnachweis, um die Anfrage des Agents mit der Antwort der Remote-Seite zu vergleichen.

## Ergebnissen erst vertrauen, wenn der Vertrag feststeht

Das Ergebnis eines Agent-Befehls ist vertrauenswürdig, wenn du sagen kannst, was ausgeführt wurde, ohne dich auf die aktuellen Shell-Gewohnheiten einer Person zu verlassen. Dazu gehören mehr als Hostname und Exit-Code. Benannt werden sollten SSH-Konto, Identität des Zielhosts, Terminaleinstellung, eventuelle Serverbeschränkung, ausgewählte Shell, Aufbau der Umgebung, Quelle des Skripts und Pfad der ausführbaren Datei.

Hier gibt es eine unangenehme Grenze. Aus der Ausgabe eines Remote-Befehls selbst kannst du nicht beweisen, dass die Remote-Shell den Befehl vor dieser Ausgabe nicht verändert hat. Wenn Shell des Kontos, Einschränkung des autorisierten Schlüssels oder erzwungener Befehl außerhalb deiner Kontrolle liegen, brauchst du administrative Nachweise oder ein anderes Konto. Dieselbe Probe zehnmal zu wiederholen, wiederholt nur dieselbe Annahme.

Beginne mit den Befehlen, die Agents bereits ausführen und die Code, Infrastruktur oder Produktionsdaten verändern können. Führe jeden mit und ohne Terminal aus, prüfe die Auflösung der ausführbaren Datei und ersetze geerbte Einrichtung durch einen expliziten Launcher, wenn das Ergebnis wichtig ist. Die erste Überraschung ist meist der PATH. Die zweite ist meist eine Startup-Datei, von der jemand vergessen hatte, dass sie noch geladen wird.

Wenn du eine solche Überraschung findest, füge nicht einfach eine weitere Bedingung in ein Profil ein und nenne das Problem gelöst. Verschiebe das Verhalten in ein kontrolliertes Konto oder ein festes Skript, dokumentiere den Befehlsvertrag und mache den nächsten Agent-Lauf so langweilig, dass seine Ausgabe genau das bedeutet, was sie sagt.
