🤮

actions/checkout@v2はgitconfigを書き換える副作用がある

3 min read 2

一言で言うと

github actionsで使用するactions/checkout@v2は.git/configを書き換えるので、actions/checkout@v2を使用した後にgitコマンドを使うと思わぬ動きをすることがあるから気をつけてほしい。
あと、.dockerignore.gitを忘れないように。

追記

コメントで頂きましたが、以下のように記述することで回避できました。

- uses: actions/checkout@v2
  name: "チェックアウト"
  with:
    persist-credentials: false

何が起きたか

githubのプライベートリポジトリを依存に含んでいたため、トークンを使って依存解決していた。
以下のようなワークフローを書いていた。

# at github.com/Urotea/sample-private-app.git
name: sample
on:
  push:
    branches:
    - "*"

jobs:
  test1:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        name: "チェックアウト"
      - name: set git config
        env:
          READONLY_GITHUB_TOKEN: ${{ secrets.PAT }}
        run: git config --global url."https://${READONLY_GITHUB_TOKEN}:x-oauth-basic@github.com/Urotea".insteadOf "https://github.com/Urotea"
      - name: access remote
        # gitでリモートアクセスするサンプル
        run: git clone https://github.com/Urotea/sample-private-lib.git
  test2:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
        name: "チェックアウト"
      - name: set git config
        env:
          READONLY_GITHUB_TOKEN: ${{ secrets.PAT }}
        run: git config --global url."https://${READONLY_GITHUB_TOKEN}:x-oauth-basic@github.com/Urotea".insteadOf "https://github.com/Urotea"
      - name: access remote
        # gitでリモートアクセスするサンプル
        run: git clone https://github.com/Urotea/sample-private-lib.git

なんとtest1は落ちるが、test2は正しく動く。
原因はactions/checkout@v2が.git/configを勝手に書き換えており、私が設定したconfigより優先されて適用されているからである。
(configの優先順位はlocal > global)
actions/checkout@v1はそのようなことをやっていないっぽい。なのでtest2は通る。

「いや、ワークフロー上でgitコマンドなんか使わないよ。」と思うかもしれないが、もう一段罠がある。
docker buildをする場合である。次にこちらを説明する。

github actionsでdocker buildするときの注意

上記の発展形としてactions/checkout@v2のせいでdocker buildが失敗することがある。
以下の例はgithubプライベートリポジトリを依存に含んだjsアプリをdockerビルドする場合である。

workflow.yaml
# at github.com/Urotea/sample-private-app.git
name: sample
on:
  push:
    branches:
    - "*"

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        name: "チェックアウト"
      - name: build docker
        env:
          READONLY_GITHUB_TOKEN: ${{ secrets.PAT }}
        run: docker build --build-arg TOKEN=$READONLY_GITHUB_TOKEN -t test:latest .
Dockerfile
FROM node:14
ARG TOKEN
WORKDIR /src
COPY . .
RUN git config --global url."https://${TOKEN}:x-oauth-basic@github.com/Urotea".insteadOf "https://github.com/Urotea"
RUN yarn install --frozen-lockfile # ここで落ちる
package.json
{
  "dependencies": {
    "sample-private-lib": "git+https://github.com/Urotea/sample-private-lib.git#v0.0.1",
    },
    // 以下略
}

なぜビルドがこけるのか。

  1. actions/checkout@v2.git/configを書き換える
  2. docker build時にCOPY . .によって.git/*がdocker内にコピーされる
  3. yarn install --frozen-lockfileを実行したときに、裏でgitが叩かれるが、.git/configを読み込んでしまい失敗する

適切に.dockerignoreを設定しないとactions/checkout@v2が勝手に書き換えた.git/configをdocker内に持ち込んでしまい、そのままビルドがこける。
そもそもCOPY . .で全部持っていっているのが良くない?それはそう...
でも開発時にはみんなやるでしょ?

最後に

.dockerignoreを軽視してはいけない。また、COPY . .みたいに全部持っていかず適切に持っていくものを選ぶこと。
同じgithubトークン使ってて、ローカルではdockerビルドが通るのにactionsのワークフローでは落ちる現象に悩まされて半日潰してしまった...
というか、actions/checkout@v2も副作用がある動きをするのはやめてほしい。実行し終わったらconfig戻しておいてくれないかなー
ある意味プルリクチャンスかも。