Learn (Almost) Anything
КаталогСкачать курс

Автоматизация в GitHub

Публикация npm/Maven/NuGet/PyPI/Docker artifacts, GitHub Packages, container registry, provenance, permissions и привязка публикации к tags/releases.

ruЭнциклопедия33 урока6 модулей9
GitHub actionsАвтоматизация в GitHubМодель workflowсостояние и артефактыматрицы и runtimeрелизы и environmentsПереиспользование и собственные actionsgovernance и эксплуатацияgithubactions

Packages и container images

Публикация npm/Maven/NuGet/PyPI/Docker artifacts, GitHub Packages, container registry, provenance, permissions и привязка публикации к tags/releases.

Packages и container images

Packages и container images — это часть CD, где результат сборки становится распространяемым артефактом: npm-пакетом, Maven/NuGet/PyPI-дистрибутивом, Docker/OCI image или записью в GitHub Packages. В Release automation release фиксировал «версию как событие». Здесь важнее другое: где лежит версия, кто может её скачать, какой токен имел право её опубликовать и можно ли доказать, из какого commit она собрана.

Не путайте package registry с Artifacts и reports. Artifact в Actions обычно нужен внутри workflow: передать dist/, junit-report или бинарник между jobs и сохранить результат run. Registry — это интерфейс для потребителей: npm install, mvn dependency:get, pip install, docker pull. У registry есть версии, permissions, visibility, retention/immutability-политики, metadata и иногда provenance.

flowchart TD A[CI: tests и build] --> B{Release или tag?} B -->|release: published| C[Publish jobs] B -->|push.tags v*| C C --> D[npm / Maven / NuGet / PyPI] C --> E[Container registry: ghcr.io / Docker Hub] C --> F[Provenance / attestations] D --> G[Consumers: install] E --> H[Deploy by digest] F --> H H --> I[Deployment history / rollback]
flowchart TD
  A[CI: tests и build] --> B{Release или tag?}
  B -->|release: published| C[Publish jobs]
  B -->|push.tags v*| C
  C --> D[npm / Maven / NuGet / PyPI]
  C --> E[Container registry: ghcr.io / Docker Hub]
  C --> F[Provenance / attestations]
  D --> G[Consumers: install]
  E --> H[Deploy by digest]
  F --> H
  H --> I[Deployment history / rollback]
Publish pipeline: от проверенного commit к registry, provenance и deploy по digest.

Что именно публикуется

У language packages идентичность задаёт manifest: name и version в package.json, groupId/artifactId/version в Maven, package id/version в NuGet, имя и version в Python project metadata. У container images есть два уровня имени: tag и digest. Tag вроде ghcr.io/acme/api:v1.8.0 удобен людям, но в большинстве registry это указатель, который теоретически можно передвинуть. Digest вроде @sha256:... — content-addressed ссылка на конкретный image. Для продакшен-деплоя digest надёжнее, а tag остаётся читаемой меткой.

Tag удобен как читаемая метка, а digest фиксирует конкретное содержимое image.

Типичный publish workflow привязывают к release: published, push.tags или ручному workflow_dispatch. Для библиотек часто удобен tag-trigger: v1.8.0 появился — публикуем package с версией 1.8.0. Для приложений с approval лучше release: published: человек проверил draft release, приложил notes, нажал Publish, и только после этого пошла публикация image или package. Если публикация ведёт к продакшену, используйте Environments и protection rules, concurrency из Deployment workflows и минимальные Permissions и GITHUB_TOKEN.

GitHub Packages и GITHUB_TOKEN

Для GitHub Packages главный плюс — workflow из того же репозитория обычно может публиковать через GITHUB_TOKEN, без отдельного PAT. Но права всё равно надо явно сузить:

permissions:
  contents: read
  packages: write

Для npm-пакета в GitHub Packages это выглядит так:

name: publish-gh-packages

on:
  release:
    types: [published]

jobs:
  publish:
    runs-on: ubuntu-24.04
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v4
        with:
          node-version: '22.x'
          registry-url: 'https://npm.pkg.github.com'
          scope: '@acme'
      - run: npm ci
      - run: npm test
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Если package публикуется в другой репозиторий или в registry, где GITHUB_TOKEN не подходит, нужен другой credential: npm token, NuGet API key, Maven Central/Sonatype token, PyPI trusted publisher или cloud OIDC. Это уже зона Variables, env и secrets и OIDC и секреты облаков: не кладите широкие long-lived secrets туда, где registry поддерживает короткоживущие токены.

npm, Maven, NuGet, PyPI

Для npmjs.com GitHub Docs показывает классический вариант с NPM_TOKEN, а npm поддерживает provenance через npm publish --provenance. Для provenance job должен иметь id-token: write и запускаться на GitHub-hosted runner. Если настроен npm trusted publishing, npm может генерировать provenance без publish-token в workflow; это предпочтительнее для публичных пакетов, потому что убирает долгоживущий секрет.

permissions:
  contents: read
  id-token: write

steps:
  - uses: actions/checkout@v6
  - uses: actions/setup-node@v4
    with:
      node-version: '22.x'
      registry-url: 'https://registry.npmjs.org'
  - run: npm ci
  - run: npm test
  - run: npm publish --provenance --access public
    env:
      NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Для Maven важны pom.xml, distributionManagement и settings.xml; actions/setup-java умеет подготовить Maven publishing settings. Внешний Maven Central требует отдельной настройки у Sonatype/Central Portal, поэтому не копируйте старый OSSRH workflow без проверки: часть старых примеров в документации прямо помечена как legacy. Для NuGet похожая логика: build/test, pack, затем dotnet nuget push в GitHub Packages или nuget.org с минимальным токеном.

Для PyPI сейчас сильный вариант — trusted publishing через OIDC. В PyPI задаётся доверенная связка owner/repository/workflow, опционально environment. В workflow publish job получает id-token: write, а pypa/gh-action-pypi-publish обменивает OIDC token на короткоживущий PyPI token. Пароль в YAML не передаётся.

Container images в ghcr.io

GitHub Container Registry хранит Docker и OCI images в namespace пользователя или организации. Если image публикуется из GitHub Actions через GITHUB_TOKEN, package автоматически связывается с репозиторием workflow. Для images, которые уже были вручную запушены в тот же namespace, иногда приходится отдельно связать package с репозиторием или добавить OCI label org.opencontainers.image.source.

Рабочий workflow для ghcr.io обычно делает четыре вещи: login, metadata, build/push, provenance/attestation.

name: publish-container

on:
  release:
    types: [published]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  image:
    runs-on: ubuntu-24.04
    permissions:
      contents: read
      packages: write
      attestations: write
      id-token: write
    steps:
      - uses: actions/checkout@v6

      - uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=tag
            type=semver,pattern={{version}}
            type=sha

      - id: push
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

      - uses: actions/attest@v4
        with:
          subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          subject-digest: ${{ steps.push.outputs.digest }}
          push-to-registry: true

Здесь packages: write нужен для push в GHCR, id-token: write — для provenance/attestation, attestations: write — для записи attestations. В production-репозитории сторонние actions лучше pin-ить к SHA, как описано в Marketplace actions и pinning, а floating tags (latest, main) не использовать как единственный deploy input.

Provenance и supply chain

Provenance отвечает на вопрос: «какой workflow, commit и runner собрали этот package?» Для npm это --provenance или trusted publishing. Для container images — artifact attestations, которые можно привязать к image digest. Это не магический антивирус и не гарантия, что код хороший. Это проверяемая цепочка происхождения. Она особенно полезна, когда один workflow публикует image, а другой deploy workflow принимает только digest с валидной attestation.

Хороший publish pipeline строится так: CI собрал и протестировал, release/tag зафиксировал версию, publish job получил минимальные права, registry принял package, digest/version записаны в release notes или deployment metadata. Плохой pipeline выглядит иначе: любой push в main публикует latest, секреты доступны PR-коду, package пересобирается без связи с проверенным artifact, а deploy тянет tag без digest. Такие ошибки обычно всплывают не в CI, а в момент rollback, расследования инцидента или попытки понять, что реально уехало пользователям.

ИнтерактивПрава publish job#int-1
1 / 6
Короткая шпаргалка по permissions и токенам, которые чаще всего встречаются в package publishing.

See also

Внешние справки: GitHub Docs по publishing Docker images, GitHub Container Registry, publishing Node.js packages, publishing Java packages with Maven, GITHUB_TOKEN, PyPI OIDC trusted publishing и npm Docs по provenance statements.

Быстрое повторение #rc-1

Почему package registry нельзя заменить обычным Actions artifact, если артефакт должны ставить внешние потребители?

Показать ответ

Actions artifact обычно живёт внутри workflow: передать dist/, reports или бинарник между jobs и сохранить результат run. Registry даёт потребительский интерфейс вроде npm install, pip install, mvn dependency:get, docker pull, а также версии, permissions, visibility и metadata.

Источники

  1. Publishing Docker images - GitHub Docs
  2. Working with the Container registry - GitHub Docs
  3. Publishing Node.js packages - GitHub Docs
  4. Publishing Java packages with Maven - GitHub Docs
  5. Configuring OpenID Connect in PyPI - GitHub Docs
  6. Use GITHUB_TOKEN for authentication in workflows - GitHub Docs
  7. Generating provenance statements - npm Docs