Ядро
Составные документы: `import`
И -f test.yaml, и -c config.yaml принимают верхнеуровневый ключ import:,
указывающий базовый документ. База загружается первой — рекурсивно, так как
она сама может импортировать свою базу, — а затем импортирующий документ
глубоко объединяется поверх неё. Команды используют общий согласованный базовый
документ (профиль нагрузки, переменные, пороги), а каждый сервис переопределяет
только то, что отличается.
# perf/config/_base.yaml — owned by the platform team
vus: 50
duration: 5m
variables:
region: eu-west
base_url: https://staging.example.com
# services/checkout/perf.yaml — owned by the checkout team
import: ../../perf/config/_base.yaml
variables:
base_url: https://checkout.staging.example.com # region inherited
Семантика слияния
- Объекты сливаются по ключам, рекурсивно —
variables:из базы и из импортирующего файла объединяются; при совпадении имён ключей побеждает импортирующая сторона. - Всё остальное замещается — скаляры и массивы, включая
steps:. Тестовый документ, определяющийsteps:, целиком замещает список базы (пошагового сращивания нет); документ безsteps:наследует список базы без изменений. - Цепочки работают: A импортирует B, B импортирует C → C загружается первым, B сливается поверх него, A — поверх результата. Циклы завершаются ошибкой с выводом всей цепочки.
Валидация выполняется над объединённым документом — и perfscale lint, и
perfscale run сначала разрешают импорты, поэтому ошибка указывает на то, что
реально будет выполняться.
Формы источников
# 1. relative filesystem path — resolved against the importing file's dir
import: ../shared/_base.yaml
# 2. raw HTTP(S) URL — the ref is already pinned in the path
import: "https://raw.githubusercontent.com/org/repo/v1.2.0/perf/config/_base.yaml"
# 3. a file at a ref of any git remote (SSH or HTTPS, self-hosted included)
import:
git: git@gitlab.example.com:group/repo.git
ref: v1.2.0 # tag, branch, or commit SHA
file: perf/config/_base.yaml
Git-импорты вызывают системный git (clone --depth 1), поэтому применяются
SSH-ключи, credential helpers и настройки прокси — приватные репозитории работают
с той аутентификацией, которая уже настроена для git clone. Зависимости от
libgit2 нет.
Безопасность: удалённые импорты включаются явно
Разрешение импортов происходит при загрузке конфигурации — до того, как
сработают ограничения allow_file_actions / allow_process_actions. Если сама
конфигурация получена из недоверенного источника (скажем, файл из PR), сетевой
import: внутри неё — это примитив SSRF и вектор атаки на цепочку поставок:
удалённая база может содержать allow_process_actions: true вместе с шагом
std/child_process@v1.
Поэтому разрешение на обращение к сети даёт вызывающая сторона, а не документ:
perfscale run -f t.yaml -c c.yaml --allow-remote-import
perfscale lint c.yaml --allow-remote-import
Без флага любой импорт по URL или из git завершается ошибкой с пояснением. YAML-поля, включающего такой доступ, намеренно не существует — документ не может сам выдать себе доступ к сети.
Источники остаются изолированными:
- Документ, загруженный по URL, разрешает относительные импорты относительно собственного URL. Указать локальный путь файловой системы он не может.
- Документ из git-репозитория может импортировать только файлы внутри того
же клона; выходы за пределы корня репозитория через
../отклоняются. - Только локальные документы на вашем диске могут начинать цепочку в сеть (и только при наличии флага).
Кэширование
Git-клоны размещаются в ~/.cache/perfscale/imports/<hash(git+ref)>
(учитывается $XDG_CACHE_HOME; $PERFSCALE_CACHE_DIR переопределяет корень).
| Тип ref | Поведение |
|---|---|
| Commit SHA | Неизменяемый — кэшируется навсегда, повторно не запрашивается |
| Tag | Считается неизменяемым — кэшируется навсегда; --refresh-imports запрашивает заново |
| Branch | Изменяемый — после 5-минутного TTL удалённый репозиторий перепроверяется через git ls-remote; сдвинувшаяся ветка запрашивается заново, недоступный удалённый репозиторий откатывается к кэшированной копии с предупреждением [sys] |
Правило для веток важно: без него плавающий ref: main молча застыл бы на том,
что увидела первая загрузка, и каждый последующий запуск утверждал бы, что
тестирует «последнюю версию», используя устаревшую базу. --refresh-imports
принудительно выполняет проверку немедленно.
HTTP-импорты запрашиваются при каждом запуске (для воспроизводимости закрепляйте в URL тег или SHA).
Взаимодействие с остальным движком
importсобирает документ; это не шаг, и время итераций он не расходует. После слияния результат валидируется по той же JSON Schema, что и любой обычный файл.- Интерполяция
${{ vars.* }}происходит во время выполнения, после слияния, — база может ссылаться на переменные, задаваемые импортирующим файлом, и наоборот. perfscale lintсообщает о проблемах разрешения импортов (отсутствующая база, цикл, заблокированный удалённый источник) как об обычных находках; после разрешения импортов он валидирует объединённый документ, включая проверку импортированных шагов по схеме GraphQL.
Ограничения
- Один
importна документ (вместо перечисления нескольких — выстраивайте базы в цепочку). - Никакой пошаговой хирургии слияния:
steps:замещается целиком. - Цепочки импортов ограничены 16 уровнями; тела HTTP-ответов — 10 МБ.
Готовый к запуску пример пары лежит в examples/import/.