core.cmd
Выполнение shell-строки через `sh -c`: pipes, redirects, glob, подстановки.
core.cmd выполняет shell-строку через `sh -c` — доступны pipes, redirects, glob и подстановки. Модуль TRUSTED-ONLY: строка уходит в shell без escape, поэтому любая интерполяция внутри неё исполняется shell-ом как код, и её источник должен быть автором Destiny, а не внешним вводом. По умолчанию шаг рапортует changed=true; понизить до no-op можно guard-параметрами creates / unless / onlyif.
Требования
- Rootне требуется
- Сторона
soul-side - Коллекция
soulstack.exec - Категория
exec
exec_subprocessСостояния
core.cmd.shell — Выполнить shell-строку через `sh -c`.
По умолчанию всегда (verb «выполнить»).
Сработавший guard creates / unless / onlyif удержал шаг no-op.
Параметры
| Параметр | Тип | Обяз. / дефолт | Описание |
|---|---|---|---|
cmd | string | required | Shell-строка, исполняется `sh -c`. |
cwd | string | optional | Рабочий каталог процесса. |
env | map<string> | optional | Дополнительные переменные окружения (KEY: VALUE). |
creates | string | optional | Idempotency: если файл существует — шаг пропускается (changed=false). |
unless | string | optional | Idempotency: shell-команда; exit=0 → пропуск. |
onlyif | string | optional | Idempotency: shell-команда; exit≠0 → пропуск. |
Пример — creates-guard: install пропускается, если исполняемый файл уже на месте
- name: Install exporter binary module: core.cmd.shell params: creates: /usr/local/bin/redis_exporter cmd: "install -m 0755 /tmp/build/redis_exporter /usr/local/bin/redis_exporter"Пример — Version-aware unless: переустановка при другой версии сборки
- name: Install node_exporter binary module: core.cmd.shell register: node_exporter_bin params: unless: "test -x /usr/local/bin/node_exporter && /usr/local/bin/node_exporter --version 2>&1 | grep -qF 'version 1.9.0 '" cmd: "install -m 0755 /tmp/node_exporter/node_exporter /usr/local/bin/node_exporter"Output
| Поле | Тип | Описание |
|---|---|---|
stdout | string | |
stderr | string | |
exit_code | number |
Заметки
- Guard-параметры проверяются в порядке creates → unless → onlyif; первый сработавший пропускает команду (changed=false, output { skipped: true, reason }).
- non-zero exit основной команды сам по себе не делает шаг failed — это решает failed_when: в scenario.
- creates ловит только существование пути и не замечает апгрейд версии (тот же путь → no-op даже при устаревшем содержимом); для version-aware идемпотентности берите unless с проверкой --version.
Безопасность и умолчания
- TRUSTED-ONLY — главный инвариант: cmd уходит в `sh -c` без escape, и любая интерполяция недоверенного значения (CEL-render, register.*, soulprint.*, input.*) становится shell-injection через метасимволы $, `, |, &, ;, >, <, *.
- Источник cmd-строки обязан быть автором Destiny/scenario, а не внешним вводом; guard-команды unless / onlyif тоже идут через `sh -c` и подчиняются тому же запрету.
- Модуль не объявляет run_as_root и не повышает права — команда исполняется с привилегиями процесса soul-агента; на практике агент работает под root, тогда и `sh -c` идёт под root, что лишь усиливает цену injection.
- Где shell-семантика не нужна — берите core.exec.run: argv-форма передаёт значение отдельным токеном, метасимволы не интерпретируются.