Как сломать прод с помощью HTML

1 ноября 2024 г.

Введение

Как-то раз меня попросили изменить текст на сайте. Ничего сложного, просто текст. Я внёс изменения, отправил на ревью. После того как изменения были приняты, я отправил их на продакшн. Правки были настолько малы и не могли принести никакого вреда (хе-хе 😅), что я поленился пойти и проверить сам сайт, а лишь дождался зеленой галочки на GitHub о том, что сборка прошла успешно и пошел спать.
Утром в чат слака пришло сообщение, что на сайте пропали все стили (получается, еще вчера! 😵). Сказать, что я был в шоке, это ничего не сказать. Это достаточно серьезная финансовая организация и я своими действиями мог причинить им ущерб. Но что же случилось?

Поиски утраченных стилей 👀

Я начал искать причину проблемы. Беглый взгляд в network показал, что стили не подгружаются, вместо него отдается корневой html. Это означало, что файла нет или путь к нему сломан. После того как я проверил, что конфигурации сервера не изменились и путь остался правильным, я начал искать причину в сборке. Проект собирался и деплоился с помощью AWS. Все было настроено так, что после успешной сборки, проект раскатывался на продакшн. На первый взгляд в логах было все нормально. По крайней мере сборка завершалась успешно, что сбивало с толку. Я начал проверять установленные версии пакетов. Проект был очень старым и там были зафиксированы старая версия ноды и npm.

Old node and npm versions

При этом, Grunt, который использовался для сборки не имел зафиксированной версии и первый попал под подозрение. Я проверил версию, которая устанавливается в ходе сборки, но только узнал, что последняя версия вышла 2 года назад. Пришло время тщательно изучить логи сборки. И вот что я нашел:

Grunt-cli TypeError

Это была новая ошибка, которая отсутствовала в старых логах. Вот ты и попался, вредный баг! Оказалось, что версии пакетов самого проекта не были зафиксированы и использовали "крышечку" ^.

Package.json with dependencies

Это означало, что при каждом запуске сборки, npm устанавливал последние "совместимые" версии пакетов. Совместимый в данном случае означает, что первая цифра из версии должна оставаться прежней, при этом вторая и третья могут меняться. Подробнее о версионировании пакетов можно прочитать здесь. Или воспользуйтесь калькулятором версий. Обычно такой подход работает. Но когда вы долго не следите за обновлением пакетов, а в нашем примере они не обновлялись с 2017 года, то это может сослужить вам плохую службу. В данном случае, npm установил новую версию grunt-cli, которая не была совместима с версией node, которая была зафиксирована в проекте.

Решение

Решение было простым. Нужно было зафиксировать версии пакетов в package.json. Однако установка нужной версии grunt-cli не помогла. Другие пакеты тоже обновились и использовали обновленный grunt-cli в качестве зависимости. Было два пути: либо зафиксировать все пакеты на последних версиях, совместимых с нужной нам версией node, либо обновить саму ноду. Я выбрал второй вариант. После обновления Node.js до версии 10.10.0, все заработало. Сборка прошла успешно и стили вернулись на сайт.

Выводы

  1. Даже маленькие изменения могут привести к серьезным проблемам. Когда вы беретесь за legacy проект, будьте готовы к тому, что могут появиться неожиданные сложности и закладывайте на это время. Особенно, если проект долго не обновлялся и вы не были одним из его мейнтейнеров.
  2. Не деплойте вечером (и в пятницу).
  3. Не ленитесь проверять свои изменения, даже если изменили пару букв.
  4. Зафиксируйте версии пакетов в package.json. Это поможет избежать подобных проблем.

Были ли у вас подобные случаи? Как вы указываете ваши зависимости в package.json? Поделитесь в комментариях в телеграме.