🦴

GitHub CLI を使って private repository から一つのファイルをダウンロードする

2023/01/15に公開

gh auth loginを実行して、ghコマンドに認証情報を保存した状態にして

gh api \
  -H "Accept: application/vnd.github.raw" \
  /repos/OWNER/REPO/contents/PATH > OUTPUT_FILE

のコマンドを実行すると、https://github.com/OWNER/REPO/PATHのファイルがOUTPUT_FILEに保存されます。

この方法のメリットはghコマンドの認証情報を使うので、Personal Access Tokenを使う必要が無いことです。

詳細

コマンドラインで GitHub から一つのファイルをダウンロードしたい場合、 GitHub REST API を使って取得する方法があります。

https://docs.github.com/rest/repos/contents

この API へのリクエストでAcceptヘッダーにapplication/vnd.github.rawを追加することで、ファイルの内容を Raw 形式で取得できます。(Media types

標準出力の結果をOUTPUT_FILEにリダイレクトすることで、 GitHub 上のリポジトリから一つのファイルをダウンロード出来ます。

API へのアクセス

その API の叩くやり方として、 Personal Access Token を使って curl や wget で取得するやり方があります。
これは Personal Access Token をAuthorizationヘッダーに対してBearer <YOUR-TOKEN>のように追加します。

curl \
  -H "Accept: application/vnd.github.raw" \
  -H "Authorization: Bearer <YOUR-TOKEN>"\
  https://api.github.com/repos/OWNER/REPO/contents/PATH

これの問題は Personal Access Token を使用していることです。

以前はこの方法は正しいやり方でしたが、ghコマンドが整備された今では GitHub CLI または Git Credential Manager を使用が推奨されています。

警告: アクセス トークンは、パスワードと同様の扱いとしてください。

コマンド ラインから GitHub にアクセスするには、personal access tokenを作成する代わりに GitHub CLI または Git Credential Manager を使用することを検討してください。

https://docs.github.com/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token

GitHub CLI を使用する場合、apiというサブコマンドを使うことでも同様のことができます。

https://cli.github.com/manual/gh_api

このコマンドは以下の用に使います。

gh api <endpoint> [flags]

Options は様々あるので、詳しくは公式ドキュメントを見てもらいたいのですが、実際自分が使ったものは--header--jqぐらいです。

このコマンドからリポジトリコンテンツを叩く場合、このようになります。

gh api \
  -H "Accept: application/vnd.github.raw" \
  /repos/OWNER/REPO/contents/PATH

curl を使用した方法との違いは、認証に Personal Access Token を使用していないことです。

参考

GitHub Actions での利用

GitHub Actions では${{ secrets.GITHUB_TOKEN }}を使うことで自動トークン認証を行うことができます。
しかし、このトークンが持つアクセス権限( Repository contents の read 権限)は、その GitHub Actions が実行されているリポジトリ内のみ適応されます。そのため、たとえ同じ Organization 内であっても、別のプライベートリポジトリへのアクセスすることは出来ません。

GITHUB_TOKEN で利用できないアクセス許可を必要とするトークンが必要な場合は、 personal access token を作成し、それをリポジトリのシークレットとして設定するやり方を記載しています。

https://docs.github.com/en/actions/security-guides/automatic-token-authentication#granting-additional-permissions

この記事では Personal Access Token を発行せず、プライベートリポジトリへアクセスすることが目的です。
これを達成するために GitHub Apps 経由で token を発行する方法があります。

https://zenn.dev/suzutan/articles/how-to-use-github-apps-token-in-github-actions

https://dev.classmethod.jp/articles/getting-an-access-token-with-only-the-necessary-permissions-on-github-appsgithub-actions/

詳しくは上記の参考記事を読んでもらいたいですが、これを設定すると workflow は以下のようになります。

on:
  workflow_dispatch:
jobs:
  use_api:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
	
      - name: Generate github token
        id: generate_token
        uses: tibdex/github-app-token@v1
        with:
          app_id: ${{ secrets.APP_ID }}
          private_key: ${{ secrets.PRIVATE_KEY }}

      - name: Run GitHub CLI
        run: |
          gh api repos/octocat/Spoon-Knife/issues
        env:
          GH_TOKEN: ${{ steps.generate_token.outputs.token }}

これで、自ら Personal Access Token を発行し、管理する事なく、認証情報が必要なリソースへのアクセスが出来るようになります。

ちなみに、この場合は curl を使ってもghコマンドを使っても問題ないです。
GitHub REST API のドキュメントの方には、 GitHub CLI / cURL / JavaScript のそれぞれを使用した場合のやり方が書いてあります。

注意事項

今回紹介しているやり方は、ローカルのghコマンドを実行する Makefile やシェルスクリプトなどに有効です。

Docker や CI ( GutHub Actions を除く)でのやり方は確認していないので、動作を保証出来ません。

また、「 Personal Access Token を利用する事自体が良くない」と言うような論調で書いてしまいましたが、必要に応じて使うことは全く問題ないです。ただし、ローカルでghコマンドが使えるのであれば、あえて Personal Access Token を利用する必要はないと思います。

不慮の事故を防ぐためにも、アクセストークンというものは慎重に取り扱いたいものです。詳しくは参考1を読むと良いかもです。

参考

  1. GitのHTTPS認証に個人アクセストークンを求めるのは間違っているだろうか (Git Credential Manager のすゝめ)
  2. GitHub REST API のクイックスタート

Discussion