【EAS】Expoプロジェクトのビルド時にGitHubのプライベートリポジトリにあるnpmパッケージをインストールする

## はじめに

この記事はタイトルにもある通り、ExpoプロジェクトをEASでビルドする際に遭遇したエラーとその解決方法についての忘備録となります。

## EASとは？

EASとは**Expo Application Service**の略であり、Expoプロジェクトの開発、ビルド、配布等のサポートをするクラウドツールです。

## 概要

今回、プロジェクト内でGitHubのプライベートリポジトリに配置された自作のnpmパッケージを使用しており、ビルド時の`npm install`でGitHubにSSH接続をする必要がありました。

以下はそのための手順となります。

### 1. Ed25519方式などで秘密鍵を作成

DSA方式は2021年にGitHubでのサポートを打ち切られているので注意してください。

```sh
$ ssh-keygen -t ed25519 -f eas_id
```

### 2. 生成された秘密鍵`eas_id`をBase64文字列にエンコード

```sh
$ cat eas_id | base64
```

### 3. EASのSecretに`DEPLOY_KEY`という名前でエンコードされた秘密鍵を登録

EASのコンソール上でも可能ですが、以下のようにターミナルからも登録できます。

```sh
$ eas secret:create --scope project --name DEPLOY_KEY --value {secretvalue} --type string
```

### 4. GithubのSSH and GPG keysから公開鍵を登録

登録方法がわからない人はこの辺を参照してください。

https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account#adding-a-new-ssh-key-to-your-account

### 5. `package.json`上でpre installスクリプトを指定

package.jsonのscripts内に`"eas-build-pre-install": "./pre-install"`を追記する。

```sh
touch pre-install
```

```json:package.json
"scripts": {
  "start": "expo start --dev-client",
  "android": "expo run:android",
  "ios": "expo run:ios",
  "web": "expo start --web",
  "eas-build-pre-install": "./pre-install"
}
```

これによって、EASでのビルド時、`npm install`が走る前に`pre-install`ファイル内のシェルスクリプトが実行されるようになります。

### 5. `pre-install`ファイルにスクリプトを記載

```sh
#!/bin/bash

eval "$(ssh-agent -s)"
ssh-add <(echo "$DEPLOY_KEY" | base64 -d)
touch ~/.ssh/config
echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
```

## 発生したエラーと解決策

### 1. `Permissions 0660 for '/dev/fd/63' are too open.`

```sh
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0660 for '/dev/fd/63' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
```

`dev/fd/63`はFD（ファイルディスクリプタ）といって、プロセス置換のパイプ出力をパスで扱うことのできるインターフェースになっています。なぜかこのFDがPermission 0660（crw-rw----）になってしまうみたいなので、一度ファイルに書き出してから権限変更をすることにしました。

修正後のスクリプト↓

```sh
#!/bin/bash

eval "$(ssh-agent -s)"
echo "$DEPLOY_KEY" | base64 -d > ~/.ssh/eas_id
chmod 0600 ~/.ssh/eas_id
ssh-add ~/.ssh/eas_id
touch ~/.ssh/config
echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
```

### 2. `git@github.com: Permission denied (publickey).`

本題はこちらです。

```sh
npm ERR! code 128
npm ERR! An unknown git error occurred
npm ERR! command git --no-replace-objects ls-remote ssh://git@github.com/{organization-name}/{repository-name}.git
npm ERR! git@github.com: Permission denied (publickey).
npm ERR! fatal: Could not read from remote repository.
npm ERR! 
npm ERR! Please make sure you have the correct access rights
npm ERR! and the repository exists.
```

ssh-addで鍵の登録が済んでいるはずなのに`Permission denied`になります。

結論から言うと、以下のようにして解決しました。

修正後のスクリプト↓

```sh
#!/bin/bash

eval "$(ssh-agent -s)"
echo "$DEPLOY_KEY" | base64 -d > ~/.ssh/eas_id
chmod 0600 ~/.ssh/eas_id
ssh-add ~/.ssh/eas_id
touch ~/.ssh/config
echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
npm ci
```

`Install dependencies`を待たず、`Pre-install hook`内でパッケージのインストールを完了させたところうまくいきました。

## おわりに

詳細に関しては未だ不明です。一旦`expo/eas-cli`のissueにあげて反応を見てみようと思います。今後新しく何かがわかったら記事を更新します。