RAKSUL TechBlog

ラクスルグループのエンジニアが技術トピックを発信するブログです

シェル起動時にGitHub CLIでPATを生成して開発を効率化!

こんにちは!ラクスル事業本部でエンジニアをやっています、灰原です!

皆さんは普段の開発でGitHubのPersonal Access Token (PAT) を使うことはありますか? ラクスルではいくつかの社内パッケージをGitHub Packagesで管理しており、それらのインストールのためにPATが使われています。 例えばRubyのgemであればbundle configコマンドでPATを指定したり、npmパッケージであれば.npmrcファイルにPATを書いたりします。この対応自体はGitHub Packagesのドキュメントにも書かれているものですが、言わずもがなPATの扱いには注意が必要です。不必要な権限 (scope) を付与しない、有効期限を設定するなど基本的な対策を取るべきでしょう。

しかしPATの有効期限が切れるたびに、GitHubの画面から適切なscopeと有効期限を指定したPATを再生成して、bundlerやnpmなどそれぞれの設定をやり直すという、この一連の作業はそれなりに面倒なものです。

この記事では、そんな面倒な作業をGitHub CLIとちょっとしたスクリプトで効率化する方法について紹介します。

GitHub CLIでPATを取得

まずはPATの作成作業の効率化です。これには GitHub CLI を使います。コマンドラインからプルリクエストを作ったりラベルを付けたりできて便利なGitHub CLIですが、実はGitHubのPATを取得することもできます。

まずは gh auth login コマンドで認証情報を獲得します。これを実行するとワンタイムパスワードが表示され、それをブラウザで開いたGitHubの画面に入力すると、認証が完了します。その後、gh auth token コマンドを実行すると、先の認証時に取得したPATが表示されます。

$ gh auth login # ログイン
$ gh auth token # PAT取得

gh auth token で取得したPATを使って、curlでGitHub APIにアクセスしてみます。

$ curl --request GET \
       --url "https://api.github.com/octocat" \
       --header "Authorization: Bearer $(gh auth token)"

curlでGitHub APIにアクセスする

無事にOctocatが表示されました。

(上記の例では検証のためにcurlを使っていますが、GitHub CLIにはGitHub APIにアクセスする機能があります。)

追加のscopeを設定する

ところでGitHubのPATはscopeが設定されています。 gh auth statusコマンドを使えば、GitHub CLIが提供するPATのscopeを確認することができます。 単にgh auth loginした後の状態のscopeは、admin:public_key / gist / read:org / repo となっていました。

gh auth status

しかしGitHub Packagesからパッケージをインストールする際には、read:packages scopeが必要です。 このような追加のscopeを設定するには、gh auth login コマンドの -s ( --scopes ) オプションを使います。

例えば下記のように、read:packages scopeを追加で要求することができます。

$ gh auth login -s 'read:packages' 

gh auth status コマンドで確認してみると、確かに read:packages scopeが追加されていることがわかります。

gh auth status (read:packages scope付きでログインした後)

これでGitHub Packagesも扱えるようになりました。

envsubstで設定ファイルにPATを埋め込む

envsubstというコマンドを使うと、テンプレートエンジンのように環境変数をテキストに埋め込むことができます。

In normal operation mode, standard input is copied to standard output, with references to environment variables of the form $VARIABLE or ${VARIABLE} being replaced with the corresponding values.

envsubst Invocation (GNU gettext utilities)

これを使うと、gh auth tokenで生成したPATを簡単に設定ファイルに埋め込むことができます。 例えば、.npmrc.templateとして以下のようなファイルを用意しておきます。

@NAMESPACE:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GH_TOKEN}

そのうえで、次のワンライナーを実行すると、PATを含んだ .npmrc ファイルが生成されます。

$ cat .npmrc.template | GH_TOKEN=$(gh auth token) envsubst > .npmrc

このようなテンプレートファイルと、envsubstを実行するMakefileなどをレポジトリごとに用意するのも1つのアプローチでしょう。

シェル起動時にまとめて設定する

もう1つのアプローチとして、bundlerの設定したり、ホームディレクトリ直下に.npmrcを置いたりするシェルスクリプトを作り、それをシェル起動時に読み込ませる方法もあります。

例えば以下のようのシェルスクリプトです。

#!/bin/bash

set -eu

function login() {
    if gh auth status; [ $? -ne 0 ] ; then
        gh auth login -s 'read:packages'
    fi
}

function substitute() {
    token=$1
    template=$2
    file=$(echo ${template} | sed -e "s/\.template$//")

    cat ${template} | GH_TOKEN=${token} envsubst > ${file}
    echo substitute: ${file}
}

function main() {
    login
    token=$(gh auth token)

    # bundle
    bundle config --global https://rubygems.pkg.github.com/raksul w-haibara:$(gh auth token) 

    # npm
    substitute ${token} ~/.npmrc.template
}

main

おわりに

GitHub CLIを使ってPATを生成し、それを各種設定ファイルに埋め込む方法を紹介しました。 小さなところから日常の手間を減らしていきたいものですね。