From 25bebadca5abc90b090b040f93a93eff866485b6 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Sat, 29 Aug 2026 14:01:14 +0300 Subject: [PATCH] =?UTF-8?q?chore(deps):=20=D1=82=D1=80=D0=B8=20=D0=BC?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=B0,=20=D0=B3=D0=B4=D0=B5=20=D1=81=D0=B1?= =?UTF-8?q?=D0=BE=D1=80=D0=BA=D0=B0=20=D0=BD=D0=B5=20=D0=B2=D0=BE=D1=81?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B8=D0=B7=D0=B2=D0=BE=D0=B4=D0=B8=D1=82?= =?UTF-8?q?=D1=81=D1=8F=20=E2=80=94=20=D0=BB=D0=BE=D0=BA-=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=B7=D1=80=D0=B0=D0=BA,=20=D0=B3=D0=BB=D0=BE=D0=B1=20?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B5=D0=BF=D1=80=D0=B8=D0=BF=D0=B8=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B=D0=B9=20=D1=81=D0=B0=D0=B9=D0=B4?= =?UTF-8?q?=D0=BA=D0=B0=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ничего не апгрейдит. Убирает три способа собрать образ не тем, что в репозитории. 1. tradein-mvp/backend/uv.lock — удалён (файл был untracked, в .gitignore с рождения). Мера — uv-workspace, сборка берёт КОРНЕВОЙ tradein-mvp/uv.lock (`context: ./tradein-mvp`, `COPY pyproject.toml uv.lock ./` + `uv sync --frozen`). Лок, созданный `uv lock` из backend/, не читает никто, и он тихо разошёлся с рабочим: на 2026-08-29 в нём pillow 12.2.0, starlette 1.0.1, python-multipart 0.0.29, pydantic-settings 2.14.1, weasyprint 68.1 — пять пакетов с открытыми advisory, которых в реальной сборке Меры нет вообще. Именно он подмешал пять фантомных строк в OSV-скан этой серии. Строка .gitignore остаётся (второй лок не нужен), но теперь с объяснением почему — иначе следующий читатель снимет ignore и закоммитит призрак. 2. backend/Dockerfile — `COPY pyproject.toml uv.lock* ./` + `if [ -f uv.lock ]; then uv sync --frozen ...; else uv sync ...; fi` → без глоба и без фолбэка. Глоб + фолбэк означали: пропал лок — сборка не падает, а молча переключается на резолв «свежайшее из диапазонов pyproject». Образ собрался бы с версиями, которых никто не видел ни в одном PR. Теперь пропажа лока роняет COPY. 3. tradein-mvp/browser/Dockerfile — `pip install "camoufox[geoip]" aiohttp` без единого пина. У сайдкара нет лока вообще, так что любая пересборка (в том числе на несвязанном коммите) тянула свежайший camoufox, а с ним другой playwright — под который НЕ написан sed-патч coreBundle.js в том же файле. Запинено по факту прод-контейнера tradein-browser: camoufox 0.5.5, playwright 1.60.0, aiohttp 3.14.3. playwright явно, хотя и транзитивный (camoufox 0.5.5 → playwright<1.61): патч завязан на конкретную сборку драйвера. Там же переписан комментарий «Апгрейд playwright невозможен — camoufox 0.4.11 pinned»: неверны обе половины. camoufox не был запинен ни на что, а 0.4.11 в проде не стоит с неизвестно каких пор — контейнер сейчас несёт 0.5.5 и playwright 1.60.0. Версии сняты с живого прод-контейнера, наличие на PyPI проверено. --- backend/Dockerfile | 10 ++++++++-- tradein-mvp/.gitignore | 9 +++++++++ tradein-mvp/browser/Dockerfile | 21 +++++++++++++++++---- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 0da0ae0c..299c4444 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -28,10 +28,16 @@ RUN pip install --no-cache-dir uv WORKDIR /app -COPY pyproject.toml uv.lock* ./ +# Без глоба и без фолбэка: uv.lock ОБЯЗАТЕЛЕН. `uv.lock*` + `if [ -f uv.lock ]` +# означали, что пропавший лок не ломает сборку, а тихо переключает её на резолв +# «свежайшее из диапазонов pyproject» — образ собирался бы с версиями, которых +# никто не видел ни в одном PR, и воспроизвести прод-сборку было бы нечем. +# Теперь пропажа лока = падение COPY, то есть красный билд вместо незаметной +# подмены зависимостей. +COPY pyproject.toml uv.lock ./ # uv-кеш переживает между билдами: при неизменном lock'е sync ~5 сек вместо 1-2 мин. RUN --mount=type=cache,target=/root/.cache/uv \ - if [ -f uv.lock ]; then uv sync --frozen --no-dev; else uv sync --no-dev; fi + uv sync --frozen --no-dev COPY app ./app COPY alembic.ini ./ diff --git a/tradein-mvp/.gitignore b/tradein-mvp/.gitignore index a746885d..c1c4ab25 100644 --- a/tradein-mvp/.gitignore +++ b/tradein-mvp/.gitignore @@ -8,6 +8,15 @@ backend/*.egg-info/ backend/.pytest_cache/ backend/.ruff_cache/ backend/.mypy_cache/ +# backend/uv.lock — ИГНОРИРУЕТСЯ НАМЕРЕННО, это не забытый файл. +# Мера — uv-workspace: единственный лок живёт в корне (tradein-mvp/uv.lock), и +# именно его берёт сборка (context: ./tradein-mvp, `COPY pyproject.toml uv.lock ./` +# + `uv sync --frozen`). `uv lock`, запущенный из backend/, создаёт ВТОРОЙ лок, +# который никто не читает и который тихо расходится с рабочим: на 2026-08-29 +# в нём висели pillow 12.2.0, starlette 1.0.1, python-multipart 0.0.29, +# pydantic-settings 2.14.1 и weasyprint 68.1 — пять пакетов с открытыми +# advisory, которых в реальной сборке Меры нет вообще. +# Локи обновлять из корня: `cd tradein-mvp && uv lock`. backend/uv.lock # Frontend Node diff --git a/tradein-mvp/browser/Dockerfile b/tradein-mvp/browser/Dockerfile index d98b761c..5f789592 100644 --- a/tradein-mvp/browser/Dockerfile +++ b/tradein-mvp/browser/Dockerfile @@ -20,8 +20,18 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ WORKDIR /app -# camoufox[geoip] тянет playwright как зависимость -RUN pip install --no-cache-dir "camoufox[geoip]" aiohttp +# Пины, а не плавающие версии: единственный лок этого сайдкара — вот эти строки. +# Без них любая пересборка образа (в том числе автоматическая, на не связанном +# коммите) втягивала свежайший camoufox — а вместе с ним другой playwright, под +# который написан sed-патч coreBundle.js ниже. Версии сняты с работающего +# прод-контейнера tradein-browser (2026-08-29): camoufox 0.5.5, playwright +# 1.60.0, aiohttp 3.14.3. playwright запинен явно, хотя и приходит транзитивно +# (camoufox 0.5.5 требует playwright<1.61) — патч завязан на конкретную сборку +# драйвера, диапазон тут не годится. +RUN pip install --no-cache-dir \ + "camoufox[geoip]==0.5.5" \ + "playwright==1.60.0" \ + "aiohttp==3.14.3" # ── #915/#918: null-guard + ВАЛИДНЫЕ дефолты для pageError.location (playwright 1.60.0) ─ # Firefox/juggler-бэкенд иногда отдаёт uncaught JS-ошибку страницы (реклама / @@ -42,8 +52,11 @@ RUN pip install --no-cache-dir "camoufox[geoip]" aiohttp # страницы вместо краша → pipeline видит firewall и штатно ротирует IP, а не # уходит в crash-storm (подтверждено прод-дебагом локального стека 2026-05-31). # -# Апгрейд playwright невозможен — camoufox 0.4.11 pinned под Firefox+juggler. -# Сборка падает (exit 1), если паттерн не найден — сигнал что bump playwright сломал патч. +# Апгрейд playwright не заблокирован, но связан: camoufox тянет playwright сам +# (0.5.5 → playwright<1.61), поэтому поднимать его можно только вместе с +# camoufox и только проверив, что паттерны sed ниже ещё есть в coreBundle.js. +# Сборка падает (exit 1), если паттерн не найден — это и есть сигнал, что bump +# сломал патч. RUN PW_BUNDLE="$(python -c 'import os,playwright;print(os.path.join(os.path.dirname(playwright.__file__),"driver","package","lib","coreBundle.js"))')" \ && sed -i -E "s/pageError\.location\.url,/pageError.location?.url ?? '',/g" "$PW_BUNDLE" \ && sed -i -E 's/pageError\.location\.lineNumber,/pageError.location?.lineNumber ?? 0,/g' "$PW_BUNDLE" \