From c99665542adc4ebd7472cdd3654d21af7985bdad Mon Sep 17 00:00:00 2001 From: ayurishchev Date: Mon, 21 Sep 2026 07:47:02 +0300 Subject: [PATCH] Pin dependency versions and add constraints.txt Exact versions for direct dependencies, full pip freeze of the tested image as constraints, both Dockerfiles install with -c constraints.txt. Co-Authored-By: Claude Sonnet 5 --- Dockerfile | 4 ++-- Dockerfile.test | 4 ++-- README.md | 11 ++++++++--- constraints.txt | 26 ++++++++++++++++++++++++++ docs/plan-pin-dependencies.md | 25 +++++++++++++++++++++++++ docs/summary-pin-dependencies.md | 20 ++++++++++++++++++++ requirements-dev.txt | 4 ++-- requirements.txt | 8 ++++---- 8 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 constraints.txt create mode 100644 docs/plan-pin-dependencies.md create mode 100644 docs/summary-pin-dependencies.md diff --git a/Dockerfile b/Dockerfile index 0e8994b..d2ec47c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,8 +6,8 @@ ENV PYTHONUNBUFFERED=1 \ WORKDIR /app -COPY requirements.txt ./ -RUN pip install --no-cache-dir -r requirements.txt +COPY requirements.txt constraints.txt ./ +RUN pip install --no-cache-dir -c constraints.txt -r requirements.txt COPY api_server.py cidr_collector.py collector_daemon.py db.py formatters.py storage.py healthcheck.py ./ diff --git a/Dockerfile.test b/Dockerfile.test index c6562e5..4225720 100644 --- a/Dockerfile.test +++ b/Dockerfile.test @@ -2,8 +2,8 @@ FROM python:3.11-slim WORKDIR /app -COPY requirements.txt requirements-dev.txt ./ -RUN pip install --no-cache-dir -r requirements.txt -r requirements-dev.txt +COPY requirements.txt requirements-dev.txt constraints.txt ./ +RUN pip install --no-cache-dir -c constraints.txt -r requirements.txt -r requirements-dev.txt COPY . . diff --git a/README.md b/README.md index 0bd2c05..77db7c5 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ The system consists of **two independent processes**: the collector daemon (`col ```bash mkdir -p /opt/ripe_collector cd /opt/ripe_collector - # Copy files: cidr_collector.py, api_server.py, storage.py, requirements.txt, config.json + # Copy files: *.py (api_server, cidr_collector, collector_daemon, db, formatters, storage, healthcheck), + # requirements.txt, constraints.txt, config.json ``` 2. **Create a Virtual Environment**: @@ -30,7 +31,7 @@ The system consists of **two independent processes**: the collector daemon (`col 3. **Install Dependencies**: ```bash source venv/bin/activate - pip install -r requirements.txt + pip install -c constraints.txt -r requirements.txt # exact versions, see "Dependency versions" below deactivate ``` @@ -57,6 +58,10 @@ The system consists of **two independent processes**: the collector daemon (`col 7. **Repository:** `main` branch, remote `origin` = `https://artstore.rxmsk.ru/ayurishchev/ripe-cidr-collector.git`. Committed: code, tests, Docker files, `config.json` (initial sources), `.env.example`, `docs/`. Not committed (`.gitignore`): `venv/`, `.env`, databases `*.db*`, collected data `data.json` / `fqdn_data.json`, `graphify-out/`, service files. Every change follows the plan -> implementation -> summary flow in `docs/` and gets its own commit. + +### Dependency versions +`requirements.txt` / `requirements-dev.txt` list direct dependencies with exact versions (`==`); `constraints.txt` is the full `pip freeze` (including transitive packages) of the image the tests pass on. Both Dockerfiles install with `-c constraints.txt`. To update: change the versions in a container, run the tests, regenerate `constraints.txt` (`docker run --rm --entrypoint pip freeze > constraints.txt`) and commit all three files together. + --- ## 2. Running the Collector @@ -476,7 +481,7 @@ docker compose down # stop; data stays in the volume ### Notes and risks - **Port 8000 is published without TLS**, so `X-API-Key` travels in clear text. Restrict access with a firewall or put a TLS reverse proxy in front (bind the port to `127.0.0.1` by changing `ports` in `docker-compose.yml`). -- The image installs unpinned dependencies from `requirements.txt`; rebuilds may pick up newer versions. +- Dependencies are pinned (see "Dependency versions" below), so rebuilds give the same libraries. The base image `python:3.11-slim` is not pinned by digest: Python patch releases arrive on rebuild. - Files written by the services in the volume (`config.json`, `status.json`) have mode `600`; both services run as the same user. - `docker compose` uses the image name `ripe-cidr-collector`; `Dockerfile.test` is used only for running the tests (section 1, step 5). diff --git a/constraints.txt b/constraints.txt new file mode 100644 index 0000000..bf16b47 --- /dev/null +++ b/constraints.txt @@ -0,0 +1,26 @@ +annotated-doc==0.0.5 +annotated-types==0.8.0 +anyio==4.15.1 +APScheduler==3.11.3 +certifi==2026.7.22 +charset-normalizer==3.5.1 +click==8.5.0 +fastapi==0.141.1 +h11==0.16.0 +httpcore==1.0.9 +httpx==0.28.1 +idna==3.20 +iniconfig==2.3.0 +packaging==26.3 +pluggy==1.6.0 +pydantic==2.13.5 +pydantic_core==2.46.5 +Pygments==2.21.0 +pytest==9.1.1 +requests==2.34.2 +starlette==1.6.0 +typing-inspection==0.4.4 +typing_extensions==4.16.0 +tzlocal==5.4.4 +urllib3==2.8.0 +uvicorn==0.53.0 diff --git a/docs/plan-pin-dependencies.md b/docs/plan-pin-dependencies.md new file mode 100644 index 0000000..97885e4 --- /dev/null +++ b/docs/plan-pin-dependencies.md @@ -0,0 +1,25 @@ +# План: закрепление версий зависимостей (п. 1.2 рекомендаций) + +## Цель +Сборка образа и запуск тестов воспроизводимы: завтрашняя сборка использует те же версии библиотек, что и сегодняшняя (риск 2 анализа). Обновление библиотек становится осознанным действием. + +## Дизайн +- **Версии берутся из образа, на котором сейчас проходят 18 тестов** (`pip freeze` в контейнере, Python 3.11), поэтому поведение не меняется. +- `requirements.txt` и `requirements-dev.txt`: только прямые зависимости с точной версией (`==`), файлы остаются читаемыми. + - прод: `requests`, `fastapi`, `uvicorn`, `APScheduler`; + - разработка: `pytest`, `httpx`. +- `constraints.txt` (новый): полный список всех установленных пакетов, включая транзитивные (`starlette`, `pydantic`, `urllib3` и др.). Оба Dockerfile ставят пакеты с `-c constraints.txt`, поэтому закреплены и косвенные зависимости. +- Базовый образ `python:3.11-slim` не закрепляется по дайджесту (патчи безопасности Python приходят автоматически); это осознанный компромисс, указан в README. +- Порядок обновления (в README): поднять версии в контейнере, прогнать тесты, обновить `constraints.txt` из `pip freeze`, коммит. + +## Изменения +1. `requirements.txt`, `requirements-dev.txt`: точные версии. +2. `constraints.txt`: новый файл. +3. `Dockerfile`, `Dockerfile.test`: копирование `constraints.txt`, установка с `-c`. +4. `README.md`: ручная установка с `-c constraints.txt`, порядок обновления версий. +5. Тестов не добавляется (код не меняется). + +## Проверка +- Сборка обоих образов, 18 тестов проходят. +- В прод-образе `pip freeze` совпадает с закреплёнными версиями (нет лишних пакетов вроде `pytest`). +- Импорт `api_server` и `collector_daemon` в прод-образе. diff --git a/docs/summary-pin-dependencies.md b/docs/summary-pin-dependencies.md new file mode 100644 index 0000000..22640be --- /dev/null +++ b/docs/summary-pin-dependencies.md @@ -0,0 +1,20 @@ +# Итоги: закрепление версий зависимостей (п. 1.2) + +План: `docs/plan-pin-dependencies.md`. + +## Сделано +- `requirements.txt` и `requirements-dev.txt`: прямые зависимости с точными версиями. Прод: `requests==2.34.2`, `fastapi==0.141.1`, `uvicorn==0.53.0`, `APScheduler==3.11.3`. Разработка: `pytest==9.1.1`, `httpx==0.28.1`. +- `constraints.txt` (новый, 26 пакетов): полный `pip freeze` образа, на котором проходили тесты, включая транзитивные пакеты (`starlette`, `pydantic`, `urllib3` и др.). +- `Dockerfile` и `Dockerfile.test` ставят пакеты с `-c constraints.txt`. +- README: ручная установка с `-c constraints.txt`, список копируемых файлов приведён в соответствие с кодом (был неполным), раздел «Dependency versions» с порядком обновления, замечание об образе исправлено. + +## Проверка +- Оба образа собраны без кэша, 18 тестов проходят. +- Прод-образ: пакеты полностью совпадают с `constraints.txt`, `pytest` и `httpx` в нём нет; `api_server`, `collector_daemon`, `db`, `healthcheck` импортируются. +- Версии взяты из того, что уже стояло и проходило тесты, поведение не менялось. + +## Замечания +- Базовый образ `python:3.11-slim` не закреплён по дайджесту: патчи Python приходят при пересборке (осознанный компромисс). +- Закрепление даёт воспроизводимость, но не обновляет уязвимые версии само: проверку обновлений нужно делать вручную (порядок в README). +- Не проверялась сборка на другой архитектуре: часть пакетов (`pydantic_core`) содержит бинарные сборки под платформу. +- `docker compose up` не запускался повторно: образ собран тем же Dockerfile, стенд не менялся. diff --git a/requirements-dev.txt b/requirements-dev.txt index 5769ad4..7ad123c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,2 @@ -pytest -httpx +pytest==9.1.1 +httpx==0.28.1 diff --git a/requirements.txt b/requirements.txt index 0b65ed8..5978aad 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -requests -fastapi -uvicorn -APScheduler +requests==2.34.2 +fastapi==0.141.1 +uvicorn==0.53.0 +APScheduler==3.11.3