Устаревшие зависимости — одна из причин инцидентов информационной безопасности. При этом это рутинная задача, которую можно сильно упростить для Python проекта.

В статье прочитаешь, как можно настроить автоматическое обновление зависимостей в Github с помощью Dependabot и GitHub Actions.

Примечание: как и любое автоматическое действие, обновление требует контроля

Как узнать, какие обновления вышли

В Github есть Dependabot, который автоматически отслеживает новые версии всех зависимостей в твоем проекте, включая security updates и bug fixes. Чтобы настроить его, воспользуйся инструкцией.

Dependabot работает автоматически, если используешь uv/poetry/requirements.txt

В итоге ты будешь получать Pull Requests с изменениями, которые можно протестировать перед слиянием.

Чтобы регулярно получать PR, создай файл .github/dependabot.yml в репозитории:

version: 2
updates:
  - package-ecosystem: 'pip'  # одинаково для uv/poetry/requirements.txt
    target-branch: "develop"  # git ветка, в которую будет создавать PR
    directory: '/'  # где искать твой файл poetry.lock или requirements.txt
    schedule:
      interval: 'daily'  # проверять обновления раз в день

Как ты зафиксируешь минорную версию/major версию для библиотеки, так и dependabot это учтет

Как проверить обновление

Перед тем как вливать код куда-то, надо его проверить. Проще это делать через тесты. Даже если у тебя их нет — напиши самый простой hello world тест, это уже будет хорошо.

Для прогона тестов создай workflow .github/workflows/dependabot-apply.yml:

name: Test requirement (dependabot)

on:
  pull_request:
    branches: [ "develop", "dependabot/*" ]

jobs:
  test:
    runs-on: ubuntu-24.04
    if: github.actor == 'dependabot[bot]'
    steps:
      - name: Checkout code
        uses: actions/checkout@v5
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.13' # у тебя может быть другая версия

      # Здесь пример для poetry, но может у тебя другой менеджер
      - name: Install Poetry
        uses: snok/install-poetry@v1

      - name: Install dependencies
        run: poetry install --no-interaction

      # Запуск тестов. У тебя могут по-другому запускаться тесты
      - name: Run tests
        run: poetry run pytest

Как смержить обновление

Когда тесты пройдены, можно смержить изменение.

  dependabot_merge:
    runs-on: ubuntu-24.04
    if: github.actor == 'dependabot[bot]'
    needs: [dependabot_test]
    steps:
      - name: Dependabot metadata
        id: metadata
        uses: dependabot/fetch-metadata@v2
        with:
          github-token: "${{ secrets.GITHUB_TOKEN }}"
      - name: Approve a PR
        run: gh pr review --approve "$PR_URL"
        env:
          PR_URL: ${{github.event.pull_request.html_url}}
          GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
      - name: Enable auto-merge for Dependabot PRs
        run: gh pr merge --auto --merge "$PR_URL"
        env:
          PR_URL: ${{github.event.pull_request.html_url}}
          GH_TOKEN: ${{secrets.GITHUB_TOKEN}}

Этот код автоматически заапрувит PR, затем смержит его в код.

Итоговый workflow

Итоговый файл для github будет такой. Здесь запускаются тесты в Django приложении, а потом смерживается код.

name: Test requirement (dependabot)

env:
  DOCKER_BUILDKIT: 1
  COMPOSE_DOCKER_CLI_BUILD: 1

on:
  pull_request:
    branches: [ "develop", "dependabot/*" ]

permissions:
  contents: write
  pull-requests: write

jobs:
  dependabot_test:
    name: Test
    runs-on: ubuntu-24.04
    if: github.actor == 'dependabot[bot]'
    services:
      redis:
        image: redis:6
        ports:
          - 6379:6379
      postgres:
        image: postgres:16
        ports:
          - 5432:5432
        env:
          POSTGRES_PASSWORD: postgres
    env:
      REDIS_URL: 'redis://localhost:6379/0'
      CELERY_BROKER_URL: 'redis://localhost:6379/0'
      CELERY_RESULT_BACKEND: 'redis://localhost:6379/1'
      DATABASE_URL: 'postgres://postgres:postgres@localhost:5432/postgres'

    steps:
      #----------------------------------------------
      #       check-out repo and set-up python
      #----------------------------------------------
      - name: Check out repository
        uses: actions/checkout@v5
      - name: Set up python
        id: setup-python
        uses: actions/setup-python@v5
        with:
          python-version: '3.13'
      #----------------------------------------------
      #  -----  install & configure poetry  -----
      #----------------------------------------------
      - name: Install Poetry
        uses: snok/install-poetry@v1
        with:
          virtualenvs-create: true
          virtualenvs-in-project: true
          installer-parallel: true

      #----------------------------------------------
      #       load cached venv if cache exists
      #----------------------------------------------
      - name: Load cached venv
        id: cached-poetry-dependencies
        uses: actions/cache@v4
        with:
          path: .venv
          key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}
      #----------------------------------------------
      # install dependencies if cache does not exist
      #----------------------------------------------
      - name: Install dependencies
        if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
        run: |
          poetry install --no-interaction --no-root

      #----------------------------------------------
      # install your root project, if required
      #----------------------------------------------
      - name: Install project
        run: poetry install --no-interaction
      #----------------------------------------------
      #              run test suite
      #----------------------------------------------
      - name: Run tests
        run: |
          source .venv/bin/activate
          pytest

  dependabot_merge:
    runs-on: ubuntu-24.04
    if: github.actor == 'dependabot[bot]'
    needs: [dependabot_test]
    steps:
      - name: Dependabot metadata
        id: metadata
        uses: dependabot/fetch-metadata@v2
        with:
          github-token: "${{ secrets.GITHUB_TOKEN }}"
      - name: Approve a PR
        run: gh pr review --approve "$PR_URL"
        env:
          PR_URL: ${{github.event.pull_request.html_url}}
          GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
      - name: Enable auto-merge for Dependabot PRs
        run: gh pr merge --auto --merge "$PR_URL"
        env:
          PR_URL: ${{github.event.pull_request.html_url}}
          GH_TOKEN: ${{secrets.GITHUB_TOKEN}}

FAQ

Как часто стоит обновлять зависимости?

Dependabot имеет достаточно хорошие лимиты на свою работу, поэтому проверяй наличие обновлений раз в день-неделю.

Этого достаточно, чтобы получать security updates вовремя.

Что делать, если обновление сломало тесты?

Dependabot находит зависимость и создает PR, но он не знает, что именно в библиотеке обновилось. Если тест не пройдет, ты сможешь разобраться с проблемой совместимости, возможно, добавить миграционный код или обновить тесты.

Можно ли автоматически обновлять major версии?

Технически да, но не рекомендуется. Major версии часто содержат breaking changes. Лучше настраивать ручное ревью для таких обновлений.