8 min de lecture

Quand l'allocation de TTY SSH change-t-elle une commande ?

L'allocation de TTY SSH modifie invites, flux, signaux et détection du terminal. Apprenez quand utiliser -T, -t ou -tt sans casser l'automatisation.

Quand l'allocation de TTY SSH change-t-elle une commande ?

Ajouter -t à une commande SSH fait bien plus qu'afficher une invite. Cette option remplace trois flux distants distincts par un terminal, installe les règles de ligne du terminal, attribue un terminal de contrôle à la session et incite les programmes à se comporter comme si une personne les observait. Cela peut réparer une exécution interactive de sudo tout en cassant discrètement un analyseur, un pipeline ou l'annulation.

Pour un travail sans surveillance, l'absence de PTY doit rester le choix par défaut. Demandez-en un uniquement lorsque le programme distant a réellement besoin de la sémantique d'un terminal et considérez ce choix comme une partie du contrat de la commande. J'ai vu trop de scripts de déploiement recevoir -tt pendant une urgence et le garder des années, bien après que quiconque se soit souvenu du défaut qu'il masquait.

Un PTY modifie l'environnement du processus

L'allocation de TTY SSH modifie les descripteurs de fichier reçus par le processus distant, pas seulement l'apparence de sa sortie. Sans PTY, OpenSSH relie l'entrée standard, la sortie standard et l'erreur standard au moyen de tubes ou de paires de sockets. Avec un PTY, OpenSSH en fait le terminal de contrôle et duplique le même descripteur de terminal sur les trois flux standard.

Ce détail d'implémentation a des conséquences visibles. Un programme peut appeler isatty() et choisir un chemin interactif. Le pilote du terminal peut traiter des caractères spéciaux, renvoyer l'entrée en écho, convertir les fins de ligne et suivre un groupe de processus au premier plan. L'erreur standard ne dispose plus d'un canal distant indépendant puisque les deux descripteurs de sortie pointent vers le même terminal.

RFC 4254 sépare ces notions au niveau du protocole. Une session peut demander pty-req, puis demander un shell ou une commande exec. La demande de PTY contient un type de terminal, des dimensions et des modes de terminal encodés. Rien dans cette demande ne transforme une requête exec en shell de connexion.

OpenSSH présente ce choix sous trois formes utiles :

  • ssh -T host command désactive explicitement l'allocation de PTY.
  • ssh -t host command demande un PTY lorsque le client local possède un terminal.
  • ssh -tt host command force la demande même si l'entrée locale vient d'un tube ou d'une autre source sans terminal.

Le double -t ne fournit pas un terminal distant plus puissant. Il passe outre la vérification de sécurité locale. Cette différence compte dans un exécuteur de compilation, un processus agent ou printf ... | ssh, où un seul -t peut afficher « Pseudo-terminal will not be allocated because stdin is not a terminal » et continuer sans la sémantique attendue par l'auteur.

L'absence de PTY préserve aussi un chemin transparent pour les octets. Le manuel ssh(1) d'OpenSSH décrit ce mode comme adapté au transfert fiable de données binaires. Un PTY est un périphérique caractère soumis à des règles de traitement, ce qui en fait un mauvais transport pour une archive, une sauvegarde de base de données ou une sortie lisible par une machine dont les octets doivent rester exacts.

Le même choix peut se cacher dans la configuration. Le réglage client RequestTTY d'OpenSSH accepte no, yes, force ou auto, ce qui correspond aux comportements généralement obtenus avec -T, -t et le réglage par défaut. Vérifiez la configuration client effective avec ssh -G host.example lorsqu'une commande obtient un terminal sans l'avoir demandé sur sa ligne. Les blocs d'hôtes et les fichiers inclus peuvent transformer deux commandes apparemment identiques en sessions différentes.

Le serveur participe aussi à la décision. PermitTTY peut refuser l'allocation et une entrée authorized key peut porter une restriction no-pty. Une commande forcée ne s'exécute sur un PTY que si le client le demande et que le serveur l'autorise. Traitez le refus comme une véritable incompatibilité d'interface, et non comme une raison de réessayer avec davantage d'options -t.

Mesurez les deux modes avant de les modifier

Une petite sonde en dit plus qu'une nouvelle série d'hypothèses sur les options SSH. Exécutez-la avec le même compte, la même configuration d'hôte et le même chemin de commande qu'en production :

probe='
for fd in 0 1 2; do
    if test -t "$fd"; then kind=tty; else kind=not-tty; fi
    printf "fd%s=%s\n" "$fd" "$kind"
done
printf "term=%s\n" "${TERM-unset}"
printf "stdout-marker\n"
printf "stderr-marker\n" >&2
exit 23
'

ssh -T host.example "$probe" >no-pty.out 2>no-pty.err
printf 'no-pty ssh status=%s\n' "$?"

ssh -tt host.example "$probe" >pty.out 2>pty.err
printf 'pty ssh status=%s\n' "$?"

L'exécution sans terminal doit placer les trois lignes fdN=not-tty, term=unset et stdout-marker dans no-pty.out. Elle doit placer uniquement stderr-marker dans no-pty.err. La valeur exacte de TERM peut varier, car clients et serveurs acceptent les réglages d'environnement de différentes manières. Consignez donc ce que fournit votre chemin réel au lieu de dépendre de l'exemple.

L'exécution avec PTY doit signaler les trois descripteurs comme tty. Les deux marqueurs arrivent normalement dans pty.out, souvent avec des fins de ligne composées d'un retour chariot et d'un saut de ligne. pty.err contient les diagnostics SSH locaux éventuels, mais ne peut pas récupérer l'erreur standard d'origine du programme distant sous forme de flux séparé. Les deux commandes SSH doivent renvoyer 23, car l'allocation d'un PTY ne supprime pas à elle seule le code de sortie distant.

Complétez la sonde avec le véritable exécutable avant de modifier une tâche. Ajoutez command -V tool, pwd, un affichage filtré de l'environnement et les options de diagnostic sans secret du programme. Si la sortie change, déterminez quelle observation a déclenché la branche : détection du terminal, TERM, largeur du terminal, fusion des flux, fichier de démarrage ou invite. « Fonctionne avec -t » ne décrit qu'un symptôme.

Exécutez aussi la sonde avec le même lanceur. Une commande collée dans un shell dispose d'un TTY local, contrairement à la plupart des agents ou travailleurs d'intégration continue. C'est pourquoi un essai avec -t au clavier peut diverger de l'exécution automatisée jusqu'à ce que vous testiez -tt, et pourquoi forcer un PTY peut exposer une tâche à des entrées qu'elle n'attendait pas.

Testez l'entrée séparément de la sortie. ssh -n redirige l'entrée standard du client depuis /dev/null, et le réglage StdinNull fait de même dans la configuration. C'est utile lorsqu'une commande distante ne doit jamais consommer l'entrée de l'appelant, mais cela ne désactive pas l'allocation de PTY. Un PTY forcé avec une entrée nulle modifie toujours la détection du terminal, la fusion des flux et le comportement à la déconnexion.

Soyez prudent lorsque SSH s'exécute dans une boucle. Sans -n, la première commande distante peut lire des lignes destinées à la boucle, même si le processus distant ne devait pas les consommer. Avec un PTY, l'écho du terminal peut également renvoyer ces octets dans la transcription. Définissez qui contrôle l'entrée standard avant d'interpréter toute autre différence.

Les invites sudo exigent un contrat explicite

sudo a besoin d'un moyen de s'authentifier et un PTY lui offre un terminal où lire un mot de passe. Le manuel de sudo précise qu'il lit normalement le mot de passe dans le terminal de l'utilisateur. Sans terminal, l'exigence d'un mot de passe échoue, sauf si un assistant askpass existe ou si l'appelant choisit une autre méthode d'entrée.

Voilà pourquoi cette correction courante fonctionne :

ssh -t host.example 'sudo systemctl restart example.service'

Elle convient à une personne qui prévoit de saisir un mot de passe et de surveiller la commande. Elle répare mal une exécution sans surveillance. La tâche peut attendre indéfiniment, une invite peut contaminer la sortie attendue et quelqu'un finira peut-être par envoyer un mot de passe dans le même canal que les données de la commande.

Utilisez sudo en mode non interactif pour l'automatisation :

ssh -T host.example \
  'sudo -n /usr/bin/systemctl restart example.service'

L'option -n demande à sudo de ne pas afficher d'invite. Si des identifiants en cache ou la politique sudoers n'autorisent pas l'action sans interaction, sudo se termine avec une erreur. Cet échec est utile : l'appelant reçoit un état précis plutôt qu'une invite cachée. Associez-le à une règle sudoers limitée à une commande et à des arguments exacts lorsqu'une automatisation privilégiée est vraiment nécessaire. Autoriser un shell entier sans mot de passe remplace un problème de disponibilité par un problème d'autorité bien plus grave.

Ne faites pas dépendre une tâche sans surveillance d'un horodatage sudo mis en cache. Le cache appartient à un contexte d'authentification dont les détails de terminal et de session varient selon la politique. Une tâche qui réussit parce qu'un administrateur a utilisé sudo une minute plus tôt, mais échoue après un week-end calme, n'a pas de conception d'autorisation. Elle a seulement profité du bon moment.

sudo -S lit un mot de passe depuis l'entrée standard. Cette option peut faire fonctionner une commande sans PTY, mais elle mélange un secret au chemin des données et confie la gestion du mot de passe à l'appelant. Évitez-la pour les agents et l'automatisation courante. Un assistant askpass peut convenir à un processus graphique supervisé par une personne, mais il s'agit toujours d'une authentification interactive qui ne doit pas être improvisée dans une tâche censée être autonome.

Deux PTY sont souvent confondus ici. SSH peut allouer un PTY distant avant de lancer sudo. Indépendamment, un sudo moderne peut exécuter la commande autorisée dans son propre PTY pour journaliser les E/S et l'isoler ; sudo 1.9.14 active son réglage use_pty par défaut. Ce PTY interne ne fournit pas l'invite de mot de passe externe quand la session SSH n'a pas de terminal. Il intervient une fois que sudo possède assez de contexte pour exécuter la commande.

Certaines configurations sudoers imposent également un terminal dans leur politique. Les anciennes configurations d'entreprise utilisaient souvent requiretty, qui peut encore exister sur un système actuel. Confirmez la politique sudoers effective au lieu de supposer que chaque message « terminal is required » désigne une demande de mot de passe.

Un PTY ne choisit pas les fichiers de démarrage du shell

Une commande SSH dotée d'un PTY reste une commande exécutée par le shell configuré du compte avec -c. Le manuel sshd(8) d'OpenSSH indique qu'une commande demandée est exécutée ainsi, et le code du serveur la transmet au shell de l'utilisateur. L'allocation de PTY modifie les descripteurs autour de ce shell ; elle n'ajoute ni -i, ni -l, ni option de connexion.

Ce point compte lorsque PATH, un gestionnaire de langage ou un alias existe dans une invite interactive, mais pas dans l'automatisation. Ajouter -t peut sembler corriger le chemin parce qu'un fichier de démarrage contient des tests de terminal ou parce que l'outil appelé détecte un terminal. Il peut aussi ne rien changer. En dépendre lie la tâche à des fichiers que les développeurs modifient pour leur propre terminal.

Bash comporte un cas particulier qui rend cette croyance plus difficile à démêler. Son manuel indique qu'un shell de connexion interactif lit les fichiers de profil, qu'un shell interactif hors connexion lit .bashrc et qu'un shell non interactif utilise BASH_ENV. Bash tente également de reconnaître une exécution par un daemon de shell distant et peut lire .bashrc même sans interaction, sauf s'il est appelé comme sh. C'est un comportement de Bash, pas une promesse de SSH, et il n'est pas transposable à tous les shells de compte.

Sélectionnez directement le mode du shell quand vous en avez besoin :

# A predictable noninteractive Bash command with explicit inputs
ssh -T host.example \
  'PATH=/usr/local/bin:/usr/bin:/bin /bin/bash -c '\''command -v deploy && deploy'\'''

# A login environment, requested because the command truly depends on it
ssh -T host.example \
  '/bin/bash -lc '\''command -v deploy && deploy'\'''

La seconde forme lit volontairement les fichiers de démarrage de connexion et hérite de leurs risques : une sortie produite par un profil peut corrompre un protocole et un profil peut changer de comportement sans examen du déploiement. Pour les tâches de production, un chemin absolu vers l'exécutable et un environnement réduit et explicite sont généralement préférables.

Les alias constituent un autre piège. Bash non interactif ne développe pas les alias sans l'activation de expand_aliases, et une fonction de shell n'existe que si un mécanisme de démarrage la définit ou l'importe. Si ssh host deploy ne fonctionne qu'après avoir ajouté -t, vérifiez que deploy est un véritable exécutable. Un terminal ne doit pas décider si le compte distant trouve le programme.

N'oubliez pas que SSH envoie une chaîne de commande, et non un vecteur d'arguments pour l'exécutable final. Le shell du compte distant analyse cette chaîne après que le shell local a déjà traité ses propres guillemets. L'allocation de PTY ne modifie aucune de ces analyses. Quand des valeurs peuvent contenir des espaces ou des métacaractères de shell, envoyez un script avec des entrées fixes, utilisez un assistant distant au format de données défini ou protégez chaque couche délibérément. Un terminal ne peut pas réparer un argument développé trop tôt par le shell local.

Ctrl-C suit les règles du terminal uniquement avec un PTY

Gardez les clés SSH hors des invites
Sallyport fournit la clé SSH dans sp-ssh et l'agent ne reçoit que le résultat.

Avec un PTY, Ctrl-C est généralement un octet d'entrée interprété par le pilote du terminal distant. POSIX le nomme caractère INTR. Lorsque le drapeau ISIG est actif, le pilote supprime cet octet et envoie SIGINT à chaque processus du groupe au premier plan du terminal. C'est pourquoi un pipeline distant au premier plan peut s'arrêter comme une seule tâche.

Le client SSH local place le terminal local dans un mode approprié et envoie les frappes dans le canal. Le PTY distant gère l'entrée canonique, l'écho, les caractères spéciaux et la taille de la fenêtre. Des programmes tels que les éditeurs plein écran peuvent changer ces modes, et une déconnexion anormale peut laisser l'affichage local dans un état incorrect jusqu'à la réinitialisation du terminal.

Sans PTY, aucun pilote de terminal distant n'interprète Ctrl-C et aucun groupe de premier plan n'est associé à un terminal. RFC 4254 définit une demande de canal SSH signal distincte, mais autorise les systèmes qui n'implémentent pas les signaux à l'ignorer. Un client, un serveur, un script enveloppe et le programme appelé peuvent donc produire une annulation différente de celle d'un terminal interactif.

Ctrl-Z et le contrôle des tâches révèlent encore plus vite la différence. Dans un terminal, le caractère SUSP peut envoyer SIGTSTP au groupe au premier plan, et un shell interactif peut ensuite reprendre la tâche. Une commande distante ponctuelle n'obtient pas un dialogue de contrôle des tâches utile simplement parce qu'elle possède un PTY. Sa suspension peut laisser le client SSH attendre un groupe distant arrêté, sans invite de shell pour exécuter fg.

Ne supposez pas qu'une transaction distante est sûre parce que l'opérateur pourra appuyer sur Ctrl-C au bon moment. Placez les règles d'annulation dans la commande distante. Un script enveloppe peut capturer les signaux et terminer son groupe d'enfants, un gestionnaire de services peut prendre en charge le processus et un délai distant peut limiter l'exécution. Testez ensuite la déconnexion, pas seulement le clavier.

ssh -tt host.example '
  trap '\''printf "wrapper got INT\n" >&2; exit 130'\'' INT
  printf "remote shell pid=%s\n" "$$"
  sleep 300
'

Appuyer sur Ctrl-C doit emprunter le chemin PTY et rendre le contrôle. Répétez avec le véritable programme, car les shells, applications de terminal et superviseurs de processus installent des gestionnaires différents. Testez aussi la fermeture de la connexion réseau. La suppression du PTY peut provoquer un signal de déconnexion pour la session de contrôle, tandis qu'un enfant sans PTY qui conserve un tube de sortie peut maintenir le canal SSH ouvert. Mettre un processus en arrière-plan ne constitue un plan de détachement dans aucun des deux modes.

Pour un long travail, soumettez-le à un gestionnaire de services ou à un système de tâches distant et renvoyez un identifiant. L'annulation dispose ainsi d'une cible distante explicite et SSH indique uniquement si la soumission a réussi. Une brève coupure du client ne décidera pas non plus si la moitié d'une migration se poursuit.

Le code de sortie subsiste, mais les enveloppes peuvent le remplacer

OpenSSH renvoie le code de sortie de la commande distante dans les deux modes. Son manuel client indique que ssh se termine avec ce code, ou avec 255 en cas d'erreur. RFC 4254 décrit le message de canal exit-status comme une valeur non signée de 32 bits et définit un message exit-signal séparé pour un arrêt par signal.

L'allocation de PTY ne rend pas un état de réussite plus fiable. La composition du shell détermine quel état devient celui de la commande distante. Cette commande signale l'état de printf et peut donc masquer un échec de déploiement :

ssh -tt host.example 'deploy; printf "finished\n"'

Préservez le résultat explicitement :

ssh -T host.example '
  deploy
  rc=$?
  printf "deploy_status=%s\n" "$rc" >&2
  exit "$rc"
'
rc=$?
printf 'ssh_status=%s\n' "$rc"
exit "$rc"

Les pipelines locaux peuvent le masquer à nouveau. Dans les shells sans option d'état des pipelines, ssh host command | tee log renvoie généralement l'état de tee. Capturez d'abord la sortie SSH dans un fichier, utilisez un shell doté d'une fonction d'état de pipeline testée ou lisez les états de chaque commande. Ne supposez pas que set -e répare tous les pipelines, conditions ou sous-shells.

Le code 255 est ambigu, car OpenSSH le réserve aux erreurs client alors qu'un programme distant peut aussi quitter avec 255. Si cette distinction compte, demandez à l'enveloppe distante d'émettre un enregistrement structuré de fin sur un canal protégé ou transposez les états de l'application dans une plage convenue. Échec d'authentification, échec de vérification de l'hôte, perte du transport et véritable 255 distant ne doivent pas déclencher la même nouvelle tentative.

Les échecs de connexion se produisent avant que l'enveloppe distante puisse afficher quoi que ce soit. Utilisez des délais côté client et suffisamment de diagnostics SSH pour les classer localement, mais tenez ces diagnostics à l'écart du fichier de données du programme. Dès que le serveur lance l'enveloppe, incluez un identifiant d'exécution et un enregistrement d'état final afin que l'appelant distingue « jamais démarré » de « démarré, puis connexion perdue ». Cette distinction évite de relancer aveuglément des commandes qui ont peut-être déjà modifié l'état.

Les arrêts par signal exigent la même prudence. Un shell représente souvent un signal par 128 plus son numéro, mais le protocole SSH peut signaler directement un signal de sortie et le comportement du client ne ressemble pas forcément à l'état d'un enfant de shell local dans tous les cas. Définissez les états émis par votre enveloppe au lieu d'interpréter après un incident toutes les valeurs supérieures à 128.

Un PTY fusionne les flux et modifie les octets

Faites passer SSH par une passerelle
Un agent MCP envoie les actions SSH par l'assistant sans état sp-ssh inclus.

Demander un PTY renonce à une séparation nette entre la sortie standard et l'erreur standard distantes. L'implémentation serveur d'OpenSSH duplique l'esclave du PTY sur les descripteurs 0, 1 et 2. Le protocole possède un canal de données étendu pour l'erreur standard, mais un processus relié à un terminal unique a déjà écrit les deux flux dans la même suite d'octets.

Cela casse un schéma d'automatisation fréquent :

ssh -T host.example command >result.json 2>diagnostic.log

Sans PTY, l'erreur standard du programme distant peut atteindre diagnostic.log tandis que le JSON reste dans result.json. Avec un PTY, avertissements distants, demandes de mot de passe, bannières, affichages de progression et JSON peuvent tous arriver dans result.json ; les diagnostics SSH locaux peuvent encore apparaître dans diagnostic.log. Une redirection côté client ne peut pas séparer les octets après leur fusion par le serveur.

Le traitement de sortie du terminal peut aussi convertir un saut de ligne en retour chariot suivi d'un saut de ligne. L'entrée peut être renvoyée en écho, le mode canonique peut attendre une ligne entière et des caractères de contrôle peuvent déclencher des fonctions du terminal. Ce sont des comportements normaux pour un terminal et des corruptions pour un protocole binaire.

Les programmes sensibles au terminal ajoutent souvent des couleurs, des barres de progression, des pagineurs ou des invites. Ils peuvent utiliser un tampon par ligne sur un terminal et par bloc sur un tube, ce qui donne l'impression qu'une exécution sans PTY est bloquée alors qu'elle travaille. Corrigez le tampon dans l'application si possible : choisissez son option de sortie simple, son mode sans tampon ou son réglage de journalisation. Un faux terminal modifie plusieurs variables à la fois et peut masquer le véritable problème.

Si une commande produit des données pour une machine, conservez -T et demandez au programme d'émettre un format non interactif. Si elle a réellement besoin d'un terminal, traitez toute sa sortie comme une transcription. N'analysez pas une transcription PTY comme une API stable.

Un SSH lancé par un agent doit échouer sans dialogue

Consignez l'appel SSH exact
Le journal Activity enregistre chaque action même si un PTY fusionne les flux distants.

Un appelant autonome ne peut pas gérer de façon sûre une conversation de terminal. Une invite utile à un humain peut faire attendre un agent, l'inciter à improviser une entrée ou lui faire classer une action partielle comme une réussite. La commande SSH doit annoncer si l'interaction est permise avant l'intervention d'identifiants, de privilèges ou d'un état distant.

Pour les exécutions par agent, combinez l'absence de PTY avec la suppression des invites à chaque couche. L'authentification et la vérification de l'hôte SSH nécessitent une politique préparée. L'élévation de privilèges doit utiliser sudo -n. L'outil distant doit recevoir son option non interactive, un délai explicite et ses entrées par fichiers ou arguments nommés plutôt que par une invite. Capturez séparément la sortie standard, l'erreur standard et l'état.

Ne résolvez pas une invite de mot de passe absente en exposant un mot de passe ou une clé privée à l'agent. Les éléments d'authentification et le comportement du terminal sont des questions distinctes. Donner un PTY au processus ne réduit pas ce que peuvent faire des identifiants volés, et le lui refuser ne protège pas des identifiants déjà présents dans son environnement.

Sallyport retire la limite des identifiants du processus agent : un agent compatible MCP demande une action SSH par l'assistant sans état sp-ssh, tandis que le coffre chiffré fournit la clé SSH et que le journal Activity consigne l'appel. La commande a toujours besoin d'un contrat de PTY intentionnel, car l'isolation des secrets ne peut pas décider si le programme distant attend la sémantique d'un terminal.

Une approbation diffère également d'une invite distante. Une carte d'approbation locale peut autoriser une action définie avant son exécution ; une invite du terminal distant apparaît dans une session déjà ouverte et peut survenir après des effets antérieurs. Conservez l'autorisation humaine hors du flux d'octets distant afin qu'un refus ait un sens clair et que les journaux identifient l'action tentée.

Quand un agent a besoin d'un outil de maintenance interactif, divisez le processus. Laissez l'agent préparer une commande ou une demande, puis confiez la session de terminal en direct à une personne, ou remplacez l'outil par une opération non interactive conçue pour l'automatisation. Faire semblant qu'un agent est un opérateur au clavier produit la version la moins testable des deux systèmes.

Choisissez le mode comme une partie de l'interface

Le bon mode découle de l'interface du programme distant, et non d'une règle générale selon laquelle les PTY seraient bons ou mauvais. Utilisez cette liste pendant l'examen :

  • Utilisez -T pour le JSON, les archives et les octets exacts, car il préserve des données transparentes et une sortie d'erreur séparée.
  • Utilisez -T avec sudo -n pour un travail privilégié sans surveillance afin que l'authentification échoue au lieu d'attendre.
  • Utilisez -t lorsqu'une personne saisira un mot de passe sudo ou manipulera une interface de terminal.
  • Utilisez -tt depuis un tube ou un lanceur d'agent uniquement après avoir examiné le contournement de la vérification du TTY local.
  • Soumettez un long travail à un gestionnaire distant, car un PTY ne fournit pas une propriété durable du processus.

Consignez le choix près de la commande. Les tests doivent vérifier les types de descripteurs, la séparation des flux, l'annulation et l'état, pas seulement quelques mots de sortie attendus. Si la mise à jour d'une dépendance commence à exiger un terminal, laissez le test échouer et examinez la nouvelle invite ou branche de détection avant d'ajouter -t.

Incluez le mode choisi dans les journaux sous forme de métadonnée structurée au lieu de le déduire d'une sortie colorée ou d'une invite. Quand un incident traverse plusieurs hôtes, ce seul champ permet de séparer le comportement du terminal des échecs d'authentification, de réseau et d'application avant toute nouvelle exécution.

La politique du serveur peut refuser les PTY par la configuration OpenSSH ou une restriction authorized key. C'est une raison supplémentaire de ne pas en faire une dépendance accidentelle. Une commande conçue pour l'automatisation doit rester utilisable sous -T ; une commande interactive doit échouer clairement lorsqu'elle ne peut pas obtenir de terminal.

Traitez toute proposition de -tt comme un changement d'interface. Relancez la sonde, redirigez les deux flux locaux, envoyez Ctrl-C, forcez la commande distante à renvoyer un code non nul et interrompez la connexion en cours d'exécution. Si le résultat ne peut pas être décrit précisément, la commande n'est pas prête pour une exécution sans surveillance.

FAQ

Que fait vraiment ssh -t ?

Il demande au serveur SSH d'allouer un PTY et d'y relier la session distante. Les programmes voient des descripteurs de terminal, les flux distants fusionnent et les règles d'entrée peuvent produire des signaux.

Quelle différence existe entre ssh -t et ssh -tt ?

-t force une demande de PTY lorsque le client local possède un terminal. Répété sous la forme -tt, il force aussi l'allocation lorsque l'entrée standard locale n'est pas un terminal, ce qui est fréquent dans les pipelines et lanceurs d'agents.

SSH alloue-t-il un TTY par défaut à une commande distante ?

En général, une commande distante précisée s'exécute sans PTY. Utilisez -T pour rendre ce choix explicite ou -t lorsque la commande a réellement besoin d'un terminal.

Pourquoi sudo échoue-t-il par SSH sans TTY ?

Lorsque sudo a besoin d'un mot de passe, il le lit normalement dans le terminal de l'utilisateur. Pour automatiser, utilisez sudo -n et une règle sudoers assez étroite afin que la commande échoue au lieu d'afficher une invite.

sudo -S est-il sûr dans un script SSH ?

sudo -S confie le transport du mot de passe au script et mélange le secret avec l'entrée standard. Évitez-le pour les agents et l'automatisation courante ; utilisez une autorisation sans invite.

ssh -t charge-t-il .bashrc ou .profile ?

Non, l'allocation de PTY ne sélectionne pas les fichiers de démarrage du shell. Demandez explicitement un shell interactif ou de connexion si nécessaire, même si un environnement et un exécutable explicites donnent des tâches plus prévisibles.

Pourquoi stdout et stderr sont-ils mélangés avec ssh -t ?

OpenSSH relie les descripteurs 1 et 2 au même esclave PTY, de sorte que le serveur ne dispose que d'un flux d'octets de terminal. Une redirection ultérieure du client ne peut pas reconstruire les flux d'origine.

Un PTY modifie-t-il le code de sortie SSH ?

Le PTY seul ne le modifie pas ; OpenSSH renvoie toujours l'état de la commande distante. Les enveloppes, pipelines, signaux et le code client spécial 255 peuvent modifier ou masquer ce que voit l'appelant.

Pourquoi Ctrl-C réagit-il différemment avec et sans ssh -t ?

Le pilote d'un PTY convertit le caractère d'interruption en SIGINT pour son groupe au premier plan. Sans PTY, ce groupe distant n'existe pas et l'annulation dépend des signaux SSH et de la structure des processus.

Les agents IA doivent-ils utiliser ssh -tt pour les commandes susceptibles de demander une entrée ?

Non. Une commande destinée à un agent doit supprimer les invites et échouer avec un état utile ; forcer un terminal peut transformer une erreur de configuration en dialogue sans fin et fusionner les sorties nécessaires au diagnostic.

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