Skip to content

fix(webhooks): bound the size of watch paths and deploy when a pattern cannot be evaluated - #259

Merged
agentHits merged 1 commit into
AgentHits-Devfrom
fix/watch-paths-limits
Nov 11, 2026
Merged

agentHits merged 1 commit into
AgentHits-Devfrom
fix/watch-paths-limits

Conversation

@agentHits

Copy link
Copy Markdown
Collaborator

Зачем

Проверка зависимостей через cve-now нашла braces 3.0.3 (CVE-2026-93687 / GHSA-vfj7-8cjw-p6xm, высокая, исправленной версии нет). braces приходит через micromatch, который форк вызывает в одном месте, shouldDeploy, на шаблонах watchPaths.

Я проверил, достижима ли она. На micromatch 4.0.8 с braces 3.0.3 (VM, Bun 1.4.4 и Node 26.13.0):

  • micromatch(files, patterns) не доходит до braces: braces зовутся только из micromatch.parse, micromatch.braces и micromatch.braceExpand. Все формы шаблонов с переполнением стека или взрывом раскрытия (подряд идущие {a,b} почти до предельной длины) на этом вызове завершаются за миллисекунды. CVE форка не затрагивает.
  • Нашлось другое: у watchPaths нет ограничения длины, а разбор вложенных скобок в picomatch растёт квадратично. Шаблон из 40 000 символов блокирует цикл событий на 8,6 с под Bun (на Node SyntaxError после 8 с), а такой запрос приходит на каждый вебхук. Шаблон мог задать пользователь с правом менять сервис.
  • Пустая строка в watchPaths заставляет micromatch бросить TypeError: Expected pattern to be a non-empty string; обработчик вебхука падал.

Что изменилось

  • packages/server/src/utils/watch-paths/limits.ts: watchPathsSchema — не больше 64 путей по 256 символов.
  • db/schema/application.ts и db/schema/compose.ts: поле watchPaths в createSchema теперь использует эту схему. Через createSchema идут apiSave{Github,Gitlab,Bitbucket,Gitea,Git}Provider, apiUpdateApplication и apiUpdateCompose, так что ограничение действует на всех путях сохранения.
  • shouldDeploy: слишком большой набор не разбирается, micromatch обёрнут в try/catch. В обоих случаях деплой запускается (как при пустом watchPaths), в лог идёт предупреждение без самих шаблонов.
  • Тесты: should-deploy.test.ts 10 → 17 тестов.

Что меняется для пользователей

  • Путь длиннее 256 символов или больше 64 путей сохранить нельзя, API отвечает сообщением схемы. Настоящие шаблоны (src/**, {apps,packages}/*/src/**, !tests/**) на порядки короче.
  • Уже сохранённые длинные шаблоны не ломаются, но ведут к деплою на каждый пуш, пока их не сократят.

Проверки

Linux, Bun 1.4.4, Node 26.13.0:

  • bun run server:build, bun run typecheck, biome check по изменённым файлам проходят.
  • should-deploy.test.ts: 17 из 17.
  • Unit-тесты целиком: 6136 прошли, 2 упали. Оба так же падают на базовой ветке: backup-files (таймаут под нагрузкой) и service-webhook-secret > Bitbucket (обращается к настоящему Bitbucket API).

Что проверить вручную на dev

  • Сохранение watchPaths с обычным шаблоном проходит; с шаблоном длиннее 256 символов форма показывает ошибку.
  • Пуш в репозиторий приложения с watchPaths по-прежнему запускает или пропускает деплой.

🤖 Generated with Claude Code

…n cannot be evaluated

Что: у watchPaths появились ограничения: не больше 64 путей по 256 символов (watchPathsSchema в utils/watch-paths/limits.ts; подключена в createSchema приложения и compose, поэтому действует во всех apiSave*Provider, apiUpdateApplication и apiUpdateCompose). shouldDeploy не разбирает слишком большой набор и оборачивает micromatch в try/catch: и в том, и в другом случае деплой запускается, в лог идёт предупреждение без самих шаблонов.

Зачем: проверка зависимостей через cve-now нашла braces 3.0.3 (CVE-2026-93687, высокая, исправления нет). Измерение на micromatch 4.0.8 показало, что форк её не затрагивает: micromatch(files, patterns) идёт в picomatch и до braces не доходит (braces зовутся только из micromatch.parse, .braces и .braceExpand); формы шаблонов с переполнением стека и взрывом раскрытия ({a,b} подряд до предела длины) через этот вызов завершаются за миллисекунды. Зато сам разбор вложенных скобок в picomatch растёт квадратично, а длина watchPaths не была ограничена: шаблон из 40 000 символов блокировал цикл событий на 8,6 с под Bun, на Node заканчивался SyntaxError после 8 с. Кроме того, пустая строка в watchPaths делала micromatch TypeError ("Expected pattern to be a non-empty string"), и обработчик вебхука падал.

Риски: путь длиннее 256 символов или больше 64 путей нельзя сохранить, API вернёт сообщение схемы (формы показывают ошибку сохранения). Уже сохранённые длинные шаблоны не ломаются, а ведут к деплою на каждый пуш, пока их не сократят. Обычные шаблоны (src/**, {apps,packages}/*/src/**, !tests/**) оцениваются как раньше.

Проверки на Linux, Bun 1.4.4, Node 26.13.0: server:build, typecheck и biome проходят; should-deploy.test.ts 17 из 17 (было 10: добавлены оценка слишком большого шаблона за миллисекунды, 65 путей, путь ровно в 256 символов, пустой путь, схемы приложения и compose); unit-тесты: 6136 прошли, 2 упали, и каждый из них так же падает на базовой ветке (backup-files под нагрузкой, service-webhook-secret обращается к настоящему Bitbucket API).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@agentHits
agentHits merged commit 720089d into AgentHits-Dev Nov 11, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant