Aller au contenu

Rigs

Des faits, rien de plus. Pour le modèle qui les sous-tend, consultez Rigs et enceintes; pour ouvrir une machine, suivez le guide.

Surface Pilote Backend Valeur Sortie réseau confinée
Terminal (exec) Un interpréteur de commandes sur le canal exec de la VM microVM smolvm Oui
Navigateur Chromium sans interface (CDP), Firefox (WebDriver BiDi) ou WebKit (W3C WebDriver) microVM smolvm Oui
Ordinateur Bureau X11 : entrée par l’hyperviseur, capture par l’agent de l’invité QEMU qemu-hvf (macOS), qemu-kvm (Linux), qemu-tcg (solution de repli non accélérée, jamais choisie automatiquement) Oui
Android Android par ADB Émulateur de Google android-emulator Non — l’émulateur gère son propre réseau
iOS Simulateur iOS par WebDriverAgent CoreSimulator ios-simulator Non — le réseau suit le Mac hôte

Le terminal et la surface computer_use partagent la valeur de surface computer; le terminal se distingue par son marqueur d’image exec et n’est jamais réutilisé comme bureau pilotable (ni l’inverse). Une conversation réutilise une même machine terminale.

Moteur Valeur Protocole Vue en direct Images fixes
Chromium chromium (par défaut) Chrome DevTools Protocol Diffusion d’écran — le navigateur pousse les images à mesure que la page se redessine JPEG
Firefox firefox WebDriver BiDi Images fixes interrogées périodiquement (BiDi n’a pas de diffusion d’écran), plafonnées à 6 images/s JPEG
WebKit webkit W3C WebDriver (classique) Images fixes interrogées périodiquement, transcodées par le ffmpeg de l’hôte PNG

Un rig exécute un seul moteur pendant toute sa vie. Une même conversation peut contenir un rig par moteur, ce qui rend possible la comparaison côte à côte : ouvrir « Firefox (VM) » à côté de « Chromium (VM) » donne deux machines, et fermer l’une laisse l’autre en marche.

Passez engine à rig.open ou à l’outil browser_use. Un nom inconnu est refusé plutôt que remplacé par la valeur par défaut — demander un navigateur et en obtenir silencieusement un autre répond à une question de compatibilité par la mauvaise réponse.

Limites propres à chaque moteur, énoncées plutôt que contournées :

  • Firefox n’a pas de rechargement contournant le cache (il rejette carrément ignoreCache de BiDi), de sorte qu’un rechargement forcé est un rechargement normal.
  • WebKit n’a pas non plus de rechargement contournant le cache, ni de flux de console (la sortie est capturée en interceptant console.* après chaque navigation, de sorte que tout ce qui est consigné pendant le chargement est manqué — chaque extraction de console le dit), et nécessite ffmpeg sur l’hôte pour sa vue en direct.
  • Ni l’un ni l’autre n’expose d’arbre d’accessibilité de plateforme par son protocole, de sorte que extract (a11y) renvoie une approximation dérivée du DOM, étiquetée comme telle.
  • Ni l’un ni l’autre ne peut recevoir un véritable dépôt de fichier; un champ de fichier peut tout de même être pointé vers des chemins à l’intérieur de la machine.
Surface Image Récupération
Terminal ubuntu:24.04, épinglée par empreinte Automatiquement au premier démarrage, par le réseau protégé de la machine elle-même
Navigateur (Chromium, Firefox, WebKit) debian:trixie-slim, épinglée par empreinte, plus les paquets propres au moteur Automatiquement au premier démarrage, puis mise en cache sous forme de pack préchauffé
Ordinateur Une image de bureau qcow2 avec Chromium, Firefox, WebKit et le même socle d’outils CLI de type exécuteur hébergé par GitHub que celui que préchauffe le terminal Importer sous Paramètres → Serveur → Rigs (téléchargements épinglés par somme de contrôle lorsqu’ils sont publiés)
Android Images système de Google Par le SDK Android
iOS Un environnement d’exécution de simulateur Xcode plus WebDriverAgent épinglé par somme de contrôle L’environnement d’exécution par Xcode; passerelle d’automatisation depuis Paramètres → Serveur → Rigs

Après le premier démarrage de chaque type de microVM, le serveur met en cache une copie préextraite sous le répertoire de données et démarre toutes les machines suivantes à partir de celle-ci — y compris les images préchauffées avec les paquets déjà installés. Le terminal préchauffe un socle d’outils CLI de type exécuteur hébergé par GitHub (git, gcc, python3, jq, rsync, les outils d’archivage et le reste de la base apt; ni Docker ni les caches d’outils de langage). Le qcow2 Ordinateur intègre ces mêmes noms d’outils CLI au moment de la construction de l’image, aux côtés de XFCE et des trois navigateurs. Chaque navigateur préchauffe son moteur. Les trois moteurs partagent une base Debian mais ne partagent jamais un pack : le cache est indexé sur l’image, le moteur et une révision audio (audio-v1-<engine>), parce qu’une machine préchauffée pour un moteur — ou avant que PulseAudio et ffmpeg fassent partie de la charge de travail — ne contient rien de l’autre. Le pack du terminal est indexé sur une révision d’outillage (tools-v1) pour la même raison : un pack préchauffé avant que le compilateur fasse partie de l’image ne doit pas servir une machine censée en avoir un.

Aucune image d’automatisation préintégrée ne vaut la peine d’être reprise — le chromedp/headless-shell de Chromium exclut à la compilation ALSA et PulseAudio, de sorte qu’il ne peut jamais émettre de son; la seule image Firefox maintenue fait 33× la taille de la base Debian et n’embarque toujours pas socat; il n’existe aucune image WebKit maintenue. Chaque moteur s’installe donc au premier démarrage (chromium, firefox-esr ou webkit2gtk-driver) et atteint les archives Debian (deb.debian.org, security.debian.org, cloudfront.debian.net) pour ce faire. Chromium est le binaire de la distribution lancé sous la forme chromium --headless=new.

Clé de paramètre Remplace
rigs.smolvm.execImage L’image Terminal (VM)
rigs.smolvm.browserImage L’image Navigateur (VM) Chromium

Défini par le magasin de paramètres d’espace de travail réservé aux administrateurs (Paramètres → Serveur → Rigs → Images personnalisées (cet espace de travail)). La valeur doit être une référence de registre — les chemins locaux, les archives et les chaînes ressemblant à des indicateurs sont refusés, tant à la saisie qu’à nouveau au démarrage. Une valeur stockée invalide est ignorée bruyamment et c’est la valeur par défaut qui démarre. Le registre propre à l’image (ainsi que les CDN de blobs connus pour Docker Hub, GHCR, Quay, GitLab et GCR) est admis par la barrière de sortie réseau pour le tirage.

Contrat d’image Terminal — bash présent; git, curl, socat préinstallés ou une base apt Debian/Ubuntu (l’enceinte installe ces trois outils plus un socle d’outils CLI de type exécuteur hébergé par GitHub au premier démarrage : compilateurs, Python 3, jq, outils d’archivage, rsync. Les caches d’outils de langage et Docker ne sont pas installés).

Contrat d’image Navigateur — une base apt Debian/Ubuntu (ou les paquets déjà installés) avec bash et socat, plus un binaire chromium que le serveur lance lui-même sous la forme chromium --headless=new, avec DevTools sur la boucle locale de l’invité 9223, relayé vers le port invité 9222. PulseAudio et ffmpeg sont installés au premier démarrage pour la voie audio. Ne construisez pas FROM chromedp/headless-shell : en amont, headless.gn exclut à la compilation ALSA et PulseAudio, de sorte que ce binaire ne peut pas émettre de son. La substitution s’applique aux rigs Chromium seulement — la commande de charge de travail qu’elle démarre est celle de Chromium, et la transmettre à Firefox ou WebKit lancerait un binaire absent. Un rig Firefox ou WebKit l’ignore bruyamment et démarre son image épinglée.

Ports d’automatisation — chaque machine de navigateur transfère exactement un port de boucle locale de l’hôte vers le port invité 9222. Derrière celui-ci : les DevTools de Chromium et l’agent distant de Firefox se trouvent sur la boucle locale de l’invité 9223, avec un relais socat devant (les deux se lient à la boucle locale sans condition); le pilote de WebKit accepte un --host et se lie lui-même à la carte réseau de l’invité. Firefox valide en outre l’en-tête Host par rapport à son propre port, de sorte que le client envoie l’autorité côté invité plutôt que celle qu’il a contactée.

Chaque action est analysée de façon exhaustive : une charge utile malformée renvoie un message nommant le champ, jamais une exception. Les verbes d’observation (marqués ○) restent autorisés pendant qu’une personne détient le contrôle; les verbes de modification sont refusés.

screenshot○, cursor_position○, mouse_move, left_click, right_click, middle_click, double_click, triple_click, left_mouse_down, left_mouse_up, left_click_drag, scroll, key, hold_key (0–60 s), type, wait○ (0–60 s), set_display, clipboard_read○, clipboard_write.

Les coordonnées sont des pixels de l’invité dans le mode courant de celui-ci; chaque capture d’écran indique la taille de l’affichage. Les combinaisons de touches utilisent l’orthographe X11 (ctrl+s, alt+Tab, Return).

clipboard_read accepte une selection : clipboard (ce que remplit ctrl+C, la valeur par défaut), primary (sélection pour copie X11) ou xdnd (un glisser en cours). Un résultat vide est une réponse normale pour les trois. clipboard_write n’accepte que text — les images et les fichiers passent par la voie des fichiers, parce que les arguments d’une action sont conservés dans le journal d’audit et que les octets d’image n’y ont rien à faire. Le contenu du presse-papiers revient encadré comme donnée non fiable.

navigate (http/https seulement), reload (hard facultatif), stop_loading, click (sélecteur ou coordonnée), fill, type, key (noms de touches DOM), scroll, mouse_move, drag, left_mouse_down, left_mouse_up, extract○ (a11y | dom | console), screenshot○ (full_page facultatif), set_viewport (min 320×240), history, wait_for○ (sélecteur, 0,1–30 s), clipboard_read○, clipboard_write.

Le contenu de page extrait revient encadré comme donnée non fiable.

Le navigateur n’a qu’un seul presse-papiers, de sorte que clipboard_read n’accepte pas de selection. Les deux verbes de presse-papiers exigent un contexte sécurisé : une page servie en http:// simple n’a aucune API de presse-papiers, et le verbe le dit plutôt que de signaler un presse-papiers vide — utilisez type dans ce cas, qui insère au point d’insertion sans passer par un presse-papiers.

tap, swipe (50–5000 ms), type, key (alias back, home, recents, enter, delete, backspace, tab, escape, search, menu, volume_up, volume_down, power, ou tout KEYCODE_*), screenshot○, ui_dump○, install_apk (limité à l’arbre de travail du rig et au répertoire de données du serveur), start_app, stop_app, clear_app_data, uninstall_app, open_url, et shell. shell accepte une liste argv et s’exécute à l’intérieur d’Android, jamais par un interpréteur de commandes de l’hôte; il couvre les diagnostics de développement tels que logcat, dumpsys et pm grant.

mobile_use n’a pas de verbes de presse-papiers. Depuis Android 10, seule l’application au premier plan peut lire le presse-papiers.

tap, swipe (50–5000 ms), type, key (enter, backspace, tab, escape, touches fléchées ou un caractère imprimable; modificateurs command, control, option et shift facultatifs), home, lock, unlock, screenshot○, ui_dump○, install_app (un répertoire .app de simulateur limité à l’arbre de travail du rig ou au répertoire de données du serveur), start_app, stop_app, uninstall_app, open_url, et spawn. spawn accepte argv et s’exécute dans le simulateur par simctl; il n’invoque jamais un interpréteur de commandes de l’hôte.

Les coordonnées sont des points d’écran iOS, et non des pixels de capture d’écran. Le flux en direct conserve la taille fixe du simulateur et l’affiche en boîte aux lettres au lieu de redimensionner l’appareil. Le transfert de texte par presse-papiers de l’hôte vers le simulateur et du simulateur vers l’hôte suit la même politique d’autorisation par utilisateur et par sens que les autres rigs; les fichiers et les images ne sont pas acceptés par la voie du presse-papiers iOS.

Chaque rig crée un appareil CoreSimulator et une session WebDriverAgent qui lui appartiennent. Le fermer arrête WebDriverAgent, éteint et supprime cet appareil, puis retire son entrée du registre. Les rigs iOS ne tournent que sur un serveur macOS avec Xcode, un environnement d’exécution iOS installé et la passerelle d’automatisation épinglée. Ils n’offrent ni audio, ni microphone, ni dépôt de fichier, ni interpréteur de commandes de l’hôte, ni garantie de réseau en enceinte.

Outil Description
rig_list Liste les rigs d’un espace de travail avec leur surface, leur état, leur affichage et leur contrôleur
rig_close Détruit un rig et jette son disque
Phase Signification
provisioning Démarrage; le détail d’état reprend l’étape courante textuellement
ready Joignable et acceptant des actions
parked Mis en veille faute d’activité : vCPU arrêtés, mémoire RAM toujours résidente; l’action suivante le réveille
closing En cours d’arrêt
closed Disparu; la ligne subsiste pour la piste d’audit
failed Mort ou jamais démarré; distinguable pour que l’interface puisse proposer de réessayer
Motif de fermeture Déclenché quand
requested Une personne ou un agent l’a demandé
idleTimeout Inactif au-delà du double de la fenêtre d’inactivité, ou évincé pour libérer de la mémoire
ttlExpired La durée de vie stricte est épuisée
conversationEnded La conversation propriétaire a pris fin
workspaceGone L’espace de travail a été supprimé ou l’appartenance a été perdue
serverShutdown Le serveur s’arrête
backendFailure L’hyperviseur est mort en dessous
Valeur Terminal Navigateur Ordinateur Mobile
Mémoire 512 MB 2048 MB (Chromium); 2560 MB (Firefox, WebKit) 4096 MB 4096 MB
vCPU 2 2 4 4
TTL strict 8 h 2 h 2 h 2 h
Fenêtre d’inactivité 45 min 15 min 15 min 15 min
Affichage au démarrage — 1280×800 1280×800 1080×1920
  • Les images fixes de la voie de l’agent sont plafonnées à 1280×800; la voie humaine négocie jusqu’à 2560×1600.
  • Le budget de mémoire résidente de l’hôte pour l’ensemble des rigs est de 12 GB par défaut, compté en mégaoctets résidents (une VM en veille conserve sa mémoire RAM). L’éviction se fait selon la moins récemment utilisée et ne prend jamais une machine que quelqu’un pilote, regarde ou dans laquelle il a un terminal ouvert.
  • Un terminal ouvert ou une voie d’observation empêche le rig d’être mis en veille ou récupéré faute d’activité; le TTL strict s’applique tout de même.
Port Emplacement Réservé à
7911 Invité du terminal Le multiplexeur de ports sur lequel passe chaque transfert
9222, 9223 Invité du navigateur Le relais et le point de terminaison d’automatisation (WebKit se lie directement à 9222 et n’utilise aucun relais)
80, 443 Boucle locale de l’invité du navigateur Les voies HTTP/HTTPS des domaines de développement
  • La découverte interroge les ports TCP en écoute de l’invité du terminal toutes les ~4 s, côté serveur.
  • Au plus 16 ports sont transférés automatiquement par rig; les autres sont listés dans le journal, sans être transférés.
  • Le transfert côté hôte se lie à la boucle locale, en préférant le numéro de port de l’invité; Partager sur le réseau local ajoute un port LAN attribué par le système.
  • Les domaines de développement doivent correspondre à name.test ou name.localhost (en minuscules, étiquette d’au plus 63 caractères). Un domaine correspond à un port.
  • Le HTTPS des domaines de développement utilise une autorité de certification locale au serveur (EC P-256, sous <dataDir>/rigs/tls/, clés en 0600 et jamais dans un invité) avec un seul certificat feuille générique pour *.test / *.localhost. Sans openssl sur l’hôte, pas de voie HTTPS; le HTTP simple achemine quand même.
Surface Liste d’hôtes autorisés par défaut
Terminal La base de référence du développeur en bac à sable (forges, registres de paquets, fournisseurs de modèles) + les miroirs apt Ubuntu + l’hôte de forge propre à l’arbre de travail
Navigateur usectrl.dev (le site du produit) — plus les archives Debian au premier démarrage de chaque moteur, pendant l’installation de ses paquets. La page d’accueil est un document file:// local et n’a besoin d’aucune sortie réseau
Ordinateur Vide — tout est refusé — jusqu’à ce qu’un appelant accorde des hôtes
Mobile Non appliquée (réseau géré par l’émulateur)

Chaque microVM obtient en outre les hôtes de registre de son image, pour le tirage uniquement. L’ensemble d’hôtes autorisés du courtier d’identifiants est dérivé de la même liste : aucun jeton n’est émis pour un hôte que l’invité ne peut pas atteindre.

Les deux sens du copier-coller, et le glisser-déposer de fichiers vers l’intérieur et vers l’extérieur. À la disposition d’une personne qui pilote un rig; un agent obtient le presse-papiers par les verbes ci-dessus et aucun transfert de fichiers du tout (il dispose déjà d’un interpréteur de commandes à l’intérieur de l’enceinte).

Le franchissement du presse-papiers est propre à chaque utilisateur et à chaque sens. Le collage de l’hôte vers un rig est autorisé par défaut; la copie d’un rig vers l’hôte demande d’abord une autorisation (une autorisation de dix minutes, ou toujours autoriser sous Paramètres → Serveur → Rigs → Accès au presse-papiers). Les deux choix sont indépendants et ne constituent jamais un paramètre d’espace de travail.

Voie Route Contenu
Presse-papiers GET/POST /rig/clipboard/<rigId> Du texte, un PNG/JPEG (≤16 MB) et les chemins d’invité des fichiers présents dans le presse-papiers
Fichiers POST /rig/files/<rigId> Jusqu’à 64 fichiers, ≤256 MB chacun et ≤512 MB par dépôt, avec un point de dépôt facultatif en pixels de l’invité
Fichiers GET /rig/files/<rigId>?p=<base64url path> Les octets d’un fichier, en sens inverse
  • HTTP, pas RPC. La socket RPC ferme une connexion dès qu’une trame entrante dépasse 256 KB — une protection contre les attaques DoS qui convient aux commandes JSON et qui est fatale à une capture d’écran collée. Les octets empruntent le même type de route que celui déjà utilisé par les trames de rig et l’audio de réunion.
  • L’authentification repose sur la cible signée rig-files:<workspaceId>/<rigId> plus l’appartenance à l’espace de travail — une cible distincte, de sorte qu’une URL émise pour regarder une machine ne peut pas aussi y écrire des fichiers.
  • La prise de contrôle s’applique. Écrire dans le presse-papiers et déposer des fichiers sont des actions de modification, et elles sont refusées pendant que quelqu’un d’autre détient le contrôle; lire le presse-papiers et extraire un fichier sont des observations et ne le sont pas.
  • Où arrivent les dépôts : ~/Drops (bureau), ~/drops (terminal — à côté de l’arbre de travail, jamais dedans, de sorte qu’un dépôt n’apparaisse jamais comme une modification non suivie), /tmp/cc-drops (navigateur). C’est le serveur qui choisit le répertoire; un appelant ne peut pas le nommer. Les fichiers existants ne sont jamais écrasés — un nom en collision arrive sous la forme 2-name.ext.
  • Ce qu’on annonce à l’invité : une page de navigateur reçoit un véritable événement de dépôt à l’endroit demandé (Input.dispatchDragEvent); un bureau reçoit les fichiers plus leurs URI dans son presse-papiers, car aucun hôte ne peut synthétiser un glisser XDND vers une boîte à outils arbitraire sans un démon privilégié dans l’invité. La réponse indique lequel des deux s’est produit.
  • Le glisser vers l’extérieur ne fonctionne que sur le bureau et lit la XdndSelection de l’invité pendant qu’un glisser est en cours. Une charge utile identique à ce que l’invité détenait déjà au début de l’appui est traitée comme une sélection périmée d’un glisser terminé, et non comme une nouvelle — X n’a pas d’étape « le glisser est terminé ».
  • Exigences relatives à l’image : l’image de bureau doit être de protocole 2 ou ultérieur (construite après l’arrivée de la prise en charge du presse-papiers). Une image plus ancienne répond 404 et l’application invite à la reconstruire plutôt que de signaler une machine défectueuse.
  • Le journal d’audit consigne la forme, jamais le contenu : les lignes clipboard_read, clipboard_write, drop_files et read_file portent des comptes, des tailles et des chemins. Un presse-papiers est l’endroit où vivent les identifiants pendant quelques secondes à la fois, et rien de tout cela n’est écrit.
  • Les outils de rig déclarent la classe d’action enclosureControl (plus networkEgress et processSpawn sur les outils d’utilisation; mobile_use et ios_use déclarent aussi packageInstall). rig_close déclare enclosureControl; rig_list n’en déclare aucune. Autorisée par défaut; les modes en lecture seule la refusent entièrement; le réglage d’autonomie par espace peut la ramener à une demande d’approbation.
  • Événements de domaine : RigClosedEvent (avec son motif de fermeture), RigControlChanged (prise de contrôle / remise du contrôle), RigReaped (récupération pour inactivité, TTL ou éviction de mémoire, avec l’agent pilote). L’ouverture d’un rig n’est pas un événement. Voir les événements de domaine.
  • Stockage : rig_sessions et rig_action_log dans la base de données de chaque espace de travail. Le journal d’actions consigne chaque événement d’entrée avec son principal et une séquence monotone propre au rig; le texte saisi est réduit à une longueur et à un hachage avant d’être écrit.
  • Répertoire de données : rigs/images/ (images qcow2 importées), rigs/smolvm/ (état d’exécution propre à chaque rig), rigs/smolvm-packs/ (packs de machines préextraits), rigs/tls/ (l’autorité de certification des domaines de développement), rigs/run/ (surcouches et amorces QEMU).
  • Routes : la vue en direct est un onglet dans un espace ou une page de PR; /settings/server/rigs est l’écran de paramètres Rigs.