8 min de lecture

Déconnexion SSH et état distant inconnu : comment vérifier ce qui s’est passé

Gérez un état distant SSH inconnu grâce à un identifiant d’exécution durable, un enregistrement d’état distant, des contrôles de postcondition et des décisions de nouvelle tentative sûres.

Déconnexion SSH et état distant inconnu : comment vérifier ce qui s’est passé

Une déconnexion SSH ne signifie pas que la commande distante a échoué. Elle signifie que le client a perdu les éléments nécessaires pour déterminer ce qui s’est passé. La différence est gênante quand vous avez lancé uname, et coûteuse quand vous avez exécuté une migration de base de données, une mise en production, une rotation d’identifiants ou une commande qui appelle une API externe.

La solution n’est pas d’augmenter le délai d’attente. Il faut mettre en place une séquence de vérification distante avec une identité d’exécution durable, des transitions d’état explicites et une preuve de réussite adaptée à l’effet recherché. Une fois ce mécanisme en place, une reconnexion ne pose plus la question « Dois-je la relancer ? », mais plutôt « Que dit l’enregistrement de cette exécution et qu’a-t-elle modifié ? »

Une connexion interrompue laisse trois réponses honnêtes

Après un message SSH indiquant une réinitialisation, un délai d’attente, un tube brisé ou une fin de fichier brutale, la commande se trouve dans l’un de trois états : elle n’a jamais démarré, elle a démarré et est encore en cours, ou elle est terminée. Le code de sortie côté client ne permet pas de les distinguer de manière fiable.

Plusieurs frontières séparent votre shell du programme distant :

  • Votre shell local démarre ssh.
  • Le client envoie une requête de canal SSH et les octets de la commande.
  • Le serveur accepte la requête et démarre un shell ou un programme distant.
  • Ce programme effectue réellement le travail.
  • Le programme se termine, puis sshd renvoie la sortie et le code de sortie.

Une rupture réseau après n’importe laquelle de ces étapes peut produire une erreur locale. Si elle survient avant le démarrage du programme distant, rien ne s’est passé. Si elle survient après la validation d’une modification distante, mais avant le retour du code de sortie, la modification a bien eu lieu alors que votre client signale toujours un échec.

C’est pourquoi un message local comme Connection reset by peer constitue une preuve de transport, pas une preuve métier. Il indique que le client n’a pas pu terminer la conversation SSH. Il ne dit pas si l’opération distante a été exécutée.

Le manuel de configuration d’OpenSSH souligne un point lié aux canaux inactifs : fermer une session ne garantit pas que les processus shell associés se sont arrêtés. Un délai d’expiration du canal n’est donc pas un mécanisme de contrôle des tâches.

L’habitude qui provoque des dégâts consiste à traiter un résultat ambigu comme une opération échouée. C’est compréhensible, car la plupart des outils en ligne de commande nous apprennent à interpréter un code de sortie non nul comme « recommencer ». Une défaillance du transport SSH rend ce raccourci dangereux.

La livraison et la fin d’une commande sont deux affirmations différentes

Pour une commande distante, il faut au moins prouver quatre éléments : la soumission, le démarrage, la fin et l’effet. Les équipes en consignent souvent un seul et supposent disposer des quatre. La soumission signifie que le client a tenté d’envoyer la commande. Votre terminal local le sait, mais c’est la preuve la plus faible. Le démarrage signifie que le wrapper distant a créé une preuve durable avant d’agir. La fin signifie que le wrapper a enregistré un résultat final. L’effet signifie que l’état distant ou externe recherché correspond maintenant au résultat demandé.

Une liste de processus prouve moins qu’on ne le pense. Voir un PID peut indiquer qu’un processus portant un nom similaire existe maintenant. Cela ne prouve pas qu’il correspond à votre requête, qu’il n’a pas déjà effectué la partie importante du travail ni qu’une nouvelle tentative serait sans danger. Après la fin d’un processus, la réutilisation du PID rend les anciens enregistrements encore moins fiables.

Les codes de sortie ont une limite similaire. POSIX définit wait comme un moyen pour un shell d’obtenir l’état d’un processus fils qu’il connaît. Cette relation existe dans le shell distant. Lorsque la connexion SSH disparaît, le shell local perd l’accès à cet état. Une session SSH ultérieure ne peut pas le recréer avec wait ; elle doit lire un enregistrement conservé par la première exécution.

Gardez ces affirmations séparées dans les procédures et les sorties d’automatisation :

  1. « Le client n’a pas pu confirmer la fin de l’opération. »
  2. « L’exécution r-20260722-1842-a91f a commencé sur l’hôte distant. »
  3. « Cette exécution a enregistré le code de sortie 0. »
  4. « Le marqueur de déploiement indique la version 2026.07.22.3. »

La quatrième affirmation est parfois la seule à répondre à la vraie question opérationnelle. Une copie de fichier nécessite une somme de contrôle ou un chemin final contenant le contenu attendu. Une migration nécessite la version du schéma ou une entrée dans le registre des migrations. Une requête vers une API de paiement ou de tickets nécessite un enregistrement d’idempotence auprès de cette API, pas seulement une ligne dans un journal local.

Placez l’identifiant d’exécution sur l’hôte distant avant le travail

Un identifiant d’exécution durable transforme une reconnexion vague en simple recherche. Générez-le avant d’appeler SSH, transmettez-le au wrapper distant et placez chaque artefact sous un chemin dérivé de cet identifiant.

N’utilisez pas uniquement un horodatage. Deux agents peuvent démarrer à la même seconde, les horloges peuvent dériver et les horodatages sont de mauvais identifiants opaques. Combinez un horodatage avec des données aléatoires ou utilisez un générateur d’UUID disponible dans votre environnement. L’identifiant doit être fourni à nouveau pour la vérification et apparaître dans chaque entrée de journal importante.

Ce fragment shell crée un répertoire d’exécution, écrit l’opération demandée, enregistre un marqueur de démarrage et conserve les deux flux de sortie. Il attend une commande après --. Gardez le wrapper dans un emplacement contrôlé comme /usr/local/sbin/run-recorded, au lieu de le recopier au hasard dans chaque chaîne de commande.

#!/bin/sh
set -eu

run_id=$1
shift
[ "$1" = "--" ]
shift

base=/var/lib/recorded-runs
run_dir="$base/$run_id"

case "$run_id" in
  *[!A-Za-z0-9._-]*|'')
    printf '%s\n' "invalid run id" >&2
    exit 64
    ;;
esac

if ! mkdir "$run_dir" 2>/dev/null; then
  printf '%s\n' "run already exists: $run_id" >&2
  exit 75
fi

umask 077
printf '%s\n' "$*" > "$run_dir/request"
date -u +%Y-%m-%dT%H:%M:%SZ > "$run_dir/started_at"
printf '%s\n' "started" > "$run_dir/state"
printf '%s\n' "$$" > "$run_dir/pid"

set +e
"$@" >"$run_dir/stdout" 2>"$run_dir/stderr"
status=$?
set -e

printf '%s\n' "$status" > "$run_dir/exit_status"
date -u +%Y-%m-%dT%H:%M:%SZ > "$run_dir/finished_at"
printf '%s\n' "finished" > "$run_dir/state"
exit "$status"

L’appel à mkdir ne sert pas seulement à l’entretien. La création échoue si l’identifiant existe déjà, ce qui en fait une réservation simple et unique. Deux appels utilisant le même identifiant ne peuvent donc pas exécuter silencieusement deux fois le travail. Cela ne résout pas les exécutions concurrentes utilisant des identifiants différents, qui nécessitent un verrou distinct ou une contrainte au niveau de l’application.

L’ordre est important. Le wrapper écrit started_at, state et pid avant d’exécuter la charge utile. Il enregistre exit_status avant de faire passer l’état à finished. Un vérificateur qui voit finished sans code de sortie doit considérer l’enregistrement comme endommagé, et non comme réussi. S’il trouve un répertoire d’exécution sans started_at, il doit y voir un échec de préparation incomplet.

N’écrivez pas finished via un piège shell en considérant l’opération comme terminée. Une panne brutale de l’hôte, un problème de stockage, un arrêt forcé ou une défaillance du système de fichiers peut empêcher l’exécution des pièges. Un marqueur final constitue une preuve lorsqu’il est présent, mais son absence ne prouve pas que la charge utile n’a pas fini.

Vérifiez une exécution dans un ordre qui évite les fausses conclusions

Commencez par vous reconnecter avec une commande d’état en lecture seule. Ne vous reconnectez pas en relançant la charge utile avec les mêmes arguments dans l’espoir que la réponse devienne évidente.

Un bon vérificateur doit classer l’enregistrement dans l’un des états absent, running, finished ou damaged. Cet exemple utilise le format de répertoire précédent et affiche des faits qu’une personne ou un agent peut évaluer.

#!/bin/sh
set -eu

run_id=$1
run_dir="/var/lib/recorded-runs/$run_id"

if [ ! -d "$run_dir" ]; then
  printf '%s\n' 'state=absent'
  exit 0
fi

if [ ! -f "$run_dir/started_at" ]; then
  printf '%s\n' 'state=damaged reason=missing-start-marker'
  exit 2
fi

if [ -f "$run_dir/finished_at" ] && [ -f "$run_dir/exit_status" ]; then
  printf '%s\n' 'state=finished'
  printf 'exit_status=%s\n' "$(cat "$run_dir/exit_status")"
  printf 'started_at=%s\n' "$(cat "$run_dir/started_at")"
  printf 'finished_at=%s\n' "$(cat "$run_dir/finished_at")"
  exit 0
fi

if [ -f "$run_dir/pid" ]; then
  pid=$(cat "$run_dir/pid")
  if kill -0 "$pid" 2>/dev/null; then
    printf 'state=running pid=%s\n' "$pid"
    exit 0
  fi
fi

printf '%s\n' 'state=damaged reason=no-finish-record-and-pid-not-live'
exit 2

Lancez-la avec une nouvelle commande SSH :

ssh ops@host /usr/local/sbin/check-recorded-run r-20260722-1842-a91f

Sa sortie doit correspondre à l’un de ces exemples :

state=absent
state=running pid=48192
state=finished
exit_status=0
started_at=2026-07-22T18:42:19Z
finished_at=2026-07-22T18:47:03Z

L’état inconfortable damaged doit faire partie du protocole. L’omettre oblige le vérificateur à transformer l’absence de preuve en supposition optimiste. Si l’hôte a redémarré pendant l’exécution, kill -0 échouera et aucun marqueur final n’existera. La bonne réponse consiste à inspecter l’effet recherché et les journaux de l’application, puis à décider s’il faut réconcilier l’état.

Ne faites pas utiliser ps | grep au vérificateur. Il trouvera des processus sans rapport, les noms de commande changent et les formats de sortie varient. kill -0 n’est qu’un indice de vivacité pour un PID enregistré. Ce n’est pas une preuve de fin, raison pour laquelle le vérificateur examine les artefacts finaux avant le PID.

Même un code de sortie final ne prouve pas toujours l’effet recherché

Sachez qui ouvre la session
Autorisez un nouveau processus d’agent une seule fois, après avoir vérifié son autorité de signature avant l’exécution de SSH.

L’enregistrement final du wrapper prouve ce que le wrapper a observé, pas nécessairement ce que le monde extérieur a accepté. C’est évident pour les commandes qui envoient des requêtes.

Imaginez un script distant qui crée un enregistrement DNS via une API, puis écrit exit_status=0. Le script peut recevoir une réponse positive de l’API avant qu’un résolveur ne voie le nouvel enregistrement. Un script de déploiement peut se terminer avec succès après avoir soumis un déploiement qui échoue ensuite aux contrôles de santé. Un outil de base de données peut signaler une connexion réussie alors qu’une instruction dans une procédure en plusieurs étapes est validée et qu’une instruction suivante échoue.

Chaque opération a besoin d’une postcondition adaptée à son effet. Cette postcondition doit pouvoir être lue plusieurs fois sans risque et être assez précise pour écarter un résultat ancien ou sans rapport.

Pour une mise en production, écrivez l’identifiant d’exécution dans un manifeste de version et interrogez la version active du service. Pour une modification de base de données, consultez la table des migrations avec l’identifiant de migration et sa somme de contrôle. Pour un artefact généré, comparez une empreinte SHA-256 précalculée une fois le fichier placé à son chemin final. Pour une requête API, fournissez le jeton d’idempotence du fournisseur lorsqu’il en propose un, puis recherchez la ressource créée avec ce jeton ou avec un identifiant de requête conservé.

Le pire modèle est un script qui affiche « terminé » après l’envoi d’une requête et traite ce mot comme une preuve. Le fichier stdout indique ce qu’un processus a affiché. Une postcondition indique ce que le système contient maintenant.

Cette distinction montre aussi quand une opération ne peut pas être automatisée sans risque avec SSH seul. Si la commande distante appelle un service tiers dépourvu de mécanisme d’idempotence et incapable de rechercher une requête précédente, il peut être impossible de déterminer l’issue d’un appel interrompu. Ajoutez une validation humaine ou un processus compensatoire. Des tentatives supplémentaires ne créeront pas les preuves manquantes.

L’idempotence vaut mieux qu’une mise en scène de la récupération

Un protocole de vérification réduit l’incertitude. Une conception idempotente réduit le coût de cette incertitude. Il faut les deux.

Une opération idempotente atteint le même état recherché lorsqu’elle est appliquée à nouveau avec la même requête. mkdir -p /srv/app/cache s’en approche. useradd deploy ne l’est pas, sauf si le script vérifie d’abord que le compte existant possède les propriétés attendues. curl -X POST /orders ne l’est pas non plus, sauf si le service comprend un jeton d’idempotence et traite un jeton répété comme la même requête.

Ne confondez pas « la commande ne fera probablement rien la deuxième fois » avec l’idempotence. Une commande de déploiement peut écraser un fichier de la même façon deux fois, tout en déclenchant deux redémarrages. Un outil de migration peut reconnaître son historique, mais exécuter une initialisation dangereuse avant cette vérification. Étudiez le comportement de la commande et testez le cas d’interruption.

Construisez les requêtes autour d’un identifiant d’opération stable. Transmettez le même identifiant au wrapper distant et, lorsque c’est possible, au système cible. Un wrapper de mise en production distant pourrait créer /var/lib/recorded-runs/$run_id/effect seulement après que le point de terminaison de la version active indique la version demandée. Un appel à une API de provisionnement pourrait utiliser run_id comme valeur d’idempotence. Une nouvelle tentative SSH peut alors interroger les deux systèmes au sujet de la même opération.

La règle pratique est simple : relancez librement une lecture, ne relancez une création qu’avec une contrainte d’unicité durable et ne relancez une modification en plusieurs étapes qu’après avoir classé la première exécution grâce à sa postcondition. C’est plus lent que de renvoyer aveuglément une commande. C’est beaucoup plus rapide que de nettoyer une infrastructure dupliquée.

Exécuter la commande en arrière-plan déplace le problème

Approuvez chaque commande sensible
Marquez les clés SSH sensibles pour demander une approbation à chaque utilisation, avec confirmation en un clic ou par Touch ID.

nohup, &, disown, tmux, screen et les gestionnaires de services résolvent chacun une partie différente du problème. Aucun ne transforme une requête distante incertaine en résultat vérifié.

nohup aide un processus à survivre à un signal de déconnexion dans les configurations shell courantes. Un simple nohup task & laisse toutefois les fichiers de sortie, un PID et aucun enregistrement structuré de fin, sauf si vous en ajoutez un. Il introduit aussi une nouvelle ambiguïté : le shell distant a-t-il démarré nohup, ou la connexion s’est-elle interrompue avant cela ?

tmux et screen gardent un environnement interactif en vie. Ils conviennent lorsqu’un opérateur doit se reconnecter et inspecter manuellement une longue commande. Ils conviennent mal comme contrat d’automatisation, car les noms de session peuvent entrer en collision, l’historique de terminal n’est pas un schéma de résultat et un terminal détaché n’indique pas à un autre système si l’effet recherché s’est produit.

Un gestionnaire de services est plus solide lorsque le travail est réellement un service ou une tâche mise en file. Une commande distante peut par exemple soumettre une unité nommée, puis une requête ultérieure peut examiner son cycle de vie et ses journaux. Utilisez ce modèle lorsque l’hôte possède déjà un responsable opérationnel pour les tâches. N’ajoutez pas un gestionnaire de services à une commande administrative de cinq secondes uniquement pour éviter d’écrire un petit enregistrement d’exécution.

La distinction utile est simple. Gardez les interventions interactives dans un multiplexeur de terminal. Placez les charges planifiées ou durables sous le contrôle d’un gestionnaire de services. Utilisez un wrapper enregistré pour les commandes impératives dont l’appelant SSH doit pouvoir connaître le résultat après une reconnexion.

Les keepalives réduisent l’attente, mais ne ferment pas la fenêtre d’ambiguïté

Les keepalives du client OpenSSH permettent de détecter plus rapidement les connexions mortes. Ils ne garantissent pas qu’une commande n’a pas été acceptée avant la défaillance du chemin réseau.

Pour les hôtes où un client bloqué fait perdre du temps, une configuration client comme celle-ci est raisonnable :

Host production-*
    ServerAliveInterval 20
    ServerAliveCountMax 3
    TCPKeepAlive yes

ServerAliveInterval envoie des messages au niveau de l’application dans le canal SSH chiffré lorsqu’aucune donnée n’arrive. Si le client ne reçoit pas suffisamment de réponses, il quitte la session au lieu d’attendre indéfiniment. OpenSSH distingue ce mécanisme des keepalives TCP, qui fonctionnent au niveau du transport.

Utilisez ce réglage pour limiter le temps d’attente avant de commencer la vérification. Ne le présentez pas comme une garantie de livraison de commande. La déconnexion peut encore se produire après l’acceptation de la commande par l’hôte distant et avant la réception du résultat par le client.

Le multiplexage appelle la même prudence. ControlMaster et ControlPersist peuvent réutiliser une connexion réseau existante pour plusieurs commandes SSH. Cela réduit le coût de configuration, mais une connexion maître défaillante peut aussi toucher plusieurs appels à la fois. Le manuel OpenSSH précise qu’un maître persistant reste en arrière-plan après la fermeture du client d’origine. C’est utile en exploitation, mais cela n’ajoute aucune preuve de fin à une commande envoyée par son intermédiaire.

Pour l’automatisation, définissez un délai explicite de connexion, des limites de vivacité adaptées à l’environnement et un chemin de vérification indépendant de la session SSH d’origine. Un échec rapide n’est utile que si l’étape suivante est une consultation d’état plutôt qu’une nouvelle tentative aveugle.

Créez le test de défaillance avant d’en avoir besoin à 2 heures du matin

Révoquez rapidement une exécution
Révoquez instantanément une exécution d’agent lorsque son activité SSH ne doit plus être autorisée.

Un protocole que vous n’avez jamais interrompu reste une esquisse. Testez-le avec une opération sans danger, mais assez lente pour couper la connexion à différents moments.

Commencez par une charge utile qui écrit un fichier de progression numéroté, attend entre les étapes et écrit un marqueur d’effet final. Lancez-la via le wrapper. Arrêtez le client SSH local après l’apparition du marqueur distant started_at, puis reconnectez-vous et lancez le vérificateur. Recommencez en arrêtant la charge utile distante avant l’écriture de finished_at. Simulez enfin un redémarrage de l’hôte si votre environnement le permet.

Les classifications attendues doivent être explicites :

  • Avant que le wrapper ne réserve l’identifiant d’exécution, la vérification renvoie absent.
  • Pendant l’exécution de la charge utile, elle renvoie running.
  • Après une fin normale, elle renvoie finished avec le code enregistré.
  • Après une interruption forcée ou une perte de l’hôte, elle renvoie damaged, suivie d’une vérification de la postcondition.

Testez aussi les soumissions en double. Appelez deux fois le même identifiant à quelques instants d’intervalle. Un seul appel doit obtenir le répertoire ; l’autre doit renvoyer un résultat de doublon clair sans exécuter la charge utile. Essayez ensuite deux identifiants différents visant la même ressource. Si cela crée une course, le wrapper a besoin d’un verrou propre à la ressource ou le système cible d’une règle d’unicité.

Conservez les enregistrements assez longtemps pour couvrir votre fenêtre de nouvelle tentative opérationnelle. Si une tâche peut être relancée un jour plus tard, mais que l’hôte supprime les enregistrements après une heure, vous avez ajouté un délai à votre incertitude. Protégez aussi les enregistrements contre les modifications ordinaires. Le compte qui vérifie une exécution ne devrait pas pouvoir modifier exit_status ni remplacer le journal de charge utile. Sur les systèmes partagés, séparez les rôles de soumission, d’exécution et de lecture lorsque le modèle opérationnel le permet.

Lorsque des agents IA invoquent SSH, l’isolation des identifiants et la vérification des commandes doivent fonctionner ensemble. Sallyport conserve les identifiants SSH dans son coffre et peut enregistrer l’action demandée par un agent, tandis que le wrapper distant fournit la réponse durable sur la tâche elle-même. L’enregistrement de l’action indique quel processus a demandé la commande ; l’identifiant d’exécution distant indique ce qui s’est passé après que la connexion est devenue incertaine.

La décision de nouvelle tentative sûre comporte quatre issues

Après une déconnexion, classez la situation avant d’agir. Il existe quatre issues utiles, et une seule autorise une nouvelle tentative automatique.

Si l’exécution est absent, le wrapper distant n’a jamais créé son enregistrement. Vous pouvez soumettre la même opération avec le même identifiant si vous faites confiance à son comportement de création unique. Si la commande a pu être exécutée en dehors du wrapper, inspectez d’abord la cible, car le wrapper ne peut pas prouver ce qui l’a contourné.

Si l’exécution est running, attendez ou annulez-la par un mécanisme propre à l’opération. Ne lancez pas une seconde copie. Une politique de délai appartient à la charge utile ou au gestionnaire de tâches, pas à une deuxième invocation SSH qui entrerait en concurrence avec la première.

Si l’exécution est finished, évaluez son code de sortie, puis contrôlez la postcondition lorsque l’opération produit des effets externes importants. Un code de sortie nul associé à une postcondition en échec signifie que l’opération a échoué. Considérez le contrôle de l’effet comme la référence.

Si l’exécution est damaged, cessez de parler d’une simple nouvelle tentative. Il s’agit d’un travail de réconciliation. Inspectez les journaux, les entrées du journal système, l’état de la cible et tout enregistrement d’idempotence. Décidez s’il faut corriger l’effet partiel, marquer l’opération comme terminée ou soumettre une nouvelle exécution qui traite explicitement l’état observé. Cette décision peut nécessiter une intervention humaine, car l’enregistrement manquant a supprimé la preuve dont dépend l’automatisation.

Le changement utile est modeste : chaque commande dont une répétition pourrait vous nuire reçoit un identifiant d’exécution, un enregistrement distant de démarrage, un enregistrement distant final et une vérification de l’état cible. SSH continuera de se déconnecter. Votre automatisation n’aura plus à prétendre qu’elle sait ce qui s’est passé.

FAQ

Que signifie un état distant inconnu après une déconnexion SSH ?

Cela signifie que votre client SSH a perdu la connexion après avoir peut-être envoyé la requête, mais avant de recevoir un résultat fiable. L’hôte distant peut ne jamais avoir démarré la commande, être encore en train de l’exécuter ou l’avoir terminée. Considérez ces trois possibilités jusqu’à ce que les preuves distantes les écartent.

Ma commande distante s’est-elle exécutée si SSH s’est déconnecté ?

Non. Une écriture locale réussie prouve seulement que votre client a remis des octets à sa pile réseau locale. Un délai d’attente ou une réinitialisation à ce stade ne permet pas de savoir si sshd a accepté la requête du canal ni si le shell distant a démarré la commande.

Comment vérifier si une commande est toujours en cours après une coupure SSH ?

Reconnectez-vous et consultez un enregistrement d’exécution durable, pas seulement la liste des processus. Recherchez un répertoire d’exécution, un marqueur de démarrage, un fichier de résultat, la sortie attendue et une vérification adaptée à l’effet, comme une ligne de base de données, une version de déploiement ou une somme de contrôle d’objet.

Est-il prudent de relancer une commande SSH après un délai d’attente ?

En général, non. Relancer une commande qui produit des effets externes peut créer des doublons, écraser des données plus récentes, envoyer des requêtes en double ou démarrer une seconde migration. Ne réessayez que si l’opération est conçue pour être idempotente ou si vous avez établi avec certitude que la première exécution n’a pas commencé.

nohup résout-il les problèmes de déconnexion SSH ?

nohup modifie uniquement la façon dont un processus gère les signaux de déconnexion et redirige généralement sa sortie. Il ne crée pas d’identifiant d’exécution durable, n’enregistre pas un état final fiable et ne rend pas une opération sûre à exécuter deux fois.

Dois-je utiliser tmux ou screen pour les longues commandes SSH ?

tmux et screen permettent de conserver un shell interactif après une reconnexion, ce qui est utile pour la maintenance manuelle. Ils ne prouvent pas qu’un effet externe s’est produit et constituent un mauvais journal d’audit pour les opérations automatisées.

Les keepalives SSH peuvent-ils empêcher un état distant inconnu ?

Utilisez les keepalives du client pour détecter plus vite un chemin réseau défaillant, pas pour garantir la livraison ou la fin de la commande. ServerAliveInterval et ServerAliveCountMax d’OpenSSH aident le client à cesser d’attendre une connexion morte, mais ils ne lèvent pas l’ambiguïté d’une requête déjà envoyée.

Pourquoi un PID ne suffit-il pas à prouver qu’une tâche distante est terminée ?

Un PID identifie un processus à un moment donné et peut être réutilisé après sa fin. Conservez-le comme élément de diagnostic avec un identifiant d’exécution, l’heure de démarrage, la version de la commande, un fichier de résultat et un enregistrement de fin adapté à l’effet recherché.

Quand faut-il créer un wrapper pour les commandes distantes ?

Utilisez un wrapper distant lorsque la commande modifie des données, déploie un logiciel, fait tourner des identifiants, contrôle une infrastructure ou coûte de l’argent. Une commande distante simple convient aux lectures sans risque, mais un wrapper justifie sa complexité dès qu’une nouvelle tentative peut causer des dommages.

Un agent IA peut-il exécuter sans risque des commandes SSH susceptibles de se déconnecter ?

Sallyport peut exécuter des actions SSH sans exposer l’identifiant SSH à l’agent et enregistre chaque action, mais le programme distant a toujours besoin d’un protocole de fin. Le contrôle des identifiants et l’état distant inconnu sont deux problèmes distincts. Traiter l’un comme une solution de remplacement pour l’autre donne une fausse impression de sécurité.

Sallyport

Sallyport exécute les appels d'API et les commandes SSH à la place de votre agent IA. Les clés restent dans un coffre-fort local sur votre Mac ; vous approuvez chaque exécution et chaque action est consignée dans un journal scellé.

© 2026 Sallyport · Open source sous Apache-2.0 · Oleg Sotnikov