GitHub ActionsでEnvironmentsが使えないけど承認付きワークフローっぽい事をしたい

## はじめに
[Environments](https://docs.github.com/ja/actions/reference/environments)を使うと、ワークフローに対して保護ルールをかけられるようになる。
これを使ってGitHub Actionsで承認付きDeployを！
と思ったらEnterprise版では未提供で躓いてしまったので、Environmentsを使わない承認付きのワークフローっぽいものを構築する方法をまとめる。
（一時的にしか使わないと思われるが…）

## どうやるのか？
単純にifを使う。
以下はEC2にgit pullするDeployを想定したワークフロー。

```yaml:approval-sample.yml
name: 承認付きっぽいDeploy

on:
  workflow_dispatch:
     inputs:
       DeployBranch:
         description: 'Deploy Branch'     
         required: true
         default: 'stg'
       DeployEnv:
         description: 'Deploy Environments'     
         required: true
         default: 'stg'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:            
      - name: Deploy of STG
        if: ${{ github.event.inputs.DeployEnv == 'stg' && contains(fromJSON(env.DEPLOY_USERS), github.event.sender.login) }}
        env:
          DEPLOY_USERS: ${{ secrets.STG_DEPLOY_USERS }}
        run: |
          echo '${{ secrets.SSH_KEY }}' > ssh_secret_key
          chmod 600 ssh_secret_key
          ssh -o StrictHostKeyChecking=no '${{ secrets.USER }}'@'${{ secrets.HOST }}' -i ssh_secret_key "
            cd /home/'${{ secrets.USER }}'/hogehoge/ && 
            git -c core.sshCommand=\"ssh -i ~/.ssh/deploy_key -F /dev/null\" pull
          "

      - name: 権限エラー（STG） 
        if: ${{ github.event.inputs.DeployEnv == 'STG' && !contains(fromJSON(env.STG_DEPLOY_USER), github.event.sender.login) }}
        env:
          DEPLOY_USERS: ${{ secrets.STG_DEPLOY_USERS }}
        run: |
          echo "STGのDeployを行う権限がありません。"
          exit 1
```

一部詳細を見ていく。

## if文の中身について
```
if: ${{ github.event.inputs.DeployEnv == 'ステージング' && contains(fromJSON(env.STG_DEPLOY_USER), github.event.sender.login) }}
```

### github.event.inputs.DeployEnv == 'stg'
入力されるDeploy先環境について一致しているか？を検証している

### contains(fromJSON(env.DEPLOY_USERS), github.event.sender.login)
ここがポイントになるが、ここではsecretsに配列(`['hoge']`)でDeployを行ってよいユーザ名を設定しておき、それをgithub.eventコンテキストが持つjob実行ユーザと突合させている
`contains`はstring or arrayでの部分一致でbooleanを返すが、stringであればユーザ名の部分一致で制御する事になり望ましくない
そこでユーザ名と突合させる対象を配列とする事で、その配列の中にユーザ名と一致する要素(文字列)が含まれているか？の判定をするようにしている

ex1) stringのcontainsの場合
secretsの中身が`'hoge-foo'`だと、ユーザ名が`hoge`でも`foo`でもtrueになる
（※意図しているのは`hoge-foo`の場合のみDeployが流れる事）

ex2) arrayのcontainsの場合
secretsの中身が`['hoge-foo']`だと、ユーザ名が`hoge`・`foo`ではfalseになる（それぞれ配列の要素に一致しないので）
この場合、trueになるのは`hoge-foo`というユーザ名のみで、意図通りのDeploy制御になる

### なせenv.DEPLOY_USERSか？
secretsをそのまま使わず環境変数に入れ直して使っているのは、どうやらifの中でsecretsコンテキストは使えないようであるため。

## gitコマンド時のssh keyの指定
```
git -c core.sshCommand=\"ssh -i ~/.ssh/deploy_key -F /dev/null\" pull
```

そもそもDeployなどでActionsのRunnerがEC2からGitHubにアクセスする際には、通常の人間が使っているssh keyを共有するのではなく専用のものを使うべきなので、新しいssh keyを用意するようにする。
通常だと以下の左の画面でssh keyを登録すると思うが、今回のようにDeployなどで使うものについては`Deploy keys`に登録するようにする。

| 通常のssh keyの登録場所 | Deploy等の時のssh keyの登録場所<br>※アクセスを制限したい場合に使う |
|---|---|
| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/54dd93ed-10c3-40e6-8716-8d1acb0e0e0f.png)| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/f7e14b47-05f4-3c23-320c-ecb85c058cfc.png)|

ただ、普段人間が使っているssh keyもEC2上に存在する事もあるので、
それを誤って使わないようにするために`-c core.sshCommand=\"ssh -i ~/.ssh/deploy_key -F /dev/null\"`で明示的にどのssh keyを使用するのか？を指定している。

## おまけ
ssh keyは普通に作るのもできるが、`ssh-keygen -t ed25519 -C ''`強度が強くおススメらしい。