Подмена пакетов из маркета! Или кто подставил кролика Nexus-а?
Ещё одна интересная задачка, которую приходилось решать мне как разработчику! Сначала житейская сказка, а в конце добавлю технического языка для заинтересованных.
Сказка
Представьте, вы сделали заказ в магазине «Лента» и курьер доставил вам полный пакет продуктов.
Вы начинаете разбирать этот пакет — открываете пачку с печеньем, а внутри лежит не только печенье, но и конфеты, и вы недоумеваете. Открываете пачку с хлопьями для завтрака — а внутри вместе с хлопьями — чипсы. И дальше вы боитесь открывать банку с тушенкой... Ну вы поняли.
Продолжая аналогию с супермаркетом, вообразим, что моя программа — это такой «авто шеф-повар», который получает заводские запакованные пакеты с продуктами и делает из них салат. И чтобы программа работала верно, ей необходимо, чтобы в каждом принесенном курьером пакете было проверенное содержимое.
И вот мой «авто шеф-повар» дождался, получил пакеты от «курьера». А внутри одного пакета — хаос, лишние ингредиенты, и нет того самого — желанного. И это ломает всю работу! Страшно, очень страшно! Мы не знаем, что это такое, если бы мы знали, что это такое…
Ищем хитрую лису
Дальше нужно разбираться, кто виноват? Сборщик на заводе положил неверные позиции или же сборщик в магазине? Или вмешался курьер..? Найдем виновных и, естественно, надаём им по рукам и научим их нормально работать с такими важными пакетами.
Я сказал: «Мы их всех выявим» и первым делом отправился на завод. Проверка на заводе показала, что всё было собрано по всем стандартам — ничего лишнего. О, как же хорошо, что на заводе есть свои люди и есть возможность узнать, как был собран мой пакет.
На следующее утро мы отправились в магазин, где не так давно, под прицелами камер, сборщик касался именно нашего пакета. И что мы увидели? Мы обнаружили халатность! Сборщик очень часто ходил на перекур и даже в туалет. Но, к сожалению, признаков подмены товаров мы не обнаружили.
Требовалось более тщательное изучение деталей... Так под подозрение попал некий помощник. Как выяснилось, для приготовления салатов «авто шеф-повар» поручал проверку пакетов своему помощнику «Господину Ивлеву». Тот, по неопытности, нервничал и к тому же был неаккуратен и тем самым вносил хаос на кухню (в пакеты). Разгадка была, как всегда, у нас под носом.
Технический перевод
GitLab CI собрал новую версию PyPI пакета (назовём его «Russian Shuba 2.0») и успешно опубликовал во внутреннем Nexus. Docker-образ сервиса успешно собрался и установил наш «Russian Shuba 2.0». Но сервис не стартует — говорит: «Отсутствует новый секретный ингредиент, который добавили в версии 2.0».
Расследование установило, что «Russian Shuba 2.0» в Nexus репозитории имеет 100% валидный код. Далее свидетель «uv» сообщил, что у пострадавшего Docker-контейнера действительно установлена верная версия 2.0 для «Russian Shuba».
Эндоскопия Docker-контейнера показала ШОК-КОНТЕНТ! Установленный PyPI пакет версии 2.0 имеет файлы с программным кодом версии 1.0, так и файлы версии 2.0.
После прокрастинации был активирован навык экстрасенса, который указал верный путь — "/app/.dockerignore". Прохожий .dockerignore шёл по известному пути: «Запретить всё! А потом разрешать то, что необходимо».
Выданное разрешение — копировать в docker-контейнер «.py» файлы само по себе не могло привести к тяжким последствиям. Если бы не .venv директория с виртуальным окружением. Злоумышленники действовали в паре — .dockerignore был уполномочен пропускать .py файлы из .venv в Docker-контейнер, что и привело к неминуемому.
К счастью, история имела счастливый конец: Docker-контейнер снова заработал! А для .dockerignore были назначены исправительные работы, .venv отделался предупреждением, а ваш покорный слуга с навыками экстрасенсорных способностей получил отметку о спасении «Russian Shuba 2.0» в Jira-ном личном деле.