core.archive
Распаковка архивов (tar/tar.gz/tar.bz2/zip) в каталог.
core.archive распаковывает архив path в каталог dest средствами Go stdlib in-process — без внешних tar/unzip и без подпроцессов, что даёт per-entry контроль безопасности (zip-slip/zip-bomb/symlink), недоступный backend-утилитам. format опционален — auto-detect по расширению path. Идемпотентно: SHA-256 исходного архива пишется в маркер <dest>/.soul-archive.sha256, тот же архив повторно не распаковывается (changed=false). Soul-side.
Требования
- Rootтребуется
- Сторона
soul-side - Коллекция
soulstack.files - Категория
files
fs_write_rootСостояния
core.archive.extracted — Архив path распакован в каталог dest (tar/tar.gz/tar.bz2/zip).
Маркера <dest>/.soul-archive.sha256 нет либо его хэш ≠ хэшу текущего архива. Проверка grounded по хэшу архива — целостность распакованных файлов в dest не сверяется.
Маркер на месте и его хэш совпал с текущим архивом.
Параметры
| Параметр | Тип | Обяз. / дефолт | Описание |
|---|---|---|---|
path | string | required | Путь к архиву-источнику. |
dest | string | required | Каталог распаковки. |
format | string | optional | Формат (tar|tar.gz|tar.bz2|zip); опущено — auto-detect по расширению. |
max_size | string | optional | Лимит суммарного распакованного размера (число байт или N[KiB|MiB|GiB]); по умолчанию 1GiB. Защита от zip-bomb. |
max_entries | integer | optional | Лимит числа записей в архиве; по умолчанию 100000. Защита от zip-bomb. |
max_ratio | integer | optional | Лимит отношения распакованных байт к сжатым (compression ratio); по умолчанию 100, 0 — отключено. Защита от zip-bomb с маленьким сжатым размером. |
Пример — Распаковать скачанный tarball; format auto-detect по .tar.gz
- name: Extract node_exporter tarball module: core.archive.extracted params: path: /tmp/node_exporter-1.9.0.tar.gz dest: /tmp/node_exporter-1.9.0 max_size: "500MiB"Output
| Поле | Тип | Описание |
|---|---|---|
path | string | |
dest | string | |
sha256 | string | |
extracted | true |
Справочник
Поддерживаемые форматы
format опционален — при отсутствии определяется по суффиксу path; нераспознанный суффикс → шаг падает (cannot auto-detect format).
| Формат | Расширения (auto-detect) | Примечание |
|---|---|---|
| tar | .tar | — |
| tar.gz | .tar.gz, .tgz | — |
| tar.bz2 | .tar.bz2, .tbz2 | только распаковка (bzip2 в stdlib decompress-only) |
| zip | .zip | — |
Заметки
- Распаковка in-process на Go stdlib (archive/tar, archive/zip, compress/gzip, compress/bzip2) — без внешних tar/unzip и без порождения подпроцессов. Хостовые утилиты распаковки не нужны, зато есть per-entry контроль безопасности, недоступный backend-утилитам.
- max_size принимает голое число (байты) либо число с бинарным суффиксом KiB/MiB/GiB (регистр суффикса не важен). Десятичные SI-суффиксы (KB/MB/GB) и дроби не поддерживаются — нераспознанный суффикс или мусор → явная ошибка invalid size, а не тихий отброс хвоста.
- Маркер .soul-archive.sha256 лежит внутри dest — учитывайте при последующей сверке содержимого каталога другими шагами. changed=true проверяет «архив тот же» (хэш маркера), а не «все файлы внутри dest на месте».
- Неподдерживаемые типы записей (hardlink, устройства block/char, fifo, socket) → явная ошибка (unsupported type), а не тихий пропуск. Служебные PAX/GNU-заголовки и sparse-метаданные молча игнорируются.
- dest создаётся (MkdirAll, mode 0755), если не существует.
Безопасность и умолчания
- zip-slip / path-traversal — fail-fast: целевой путь каждой записи строится через filepath-securejoin относительно dest плюс лексический детект escape; запись с .. либо абсолютным путём наружу → шаг падает целиком (entry escapes dest), уже распакованные файлы остаются, маркер не пишется. Не тихий clamp — запись наружу не создаётся.
- zip-bomb — лимиты max_size (дефолт 1GiB, суммарный распакованный размер), max_entries (дефолт 100000, число записей) и max_ratio (дефолт 100, 0 — выкл; отношение распакованных байт к сжатым). Превышение любого → шаг падает с указанием пробитого лимита.
- symlink — within-dest only: symlink из архива создаётся, только если его target (резолвнутый относительно директории самого symlink-а) остаётся внутри dest; абсолютный или выводящий за dest target → шаг падает. Запись «сквозь» symlink-каталог из того же архива fail-closed (securejoin резолвит по уже лежащему на диске пути) — target-каталог адресуйте напрямую.
- setuid / setgid / sticky маскируются всегда (mode применяется как entry.Mode() & 0o777) — архив не может протащить исполняемый файл с setuid-root. owner/group из архива не берутся — файлы получают владельца процесса soul-агента.
- Checksum — для идемпотентности, не для верификации источника: SHA-256 считается по уже лежащему на диске архиву («тот же ли архив, что в прошлый раз»), против доверенного эталонного хэша/подписи не сверяется. Для недоверенных артефактов сверяйте подпись/хэш отдельным шагом (register + failed_when:) до распаковки и распаковывайте в изолированный непривилегированный dest.
- Привилегии: манифест объявляет только fs_write_root, но не run_as_root и не exec_subprocess (подпроцессы не порождаются); для распаковки в системные пути агент на практике работает под root — тем ценнее setuid-маскинг и within-dest-инварианты.