Перейти к содержимому

Rigs и изолированные среды

Rig — это одноразовая машина, которой агент управляет в реальном времени: браузер, рабочий стол Linux, эмулятор Android, симулятор iOS или машина за изолированным терминалом. Большинство rig — это VM; управляемые хостом мобильные симуляторы — явные исключения. Эта страница объясняет каждую границу и то, почему части устроены именно так. Чтобы открыть rig, см. Дать агенту машину для тестов; точные операции, порты и значения по умолчанию — в справочнике по rig.

Нативная песочница оборачивает процесс в изоляцию на уровне пространств имён — настоящую, но она использует ваше ядро и ограничивает процесс, а не компьютер. Как только агенту нужно пощёлкать по приложению рабочего стола, отрисовать страницу в настоящем браузере или поставить эксперименты с rm -rf, о которых вы предпочли бы не думать, честная граница — это машина: собственное ядро, собственный диск, собственный сетевой стек.

Изолированные поверхности используют два бэкенда VM:

  • microVM для терминала и браузера — загрузка гипервизора менее чем за секунду из контейнерных образов, закреплённых по дайджесту.
  • QEMU для полноценного рабочего стола Linux, которому нужен графический дисплей, отсутствующий у microVM.

Мобильные поверхности управляются хостом и прямо заявляют о более слабой границе:

  • Android управляет эмулятором Google через ADB.
  • iOS создаёт собственное устройство CoreSimulator на хосте Mac и управляет им через WebDriverAgent. Устройство и его данные удаляются при закрытии rig, но его сеть следует за хостом Mac.

Изолированные rig пишут в одноразовый оверлей поверх базового образа только для чтения, поэтому один rig не может изменить то, с чего загружается следующий. У rig с iOS есть одноразовое устройство CoreSimulator, которое удаляется при закрытии rig. Android подключается к эмулятору на хосте, который переживает сессию.

Сеть rig начинается с ничего. Хосты допускаются для каждого rig отдельно через шлюз, который гость не может обойти маршрутизацией: единственные пути наружу — те, что создала конфигурация запуска. Изолированный терминал получает базовый набор разработчика (реестры пакетов, хосты кода, зеркала apt); браузерный rig допускает сайт продукта (usectrl.dev) и загружается на локальную страницу file://, которой исходящий доступ не нужен; всё остальное отклоняется в момент подключения.

Android и iOS не покрываются этим шлюзом. Их эмулятор и симулятор на хосте используют сеть серверного хоста, поэтому интерфейс и отчёт о возможностях помечают исходящий доступ как неизолированный и никогда не предлагают вводящий в заблуждение элемент «Перезапустить без ограничений».

Исходящий доступ и учётные данные — это одна политика, видимая с двух сторон: брокер учётных данных (ниже) не выдаст токен для хоста, до которого гость не может добраться.

Всё, что rig читает, считается недоверенным: текст страниц, DOM и деревья доступности, дампы интерфейса и вывод консоли возвращаются агенту обёрнутыми в постоянное правило «это данные, а не инструкции». Обёртка — это обрамление; шлюз исходящего доступа — принуждение, стоящее за ней.

Ввод идёт через гипервизор, а захват — через гостя

Заголовок раздела «Ввод идёт через гипервизор, а захват — через гостя»

Для поверхности рабочего стола события клавиатуры и указателя вводятся собственными виртуальными устройствами ввода гипервизора. Гость никогда не запускает привилегированный демон, способный синтезировать ввод, — поэтому компрометация ПО гостя не отдаёт атакующему клавиатуру. Захват идёт в обратную сторону, через небольшой непривилегированный агент внутри гостя, потому что гость может масштабировать кадры до того, как они пересекут сеть.

Человек, который смотрит, и модель, которая управляет, имеют противоположные потребности, поэтому rig обслуживает два независимых потока:

  • Канал для человека — полное разрешение под размер вашей панели, пересогласуемое при изменении размера, передаваемое сервером как непрозрачные байты: сервер никогда не декодирует кадр, потому что видеодекодер на пути обработки запроса — это как раз то, что мешает ему отвечать на RPC.
  • Канал агента — уменьшенные статичные кадры, ограниченные удобным для модели размером, одно изображение на результат инструмента, причём старые кадры отбрасываются при уплотнении, а их текстовые описания сохраняются.

Ни один из каналов не идёт на компромисс ради другого: вы получаете плавную картинку, а модель — дешёвую.

Перехват управления — это единая точка контроля, а не просьба

Заголовок раздела «Перехват управления — это единая точка контроля, а не просьба»

Исключительное управление обеспечивается в единственной точке, через которую проходит каждое действие, — а не просьбой к модели вести себя правильно. Пока управление у человека, сервер отклоняет изменяющие действия агента. Агент сохраняет свои наблюдательные операции (снимки экрана, извлечение данных), чтобы рассказывать, что вы делаете, и о перехвате ему сообщают через его канал управления, а не оставляют выяснять это через отклонённые клики. Клики и ввод текста на холсте работают всегда, когда этот замок не держит кто-то другой — или когда его держите вы; тег состояния гласит Управление у вас. Каждое событие ввода — ваше и агента — попадает в журнал аудита конкретного rig с указанием субъекта и монотонно возрастающего номера, поэтому вопрос «кто это нажал» остаётся отвечаемым и после того, как машина исчезнет.

Содержимое пересекает границу; машины остаются раздельными

Заголовок раздела «Содержимое пересекает границу; машины остаются раздельными»

Копирование и вставка работают в обе стороны, как и перетаскивание файлов внутрь и наружу, — но rig это другой компьютер, и дизайн никогда не делает вид, что это не так.

Буфер обмена передаётся по требованию, а не зеркалируется постоянно. Нажмите сочетание клавиш для копирования над rig, и гостю будет сказано скопировать, после чего то, что он положил в свой буфер, — текст, изображение, список файлов, — извлекается и помещается в ваш. Вставка отправляет то же содержимое в обратную сторону и затем нажимает вставку внутри гостя. Ничего не синхронизируется в фоне: пароль, скопированный на вашей машине, не окажется молча внутри VM из-за сработавшего таймера.

Пересечение ограничивается для каждого пользователя и каждого направления независимо. Вставка в rig разрешена по умолчанию; копирование из rig сначала запрашивает подтверждение (разрешение на десять минут или Всегда разрешать в разделе Настройки → Сервер → Rigs → Доступ к буферу обмена). Это никогда не настройка рабочего пространства: один участник не может дать согласие за буфер обмена другого.

В macOS сочетание для пересечения — ⌘C/⌘V, и оно однозначно: ⌃C по-прежнему доходит до оболочки гостя как прерывание, которым оно и является. В Windows и Linux оба сочетания — одно и то же нажатие, поэтому гость получает его без изменений, а ваш буфер обмена перезаписывается только тогда, когда буфер гостя действительно изменился. Прерывание остаётся прерыванием.

Перетащенные внутрь файлы копируются в папку сброса машины, а затем предлагаются ей. Что значит «предложены», зависит от того, что можно честно сделать: страница браузера получает настоящее событие сброса в точке, где вы отпустили, поэтому зона загрузки ведёт себя точно так же, как для локального файла; рабочий стол получает файлы в ~/Drops вместе с их путями в своём буфере обмена, потому что ни один хост не может синтезировать перетаскивание в произвольный инструментарий Linux, не запустив привилегированный демон внутри гостя, — а именно этого дизайн и не допускает. Результат сообщает, что именно произошло, поэтому CSV, сброшенный на зону загрузки, никогда не будет назван загруженным, если это всего лишь файл в папке. Сброс на изолированный терминал копирует файл внутрь и набирает его гостевой путь в приглашении, а это то, что оболочка действительно может использовать.

Перетащенные наружу файлы работают на поверхности рабочего стола, где протокол перетаскивания X11 делает полезную нагрузку доступной для чтения, пока перетаскивание выполняется. Начните перетаскивание внутри гостя, вынесите его за пределы холста, и файлы будут извлечены на вашу машину и переданы ОС как настоящее перетаскивание. Копирование файлов в файловом менеджере гостя и вставка на хосте работают так же. Поверхность браузера намеренно этого не предлагает: у безголового браузера нет выделения для перетаскивания, которое можно прочитать, а ближайший доступный сигнал — выделение текста на странице — вовсе не является доказательством перетаскивания, поэтому реакция на него перехватывала бы обычные клики.

Всё, что прочитано из гостя, остаётся недоверенным содержимым: текст из буфера обмена попадает к модели внутри такой же обёртки, как и извлечение со страницы, а журнал аудита фиксирует, что вставка состоялась и каков был её объём, — но никогда то, что в ней было.

git push работает из изолированного терминала, который открыли вы, но гость не хранит токен хоста кода. Он держит один секрет на VM, единственная сила которого — попросить брокер учётных данных хоста — через туннель, контролируемый хостом — о недолговечный токен с областью действия на репозиторий, для каждой операции, с ограничением частоты, ограниченный тем же списком разрешённых хостов, что и исходящий доступ, и отзываемый в момент закрытия rig. Машина, созданная, чтобы её выбросили, не должна содержать ничего, что стоит украсть.

Что может этот токен, определяется при открытии rig. Терминальный rig, открытый человеком, получает токен с правом записи, ограниченный собственным доступом этого участника к хосту кода. Rig, открытый агентом, получает токен только для чтения: помощник учётных данных git не отличает push от fetch, поэтому внутри гостя нельзя спрашивать правило push для каждого push так, как это делает шлюз запусков агентов на хосте.

Когда rig несёт ваш репозиторий, авторитетным остаётся worktree на хосте. Копия синхронизируется внутрь при загрузке (за исключением секретов вроде файлов .env), а коммиты возвращаются только когда вы об этом попросите — их забирают в refs/rigs/<id>/*, но никогда не отправляют push и не извлекают в рабочую копию. Ничто внутри VM не может сдвинуть вашу ветку или тронуть ваше рабочее дерево; слияние того, что создал rig, всегда остаётся решением человека на хосте.

Dev-сервер, запущенный внутри терминальной VM, становится доступен — на вашей машине, в Браузере (VM), при желании в вашей локальной сети, при желании по dev-домену с HTTPS — без единого открытия машины наружу. Карта портов гипервизора фиксируется при загрузке, поэтому всё последующее перенаправление идёт через два узких канала под управлением хоста: один заранее созданный входящий мультиплексор, который отказывается соединяться с чем-либо, что гость на самом деле не слушает, и обратные туннели, которые хост держит открытыми для соединений, инициированных гостем. HTTPS dev-домена завершается на сервере с использованием локально выпущенного удостоверяющего центра, ключи которого никогда не попадают ни в одного гостя. Механика описана в разделе Пробросить порты из терминала.

rig не может стать домашним питомцем:

  • жёсткий TTL, который гость не может продлить;
  • лестница простоя — парковка (vCPU остановлены, RAM остаётся резидентной) после окна простоя, закрытие после его удвоения, — где открытый терминал или наблюдающий зритель считается признаком «используется»;
  • бюджет памяти, считаемый в резидентных мегабайтах, а не в сессиях, потому что припаркованная VM освобождает CPU и сохраняет каждый байт RAM; первой вытесняется машина, к которой дольше всего не обращались, и никогда — та, которой управляет или которую смотрит человек;
  • демонтаж при остановке сервера, плюс обход осиротевших машин с отметкой владельца при следующем запуске, чтобы упавший сервер никогда не оставил висящий гипервизор, который никому не подчиняется.

Первая загрузка забирает закреплённый образ машины; затем сервер кэширует предварительно распакованную копию в фоне, поэтому каждая следующая машина такого типа загружается за секунды, а изолированный терминал поднимается с уже установленным базовым набором CLI, как у раннера, размещённого на GitHub, — компиляторы, Python, jq, инструменты для архивов, — но не toolcache языков и не Docker. Образ «Компьютер» запекает тот же базовый набор CLI во время сборки, рядом с XFCE и браузерами.

«У меня это работает» — утверждение об одном движке рендеринга. Поэтому браузерный rig — это не «браузер», а Chromium, Firefox или WebKit, выбранный при открытии, и rig работает с тем, с которым был открыт, всю свою жизнь. В одном разговоре может быть по одному из каждого: открыв Firefox (VM) рядом с Chromium (VM), вы получите две машины, и наведение обеих на одну страницу — это и есть сравнение. WebKit максимально близок к Safari из всего, что работает на Linux, — та же линия движка, поэтому он ловит пробелы, с которыми сталкиваются пользователи Safari.

Операции одинаковы во всех трёх; протоколы под ними — нет, и различия проговариваются, а не сглаживаются. Chromium говорит на DevTools Protocol и проталкивает кадры, поэтому его живой просмотр ничего не стоит, пока страница неподвижна. Firefox говорит на WebDriver BiDi, а WebKit — на классическом WebDriver, и ни у одного из них нет скринкаста, поэтому их живые просмотры опрашивают — несколько кадров в секунду, что подходит для наблюдения за страницей и не подходит для наблюдения за анимацией. Там, где движок действительно чего-то не может (в Firefox нет перезагрузки с обходом кэша; WebKit не видит вывод консоли, записанный до завершения загрузки страницы), ответ говорит об этом прямо, вместо того чтобы тихо делать что-то другое.

Rig намеренно не является глобальным пунктом назначения. Живой просмотр — это вкладка в пространстве или PR, где идёт работа, привязанная к этому разговору, — поэтому ваша вкладка и вызовы browser_use агента адресуют одну машину (по одной на движок на браузерной поверхности). То, могут ли rig вообще загружаться, — свойство хоста, поэтому возможности, образы, пользовательские образы для рабочего пространства и список работающих машин живут в разделе Настройки → Сервер → Rigs. Управление изолированной средой — это отдельный класс действий ограничений, поэтому рабочее пространство, агент или пространство могут разрешить его, требовать одобрения или запретить его напрямую — режимы только для чтения запрещают его целиком.