0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

リポジトリ単位で gh CLI の GitHub アカウントを自動で切り替える(direnv × GH_TOKEN × keyring)

0
Posted at

複数のお客さんのプロジェクトを回していると、特定のorganization用にGithubアカウントを分けないといけないことがある。

今までであればChromeのプロファイル分けて作業すればよかったが、Claude Codeに作業やらせるのに Github CLI(gh) が使えないと大変困る。内容コピペ作業するのなんてだるい。
よって、direnvを使ってGH_TOKENを使ってリポジトリ(=ディレクトリ)ごとに自動で切り替えるようにした。

(多分、こんなことは皆さんご存知だと思うのですが、自分は direnv 知らなくて勉強になったので、備忘録。)

TL;DR

  • リポジトリに cd した瞬間だけ gh CLI が 別の GitHub アカウントとして動く ようにしたかった。
  • direnv + .envrcGH_TOKEN を export する構成にした。
  • ただし .envrcトークンを直書きしないgh auth token --user <name> を使い、すでに gh の keyring に入っているトークンを動的に引く。
  • 結果として 平文の secret はディスクに残らない.envrc 自体も .gitignore 対象。

やりたかったこと

普段は個人 GitHub アカウント(仮に mainuser)でログインしている gh CLI を、特定の顧客プロジェクト用リポジトリに居る間だけ、別アカウント(仮に workuser)として振る舞わせたい。

  • gh pr creategh issue listそのプロジェクト用のアカウント で発火させたい
  • git push の SSH 認証は別管理(~/.ssh/config 側で済んでいる)ので、ここでは API トークン側(gh CLI)だけ を切り替えたい
  • グローバル設定(gh auth switch)を毎回叩く運用は事故るので避けたい

前提

  • macOS(zsh)
  • Homebrew 導入済み
  • 切り替えたい両方のアカウントは、すでに gh auth login 済みで keyring に保存されている

確認:

$ gh auth status
github.com
  ✓ Logged in to github.com account mainuser (keyring)
    - Active account: true
  ✓ Logged in to github.com account workuser (keyring)
    - Active account: false

両方とも keyring に居る状態がスタート地点。

設計判断

.envrc には 3 つの選択肢 があった。

.envrc に書く内容 平文 secret の有無
A export GH_TOKEN="gho_xxxx..." をベタ書き ディスクに残る
B pass / 1Password CLI 等から取る ローカルに secret 管理ツールが要る
C gh auth token --user workuser で動的に取る keyring 任せ、追加ツール不要

gh の keyring にすでに 2 アカウント入っていたので C 案 が一番素直。gh auth token は対話なしで token をそのまま標準出力に出すので $() で受けられる。

加えて ghGH_TOKEN 環境変数があればそれを優先 する。なのでこの env を立てるだけで、gh auth switch を叩かなくてもそのシェルでは自動的に workuser 扱いになる。

手順

1. direnv を入れる

brew install direnv

2. zsh の hook を有効化

~/.zshrc の末尾に追記:

# direnv hook
eval "$(direnv hook zsh)"

source ~/.zshrc するか、ターミナルを開き直す。

3. リポジトリ直下に .envrc を作る

~/work/my-project/.envrc:

# このリポジトリでだけ gh CLI を別アカウント (workuser) で動かす。
# トークンは keyring から動的に取得するので、このファイルには平文 secret を残さない。
# `direnv allow` で承認した後、cd するたびに自動で export される。
if command -v gh >/dev/null 2>&1; then
  _token="$(gh auth token --user workuser 2>/dev/null || true)"
  if [ -n "$_token" ]; then
    export GH_TOKEN="$_token"
  fi
  unset _token
fi

ポイント:

  • gh auth token --user <name> は対話なしで keyring の token を返す
  • 失敗時(gh 未インストール / 該当ユーザーが keyring にいない)は 何も export しない。この場合は global の active account にフォールバックする
  • --user を付けないと active account のもの が返ってしまうので、明示する

4. .gitignore に追加

.envrc
.envrc.local
.direnv/

トークンを直書きしない設計でも、.envrc 自体はプロジェクト固有の前提(アカウント名)を含むので、念のためコミットさせない方が安全。チームでこの仕組みを共有したい場合は .envrc.example をテンプレートとしてコミットする運用にすると良い。

5. direnv に許可を与える

$ cd ~/work/my-project
direnv: error /Users/.../my-project/.envrc is blocked. Run `direnv allow` to approve its content
$ direnv allow
direnv: loading ~/work/my-project/.envrc

direnv allowそのファイルの内容に対する署名のような承認 で、.envrc を編集するたびに再度 allow が必要になる。野良の .envrc を勝手に読まない安全装置。

動作確認

リポジトリ内(.envrc が効いた状態):

$ gh api user -q .login
workuser

リポジトリ外(素の gh):

$ cd ~
$ gh api user -q .login
mainuser

cd ひとつで gh の API 認証が切り替わるようになった。gh pr create / gh issue create 等もそのまま正しい側のアカウントで動く。

なぜ gh auth switch ではダメだったか

gh auth switchグローバルの active account を書き換える コマンドなので、

  • リポを離れても workuser のまま残る
  • 別のターミナルにも影響する
  • 戻し忘れて main アカウントのつもりで workuser から PR が出る、という事故が起きる

direnv 経由で 環境変数として スコープさせると、ディレクトリを抜けた瞬間に GH_TOKEN が unset され、global の挙動に戻る。これがやりたかった性質。

git push の認証はどうなるか

今回触ったのは gh の API 認証(GH_TOKEN)だけgit push の認証経路は別系統で、

  • HTTPS で push → credential helper(osxkeychain 等)
  • SSH で push → ~/.ssh/config の Host エイリアス

なので、git 側のアカウント分離は別途やる必要がある(多くの人はすでに SSH config で済ませているはず)。本記事の手順で影響を受けるのは gh 系コマンドだけ、というのは大事な前提。

ハマりどころメモ

  • gh auth token--user を付け忘れる: active account のトークンが返るので、結果として何も切り替わらない。
  • .envrcdirenv allow し忘れる: ディレクトリに入っても direnv: error ... is blocked が出るだけで env はセットされない。
  • GH_TOKEN をシェルの rc ファイルに global で export している: そっちが優先されて direnv の export が打ち消されるので、もし ~/.zshrc 等に書いてあれば外す。
  • 新規ターミナルで反映されない: ~/.zshrc の hook 追記後にターミナルを再起動していないだけ。

まとめ

  • direnv × GH_TOKEN × gh auth token --user の組み合わせで、リポジトリに居る間だけ gh のアカウントを安全に切り替えられる。
  • secret は keyring 任せで、.envrc には平文トークンが残らない。
  • グローバル設定(gh auth switch)を触らないので、戻し忘れ事故が起きない。

「このリポでだけ別アカウントで API を叩きたい」のような スコープ限定の認証切り替え は同じパターンで応用できるはず(AWS プロファイル切り替えや、OPENAI_API_KEY の出し分け等)。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?