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

Материализация файлов

Нода materialize доставляет файлы, заданные workflow, в файловую систему агента, удерживая их отрендеренные тела вне ответа шага. Moira выдаёт команду загрузки короткоживущего архива, приостанавливает выполнение и продолжает его только после пустого ответа агента. Хост, который не может выполнить эту команду, доставляет файлы описанным ниже fallback-маршрутом в контекст и завершает шаг так же.

Используйте эту ноду для стабильных файлов, которыми владеет определение workflow: инструкций, стандартов или пустого каркаса директорий. Файлы, чьё содержимое зависит от анализа агента, остаются ответственностью создающей их agent-directive ноды.

Объявление ноды

Храните переиспользуемый текст в строковой записи variableRegistry и ссылайтесь на неё через from:

{
"variableRegistry": {
"workspace_reference": {
"type": "string",
"description": "Инструкции, доставляемые в рабочее пространство",
"default": "# Workspace reference\n\nFollow the project contract."
}
},
"nodes": [
{
"id": "materialize-workspace",
"type": "materialize",
"basePath": "{{workspace_path}}",
"files": [
{ "path": "reference.md", "from": "workspace_reference" },
{ "path": "plans/.keep", "content": "" }
],
"connections": {
"success": "work",
"error": "materialize-failed"
}
}
]
}
СвойствоОбязательноКонтракт
basePathДаШаблонизируемая директория назначения; отрендеренное значение должно быть непустым и не содержать NUL
filesДаОт 1 до 100 записей архива
files[].pathДаБезопасный шаблонизируемый путь относительно basePath
files[].fromОдно изИмя строковой записи реестра, чей текущий default задаёт тело файла
files[].contentОдно изДолжен быть ровно ""; создаёт пустой каркасный файл
connections.successДаСледующая нода после пустого ответа
connections.errorНетМаршрут ошибки валидации, конфигурации, базы данных или выдачи разрешения во время показа шага

Каждый файл должен объявлять ровно одно из полей from и content. Непустой inline-content отклоняется; вместо него используйте одну запись реестра как источник истины.

Запуск сгенерированной команды

При показе ноды Moira рендерит basePath и сводку путей, создаёт разрешение на пять минут и возвращает POSIX-команду, где каждый аргумент уже безопасно заключён в shell-кавычки:

Terminal window
mkdir -p -- '<basePath>' && curl -sSf -- '<reusable-url>' | tar -x -C '<basePath>'

Запускайте выданную команду без изменений. URL — непрозрачный bearer credential: не собирайте его самостоятельно, не редактируйте, не записывайте в лог и не передавайте другим. Одну и ту же команду можно повторять в течение пяти минут, пока выполнение ожидает на этой ноде. После успешной распаковки завершите шаг значением null или {}. Иная форма ответа не принимается.

Сгенерированная директива сообщает срок и правила повтора, предупреждает, что переход выполнения делает URL недействительным, называет описанный ниже fallback-маршрут доставки в контекст при условии, что этот хост не может выполнить команду, и объясняет, что доставка не доказывает чтение ни на одном из маршрутов. Вызов session({ action: "current_step" }) во время паузы выдаёт новые команду и разрешение, не продвигая граф. Поздняя директива всё равно должна явно требовать чтения каждого используемого файла.

Контракт архива и путей

При запросе URL Moira заново загружает текущее определение workflow. Она рендерит каждый путь и каждое тело из реестра с контекстом выполнения, привязанным к разрешению, а затем создаёт несжатый tar-архив. Поэтому изменение workflow после выдачи команды может поменять пути и содержимое архива, но не директорию назначения, уже встроенную в команду.

Записи архива содержат только пути относительно basePath; сама директория назначения в архив не входит. Объявленные и отрендеренные пути должны быть нормализованными, непустыми, относительными и уникальными. Moira отклоняет NUL, абсолютные и начинающиеся с обратной косой черты пути, пустые сегменты, а также сегменты . и ...

Ограничения применяются к отрендеренному UTF-8-содержимому:

  • не более 100 файлов;
  • не более 1 MiB на файл;
  • не более 10 MiB несжатого содержимого суммарно.

Файлы создаются с режимом 0644. Движок проверяет basePath, но не ограничивает назначение директорией проекта. Авторы workflow должны получать его из доверенного пути рабочего пространства, а агенты — проверять назначение в выданной команде перед запуском.

Разрешение и обработка ошибок

Пятиминутное разрешение хранится на сервере и привязано к текущим пользователю, выполнению и ноде. Выполнение должно оставаться в состоянии running и ожидать на той же materialize-ноде. Сервер заново проверяет эти привязки при каждом запросе, поэтому одно разрешение поддерживает повторные загрузки в течение абсолютного пятиминутного окна, но перестаёт работать сразу после перехода выполнения. Логи запросов скрывают credential из materialize-URL.

ОшибкаРезультат
Некорректная нода или директория назначения, ошибка конфигурации, БД или выдачи разрешения при показе шагаПереход по connections.error, если он задан; иначе ошибка выходит из выполнения
Некорректный, истёкший или неверно привязанный URLHTTP 401 с Invalid or expired materialize token
Некорректный отрендеренный путь, отсутствующий источник в реестре, ошибка шаблона или превышение лимитаHTTP 400 с Materialize archive could not be generated
Локальная ошибка curl, pipe, файловой системы или tarНедоступная сеть подпадает под fallback-доставку в контекст; ошибка файловой системы или tar остаётся блокером, о котором агент сообщает, не завершая шаг
Доставка в контекст набора больше 256 KiBИнструмент отвечает именованным отказом и не доставляет файлы

connections.error не перехватывает ошибку загрузки или распаковки: эти операции выполняются уже после показа шага.

Доставка в контекст агента

У хоста, который в текущем ходе не может выполнить shell-команду или обратиться к сети, есть второй маршрут:

session({ action: "materialize", executionId: "<process-id>" })

Он возвращает те же отрендеренные тела, что содержал бы архив: по одному текстовому блоку на файл, с заголовком в виде пути этого файла, и ничего не пишет в файловую систему. Разрешение при этом не передаётся: сервер сам находит разрешение текущего показа ноды по выполнению вызывающего, поэтому URL архива не обязан проходить через ответ.

Этот маршрут расходует контекст, поэтому он именно fallback, а не основной путь, и предъявляемая директива прямо это говорит. Когда хост способен выполнить выданную команду, используйте её.

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

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

Доставка по-прежнему не доказывает чтение. Прочитайте каждый доставленный файл, который требуется последующей директиве, и завершите шаг значением null или {} как обычно.

Применение в Workflow Management Flow

Workflow Management Flow один раз определяет рабочее пространство, затем материализует стабильные bootstrap-файлы и только после этого выбирает ветку создания или редактирования:

get-action-type
-> materialize-workspace-bootstrap
-> route-action-type
| create -> gather-workflow-requirements
| edit -> prepare-edit-workflow

Его materialize-объявление эквивалентно следующему:

{
"id": "materialize-workspace-bootstrap",
"type": "materialize",
"basePath": "{{workspace_path}}",
"files": [
{ "path": "process-id.txt", "from": "workspace_process_id_file" },
{ "path": "workflow-authoring-reference.md", "from": "workflow_authoring_reference" }
],
"connections": { "success": "route-action-type" }
}

Предыдущий владелец записывает глобальный workspace_path. Значения реестра предоставляют ID выполнения и справочник автора. Последующие владельцы веток create и edit записывают динамические требования, provenance, планы и отчёты ревью, но не перезаписывают стабильные bootstrap-файлы.

Перевод ручного bootstrap

Чтобы заменить директиву агента, вручную записывающую стабильные файлы workflow:

  1. Перенесите каждое стабильное тело в default отдельной строковой записи variableRegistry.
  2. Поручите существующей ранней ответственности вернуть доверенный глобальный путь для basePath.
  3. Вставьте одну ноду materialize после этого владельца и перед первым потребителем файлов.
  4. Удалите из последующих директив только инструкции записи соответствующих статических файлов. Динамические файлы оставьте ответственности, определяющей их содержимое.
  5. Провалидируйте workflow и проверьте выданную команду, записи архива, отрендеренные тела, а также успешный и ошибочный маршруты.

Связанные материалы