【GitHub】複数リポジトリのsecretsを共通の値で更新する

チームで使用しているGitHubのリポジトリが10個ほどあり、
それぞれに同じ値のSecretsを登録する必要がありました。

10個程度なら手動で更新できないこともないですが、
ちょっと面倒です。

そこで、APIを使って一括で更新してみたので、やり方をまとめておきます。


## 補足：Organization Secretsについて

Secretsには、`Organization単位`で共通の値を設定することも可能です。

今回は、Organizationとなると範囲が大きそうなので見送りましたが、運用に合えばOrganization Secretsを使用すると良さそうです。

Organization Secretsについてはこちら↓
[GitHub OrganizationでSecretsを組織レベルで共有、設定できるようになりました！](https://dev.classmethod.jp/articles/github-organization-level-secrets/)



# 事前準備

### 1：パーソナルアクセストークンの取得

APIで使用するパーソナルアクセストークンを取得します。

手順は[個人アクセストークンを取得する](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)を参照してください。



「Select scopes」では、「Full control of private repositories」にチェックを入れます。

![スクリーンショット 2022-02-10 8.50.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311681/8b1a5a9b-4dc8-4d67-37f9-b71fb54a80a0.png)


登録するとトークンが表示されるので、控えておきます。（ghp_***）

### 2:tweetsodiumのインストール

登録するsecretsの値は事前に暗号化する必要があります。

今回は[Get a repository public key](https://docs.github.com/en/rest/reference/actions#get-a-repository-public-key)に従って、nodeを使用しました。

`tweetsodium`がない場合は、事前にインストールしておきます。

```
 npm install tweetsodium
```

# Secrets登録手順

以下の2ファイルを使います。
* encrypt.js
* register_secrets.sh

```encrypt.js
const sodium = require('tweetsodium');

// actions/secrets/public-keyで取得したキー
const key = process.argv[2]

// secretsの値
const value = process.argv[3];


// Convert the message and key to Uint8Array's (Buffer implements that interface)
const messageBytes = Buffer.from(value);
const keyBytes = Buffer.from(key, 'base64');


// Encrypt using LibSodium.
const encryptedBytes = sodium.seal(messageBytes, keyBytes);


// Base64 the encrypted secret
const encrypted = Buffer.from(encryptedBytes).toString('base64');


console.log(encrypted);
```

```register_secrets.sh
# 更新対象リポジトリのリスト
REPO_LIST=(
    "repo-1"
    "repo-2"
    "repo-3"
    "repo-4"    
)

# GithubのOrganization
ORG="ORG" # TODO：変更する

# 取得した個人アクセストークン
PERSONAL_ACCESS_TOKEN="PERSONAL_ACCESS_TOKEN" # TODO：変更する

# Secretsに登録する情報
SECRET_NAME="SECRET_NAME" # TODO：変更する
SECRET_VALUE="SECRET_VALUE" # TODO：変更する

AUTHORIZATION="Authorization: bearer "$PERSONAL_ACCESS_TOKEN
API_BASE_URL="https://api.github.com/repos"
COMMON_HEADER="Accept: application/vnd.github.v3+json"

for REPO in ${REPO_LIST[@]}; do
    echo $REPO

    # トークンを取得する
    response=$(curl \
    -X GET \
    -H "$OMMON_HEADER" \
    -H "$AUTHORIZATION" \
    $API_BASE_URL/$ORG/$REPO/actions/secrets/public-key)

    key_id=$(echo $response | jq .key_id )
    key=$(echo $response | jq .key )

    # encrypt
    encrypted_value=$(node encrypt.js $key $SECRET_VALUE)

    curl \
    -X PUT \
    -H "$OMMON_HEADER" \
    -H "$AUTHORIZATION" \
    $API_BASE_URL/$ORG/$REPO/actions/secrets/$SECRET_NAME \
    -d '{ "key_id": '$key_id', "encrypted_value":"'$encrypted_value'" }'
done

```

`TODO：変更する`とコメントがついているところの値を書き換え、シェルの方を実行します。

```
sh register_secrets.sh
```


成功すると、空のレスポンスが返ってきます。

```
{

}
```


おつかれさまでした :smile: 

公式ドキュメント：[Create or update a repository secret](https://docs.github.com/en/rest/reference/actions#create-or-update-a-repository-secret)

## エラーが発生した場合

エラーが発生した場合は、エラーメッセージが返ってきます。

```
{
  "message": "Not Found",
  "documentation_url": "https://docs.github.com/rest/reference/actions#create-or-update-a-repository-secret"
}
```

自分の場合はリポジトリ名の指定が間違っていてこのエラーが出たので、
エラーが出た場合はリポジトリ名を確認してみてください。




# さいごに

APIで複数リポジトリのSecretsを一括更新するやり方を紹介しました。

同じような悩みを持つ方のお役に立てれば幸いです。

最後までお読みいただき、ありがとうございました！