GitHub ActionsでGASをデプロイしclasp認証情報をローカルに残さない方法

GitHub ActionsでGASをデプロイしclasp認証情報をローカルに残さない方法

2026.06.09

はじめに

お疲れ様です。あきとです。

GAS(Google Apps Script)をローカルで管理するとき、claspはとても便利です。
ただしclasp loginで作られる~/.clasprc.jsonには、アクセストークンやリフレッシュトークンが含まれます。
普段使う端末に置いたままだと、ふとした拍子に流出する不安が残り、扱いには注意が必要です。

そこで今回は、その認証情報をローカル端末に残さず、GitHub Secretsへ移す方法を試しました。
GitHub ActionsからGASへ反映する流れまで、まとめて整理します。

今回作る構成

構成は次の通りです。

GitHub Secrets
  |
  | CLASPRC_JSON / scriptIdを渡す
  v
GitHub Actions
  | - ~/.clasprc.jsonを一時生成
  | - scriptIdからdist/.clasp.jsonを生成
  | - npm ci / lint / test / build
  | - clasp push
  v
Google Apps Script

ポイントは、~/.clasprc.jsonをリポジトリにもローカルにも残さない点です。
.clasp.jsonそのものもSecretには入れません。
Secretへ保存したscriptIdをもとに、GitHub Actionsの実行中だけdist/.clasp.jsonを作ります。
処理が終われば、どちらのファイルもランナーごと破棄されます。

この記事では、claspの初期設定やGASプロジェクトの作成手順は扱いません。
すでにローカルからclasp pushできる状態を前提にします。
本題は、認証情報をローカルからGitHub Actionsへ移す部分です。

GitHub Secretsへ認証情報を移す

GitHub Actionsからclasp pushするために、次の値をRepository secretsへ登録します。

  • CLASPRC_JSON: ~/.clasprc.jsonの中身
  • CLASP_SCRIPT_ID_MAIN: 本番用GASのscriptId
  • CLASP_SCRIPT_ID_DEV: 検証用GASのscriptId

CLASPRC_JSONのもとになる~/.clasprc.jsonは、clasp loginで作られます。

clasp login

CLASPRC_JSONには長く使える認証情報が含まれます。
個人の普段使いアカウントではなく、CI用のGoogleアカウントでloginし、
対象のGASだけ編集できるように共有する運用がおすすめです。

生成された~/.clasprc.jsonの中身を、そのままCLASPRC_JSONへ登録します。

.clasp.jsonは、対象のGASプロジェクトを示す設定です。
環境ごとに別のGASへ反映したいので、本番用と検証用を分けます。
今回はclasp -P distで実行するため、.clasp.jsonにはscriptIdだけを設定します。
ブランチごとに反映先のSecretを分けておくと、devへのpushで誤って本番を更新する事故を防げます。

登録が終われば、ローカルに残った認証情報はclasp logoutで削除します。

clasp logout

GitHub Actionsを作る

ワークフローは、Google公式ドキュメントの
clasp と GitHub Actions を使用した Apps Script の CI/CD」を参考にしています。
公式例では、GitHub SecretsへCLASPRC_JSONCLASP_JSONを保存し、
PRでCIを実行し、mainへのpushでclasp push --forceを実行する流れが紹介されています。

この記事では、その公式例を元にしつつ、.clasp.json全体ではなくscriptIdだけをSecretに保存します。
CIと反映用のワークフローも分けます。
PRでは検査だけ実行し、maindevへのpushでGASへ反映します。
さらに、ブランチごとに反映先のGASを切り替えます。

まず、.github/workflows/ci.ymlを作成します。

name: ci

on:
  pull_request:
    branches: [main, dev]

permissions:
  contents: read

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with:
          persist-credentials: false

      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version-file: .node-version
          cache: npm

      - run: npm ci

      - run: npm run format:check

      - run: npm run lint

      - run: npm run typecheck

      - run: npm test

      - run: npm run build

次に、.github/workflows/deploy.ymlを作成します。

name: deploy

on:
  push:
    branches: [main, dev]
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: deploy-gas-${{ github.ref_name }}
  cancel-in-progress: false

jobs:
  deploy:
    if: github.ref_name == 'main' || github.ref_name == 'dev'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with:
          persist-credentials: false

      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version-file: .node-version
          cache: npm

      - run: npm ci

      - run: npm run format:check

      - run: npm run lint

      - run: npm run typecheck

      - run: npm test

      - run: npm run build

      - name: Push with clasp
        env:
          CLASPRC_JSON: ${{ secrets.CLASPRC_JSON }}
          CLASP_SCRIPT_ID_MAIN: ${{ secrets.CLASP_SCRIPT_ID_MAIN }}
          CLASP_SCRIPT_ID_DEV: ${{ secrets.CLASP_SCRIPT_ID_DEV }}
        shell: bash
        run: |
          case "$GITHUB_REF_NAME" in
            main) CLASP_SCRIPT_ID="$CLASP_SCRIPT_ID_MAIN" ;;
            dev) CLASP_SCRIPT_ID="$CLASP_SCRIPT_ID_DEV" ;;
          esac

          printf '%s' "$CLASPRC_JSON" > "$HOME/.clasprc.json"
          printf '{"scriptId":"%s"}\n' "$CLASP_SCRIPT_ID" > dist/.clasp.json

          npx @google/clasp -P dist push --force

Push with claspで、GitHub Secretsから~/.clasprc.jsonを一時的に作っています。
このファイルはGitHub Actionsのランナー上にだけ作られます。

dist/.clasp.jsonは、ブランチに応じて切り替えます。
mainならCLASP_SCRIPT_ID_MAINdevならCLASP_SCRIPT_ID_DEVを使います。
これにより、本番用と検証用のGASを分けて反映できます。

clasp -P dist push --forceとすることで、distをルートとして扱います。
リポジトリ全体ではなく、ビルド後の成果物だけを反映できます。

今回は、clasp deployは使いません。
この記事で扱うのは、GASプロジェクトのソースをGitHub Actionsから反映するところまでです。
ウェブアプリやアドオンとして公開済みのデプロイを更新したい場合は、
別途clasp deployclasp redeployを検討してください。

PRではciだけ動きます。
Secretsを使う反映処理は、maindevへのpushに限定しています。

GitHub Actionsのアクション指定について

サンプルでは、GitHub ActionsのアクションをコミットSHAで固定しています。
actions/checkout@v6のようなタグは、提供元の更新で参照先が変わる可能性があります。
SHAで固定すると、意図しないアクション更新を避けられます。

一方で、SHA固定には更新漏れのリスクがあります。
そのため、RenovateやDependabotで更新を検知し、
リリースノートを確認してからSHAを差し替える運用がおすすめです。

actions/checkoutでは、persist-credentials: falseも明示します。
初期値のままだと、checkout後のGit操作で使える認証情報が残ります。
この記事のワークフローではpush操作をしないため、認証情報を残す必要がありません。

- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
  with:
    persist-credentials: false

まとめ

claspは手軽な反面、~/.clasprc.jsonをローカルに置いたままだと、流出したときの影響が気になります。
今回は、その認証情報をGitHub Secretsへ預け、GASへの反映をGitHub Actionsに任せる形へ移しました。

仕組みのキモは、次の3点です。

  • 認証情報はSecretsへ移し、ローカルはclasp logoutで空にする
  • ~/.clasprc.jsonはActionsの実行中だけ生成し、終われば破棄する
  • ブランチごとに反映先のGASを分け、maindevのpushだけに限定する

この形にしてからは、端末に認証情報を残さず運用でき、安心して開発に集中できるようになりました。
最初の設定こそ少し手間ですが、一度組んでしまえば、あとはpushするだけでGASが更新されます。

本ブログが、GASのCI/CDを始める方の参考になれば幸いです。

参考資料


クラスメソッドオペレーションズ株式会社について

クラスメソッドグループのオペレーション企業です。

運用・保守開発・サポート・情シス・バックオフィスの専門チームが、IT・AIをフル活用した「しくみ」を通じて、お客様の業務代行から課題解決や高付加価値サービスまでを提供するエキスパート集団です。

当社は様々な職種でメンバーを募集しています。

「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、クラスメソッドオペレーションズ株式会社 コーポレートサイト をぜひご覧ください。※2026年1月 アノテーション㈱から社名変更しました

この記事をシェアする

関連記事