fix(frontend): patch vulnerable browserslist dependency

pnpm audit по всему lock-графу остановил релизную сборку: browserslist@4.21.11
несёт high-advisory (уязвимы <= 4.28.6) и приходит транзитивно через
autoprefixer и update-browserslist-db.

Закрыто точечным pnpm.overrides на 4.28.7 — точной версией, а не диапазоном:
security-патч обязан быть детерминированным и не тащить за собой чужой major.
Обновилось только поддерево browserslist (caniuse-lite, electron-to-chromium,
escalade, node-releases, update-browserslist-db); autoprefixer, Vite и остальной
граф не тронуты.

Проверено с pnpm 9.15.9 (contract из packageManager):
  pnpm why browserslist        -> 4.28.7
  pnpm audit --audit-level high -> 0, no known vulnerabilities
  pnpm install --frozen-lockfile -> lockfile is up to date
  typecheck + build:prod        -> ok
This commit is contained in:
2026-09-03 22:39:25 +05:00
parent b9d3c03f8d
commit 7d486af712
4 changed files with 78 additions and 25 deletions
+25
View File
@@ -218,6 +218,31 @@ bundle из кода, который не проходит проверку ти
локальной работы обходить нечего: `go test ./...`, `govulncheck ./...` и
`pnpm audit` запускаются напрямую и tarball не создают.
#### Транзитивные зависимости чинятся точечным override
Уязвимость обычно приходит не из прямой зависимости, а из чужого поддерева, и
поднимать ради неё весь frontend-граф не нужно. Такие случаи закрываются
списком `pnpm.overrides` в `apps/frontend/package.json`:
| override | зачем |
| --- | --- |
| `lodash`, `lodash-es` | prototype pollution в старых ветках |
| `brace-expansion` | ReDoS |
| `picomatch` | ReDoS |
| `js-yaml` | разбор недоверенного YAML |
| `table>ajv` | уязвимая `ajv` в поддереве `table` |
| `browserslist` | high-advisory в `<= 4.28.6`; тянется через `autoprefixer` и `update-browserslist-db` |
Правило записи значения: точная версия для security-патча (`4.28.7`), диапазон
`>=` — только там, где важна нижняя граница, а не конкретный релиз. Точная
версия делает граф детерминированным и не тащит вместе с патчем чужой major.
Снимать override можно тогда, когда прямая зависимость сама поднялась выше
уязвимой границы, — и только после `pnpm why <пакет>`, показывающего, что старая
версия больше не приходит ни из одного поддерева. Просто «выглядит лишним» — не
основание: список существует ровно потому, что верхние пакеты обновляются
медленнее advisories.
### Тесты и типы
Та же политика и по той же причине. Аварийного выхода у этого шага **нет**: