• Status: Accepted
  • Mode: Standard
  • Kruchten Type: Executive/Property
  • Scope: platform
  • Implementation Status: 決定① Done (2026-06-01 実機完了・dev clasp push 88 ファイル成功) / 決定② Not Started (ADC キーレス化 PoC・後段ゲート・任意)
  • 起案者: [email protected]
  • 起案日時 (JST): 2026-06-01
  • 承認日時 (JST): 2026-06-01
  • Deciders: [email protected] (単独)

Pipeline 迂回 + 遡及記録の経緯(監査用注記): 本 ADRDecision Pipeline を経由せず通常 PR で起案した遡及 (retroactive) ADR である。元は認証・秘密情報の全体方針を 1 本に束ねた単一 ADR (KV_DRAFT auth-secret-consolidation-strategy) として起案したが、Cross-Validation で Critical 38/50 差し戻しとなり、主因が「独立決定 7 件を 1 ADR に束ねて cost/impact/baseline が曖昧化した」ことだったため、代表取締役判断で課題を 3 テーマに分割した (2026-06-01)。本 ADR はそのうちテーマ①「失効しない GAS/clasp デプロイ認証」に対応する。決定① (OAuth client の組織 Internal 化) は 2026-06-01 に実機で実施・検証済み (dev clasp push 88 ファイル成功・CLASPRC_JSON secret 更新済) であり、本 ADR は実施済みの意思決定を監査トレースとして事後記録するもの。残るテーマ② (pipeline Basic 認証→Cloudflare Access)・テーマ③ (静的 secret 単一ソース化 + GitHub OIDC/WIF キーレス化 + pre-flight 検知) は本 ADR スコープ外で、TODO_future の backlog として追って別 ADR 化する。Pipeline retroactive validation (ADR-0052) は任意。

コンテキスト

§1.1 何を解決するか

clasp の OAuth refresh token が予告なく失効し、GAS デプロイ(ローカル clasp / CI「Deploy to GAS」)が破綻する。CLAUDE.md に「clasp 認証切れ (invalid_grant) は自律実行不可 → ユーザに ! clasp login --creds creds.json を依頼」と明記される運用劣化が常態化していた。

§1.2 現状 (As-Is) と実測ベースライン

GitHub Actions deploy.yml は直近 60 run が 60 失敗(100%・2026-05-29〜06-01)。直近 8 件はすべて Requested entity was not found@clasp push で、invalid_grant 文字列は表面に出ていなかった。調査の結果、この Requested entity not found旧 OAuth client(後述)の refresh token 失効が紛らわしく表面化したものと判断した。

§1.3 真因 (2026-06-01 特定)

clasp の OAuth client(creds.json)が、Google AI Studio が自動生成した野良プロジェクト gen-lang-client-0297558711 に存在していた。このプロジェクトは bizlp.co.jp 組織配下ではなく、OAuth 同意画面が必然的に External + Testing 固定 → refresh token が 7 日で失効する。これが invalid_grant / 失効の構造的原因。

§1.4 制約・スコープ

本 ADR のスコープは clasp/GAS デプロイ認証に限定する。decision-pipeline の Basic 認証(→ Cloudflare Access)、静的シークレット集約・CI キーレス化(Secrets Store / WIF)は、それぞれ別テーマ(テーマ②/③・TODO_future backlog)に分割した。invalid_grant の真因は 7 日失効以外にも多原因(パスワード/2FA 変更・client secret rotation・GitHub Secret の base64 崩れ・複数環境同時リフレッシュ race)があり、Internal 化はこれらを消さないため「失効撲滅」と断言せず pre-flight 検知(テーマ③)との併用前提とする。

§1.5 目標 (To-Be)

clasp OAuth client を組織配下の Internal client に移行し、7 日失効を構造的に撲滅する。CI / ローカル shell の双方で予告なきデプロイ失敗を解消し、client の所在を組織配下に一元化する。

決定

clasp OAuth client を野良 External プロジェクト gen-lang-client-0297558711 から、組織配下 GCP プロジェクト bizlp-gas-accounting-devInternal ユーザータイプ client へ作り直す。2 決定を ROI 順で適用する。

  • 決定① Internal 化(実証済み・低リスク・本 ADR の中核): 組織配下 bizlp-gas-accounting-dev に Internal OAuth client を新規作成 → creds.json 差替 → 再認証 → dev clasp push で疎通確認。Internal は (i) 7 日失効なし (ii) Google 審査・CASA 不要 (iii) 外部に OAuth フロー入口が開かない(露出増ゼロ)。2026-06-01 に実機で実施・dev clasp push 88 ファイル成功・CLASPRC_JSON secret 更新済
  • 決定② clasp v3 ADC キーレス化 PoC(任意・後段ゲート): refresh token 自体を Application Default Credentials で撲滅できるか実機検証。3 モデル Deep Research で可否が割れた(Claude/OpenAI=不可、Gemini=可)ため一括前提にせず、決定①の完了・効果確認の後に着手。「実機 2 回失敗 または カレンダー工数 1.5 人日超」で自動撤退し、Internal client 運用を最終形として維持する。

決定①を先・決定②を後に固定するのは、確実に効く①を不確実な②に引きずられて後回しにしないため(元レビュー盲点 #12 への構造的回答)。

判断基準 (Decision Drivers)

§3.1 評価軸

#重要度 (係数)案件特有の解釈
1#secure[Must] (×2.0)静的・長寿命鍵の露出面を増やさない。K.O. = 現状より露出面が増えるなら不採用。→ Internal 化は外部入口を開かず露出増ゼロでクリア。残る長寿命トークン漏洩リスクは .clasprc.json/CLASPRC_JSON 保護 + 将来テーマ③で対処
2#operable[High] (×1.0)デプロイを予告なく失効させない。K.O. = clasp デプロイを恒久的に壊すなら不採用
3#reliable[High] (×1.0)CI / ローカル shell の両方で安定動作(sub サンドボックスは本 ADR スコープ外=テーマ②)
4#efficient[Medium] (×0.5)コスト増を許容しない($0 維持)。Internal は審査費(CASA Tier2 数十万円規模)も回避
5#maintainable[Medium] (×0.5)client が組織配下に一元化され、所在が明確

K.O. criterion: Must 軸 (#secure) score < 3 は不採用。

§3.2 評価軸 × 案スコア表

係数採択案 (組織 Internal 化 + ADC PoC 後段)案A (External 公開 publish)案B (現状維持 + 手動再認証)案C (clasp 完全キーレス化を一括前提)
#secure×2.05235
#operable×1.05413
#reliable×1.04312
#efficient×0.55244
#maintainable×0.55324
加重和 (正規化)0.9600.5400.4400.760
K.O. 通過 (Must ≥3)

加重和 = Σ(score × 係数) / (5 × Σ係数)、Σ係数 = 5.0。採択案は実機で決定①を完了済みのため #operable/#secure を実証値で 5、残る長寿命トークン漏洩リスクを反映し #reliable は 4。案A は External 公開が外部に OAuth フロー入口を開き #secure=2 で K.O. 不通過。案C は可否が 3 モデルで割れ #reliable=2 と不確実なため、決定②として段階化(採択案に内包)した。

検討した代替案 (Alternatives Considered)

  • 採択案(組織 Internal 化 + ADC PoC 後段): 上記決定①②。露出増ゼロ・審査不要・$0 で 7 日失効を構造的に撲滅。実機で決定①完了済み。
  • 案A(External のまま consent screen を "In production" に publish): 7 日失効は外せるが、External 公開は任意の Google アカウントに OAuth フロー入口が開き露出面が増える + 制限付きスコープ次第で Google 審査/CASA(数十万円)を発動しうる。不採用 = Internal 化が上位互換(露出増ゼロ・審査不要)。組織配下でなければこれが唯一手だが、bizlp は Workspace 組織を保有し bizlp-gas-accounting-dev が組織配下と確認できたため不要。
  • 案B(現状維持 + 手動再認証): 改修ゼロ。不採用 = 7 日ごとの手動 clasp login と予告なき CI 失敗が継続、自律実行性を損なう。
  • 案C(clasp 完全キーレス化を一括前提): 不採用 = 可否が 3 モデルで割れ、PoC で確定すべき。決定①を確実に取った上で決定②として段階検証する。

影響 (Consequences)

§5.1 正の影響 (Good)

  • 7 日失効を構造的に撲滅(Internal)。CLASPRC_JSON 起因の CI 失敗を解消見込み。
  • client が組織配下に一元化され所在が明確。コスト増なし・審査不要。

§5.2 負の影響 (Bad)

  • client 作り直し + 再認証の初期工数(実績 ≈0.3〜0.5 人日)。
  • Internal 化で「7 日自動失効という漏洩時の自動安全弁」は外れるため、長寿命トークン(~/.clasprc.json/CLASPRC_JSON)漏洩時の blast radius は拡大 → コミット禁止 hook(既設)+ secret 最小権限 + 将来テーマ③(ADC キーレス化)で対処。
  • 影響ファイル/リソース: .github/workflows/deploy.yml(secret CLASPRC_JSON)/ ~/.clasprc.json / リポジトリ creds.json / GCP プロジェクト bizlp-gas-accounting-dev の OAuth client(新規 Internal・デスクトップアプリ)/ 旧 gen-lang-client-0297558711 の client(フォールバックとして当面残置、検証後に削除)。※ wrangler・decision-pipeline・Keychain は本 ADR では触らない(テーマ②/③)。

§5.3 監査・実機結果 (2026-06-01)

Internal 化(sub)+ secret stale 解消(main)により CLASPRC_JSON 起因の CI 失敗は実機解消済(dev/prod CI green)。clasp 3.3.0 の .clasp.json cp 切替は正常動作と実証(cp dev→dev / cp prod→prod、push:prod は正しく prod を対象 = 監査問題なし)。残課題 B(CLASP_DEPLOYMENT_ID_* secret)も登録済。GAS/clasp デプロイ認証の課題はクローズ方向。

コスト試算

作業工数 (人日)備考
決定① Internal 化(GCP で Internal client 作成 + creds 差替 + 再認証 + Apps Script API 有効化 + dev 疎通)0.3〜0.5(実績)実機完了 2026-06-01
決定② ADC キーレス化 PoC≤1.5(撤退上限)任意・後段ゲート
合計約 2 人日以内
  • 運用コスト: $0/月(GCP OAuth client 無料・追加サービスなし)。
  • 審査コスト: $0(Internal は Google OAuth verification / CASA 対象外)。← External publish 案なら CASA Tier2 数十万円規模のリスクがあった。

撤退条件 (Rollback Plan)

#判定指標検知方法代替アクション
1決定② ADC PoC が実機 2 回連続失敗 または カレンダー工数 1.5 人日超PoC 実施ログ自動撤退 → Internal client 運用(決定①)を最終形として維持
2Internal 化後も clasp 認証が壊れるclasp push 失敗 / CI redバックアップから即復旧: cp ~/creds.json.bak creds.json && cp ~/.clasprc.json.bak ~/.clasprc.json(所要 1 分未満)。旧 gen-lang client もフォールバックとして当面残置
3長寿命トークン漏洩の兆候secret スキャン / hook 検知secret 即 rotation + テーマ③(ADC キーレス化)を前倒し

検証完了後(prod CI green 確認後): 旧 gen-lang client と $HOME のバックアップ(~/creds.json.bak / ~/.clasprc.json.bak)を削除し、露出面・平文認証の長期放置を排除する。

Confirmation

  • 検証手段:
    1. ローカル clasp push -f(dev)の成功(2026-06-01 実証済み・88 ファイル)。
    2. CI「Deploy to GAS」が green になること(dev/prod 実機 green 確認済)。
    3. pre-flight 失効検知(テーマ③と連携・将来)。
  • 実行頻度: デプロイ時の手動確認 + CI run ごと。
  • 観測可能 KPI:
    • invalid_grant・Requested entity not found 起因の CI デプロイ失敗を月 0 件(ベースライン: 直近 60/60 失敗)。
    • 手動 clasp login 実施回数を月 0 回(ベースライン: 7 日ごと)。
  • 違反時対応: §撤退条件を発動。決定② は撤退条件 #1 で自動撤退し Internal client 運用へ戻す。

参照 (References)

  • 関連 ADR:
    • ADR-0013(Env module abstraction): 補完。秘密アクセスの抽象化方針と整合(本 ADR は GAS デプロイ認証に限定)。並立・補完
    • ADR-0019(decision-pipeline langgraph migration, Accepted): 関連。pipeline の Basic 認証置換は本 ADR ではなくテーマ②で扱う。並立
    • ADR-0037(serverside draft staging lifecycle, Accepted)/ ADR-0064(CI trigger web→CI, Accepted): 関連(CI 認証面)。いずれも Supersede しない・補完
    • ADR-0052(retroactive validation mode): 本 ADR は実施済み決定の遡及記録であり、Pipeline retroactive validation は任意。
  • Supersede / Conflict: 元の単一 ADR(KV_DRAFT auth-secret-consolidation-strategy・Critical 38/50 差し戻し)を、本 ADR(テーマ①)+ テーマ②/③(TODO_future backlog)への分割で置換。当該 KV draft は本セッションで DELETE 済。
  • 関連調査: RQ-085「認証・秘密情報の統合管理」3 モデル Deep Research(docs/research/rq-085-auth-secret-consolidation.md ほか)。決定②の ADC 可否が割れた根拠もここに記録。
  • 将来 backlog: テーマ②(pipeline Basic 認証→Cloudflare Access Service Token)/ テーマ③(静的 secret 単一ソース化 + GitHub OIDC/WIF キーレス化 + pre-flight 検知)は TODO_future に backlog 化し、別 ADR として追って起案する。
  • バックアップ手順: 移行前に ~/creds.json.bak / ~/.clasprc.json.bak を $HOME(git 管理外)に取得済。