Детерминированный сканер и система семантического сравнения production-сборок фронтенда
https://xn--d1ah4a.com/.
Проект скачивает граф публичных ресурсов фронтенда, не выполняя код сайта, пропускает
JavaScript через консервативный уровень преобразований minimal в Wakaru, а затем применяет
собственную нормализацию с учётом областей видимости. Полученные снимки предназначены для
хранения истории в Git и проверки изменений кода, а не для пересборки или запуска исходного
приложения.
В production-сборках могут меняться хеши содержимого, минифицированные идентификаторы, имена
классов CSS Modules и отладочные идентификаторы Sentry, даже если поведение приложения почти
не изменилось. itd-scanner устраняет эти источники шума, сохраняя строки, числа, имена
свойств, порядок инструкций, пути запросов и поток управления.
Этапы нормализации:
- Сканер скачивает HTML и рекурсивно находит ресурсы того же origin: ESM-модули, зависимости Vite, CSS, шрифты, изображения и JSON.
- Проверяются перенаправления, типы ответов, UTF-8, количество ресурсов и ограничения на размер. Статические импорты обязательны, а необязательные URL-литералы могут отсутствовать.
- Ресурсам назначаются логические пути, например
entry.js,routes/login.jsиcomponents/icon-play.js. Неизвестные общие чанки сопоставляются с предыдущим манифестом по структурным отпечаткам, не зависящим от имён переменных. - JavaScript декомпилируется зафиксированной версией Wakaru на уровне
minimal. - Babel разрешает привязки идентификаторов, после чего переименовываются только лексические переменные и ссылки на них. Ключи объектов, свойства, литералы, глобальные имена и порядок выполнения сохраняются.
- Нормализуются минифицированные экспорты между чанками, пути импортов, классы CSS Modules и меняющиеся отладочные UUID Sentry.
- Формируется сводный отчёт с приоритетом объявленных маршрутов, их эффективными шаблонами и ограничениями, HTTP- и WebSocket-адресами, ключами хранилищ, пользовательскими строками и версиями Sentry. Diff маршрутов показывает изменения порядка, fallback и сужающих проверок параметров.
Скачанный JavaScript не вычисляется, не импортируется и не запускается.
- Node.js 22.18 или новее;
- Git — для истории снимков и сравнительных тестов.
Установка строго зафиксированного графа зависимостей:
npm ciСоздание снимка сайта:
npm run scan -- --output snapshotКоманда создаёт:
snapshot/raw/— точные скачанные байты для проверки результатов;snapshot/source/— стабильный, нормализованный и читаемый код;snapshot/manifest.json— хеши, исходные URL, логические имена и сигнатуры сопоставления;snapshot/reports/summary.md— сводный отчёт о текущей сборке.
Локальная snapshot/ игнорируется в ветке со сканером. GitHub Actions записывает её в
отдельную ветку snapshots.
Полезные команды:
npm test
npm run build
npm run check
npm run scan -- --output snapshot
npm run scan -- --no-wakaruФлаг --no-wakaru предназначен для диагностики и модульных тестов. Для production-снимков
следует использовать Wakaru.
Сравнить две произвольные директории со сборками можно командой:
npm run benchmark -- <старая-сборка> <новая-сборка> <каталог-результата>На реальных сборках от 13 и 20 августа обычное форматирование отмечает изменёнными все 85 файлов и 19 167 строк. В каноническом представлении остаются 11 файлов и 807 строк — уровень шума снижается на 95,79%. В оставшемся diff основной сборки видны реальные изменения, например загрузка удалённых SVG-иконок и состояние мутаций лайков, а не массовое переименование минифицированных переменных.
Workflow .github/workflows/scan.yml запускается каждые шесть часов: в 03:17, 09:17, 15:17
и 21:17 по часовому поясу Europe/Moscow. Его также можно запустить вручную. Ненулевая минута
помогает не попадать в наиболее загруженный для GitHub Actions момент в начале часа.
Код сканера хранится в основной ветке, а история сгенерированных снимков — в ветке
snapshots. При первом успешном запуске workflow автоматически создаёт эту ветку,
последовательно выполняет конкурирующие сканы, запрашивает только разрешение
contents: write и создаёт коммит лишь при изменении опубликованной сборки или версии
нормализатора.
Текущее расписание задаётся выражением:
cron: "17 3,9,15,21 * * *"
timezone: "Europe/Moscow"Сначала откройте snapshot/reports/summary.md, затем изучите соответствующие файлы в
snapshot/source/. Точные минифицированные файлы остаются в snapshot/raw/, но
.gitattributes помечает их как сгенерированные и отключает для них шумные текстовые diff.
Сканер намеренно не нормализует:
- строковые и числовые литералы;
- ключи объектов и невычисляемые свойства;
- порядок инструкций, элементов массивов и свойств объектов;
- условия и операторы;
- вызовы с наблюдаемыми побочными эффектами.
Обновление компилятора всё ещё может создавать структурный шум из-за инлайнинга, tree shaking
или изменения порядка модулей. Точный слой raw позволяет проверить каноническое
представление в спорных случаях.
Целевой URL и ограничения находятся в itd-scanner.config.json. Разрешены только HTTPS и
ресурсы или перенаправления того же origin. Сканер завершает работу без записи нового снимка,
если вместо приложения получена challenge-страница, нарушена кодировка UTF-8, отсутствует
статический импорт, возвращён неожиданный тип содержимого или превышено настроенное
ограничение на ресурсы.
Сканируйте только те сайты, условия использования и применимое законодательство которых разрешают такой анализ. Сканер не обходит защитные проверки и не обращается к содержимому, требующему авторизации.