目次

pub.devへのパッケージの自動公開

自動公開は以下から行うことができます。

以降のセクションでは、自動公開の設定方法と、好みに合わせて公開フローをカスタマイズする方法について説明します。

自動公開を設定する場合、自動デプロイ環境にコピーされる長期間有効なシークレットを作成する必要はありません。代わりに、認証は、GitHub Actions(GitHub ActionsのOIDCを参照)またはGoogle Cloud IAMによって署名された一時的なOpenID Connectトークンに依存します。

アイデンティティサービスが存在しないデプロイメント環境には、エクスポートされたサービスアカウントキーを使用できます。このようなエクスポートされたサービスアカウントキーは長期間有効なシークレットであり、一部の環境では使いやすいかもしれませんが、誤って漏洩した場合のリスクも大きくなります。

GitHub Actionsを使用したパッケージの公開

#

GitHub Actionsを使用して自動公開を設定できます。これには以下が含まれます。

  • pub.devで自動公開を有効化し、以下を指定します。

    • GitHubリポジトリと
    • 公開を許可するためのタグパターン(`{{version}}`を含む文字列)。
  • pub.devへの公開のためのGitHub Actionsのワークフローを作成します。

  • 公開するバージョンのgitタグをプッシュします。

以降のセクションでは、これらの手順を完了する方法について概説します。

pub.devでのGitHub Actionsからの自動公開の設定

#

GitHub Actionsから`pub.dev`への自動公開を有効にするには、以下が必要です。

  • パッケージのアップローダーであるか、
  • パブリッシャーの管理者である(パッケージがパブリッシャーによって所有されている場合)。

十分な権限がある場合、以下のようにして自動公開を有効にできます。

  1. 管理タブ(`pub.dev/packages//admin`)に移動します。

  2. 自動公開セクションを探します。

  3. GitHub Actionsからの公開を有効にするをクリックすると、以下を指定するように求められます。

    • リポジトリ(`/`、例:`dart-lang/pana`)、
    • タグパターン(`{{version}}`を含む文字列)。

リポジトリはGitHub上の`/`です。たとえば、リポジトリが`https://github.com/dart-lang/pana`の場合、リポジトリフィールドに`dart-lang/pana`を指定する必要があります。

タグパターンは`{{version}}`を含む文字列です。このタグパターンに一致するタグのプッシュによってトリガーされたGitHub Actionsのみが、パッケージの公開を許可されます。

Configuration of publishing from GitHub Actions on pub.dev

例:`v{{version}}`のようなタグパターンは、GitHub Actions(`git tag v1.2.3 && git push v1.2.3`によってトリガーされる)がパッケージのバージョン`1.2.3`を公開することを許可します。そのため、`pubspec.yaml`の`version`キーがこのバージョン番号と一致することも重要です。

リポジトリに複数のパッケージが含まれている場合は、それぞれに別々のタグパターンを指定します。`my_package_name`という名前のパッケージには、`my_package_name-v{{version}}`のようなタグパターンを使用することを検討してください。

pub.devへの公開のためのGitHub Actionsワークフローの設定

#

GitHub Actionsからの自動公開がpub.devで有効になっている場合、公開のためのGitHub Actionsワークフローを作成できます。これは、以下のように` .github/workflows/publish.yml`ファイルを作成することで行います。

yaml
# .github/workflows/publish.yml
name: Publish to pub.dev

on:
  push:
    tags:
    # must align with the tag-pattern configured on pub.dev, often just replace
      # {{version}} with [0-9]+.[0-9]+.[0-9]+
    - 'v[0-9]+.[0-9]+.[0-9]+' # tag-pattern on pub.dev: 'v{{version}}'
    # If you prefer tags like '1.2.3', without the 'v' prefix, then use:
    # - '[0-9]+.[0-9]+.[0-9]+' # tag-pattern on pub.dev: '{{version}}'
    # If your repository contains multiple packages consider a pattern like:
    # - 'my_package_name-v[0-9]+.[0-9]+.[0-9]+'

# Publish using the reusable workflow from dart-lang.
jobs:
  publish:
    permissions:
      id-token: write # Required for authentication using OIDC
    uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1
    # with:
    #   working-directory: path/to/package/within/repository

`on.push.tags`のパターンをpub.devで指定されたタグパターンと一致させるようにしてください。一致しないと、GitHub Actionsワークフローは機能しません。同じリポジトリから複数のパッケージを公開する場合は、`my_package_name-v{{version}}`のようなパッケージごとのタグパターンを使用し、各パッケージに個別のワークフローファイルを作成してください。

上記のワークフローファイルは、パッケージを公開するために`dart-lang/setup-dart/.github/workflows/publish.yml`を使用しています。これは、Dartチームが公開ロジックを維持し、pub.devがパッケージの公開方法を認識できるようにする再利用可能なワークフローです。この再利用可能なワークフローの使用を強くお勧めします。

パッケージに生成されたコードが必要な場合は、この生成されたコードをリポジトリにチェックインすることをお勧めします。これにより、pub.devに公開されたファイルがリポジトリのファイルと一致することを検証することが容易になります。生成されたアーティファクトまたはビルド済みアーティファクトをリポジトリにチェックインすることが妥当でない場合は、以下のようなカスタムワークフローを作成できます。

yaml
# .github/workflows/publish.yml
name: Publish to pub.dev

on:
  push:
    tags:
    - 'v[0-9]+.[0-9]+.[0-9]+' # tag pattern on pub.dev: 'v{{version}'

# Publish using custom workflow
jobs:
  publish:
    permissions:
      id-token: write # Required for authentication using OIDC
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: dart-lang/setup-dart@v1
      - name: Install dependencies
        run: dart pub get
      # Here you can insert custom steps you need
      # - run: dart tool/generate-code.dart
      - name: Publish
        run: dart pub publish --force

このワークフローは、一時的なGitHub署名付きOIDCトークンを使用して`pub.dev`を認証し、トークンは`dart-lang/setup-dart`ステップで作成および設定されます。pub.devに公開するには、後続のステップで`dart pub publish --force`を実行できます。

GitHub Actionsからの自動公開のトリガー

#

`pub.dev`で自動公開を設定し、GitHub Actionsワークフローを作成したら、パッケージの新しいバージョンを公開できます。公開するには、設定されたタグパターンに一致するgitタグをプッシュします。

$ cat pubspec.yaml
yaml
package: my_package_name
version: 1.2.3            # must match the version number used in the git tag
environment:
  sdk: ^2.19.0
$ git tag v1.2.3          # assuming my tag pattern is: 'v{{version}}'
$ git push origin v1.2.3  # triggers the action that publishes my package.

プッシュ後、`https://github.com///actions`でワークフローログを確認してください。

アクションがトリガーされなかった場合は、`.github/workflows/publish.yml`で設定されたパターンがプッシュされたgitタグと一致していることを確認してください。アクションが失敗した場合は、ログに失敗した理由のヒントが含まれている可能性があります。

公開後、pub.devaudit-logで公開イベントを確認できます。audit-logのエントリには、パッケージバージョンの公開を行ったGitHub Actions実行へのリンクが含まれています。

Audit log after publishing from GitHub Actions

タグの作成にgit CLIを使用しない場合は、https://github.com/<organization>/<repository>/releases/newからGitHubでリリースを作成できます。詳細については、GitHubのリポジトリでのリリースの管理をご覧ください。

GitHubでのタグ保護規則によるセキュリティ強化

#

GitHub Actionsからの自動公開を設定すると、リポジトリにタグをプッシュできるユーザーは誰でもpub.devへの公開をトリガーできます。GitHubのタグ保護ルールを使用して、タグをプッシュできるユーザーを制限できます。

タグパターンに一致するタグの作成者を制限することで、パッケージを公開できるユーザーを制限できます。

現時点では、タグ保護ルールの柔軟性に欠けています。次のセクションで説明するように、GitHubデプロイメント環境を使用して、公開をトリガーできるユーザーを制限することを検討してください。

GitHub Deployment Environmentsによるセキュリティ強化

#

pub.devでGitHub Actionsからの自動公開を設定する際、GitHub Actions環境を要求できます。公開にGitHub Actions環境を要求するには、次の手順を実行する必要があります。

  1. 管理タブ(pub.dev/packages/<package>/admin)に移動します。
  2. 自動公開セクションを探します。
  3. GitHub Actions環境を要求をクリックします。
  4. 環境名(pub.devが通常は適切な名前です)を指定します。

Configure pub.dev to require a GitHub deployment environment

pub.devで環境が要求されている場合、GitHub Actionsはenvironment: pub.devがない限り公開できません。そのため、次の手順を実行する必要があります。

  1. GitHubで同じ名前の環境(通常はpub.dev)を作成します。
  2. .github/workflows/publish.ymlワークフローファイルを次のように変更して、environment: pub.devを指定します。
yaml
# .github/workflows/publish.yml
name: Publish to pub.dev

on:
  push:
    tags:
    - 'v[0-9]+.[0-9]+.[0-9]+' # for tags like: 'v1.2.3'

jobs:
  publish:
    permissions:
      id-token: write # Required for authentication using OIDC
    uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1
    with:
      # Specify the github actions deployment environment
      environment: pub.dev
      # working-directory: path/to/package/within/repository

環境は、pub.devでの認証に使用される一時的なGitHub署名付きOIDCトークンに反映されます。そのため、リポジトリへのプッシュ権限を持つユーザーは、ワークフローファイルを変更して環境保護ルールを回避することはできません。

GitHubリポジトリの設定では、環境保護ルールを使用して必須レビュアーを設定できます。このオプションを設定すると、必須レビュアーのいずれかが実行を承認するまで、その環境を使用するアクションの実行がGitHubによって阻止されます。

GitHub Action waiting for deployment review

Google Cloud Buildからの公開

#

Google Cloud Buildから自動公開を設定できます。これには、次の手順が必要です。

  • Google Cloudプロジェクトを登録する(または既存のプロジェクトを使用する)、
  • pub.devへの公開のためのサービスアカウントを作成する、
  • pub.devのパッケージの管理タブで自動公開を有効にし、公開のために作成したサービスアカウントのメールアドレスを指定する、
  • デフォルトのCloud Buildサービスアカウントに、作成した公開用サービスアカウントのなりすまし権限を付与する、
  • 一時的なOIDC id_tokenを取得してpub.devへの公開に使用するcloudbuild.yamlファイルを作成する、
  • Google Cloud Buildのプロジェクトでcloudbuild.yamlの手順を実行するためのCloud Buildトリガーを作成する、

以降のセクションでは、これらの手順を完了する方法について概説します。

公開のためのサービスアカウントの作成

#

pub.devへの公開には、pub.devでパッケージを公開する権限が付与されたサービスアカウントを作成します。その後、Cloud Buildにこのサービスアカウントになりすます権限を付与します。

  1. 既存のプロジェクトがない場合は、クラウドプロジェクトを作成します

  2. サービスアカウントを次のように作成します。

    $ gcloud iam service-accounts create pub-dev \
      --description='Service account to be impersonated when publishing to pub.dev' \
      --display-name='pub-dev'

    これにより、pub-dev@$PROJECT_ID.iam.gserviceaccount.comという名前のサービスアカウントが作成されます。

  3. サービスアカウントにパッケージを公開する権限を付与します。

    この手順を完了するには、パッケージに対するアップローダー権限を持っているか、パッケージを所有するパブリッシャーの管理者である必要があります。

    a. 管理タブ(pub.dev/packages/<package>/admin)に移動します。 a. Google Cloudサービスアカウントを使用して公開を有効にするをクリックします。 a. 前の手順で作成したサービスアカウントのメールアドレスをサービスアカウントメールアドレスフィールドに入力します。pub-dev@$PROJECT_ID.iam.gserviceaccount.comです。

Configuration that allows service account to publish on pub.dev

この手順が完了すると、サービスアカウントになりすませることができるユーザーは誰でも、パッケージの新しいバージョンを公開できます。サービスアカウントになりすますことができるユーザーを確認し、必要に応じてクラウドプロジェクトの権限を変更してください。

Cloud Buildへの公開権限の付与

#

Cloud Buildから公開するには、デフォルトのCloud Buildサービスアカウントに、前のセクションで作成した公開用サービスアカウントになりすます権限を付与する必要があります。

  1. クラウドプロジェクトでIAMサービスアカウント資格情報APIを有効にします。このAPIがないと、サービスアカウントになりすまそうとする試みは失敗します。

    # Enable IAM Service Account Credentials API
    $ gcloud services enable iamcredentials.googleapis.com
  2. プロジェクト番号を見つけます。

    # The PROJECT_NUMBER can be obtained as follows:
    $ gcloud projects describe $PROJECT_ID --format='value(projectNumber)'
  3. 公開用サービスアカウントになりすます権限を付与します。

    # Grant default cloud
    $ gcloud iam service-accounts add-iam-policy-binding \
      pub-dev@$PROJECT_ID.iam.gserviceaccount.com \
      --member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
      --role=roles/iam.serviceAccountTokenCreator

Cloud Build設定ファイルの作成

#

Cloud Buildから公開するには、Cloud Buildが次の手順を実行するように指定する必要があります。

  • サービスアカウントになりすまして一時的なOIDCトークンを取得する。
  • 公開時に使用する一時的なOIDCトークンをdart pubに提供する。
  • dart pub publishを呼び出してパッケージを公開する。

Google Cloud Buildの手順はcloudbuild.yamlファイルに記載されています。形式の詳細については、ビルド構成ファイルスキーマを参照してください。

Google Cloud Buildからpub.devに公開するには、次のcloudbuild.yamlファイルを使用します。

yaml
# cloudbuild.yaml
steps:
- id: Create temporary token
  name: gcr.io/cloud-builders/gcloud
  volumes:
  - name: temporary-secrets
    path: /secrets
  script: |
    gcloud auth print-identity-token \
      --impersonate-service-account=pub-dev@$PROJECT_ID.iam.gserviceaccount.com \
      --audiences=https://pub.dev \
      --include-email > /secrets/temporary-pub-token.txt
  env:
  - PROJECT_ID=$PROJECT_ID
- id: Publish to pub.dev
  name: dart
  volumes:
  - name: temporary-secrets
    path: /secrets
  script: | 
    cat /secrets/temporary-pub-token.txt | dart pub token add https://pub.dev
    dart pub publish --force

gcloud auth print-identity-tokenは、指定されたサービスアカウントになりすましたOIDC id_tokenを作成します。このid_tokenはGoogleによって署名され、1時間以内に期限切れになる署名が付加されています。audiencesパラメーターにより、pub.devはトークンの意図された受信者であることを認識します。--include-emailオプションは、pub.devがサービスアカウントを認識するために必要です。

id_tokenが作成されると、ボリュームにあるファイルに書き込まれます。このメカニズムは、手順間でデータを渡すために使用されます。トークンを/workspaceに保存しないでください。/workspaceは、公開するリポジトリがチェックアウトされる場所です。/workspace以外の場所にトークンを保存することで、公開時に誤ってパッケージに含めてしまうリスクを軽減できます。

Cloud Buildトリガーの作成

#

サービスアカウントが構成され、リポジトリにcloudbuild.yamlファイルがあると、console.cloud.google.comダッシュボードを使用してCloud Buildトリガーを作成できます。ビルドトリガーを作成するには、ソースリポジトリに接続し、どのイベントでビルドをトリガーするかを指定する必要があります。GitHubCloud Source Repository、またはその他のオプションを使用できます。Cloud Buildトリガーの構成方法については、ビルドトリガーの作成と管理をご覧ください。

前の手順のcloudbuild.yamlを使用するには、リポジトリの/cloudbuild.yamlファイルにある「Cloud Build構成」としてCloud Buildトリガーの種類を設定します。ビルドをトリガーするサービスアカウント指定しないでください。代わりに、Cloud Buildのデフォルトのサービスアカウントを使用します。

Configuration for trigger

Cloud Buildトリガーを設定する際には、ビルドをトリガーできるユーザーを検討してください。ビルドをトリガーすると、パッケージの新しいバージョンが公開される可能性があるためです。手動ビルドのみを許可するか、次のセクションで説明されているように、Cloud Build承認を使用してビルドをゲートすることを検討してください。

Cloud Build承認によるセキュリティ強化

#

Cloud Buildトリガーを設定する際に、ビルド実行前に承認を要求するを選択できます。Cloud Buildトリガーで承認が要求されている場合、トリガーされたときに実行されません。代わりに、承認を待ちます。これは、パッケージの新しいバージョンを公開できるユーザーを制限するために使用できます。

Enabling approvals in configuration of the Cloud Build trigger

Cloud Build承認者ロールを持つユーザーのみが承認を与えることができます。承認を与える際に、承認者はURLとコメントを指定できます。

Cloud Build run waiting for approval to run

保留中の承認に関する通知も設定できます。詳細については、承認時にビルドをゲートするをご覧ください。

サービスアカウントを使用してどこからでも公開

#

GitHub Actions以外で自動公開を許可するには、Cloud Buildと同様の方法でサービスアカウントを使用して認証を行う場合があります。

通常、これには次の手順が含まれます。

Cloud Buildのセクションでは、公開用のサービスアカウントの作成方法について説明しています。これにより、pub-dev@$PROJECT_ID.iam.gserviceaccount.comなどのサービスアカウントが提供されます。

Workload Identity Federationを使用した公開

#

OIDCまたはSAMLをサポートするクラウドサービスで実行する場合は、ワークロードIDフェデレーションを使用してGCPサービスアカウントになりすますことができます。これにより、クラウドプロバイダーのIDサービスを活用できます。

例えば、EC2にデプロイする場合は、AWSとのワークロードIDフェデレーションを設定できます。これにより、EC2メタデータサービスからの一時的なAWSトークンを使用してサービスアカウントを偽装できます。これらのフローの設定方法については、ワークロードIDフェデレーションをご覧ください。

エクスポートされたサービスアカウントキーを使用した公開

#

IDサービスのないカスタムシステムで実行する場合は、サービスアカウントキーをエクスポートできます。エクスポートされたサービスアカウントキーを使用すると、そのサービスアカウントとして認証できます。詳細については、サービスアカウントキーの作成と管理方法をご覧ください。

サービスアカウントキーのエクスポート

#
  1. 既存のサービスアカウントに対してエクスポートされたサービスアカウントキーを作成します。

    $ gcloud iam service-accounts keys create key-file.json \
      --iam-account=pub-dev@$PROJECT_ID.iam.gserviceaccount.com
  2. key-file.jsonファイルを後で使用するように保存します。

エクスポートされたサービスアカウントキーを使用したパッケージの公開

#

エクスポートされたサービスアカウントキーを使用してパッケージを公開するには

  1. key-file.json(前の手順で作成)を使用して認証するようにgcloudを設定します。

    $ gcloud auth activate-service-account --key-file=key-file.json
  2. pub.devの一時トークンを作成し、dart pub token add https://pub.devに渡します。サービスアカウントを偽装するには、--include-emailオプションを含めます。

    $ gcloud auth print-identity-token \
      --audiences=https://pub.dev \
      | dart pub token add https://pub.dev
  3. 一時トークンを使用して公開します。yes/noプロンプトをスキップするには、--forceオプションを追加します。

    $ dart pub publish --force