Saltar para o conteúdo

Rigs

Apenas factos. Para o modelo por trás deles, leia Rigs e recintos; para abrir uma máquina, siga o guia.

Superfície Controla Backend Valor Saída contida
Terminal (exec) Um shell sobre o canal exec da VM microVM smolvm Sim
Navegador Chromium headless (CDP), Firefox (WebDriver BiDi) ou WebKit (W3C WebDriver) microVM smolvm Sim
Computador Ambiente de trabalho X11: entrada através do hipervisor, captura através do agente do convidado QEMU qemu-hvf (macOS), qemu-kvm (Linux), qemu-tcg (alternativa não acelerada, nunca escolhida automaticamente) Sim
Android Android sobre ADB O emulador da Google android-emulator Não — o emulador gere a sua própria rede
iOS Simulador de iOS através do WebDriverAgent CoreSimulator ios-simulator Não — a rede segue o Mac anfitrião

O terminal e a superfície computer_use partilham o valor de superfície computer; o terminal distingue-se pelo seu marcador de imagem exec e nunca é reutilizado como ambiente de trabalho controlável (nem vice-versa). Uma conversa reutiliza uma única máquina de terminal.

Motor Valor Protocolo Vista em direto Imagens fixas
Chromium chromium (predefinido) Chrome DevTools Protocol Transmissão de ecrã — o navegador envia fotogramas à medida que a página se repinta JPEG
Firefox firefox WebDriver BiDi Imagens fixas por sondagem (o BiDi não tem transmissão de ecrã), limitadas a 6 fps JPEG
WebKit webkit W3C WebDriver (clássico) Imagens fixas por sondagem, transcodificadas pelo ffmpeg do anfitrião PNG

Um rig executa um motor durante toda a sua vida. Uma conversa pode ter um rig por motor, que é o que torna possível uma comparação lado a lado: abrir o «Firefox (VM)» ao lado do «Chromium (VM)» são duas máquinas, e fechar uma deixa a outra a correr.

Passe engine a rig.open ou à ferramenta browser_use. Um nome desconhecido é recusado em vez de assumir a predefinição — pedir um navegador e receber silenciosamente outro responde a uma pergunta de compatibilidade com a resposta errada.

Limites específicos de cada motor, declarados em vez de contornados:

  • O Firefox não tem recarregamento que contorne a cache (rejeita liminarmente o ignoreCache do BiDi), pelo que um recarregamento forçado é um recarregamento normal.
  • O WebKit também não tem recarregamento que contorne a cache, nem alimentação de consola (a saída é capturada ao intercetar console.* após cada navegação, pelo que tudo o que seja registado durante o carregamento se perde — todas as extrações de consola o dizem), e precisa de ffmpeg no anfitrião para a sua vista em direto.
  • Nenhum dos dois expõe uma árvore de acessibilidade da plataforma através do seu protocolo, pelo que extract (a11y) devolve uma aproximação derivada do DOM, identificada como tal.
  • Nenhum dos dois aceita uma largada de ficheiros real; ainda assim, é possível apontar um campo de ficheiro para caminhos dentro da máquina.
Superfície Imagem Obtida
Terminal ubuntu:24.04, fixada por digest Automaticamente no primeiro arranque, através da rede controlada da própria máquina
Navegador (Chromium, Firefox, WebKit) debian:trixie-slim, fixada por digest, mais os pacotes do próprio motor Automaticamente no primeiro arranque, depois colocada em cache como um pacote pré-aquecido
Computador Uma imagem qcow2 de ambiente de trabalho com Chromium, Firefox, WebKit e a mesma linha de base de CLI ao estilo de um runner alojado no GitHub que o terminal pré-aquece Importar em Definições → Servidor → Rigs (transferências fixadas por checksum quando publicadas)
Android As imagens de sistema da Google Através do SDK do Android
iOS Um runtime do Simulador do Xcode mais o WebDriverAgent fixado por checksum Runtime através do Xcode; ponte de automatização em Definições → Servidor → Rigs

Após o primeiro arranque de cada tipo de microVM, o servidor coloca em cache uma cópia pré-extraída no diretório de dados e arranca todas as máquinas posteriores a partir dela — incluindo imagens pré-aquecidas com os pacotes já instalados. O terminal pré-aquece um conjunto de ferramentas de CLI ao estilo de um runner alojado no GitHub (git, gcc, python3, jq, rsync, ferramentas de arquivo e o resto da linha de base do apt; não o Docker nem caches de ferramentas de linguagem). A qcow2 do Computador incorpora os mesmos nomes de CLI no momento da compilação da imagem, ao lado do XFCE e dos três navegadores. Cada navegador pré-aquece o seu motor. Os três motores partilham uma base Debian, mas nunca partilham um pacote: a cache tem como chave a imagem, o motor e uma revisão de áudio (audio-v1-<engine>), porque uma máquina pré-aquecida para um motor — ou antes de o PulseAudio e o ffmpeg fazerem parte da carga de trabalho — não tem nada do outro. O pacote do terminal tem como chave uma revisão do conjunto de ferramentas (tools-v1) pelo mesmo motivo: um pacote pré-aquecido antes de o compilador fazer parte da imagem não deve servir uma máquina que se supõe tê-lo.

Não vale a pena adotar nenhuma imagem de automatização pré-construída — o chromedp/headless-shell do Chromium compila o ALSA e o PulseAudio para fora, pelo que nunca consegue emitir som; a única imagem Firefox mantida tem 33× o tamanho da base Debian e continua a não incluir o socat; e não existe nenhuma imagem WebKit mantida. Por isso, cada motor instala-se no primeiro arranque (chromium, firefox-esr ou webkit2gtk-driver) e alcança os arquivos Debian (deb.debian.org, security.debian.org, cloudfront.debian.net) ao fazê-lo. O Chromium é o binário da distribuição lançado como chromium --headless=new.

Chave de definição Substitui
rigs.smolvm.execImage A imagem do Terminal (VM)
rigs.smolvm.browserImage A imagem do Navegador Chromium (VM)

Escritas através do armazenamento de definições do espaço de trabalho, protegido por administrador (Definições → Servidor → Rigs → Imagens personalizadas (este espaço de trabalho)). O valor tem de ser uma referência de registo — caminhos locais, arquivos e strings com aspeto de flag são recusados, tanto no campo como de novo no arranque. Um valor guardado inválido é ignorado de forma ruidosa e a predefinição é que arranca. O registo da própria imagem (mais os conhecidos CDNs de blobs associados para o Docker Hub, o GHCR, o Quay, o GitLab e o GCR) é admitido através do portão de saída para o pull.

Contrato da imagem do terminal — bash presente; git, curl e socat pré-instalados ou uma base apt Debian/Ubuntu (o recinto instala esses três mais um conjunto de ferramentas de CLI ao estilo de um runner alojado no GitHub no primeiro arranque: compiladores, Python 3, jq, ferramentas de arquivo, rsync. Os caches de ferramentas de linguagem e o Docker não são instalados).

Contrato da imagem de navegador — uma base apt Debian/Ubuntu (ou os pacotes já instalados) com bash e socat, mais um binário chromium que o próprio servidor lança como chromium --headless=new com o DevTools no loopback do convidado 9223, retransmitido para a porta 9222 do convidado. O PulseAudio e o ffmpeg são instalados no primeiro arranque para o canal de áudio. Não construa FROM chromedp/headless-shell: o headless.gn a montante compila o ALSA e o PulseAudio para fora, pelo que esse binário não consegue emitir som. A substituição aplica-se apenas a rigs Chromium — o comando de carga de trabalho que arranca é o do Chromium, e entregá-lo ao Firefox ou ao WebKit lançaria um binário que não existe. Um rig Firefox ou WebKit ignora-a de forma ruidosa e arranca a sua imagem fixada.

Portas de automatização — cada máquina de navegador encaminha exatamente uma porta de loopback do anfitrião para a 9222 do convidado. Por trás dela: o DevTools do Chromium e o agente remoto do Firefox residem no loopback do convidado 9223 com um relé socat à frente (ambos se ligam ao loopback incondicionalmente); o driver do WebKit aceita um --host e liga-se ele próprio à NIC do convidado. Além disso, o Firefox valida o cabeçalho Host em relação à sua própria porta, pelo que o cliente envia a autoridade do lado do convidado em vez daquela com que contactou.

Todas as ações são analisadas de forma total: uma carga malformada devolve uma mensagem que indica o campo, nunca uma exceção. Os verbos de observação (marcados com ○) continuam permitidos enquanto uma pessoa detém o controlo; os verbos que alteram estado são recusados.

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.

As coordenadas são pixels do convidado no modo atual do convidado; cada captura de ecrã indica o tamanho do ecrã. As combinações de teclas usam a grafia do X11 (ctrl+s, alt+Tab, Return).

clipboard_read aceita uma selection: clipboard (o que o ctrl+C preenche, a predefinição), primary (selecionar-para-copiar do X11) ou xdnd (um arrastamento em curso). Um resultado vazio é uma resposta normal para os três. clipboard_write aceita apenas text — as imagens e os ficheiros circulam pelo canal de ficheiros, porque os argumentos de uma ação são persistidos no registo de auditoria e os bytes de imagem não têm nada a fazer lá. O conteúdo da área de transferência é devolvido cercado como dados não fidedignos.

navigate (só http/https), reload (hard opcional), stop_loading, click (seletor ou coordenada), fill, type, key (nomes de teclas do DOM), scroll, mouse_move, drag, left_mouse_down, left_mouse_up, extract○ (a11y | dom | console), screenshot○ (full_page opcional), set_viewport (mín. 320×240), history, wait_for○ (seletor, 0,1–30 s), clipboard_read○, clipboard_write.

O conteúdo extraído da página é devolvido cercado como dados não fidedignos.

O navegador tem exatamente uma área de transferência, pelo que clipboard_read não aceita selection. Ambos os verbos de área de transferência exigem um contexto seguro: uma página servida por http:// simples não tem sequer API de área de transferência, e o verbo di-lo em vez de comunicar uma área vazia — use aí type, que insere no cursor sem passar por uma área de transferência.

tap, swipe (50–5000 ms), type, key (aliases back, home, recents, enter, delete, backspace, tab, escape, search, menu, volume_up, volume_down, power, ou qualquer KEYCODE_*), screenshot○, ui_dump○, install_apk (confinado à worktree do rig e ao diretório de dados do servidor), start_app, stop_app, clear_app_data, uninstall_app, open_url e shell. shell aceita uma lista argv e corre dentro do Android, nunca através de um shell do anfitrião; abrange diagnósticos de programador como logcat, dumpsys e pm grant.

mobile_use não tem verbos de área de transferência. Desde o Android 10, só a aplicação em foco pode ler a área de transferência.

tap, swipe (50–5000 ms), type, key (enter, backspace, tab, escape, teclas de seta ou um único caractere imprimível; modificadores command, control, option e shift opcionais), home, lock, unlock, screenshot○, ui_dump○, install_app (um diretório .app de simulador confinado à worktree do rig ou ao diretório de dados do servidor), start_app, stop_app, uninstall_app, open_url e spawn. spawn aceita argv e executa dentro do simulador através do simctl; nunca invoca um shell do anfitrião.

As coordenadas são pontos do ecrã iOS, não pixels da captura de ecrã. A transmissão em direto mantém o tamanho fixo do simulador e coloca-o em letterbox em vez de redimensionar o dispositivo. A transferência de texto da área de transferência do anfitrião para o simulador e vice-versa usa a mesma política de permissões por utilizador e por sentido que os outros rigs; os ficheiros e as imagens não são aceites pelo canal de área de transferência do iOS.

Cada rig cria um dispositivo CoreSimulator e uma sessão WebDriverAgent próprios. Fechá-lo para o WebDriverAgent, encerra e elimina esse dispositivo e remove a sua entrada do registo. Os rigs de iOS só correm num servidor macOS com Xcode, um runtime iOS instalado e a ponte de automatização fixada. Não expõem áudio, microfone, largada de ficheiros, shell do anfitrião nem qualquer garantia de rede em recinto.

Ferramenta Descrição
rig_list Lista os rigs de um espaço de trabalho com superfície, estado, ecrã e controlador
rig_close Destrói um rig e descarta o respetivo disco
Fase Significado
provisioning A arrancar; o detalhe do estado indica textualmente o passo atual
ready Acessível e a aceitar ações
parked Em pausa por inatividade: vCPUs paradas, RAM ainda residente; a ação seguinte acorda-o
closing A encerrar
closed Desapareceu; a linha mantém-se para o registo de auditoria
failed Morreu ou nunca chegou a arrancar; distinguível para que a interface possa oferecer nova tentativa
Motivo de fecho Despoletado quando
requested Uma pessoa ou um agente o pediu
idleTimeout Inatividade superior a 2× a janela de inatividade, ou remoção por memória
ttlExpired O tempo de vida rígido chegou ao fim
conversationEnded A conversa proprietária terminou
workspaceGone O espaço de trabalho foi eliminado ou a adesão foi perdida
serverShutdown O servidor está a parar
backendFailure O hipervisor morreu por baixo dele
Valor Terminal Navegador Computador Móvel
Memória 512 MB 2048 MB (Chromium); 2560 MB (Firefox, WebKit) 4096 MB 4096 MB
vCPUs 2 2 4 4
TTL rígido 8 h 2 h 2 h 2 h
Janela de inatividade 45 min 15 min 15 min 15 min
Ecrã de arranque — 1280×800 1280×800 1080×1920
  • As imagens fixas do canal do agente estão limitadas a 1280×800; o canal humano negoceia até 2560×1600.
  • O orçamento de memória residente do anfitrião para todos os rigs tem por predefinição 12 GB, contado em megabytes residentes (uma VM em pausa mantém a sua RAM). A remoção é por menos recentemente utilizada e nunca retira uma máquina que alguém esteja a controlar, a observar, ou na qual tenha um terminal aberto.
  • Um terminal aberto ou um canal de observação fixam o rig contra a entrada em pausa e a limpeza por inatividade; o TTL rígido continua a aplicar-se.
Porta Onde Reservada para
7911 Convidado do terminal O multiplexador de portas por onde passa cada encaminhamento
9222, 9223 Convidado do navegador O relé e o endpoint de automatização (o WebKit liga-se diretamente à 9222 e não usa relé)
80, 443 Loopback do convidado do navegador Os canais HTTP/HTTPS dos domínios de desenvolvimento
  • A descoberta sonda as portas TCP à escuta do convidado do terminal a cada ~4 s, do lado do servidor.
  • No máximo 16 portas são encaminhadas automaticamente por rig; as restantes são listadas no registo, não encaminhadas.
  • O encaminhamento do lado do anfitrião liga-se ao loopback, preferindo o próprio número de porta do convidado; Partilhar na rede local acrescenta uma porta LAN atribuída pelo sistema operativo.
  • Os domínios de desenvolvimento têm de corresponder a name.test ou name.localhost (minúsculas, etiqueta com no máximo 63 caracteres). Um domínio corresponde a uma porta.
  • O HTTPS dos domínios de desenvolvimento usa uma AC local do servidor (EC P-256, em <dataDir>/rigs/tls/, chaves com 0600 e nunca num convidado) com um único certificado final wildcard para *.test / *.localhost. Sem openssl no anfitrião não há canal HTTPS; o HTTP simples continua a ser encaminhado.
Superfície Lista de permissões predefinida
Terminal A linha de base do programador da sandbox (forjas, registos de pacotes, fornecedores de modelos) + os espelhos apt do Ubuntu + o próprio anfitrião de forja da worktree
Navegador usectrl.dev (o site do produto) — mais os arquivos Debian no primeiro arranque de cada motor, enquanto este instala os seus pacotes. A página inicial é um documento file:// local e não precisa de saída
Computador Vazio — negar tudo — até quem chama conceder anfitriões
Móvel Não imposta (rede gerida pelo emulador)

Além disso, cada microVM recebe os anfitriões de registo da sua imagem, apenas para o pull. O conjunto de anfitriões permitidos do broker de credenciais deriva da mesma lista de permissões: não é emitido nenhum token para um anfitrião que o convidado não consegue alcançar.

Área de transferência e transferência de ficheiros

Secção intitulada “Área de transferência e transferência de ficheiros”

Ambos os sentidos de copiar/colar, e arrastar ficheiros para dentro e para fora. Disponível para uma pessoa que controla um rig; um agente obtém a área de transferência através dos verbos acima e nenhuma transferência de ficheiros (já tem um shell dentro do recinto).

A passagem da área de transferência é por utilizador e por sentido. A colagem do anfitrião para o rig é permitida por predefinição; a cópia do rig para o anfitrião pergunta primeiro (uma autorização de dez minutos, ou permitir sempre em Definições → Servidor → Rigs → Acesso à área de transferência). As duas escolhas são independentes e nunca são uma definição do espaço de trabalho.

Canal Rota Transporta
Área de transferência GET/POST /rig/clipboard/<rigId> Texto, um PNG/JPEG (≤16 MB) e os caminhos no convidado dos ficheiros na área de transferência
Ficheiros POST /rig/files/<rigId> Até 64 ficheiros, ≤256 MB cada e ≤512 MB por largada, com um ponto de largada opcional em pixels do convidado
Ficheiros GET /rig/files/<rigId>?p=<base64url path> Os bytes de um ficheiro, de volta
  • HTTP, não RPC. O socket RPC fecha uma ligação perante um frame de entrada superior a 256 KB — uma proteção contra DoS adequada a comandos JSON e fatal para uma captura de ecrã colada. Os bytes circulam pelo mesmo tipo de rota que os fotogramas dos rigs e o áudio das reuniões já usam.
  • A autenticação é o alvo assinado rig-files:<workspaceId>/<rigId> mais a adesão ao espaço de trabalho — um alvo próprio, para que um URL emitido para observar uma máquina não possa também escrever ficheiros nela.
  • A assunção do controlo aplica-se. Escrever na área de transferência e largar ficheiros alteram estado e são recusados enquanto outra pessoa detém o controlo; ler a área de transferência e extrair um ficheiro são observação e não o são.
  • Onde caem as largadas: ~/Drops (ambiente de trabalho), ~/drops (terminal — ao lado da worktree, nunca dentro dela, para que uma largada nunca apareça como uma alteração não rastreada), /tmp/cc-drops (navegador). É o servidor que escolhe o diretório; quem chama não o pode indicar. Os ficheiros existentes nunca são substituídos — um nome em conflito chega como 2-name.ext.
  • O que é dito ao convidado: uma página de navegador recebe um evento de largada real no ponto pedido (Input.dispatchDragEvent); um ambiente de trabalho recebe os ficheiros mais os respetivos URIs na sua área de transferência, porque nenhum anfitrião consegue sintetizar um arrastamento XDND para um toolkit arbitrário sem um daemon privilegiado dentro do convidado. A resposta indica qual dos dois aconteceu.
  • Arrastar para fora só funciona no ambiente de trabalho e lê a XdndSelection do convidado enquanto um arrastamento está em curso. Uma carga idêntica à que o convidado já tinha quando o premir começou é tratada como uma seleção obsoleta de um arrastamento terminado, e não como uma nova — o X não tem um passo de «o arrastamento terminou».
  • Requisitos da imagem: a imagem do ambiente de trabalho tem de ser do protocolo 2 ou posterior (construída depois de o suporte da área de transferência ter chegado). Uma imagem mais antiga responde 404 e a aplicação diz para a reconstruir em vez de comunicar uma máquina avariada.
  • O registo de auditoria regista a forma, nunca o conteúdo: as linhas clipboard_read, clipboard_write, drop_files e read_file contêm contagens, tamanhos e caminhos. Uma área de transferência é onde as credenciais vivem alguns segundos de cada vez, e nada disso fica registado.
  • As ferramentas de rig declaram a classe de ação enclosureControl (mais networkEgress e processSpawn nas ferramentas de utilização; mobile_use e ios_use declaram também packageInstall). rig_close declara enclosureControl; rig_list não declara nenhuma. Permitida por predefinição; os modos só de leitura negam-na integralmente; o seletor de autonomia por espaço pode rebaixá-la para perguntar primeiro.
  • Eventos de domínio: RigClosedEvent (com o seu motivo de fecho), RigControlChanged (assunção do controlo / devolução), RigReaped (inatividade, TTL ou remoção por memória, com o agente que a controla). Abrir um rig não é um evento. Consulte eventos de domínio.
  • Armazenamento: rig_sessions e rig_action_log em cada base de dados de espaço de trabalho. O registo de ações regista cada evento de entrada com o respetivo principal e uma sequência monotónica por rig; o texto escrito é reduzido a um comprimento e a um hash antes de ser gravado.
  • Diretório de dados: rigs/images/ (imagens qcow2 importadas), rigs/smolvm/ (estado de execução por rig), rigs/smolvm-packs/ (pacotes de máquina pré-extraídos), rigs/tls/ (a AC dos domínios de desenvolvimento), rigs/run/ (camadas sobrepostas e seeds do QEMU).
  • Rotas: a vista em direto é um separador numa página de espaço ou de PR; /settings/server/rigs é o ecrã de definições de Rigs.