# 파이프라인에 토큰 발급하기

OTA 도구는 토큰으로 배포합니다. Mocco만 그 토큰을 갖고 있으면, 배포할 수 있는 유일한 방법은 게이트가 승인된 Mocco 파이프라인 실행입니다. 워크플로는 게이트 뒤에 Mocco에 토큰을 요청하고, Mocco는 실행, 게이트, 허용 목록을 확인한 뒤에 응답합니다. 이 페이지에서는 이 설정을 한 번 해 둡니다. 배포 명령은 사용하는 도구의 가이드에 나옵니다.

## 1. 토큰 저장하기

OTA 도구에서 배포 토큰을 만듭니다. 토큰을 만드는 방법과 도구별로 권한 범위를 얼마나 좁힐 수 있는지는 각 도구 가이드에 있습니다. 그런 다음 프로젝트의 **OTA updates** 페이지에서 **Your OTA tool** 탭을 열고, 도구를 고르고, `acme-production` 같은 이름을 붙이고, 토큰을 붙여 넣은 뒤 **Add token**을 선택합니다.

![Add a publishing token 양식](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/aa4695f8-8ed6-4dc7-b080-18774ab6d96f/tokens-add.png)

토큰은 암호화되어 저장되며 다시 표시되지 않습니다. 카드에는 지문(도구에 표시된 값과 대조할 수 있도록 해시의 앞부분 문자), Mocco가 토큰에 쓰는 프로바이더 ID(`ota-eas`, `ota-codepush`, `ota-hot-updater`, `ota-generic`), `.mocco.yml`에 복사할 줄이 표시됩니다.

![지문, provider, 토큰을 전달받는 파이프라인, .mocco.yml 줄이 표시된 토큰 카드](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/db684bf4-40b3-4ad6-893e-79ddf90e3e53/tokens-card.png)

그 뒤에는 토큰의 다른 사본을 모두 지우세요. GitHub Actions 시크릿이나 팀원의 셸 프로필 같은 곳입니다. 사본이 남아 있는 사람은 승인 없이 배포할 수 있습니다.

## 2. 파이프라인이 받도록 허용하기

워크스페이스 소유자나 관리자가 **Access**를 열고 **Credential releases**에서 릴리스를 추가합니다. 저장소, `.mocco.yml`의 파이프라인 이름, 승인되어야 하는 게이트, 프로바이더 ID, 역할로 쓸 토큰 이름, Mocco가 이 허용을 유효하게 볼 최대 시간을 입력합니다.

![Access 페이지의 Credential releases, 추가 양식이 열린 모습](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/4730c707-8fe5-4213-b846-16fc4abed1da/access-releases.png)

그러면 토큰 카드에 토큰이 전달되는 곳이 표시됩니다. 릴리스가 없는 토큰은 어떤 파이프라인도 가져갈 수 없습니다.

## 3. .mocco.yml에서 요청하기

배포 단계에 토큰 이름과, 그 전에 승인되어야 하는 게이트를 지정합니다. 게이트는 `steps`에서 앞에 있어야 합니다.

```yaml
version: 2
pipeline: ota-production
steps:
  - kind: step
    run: build-bundle
    executor: github-actions
  - kind: gate
    name: prod
    resume: [{ role: mobile-release, count: 2 }]
    prevent_self: true
    reason_required: true
  - kind: step
    run: publish
    executor: github-actions
    credential: { provider: ota-eas, role: acme-production, ttl: 900, gate: prod }
```

## 4. 워크플로에서 가져오기

Mocco는 각 `github-actions` 단계를 `mocco-run-step` 타입의 `repository_dispatch` 이벤트로 시작합니다. 이벤트에는 실행 ID, `steps`에서 이 단계의 위치(0부터 세며 게이트도 포함하므로 위의 `publish`는 `2`), 커밋, 워크플로가 Mocco와 통신할 때 쓰는 1회 실행용 토큰이 들어 있습니다. 워크플로는 위치로 단계를 고르고, 배포 토큰을 가져오고, 배포한 뒤 결과를 보고합니다.

```yaml
name: Mocco steps
on:
  repository_dispatch:
    types: [mocco-run-step]

jobs:
  publish:
    if: github.event.client_payload.stepIndex == 2
    runs-on: ubuntu-latest
    env:
      MOCCO_RUN_ID: ${{ github.event.client_payload.runId }}
      MOCCO_STEP: ${{ github.event.client_payload.stepIndex }}
      MOCCO_RUN_TOKEN: ${{ github.event.client_payload.callbackToken }}
      MOCCO_CALLBACK_URL: ${{ github.event.client_payload.callbackUrl }}
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.client_payload.commitSha }}

      - name: Get the publishing token from Mocco
        run: |
          body=$(jq -nc --arg run "$MOCCO_RUN_ID" --argjson step "$MOCCO_STEP" --arg token "$MOCCO_RUN_TOKEN" \
            '{runId: $run, stepIndex: $step, token: $token}')
          secret=$(curl -fsS -X POST "${MOCCO_CALLBACK_URL%/callback}/credentials" \
            -H 'content-type: application/json' -d "$body" | jq -r '.credentials.value')
          echo "::add-mask::$secret"
          echo "OTA_TOKEN=$secret" >> "$GITHUB_ENV"

      # The publish command for your tool goes here, using $OTA_TOKEN (see the tool guides).

      - name: Report the result to Mocco
        if: always()
        run: |
          status=$([ "${{ job.status }}" = success ] && echo succeeded || echo failed)
          jq -nc --arg run "$MOCCO_RUN_ID" --argjson step "$MOCCO_STEP" --arg token "$MOCCO_RUN_TOKEN" \
            --arg status "$status" '{runId: $run, stepIndex: $step, token: $token, status: $status}' \
            | curl -fsS -X POST "$MOCCO_CALLBACK_URL" -H 'content-type: application/json' -d @-
```

Mocco는 거절하는 모든 경우에 이유와 상관없이 `403 denied`로 응답합니다. Mocco가 시작하지 않은 실행, 승인되지 않은 게이트, 없는 릴리스가 모두 해당합니다. GitHub에서 직접 시작한 실행에는 실행 토큰이 없으므로 배포 토큰을 가져올 수 없습니다.

## 계속 직접 챙겨야 할 일

Mocco의 허용이 만료되어도 토큰 자체는 만료되지 않습니다. 토큰을 받은 러너는 토큰을 교체하기 전까지 계속 가지고 있을 수 있습니다. 그러므로 GitHub 호스팅 러너에서 배포하고, 도구가 허용하는 한 토큰의 권한 범위를 좁게 잡고, 주기적으로 교체하세요. 도구에서 새 토큰을 만들고, 카드에서 **Rotate**를 선택하고, 도구에서 이전 토큰을 폐기합니다. 90일 동안 교체하지 않은 토큰에는 Mocco가 표시를 붙입니다.

롤백용으로는 온콜 엔지니어 한 명이 혼자 승인할 수 있는 게이트(`count: 1`, `prevent_self: false`)를 가진 두 번째 파이프라인을 추가하고, Access에 그 파이프라인의 릴리스를 따로 만드세요. 그러면 장애 중에 두 번째 사람을 기다릴 일이 없고, 롤백도 Mocco를 통해서만 토큰을 받으며, 실행 기록은 감사 로그에 남습니다.
