▲ Vercelの運用をAIに任せる — 開発から本番監視まで、2026年8月に実際に組める構成
デプロイまではもうAIでシームレスに回る。問題はその先だ。監視・セキュリティ・インシデント対応・ISMS/Pマークの証跡を、Vercelから一歩も出ずにAIへ渡すには何を入れればいいのか。稼働中のBtoB SaaS(Vercel+Neon+SvelteKit・運用者1人)を実物として診断し、8段階に分けて製品名・料金・コピペできる設定・そして任せてはいけない線引きまで並べた。
🎯 答え — 8段階に何を入れるか(これが全部)
このセクションの3点
① まず Vercel Pro($20/席・月)。監視もWAFもAIエージェントも、ここから先にある
② 監視を足すより先に、自動テストを3本書く。機械が合否を出せないものはAIに任せられない
③ 「CIが赤でも本番に出る」は今日消せる。Git連携を切り、Actions からデプロイする。費用0円
はじめての人へ — この記事に出てくる言葉を先に18個だけ 知っている人は開かなくてよい 開く ▾
| 言葉 | 一言でいうと | 日常でいうと |
|---|---|---|
| デプロイ | 書いたコードを、実際に動くサーバーへ配置して公開すること | 原稿を印刷して店に並べる |
| CI | コードを保存するたびに自動で走る検査の仕組み | 工場の出荷前チェック |
| 本番/プレビュー | 本番=お客さんが使っている環境。プレビュー=公開前に自分だけが見る環境 | 本番=営業中の店。プレビュー=閉店後の試作 |
| リポジトリ | コードとその変更履歴の置き場所 | 書きかけの原稿と、その全部の書き直し履歴 |
| ブランチ/PR | 本体を壊さずに変更を試す枝と、それを本体に取り込む申請 | 別紙で書き直して、差し替え申請を出す |
| マージ | PRを本体に取り込むこと | 差し替え申請を承認して本文に反映する |
| ブランチ保護 | 検査を通っていない変更を、本体に取り込めなくする設定 | 検印が無い書類は受け付けない窓口 |
| ロールバック | おかしくなった時に、1つ前の状態へ戻すこと | 印刷をやめて前の版に戻す |
| 監視(モニタリング) | 動いているシステムの状態を、常に見ておくこと | 店の防犯カメラと売上モニター |
| ログ | いつ何が起きたかの記録 | レジのジャーナル(打った記録の紙) |
| SAST | コードを実行せずに、危ない書き方を機械が探す検査 | 料理を作る前にレシピの危険を指摘する |
| WAF | 悪意のあるアクセスを、アプリに届く前で止める壁 | 店の入口の警備員 |
| レート制限 | 同じ相手からの短時間の大量アクセスを制限すること | 1人が何度も試着室に並び直すのを止める |
| 認可(Authorization) | ログインした人が「どこまで見てよいか」の判定 | 社員証で入れる部屋が決まっている |
| テナント分離 | 契約している会社ごとに、データを完全に分けること | 同じビルでも他社の部屋には入れない |
| E2Eテスト | 実際にブラウザを動かして、通しで動くか確かめる自動テスト | 客のふりをして注文から会計まで試す |
| ISMS / Pマーク | 情報の守り方が基準を満たしているという第三者の認証 | 衛生管理の認証を店に貼っている状態 |
| 管理策(A.8.16 など) | ISMSの規格が定めた、守るべき項目に付いた番号 | 衛生チェック表の項目番号 |
この記事は、実際に動いている1つのシステム(ストレスチェックの集計サービス)を題材にしている。読者がそのシステムを知らなくても読めるように書いた。分からない言葉が出てきたら、ここに戻ってくればよい。
依頼はこうだった。「Vercelで全部のシステムをAIで運用したい。デプロイまではもうシームレスだが、監視とセキュリティをもっと良くしたい。運用を段階に分けて、それぞれ何をすればいいか」。
先に答えを出す。下の図が、そのまま導入計画である。
→ この図は横にスクロールできます
赤=今の WebTHQ の状態/緑=この記事で足すもの。月額は 2026年8月15日時点の各社公式価格。従量課金は別途かかる。
この記事の出典と、依頼の読み方。数値は Vercel と各社の公式価格ページ、経済産業省「情報セキュリティ管理基準(令和7年改正版)」、個人情報保護委員会、JIPDEC、厚生労働省の一次資料から、すべて2026年8月15日に取得した。比較まとめサイトの数値は1つも使っていない。
依頼の「Vercel以外は考えない」は、ホスティングと本番実行基盤を Vercel から替えないという意味で読んでいる。GitHub・Sentry・Semgrep などの周辺サービスは使う。
今の構成は Vercel Hobby(Free)— 有償のBtoB SaaSは規約の対象外
・規約は「Hobbyは個人の非商用利用に限る」と明記している(原文は下の折りたたみ)
・商用の定義は「制作に関わった誰かの金銭的利益を目的とするデプロイ」。有償の従業員が書いたコードも含む
・違反が検知されると、デプロイまたはアカウントが一時停止される。事前警告の記載は確認できなかった
・止まれば全顧客のサービスが同時に止まる。ISMS では A.5.31 と A.5.30 の両方に当たる
規約の原文(英語・Vercel公式) 2026-08-15 取得 開く ▾
利用規約 Section 4(vercel.com/legal/terms)"You shall only use the Services under a Hobby plan for your personal or non-commercial use."
Fair Use Guidelines(vercel.com/docs/limits/fair-use-guidelines)"Hobby teams are restricted to non-commercial personal use only. All commercial usage of the platform requires either a Pro or Enterprise plan.""Commercial usage is defined as any Deployment that is used for the purpose of financial gain of anyone involved in any part of the production of the project, including a paid employee or consultant writing the code."
寄付を募る行為も商用に含まれると明記されている。違反時の措置は vercel.com/kb/guide/why-is-my-account-deployment-blocked に記載がある。
8段階の詳しい対応表 — AIの担当・人間の担当・ISO27001の管理策 上の図と同じ内容を、列で細かく見たい人だけ 開く ▾
| 段階 | 今のWebTHQ | 入れるもの | AIが自動でやること | 人間に残る作業 | 月額 | ISO27001 附属書A |
|---|---|---|---|---|---|---|
| ⓪ 前提 | Hobby(Free) | Vercel Pro へ移行 | (これをやらないと以下の7割が有効化できない) | 移行の判断 | $20/席 | A.5.31 / A.5.30 |
| ① 開発 | Claude Code + Codex。自動テストは1本も無い | Vitest + Playwright を3本だけ。AGENTS.md / CLAUDE.md を規約として置く | AIが自分の変更の合否を自分で確かめられるようになる | 受入基準(何をもって正しいとするか)を決める | $0 | A.8.25 / A.8.28 |
| ② コミット直前 | gitleaks・npm audit・ignore-scripts・自作の認可検査(既に強い) | Semgrep Free(10リポ・10人)+ Socket.dev 無料枠。ESLint を CI へ | SAST と、npm audit では出ないマルウェア・不審な挙動の検出 | 例外を認めるかの判断 | $0 | A.8.8 / A.8.28 |
| ③ PRレビュー | AIレビューは手動。ブランチ保護なし | GitHub Pro でブランチ保護 + Claude Code GitHub Action + Vercel Agent Code Review | PRごとの指摘。Vercel Agent は Sandbox で build/test/lint を回してから提案する、と公式ドキュメントが記載している(実際の挙動はテストPRで確認する) | 指摘の採否を決める | Agent $0.30/回+トークン実費 | A.8.29 / A.8.32 |
| ④ プレビュー検証 | プレビューは出るが、人が目で見て終わり | Playwright の認可E2E を プレビューURL に対して実行 + Checkly 無料枠 | 「A社のトークンでB社のデータが読めない」ことを毎回機械が確認する | シナリオを書く(最初の1回だけ) | $0 | A.8.29 / A.8.31 |
| ⑤ 本番昇格 | git push で本番に出る。CIが赤でも出る | Vercel の Git 連携を解除 → Actions から vercel deploy --prebuilt --prod。GitHub Environment に承認者を置く | 検査を通ったartifactだけが本番に出る。それ以外の経路が消える | merge と、Environment の承認 | $0 | A.8.31 / A.8.32 |
| ⑥ 常時監視 | ログは1時間で消える。Sentry も Log Drain も無い | Observability Plus + Sentry + Checkly(外形) | 異常検知・エラー集約・外形監視。P1だけが通知される | 週1回20分(初月の目標値。30日後に実測して見直す) | Sentry $26/月+従量 | A.8.15 / A.8.16 |
| ⑦ インシデント | 仕組みが無い | Vercel Agent Investigation + Claude Code の Channels(Discord) | ログとメトリクスを相関させた一次調査。原因の候補と根拠を出すところまで | 判断・復旧・顧客連絡。DB操作は必ず人間 | $0.30/回 | A.5.24〜27 / A.5.30 |
| ⑧ 監査 | 審査のたびに手で集める | ①〜⑦の記録が自動で貯まる形にし、対応表を1枚持つ | 証跡が勝手に貯まる(PR・Actionsのログ・デプロイ履歴・アラート履歴) | 年1回の棚卸しと、リスク受容の判断 | $0 | A.5.23 / A.8.9 / A.8.15 |
$46〜
固定費の月額合計(Vercel Pro $20 + Sentry Team $26)
8
段階の数
3本
最初に書く自動テストの数
5つ
P1(夜中に起こしてよい)アラートの数
従量課金は別にかかる。Vercel Agent が1回 $0.30 + トークン実費、Log Drains が $0.50/GB、BotID Deep Analysis が $1/1,000回、Observability Plus が $1.20/100万イベント。Pro の $20 には同額の利用クレジットが含まれるので、この規模なら実際の請求は $20 に張り付く可能性が高いが、断定はしない。Spend Management(使用量アラートと上限)は Pro で使えるようになるので、移行したその日に上限を設定する。
無料のままでいいもの / 金を出す価値があるもの
払うのは2つだけ。あとは無料枠で足りる
無料のままでよい(5つ)
1人運用の頻度なら枠に収まる見込み
- ・gitleaks — 秘密情報の検出。GitHubの同等機能は非公開リポだと $19/committer・月
- ・Semgrep Free — 10リポ・10人まで全機能
- ・Socket.dev — 月1,000スキャン
- ・Checkly Hobby — ブラウザ監視 月1,000実行
- ・Axiom Personal — ログ取込 月500GB・保持30日
金を出す(3つ)
合計 $46〜/月 + 従量
- ・Vercel Pro $20/席・月 — 規約の問題であり、同時に監視・WAF・Agent の入口
- ・Sentry Team $26/月 — 無料は月5,000件。有償はユーザー無制限で月50,000件
- ・GitHub Pro — 非公開リポでブランチ保護が使える。月額は公式に記載が見つからず取得できず
当面いらないもの2つ。CodeRabbit Pro($24/人・月。セキュリティ検査はさらに別プラン $40/人・月)と、Advanced Deployment Protection($150/月)。理由は第5章と第10章にある。
従量課金は別にかかる: Vercel Agent $0.30/回+トークン実費、Log Drains $0.50/GB、BotID Deep $1/1,000回、Observability Plus $1.20/100万イベント。Pro の $20 には同額の利用クレジットが含まれる。移行したその日に Spend Management で上限を設定する。
📎 今週やる3つ(順番を変えない)
1. Vercel Pro へ移行する。規約の問題であると同時に、この記事の道具の7割がProのゲートの向こうにある。移行したその日に Spend Management で上限を設定する。
2. Playwright の認可テストを3本書く。「A社のトークンでB社のデータが読めない」「10人未満のグループが数値を返さない」「共有リンクが許可職場以外を返さない」。2026年8月8日に実際に空いていた穴を、機械で二度と開かないように固定する。監視を足すより先にこれをやる。
3. Vercel の Git 連携を切り、GitHub Actions からのデプロイに移す。これで「CIが赤でも main に push すれば本番に出る」が消える。追加費用は0円で、その日のうちに終わる。手順は第7章にそのまま置いた。
この記事で埋まらないものを先に書いておく。①外部の専門事業者による人手の脆弱性診断。②Enterprise でしか使えない機能(チームの Audit Logs・Trusted IPs・Secure Compute)。③1人の組織では、職務の分離が原理的に作れないこと。3つとも、AIを何本重ねても埋まらない。埋まらないものを「埋まった」と書かないことが、ISMSとPマークを持っている事業者にとっては一番効く。
この記事の読み方
| 知りたいこと | 読む章 | そこに何があるか |
|---|---|---|
| 今の構成の何がまずいのか | 第2章 | 実物を読んで見つけた5つの穴。根っこは「自動テストが1本も無い」 |
| CodeRabbit を入れるべきか | 第5章 | AIレビュアー6種の比較と、入れる順序の結論 |
| CIが赤でも本番に出るのを止めたい | 第7章 | Git連携の解除から production-deploy.yml の全文まで |
| 監視は何を入れればいいか | 第8章・第9章 | 何を測るかを先に決める話と、アラートをAIに繋ぐ配線 |
| WAFはどう設定するか | 第10章 | Hobbyは3ルールまで。vercel.json には書けない、という正確な話 |
| ISMS/Pマークの審査でどう説明するか | 第12章 | 管理策番号ごとの証跡の対応表。第三者診断は必須かへの正確な回答 |
| 実際にAIで回している会社はあるのか | 第13章 | 確認できたものと、確認できなかったものを分けて書いた |
| で、明日から何をするか | 第15章 | 30日計画。「終わったと言える条件」を機械で確認できる形にしてある |
→ 次の第2章では、この表の「今のWebTHQ」列を実物で埋める。褒めるべき所と、空いている5つを分けて書く
🔍 今の構成を実物で診断する — 埋まっている所と、空いている5つ
このセクションの3点
① 本番の管理画面とリポジトリを実際に確認。CI5ジョブ・監査ログ追記専用など、1人運用としては既に厚く組んである
② 一方で「本人が公開している3つの穴」に加え、リポジトリを読んで新たに5つ見つかった。その根っこは1つ、自動テストが1本も無いこと
③ 2026年8月8日、認可の穴が4本見つかった。「AIレビューでも本番で叩くまで確定できない」が本記事の出発点
対象システム(記事内では WebTHQ と呼ぶ)は、企業向けストレスチェックの集計を扱う BtoB SaaS で、運営会社は ISMS(ISO/IEC 27001)とプライバシーマークを取得済みである。開発と運用は実質1人。以下は2026年8月15日に本番の管理画面とリポジトリを直接見て確認した事実である。
| 項目 | 内容 | 確認方法(実物) |
|---|---|---|
| フレームワーク | SvelteKit 2 / Svelte 5、@sveltejs/adapter-vercel、runtime nodejs22.x、maxDuration 60、regions: [hnd1] | svelte.config.js |
| ホスティング | Vercel Hobby(Free)プランで本番運用 | 管理画面「admin/system」に明記。CLAUDE.mdにも記載あり |
| DB | Neon PostgreSQL 17 / シンガポール ap-southeast-1(Neonに東京リージョンが無いため) | 接続文字列 |
| リポジトリ | GitHub 非公開。owner は個人アカウント | GitHub API で type: User を確認 |
| デプロイ | git push → Vercel の Git 連携で自動デプロイ | 現行の運用フロー |
| 事業 | 企業向けストレスチェック集計SaaS(BtoB・有償) | 運営会社の公表情報 |
| 運用体制 | 実質1人 | |
| 開発 | Claude Code(メイン)+ Codex CLI(クロスレビュー)の2系統AI | CI設定・スクリプト構成 |
すでに入っているもの — ここは軽く扱わない
1人でここまで組んでいるのは事実として強い。褒めるべき点を先に、実物のファイル名つきで出す。14項目、すべて確認済み。
実物確認済み — 主要6項目
CI 5ジョブ(型/秘密/依存/認可/資料)
push毎に自動実行(ci.yml)
pre-pushゲート
push前に手元で先取りチェック
ignore-scripts
install時の任意コード実行を遮断
セキュリティヘッダー
CSP/HSTS/X-Frame-Options等
テナント分離
全クエリをcompany_idで絞込
監査ログ追記専用
UPDATE/DELETEをDBトリガで拒否
実物の一覧(全14項目) 上6件+残り8件 開く ▾
CI: 型・ビルド — ビルドが通るか・型が壊れていないかを、pushのたびに機械が確認する
npm run build + npm run check(.github/workflows/ci.yml)
CI: 秘密情報 — 作業ツリーとGit履歴に混ざった鍵・トークンを検出する
gitleaks(履歴込み・--exit-code 1)(.github/workflows/ci.yml)
CI: 依存の既知脆弱性 — 公開済みCVEがあるバージョンを使っていないか確認する
npm audit --omit=dev --audit-level=high(.github/workflows/ci.yml)
CI: 認可スコープ — 公開APIで許可職場(workplaces)チェックを書き忘れていないか検査する
check-multi-share-scope.mjs(自作・.github/workflows/ci.yml)
CI: 資料整合性 — 顧客提出資料の記述と実装が一致しているか検査する
check-security-docs.mjs(自作・.github/workflows/ci.yml)
CIの権限 — CIトークンの既定を読み取り専用に落としてある
permissions: contents: read
手元のゲート — pushする前に人の確認を待たず機械が止める
scripts/pre-push-gate.mjs(npm run gate)、scripts/install-hooks.mjs、pre-commitで main 直コミット禁止
依存 — npm install 時のインストールスクリプト(任意コード実行の経路)を塞ぐ
.npmrc に ignore-scripts=true
ヘッダー — ブラウザ側の代表的な攻撃面を塞ぐ。ヘッダーとauthの順序を実測で決めている
HSTS / CSP(frame-ancestors none 等)/ X-Frame-Options: DENY / X-Content-Type-Options / Permissions-Policy / Referrer-Policy。hooks.server.ts で sequence(securityHeaders, authHandle)
認証 — セッション奪取・総当たりへの耐性
JWT(HS256)、httpOnly/secure/SameSite=lax、24時間、残6時間で自動延長。企業ユーザーと管理者は別テーブル・別トークン。bcrypt cost 12
テナント分離 — 会社をまたいだ閲覧を設計上防ぐ
全クエリが company_id で絞り込み
監査ログ — 改ざん不可の記録を残しつつ、記録自体に個人情報を持たせない
audit_logs テーブル。追記専用(UPDATE/DELETEをDBトリガで拒否・実測確認済み)。回答値・氏名・共有トークンは記録しない
プレビュー — 検証環境から本番データへの越境を防ぐ
Vercel Authentication で保護(ssoProtection: all_except_custom_domains)。プレビューDBは本番と別(受検データ0行を実測)
個人情報 — 保存する前段階で個人情報の入り口を絞る
CSV取込時に直接識別子6列(氏名/メール/フリガナ/ユーザー名/パスワード/年齢)をDB保存前に除外。組織名称は保存せずコードのみ
最小人数 — 少人数集計からの個人特定を防ぐ
10人未満のグループはサーバー側で数値を返さない(privacy.ts の MIN_GROUP_SIZE に集約)
保持期限 — 契約ごとの保持ルールをコードで強制する
retention.ts。1週間〜無期限を取引先ごとに設定、期限切れはアクセス時点で除外+削除
バックアップ — 災害復旧の手段はあるが自動実行ではない
npm run db:backup(pg_dump・手動)
実測値 — 利用者が体感する遅延の実態
DBを叩く処理の総応答143〜150ms、初回のみ約1.2秒(関数起動+Neonの5分ゼロスケール復帰)
本人が自分で「まだ機械では止められない」と公開している3つ
CIが赤でも本番に出る
ブランチ保護が未設定
第三者診断は未実施
この3つに加え、2026年8月8日に実際に事故が起きた。許可職場チェックの書き忘れにより、他職場・全社のデータが読める穴が4本見つかった。本人の言葉「AIが4視点でレビューしても、認可の穴は本番で叩くまで確定できなかった」が、この記事の出発点である。
リポジトリを読んで、私(Claude)が見つけた、本人がまだ書いていない5つ
自動テストが1本も無い
vercel.json が無い
ESLintがCIで走らない
Cloudflare時代の残骸
本番ログを誰も読まない
根拠(実装ファイル・詳細) — ①〜⑧ 確認方法の実物 開く ▾
| 項目 | 詳細 |
|---|---|
| ① CIが赤でも本番に出る | main に直接 push すれば本番に出る。デプロイのハード停止は未実装で、Vercelトークンも未設定。 |
| ② ブランチ保護が未設定 | GitHub のブランチ保護がかかっていない。private リポでは有料プランが要ると本人が判断している。 |
| ③ 第三者の脆弱性診断は未実施 | 外部専門事業者による人手の脆弱性診断は、まだ受けていない。 |
| ④ 自動テストが1本も無い | package.json の devDependencies に vitest / playwright / jest が無い。scripts にも test が無い。CIで走るのは build / check / gitleaks / audit / 自作2本のみ |
| ⑤ vercel.json が存在しない | ファイルごと無い。WAFルール・cron・リージョン制御をコードで持てていない(リージョンは svelte.config.js 側にある) |
| ⑥ ESLint がCIで走っていない | npm run lint はあるが ci.yml に無い |
| ⑦ Cloudflare 時代の残骸 | devDependencies に @sveltejs/adapter-cloudflare と wrangler が残っている。使っていない依存はそのまま攻撃面になる |
| ⑧ 本番のログを誰も読んでいない | Log Drain も Sentry も無い。Vercel のランタイムログは短期間で消える |
「4. 自動テストが1本も無い」が全部の根っこである
・機械が合否を出せないと、AIに任せられない
・確認作業が人間に残り続け、可用時間を削る
・5〜8は個別修正で消えるが、4だけは仕組みが要る
14
すでに入っている対策
3
本人が公開している穴
5
実物を読んで新たに見つかった穴
4
2026-08-08 に実際に見つかった認可の穴
ホスティングは Vercel Hobby(Free)。この差が全部の前提になる
Hobby(Free)でも使える
今のWebTHQで使えている範囲
- ・基本監視(保持12時間)
- ・WAFカスタムルール 3本
- ・Attack Challenge Mode
- ・BotID Basic
- ・DDoS緩和
Pro($20/席・月)が必須
第0段階で移行しないと使えない
- ・Observability Plus
- ・Log Drains
- ・Vercel Agent(Code Review/Investigation)
- ・BotID Deep Analysis
- ・Rolling Releases
- ・Spend Management
- ・チーム招待
規約上は商用利用にあたる可能性
・Hobbyは個人・非商用利用限定と規約にある
・有償SaaSの運用は商用利用に該当しうる
・検知されるとデプロイ/アカウントが停止する
・断罪ではなく規約に書いてある事実として提示
規約原文(英語)と ISMS 対応 2026-08-15時点 vercel.com/legal/terms 開く ▾
You shall only use the Services under a Hobby plan for your personal or non-commercial use.
Hobby teams are restricted to non-commercial personal use only. All commercial usage of the platform requires either a Pro or Enterprise plan.
Commercial usage is defined as any Deployment that is used for the purpose of financial gain of anyone involved in any part of the production of the project, including a paid employee or consultant writing the code.
規約違反が検知された場合の措置は「デプロイ/アカウントの一時停止」で、詳細と解消手順はメールで通知される。段階的な警告や猶予期間についての明記は一次情報では確認できなかった。停止されれば全顧客のサービスが同時に止まる。これはセキュリティではなく可用性の話であり、ISMS/Pマークでは A.5.31(法令・契約上の要求事項)と A.5.30(ICTの事業継続)の両方に関わる。
もう1つ食い違いがある。顧客提出資料には「maxDuration 60秒」とあるが、Vercel公式ではHobbyのFunction実行時間は300秒固定である。整合性検査の check-security-docs.mjs は、外部の一次情報との乖離までは見ていない。
→ 次のSection「段階① 開発」では、この章で見つけた根っこ(自動テストが無い)を、最初に何本のテストで、何から埋めるかを具体的に決める。
⌨️ 段階① 開発 — AIが自分で正解を確かめられる状態を作る
このセクションの3点
① 「AIに運用を任せる」前提は機械が合否を出せること。テストが無ければAIやツールを増やしても人間の確認作業は減らない
② 最初のテストは網羅でなくてよい。2026年8月8日の事故(認可の穴4本)を二度と見逃さない「認可の横断テスト」1本から
③ Vercel Agent と Claude Code は、既存のCLAUDE.md/AGENTS.mdをレビュー基準としてそのまま読む
前章で見つけた根っこは「自動テストが1本も無い」ことだった。これが埋まっていない限り、後続の章で挙げる PRレビューAI・プレビュー検証・本番監視は、どれだけ導入しても最終確認が人間の目視のまま残る。段階①「開発」の仕事は、テストを何百本も足すことではなく、AIが自分でパスかどうかを確かめられる境界線を1本引くことである。
最初に書く2種類のテスト
Vitest(ユニット)
関数単位のロジック
- ・MIN_GROUP_SIZE の判定
- ・CSV取込時の識別子除外など
- ・最初に書くもの: 「10人未満は数値を返さない」判定関数の単体テスト
Playwright(E2E)
ブラウザ/APIを実際に叩く
- ・権限とデータの境界を横断的に確認する
- ・最初に書くもの: 認可の横断テスト1本(後述)
最初の1本 — 認可の横断テスト
2026年8月8日の事故は、許可職場チェックの書き忘れにより、他職場・全社のデータが読めたというものだった。本人は「AI 4視点でレビューしても、認可の穴は本番で叩くまで確定できなかった」と書いている。叩かないと確定できないなら、機械に叩かせ続ければよい——これが最初の1本の狙いである。
横断アクセス
10人未満マスク
共有リンクの越境
このコードは疑似コードである。動かす前に4つ要る
・@playwright/test を追加インストール
・playwright.config.ts で baseURL 設定
・テスト用アカウントとシードデータを用意
・仮のURLを実装済みAPIに置換
実装用:認可の横断テストの骨格(技術者向け・開いた人だけ) Playwright 疑似コード 開く ▾
Playwright の骨格(疑似コード)。companyAToken はログイン処理の戻り値、baseURL は playwright.config.ts 側で設定する前提。実際のエンドポイントとレスポンス形式・ログイン処理はリポジトリの実装に合わせて書く。狙いは「3条件を落とさないテストを1本、CIに常駐させる」こと
import { test, expect } from '@playwright/test';
// 2026-08-08 の事故(許可職場チェックの書き忘れ)を機械で再発させないための
// 認可の横断テスト。まずはこの1本から始める。網羅は後回しでよい。
// 前提: playwright.config.ts の use.baseURL に PREVIEW_URL を設定済みであること。
test.describe('認可の横断テスト', () => {
test('A社のトークンではB社のデータを読めない', async ({ request }) => {
// ログイン処理でA社のテストアカウントのトークンを取得する(下記は前処理の例)
const loginRes = await request.post('/api/auth/login', {
data: { company: 'test-company-a', password: process.env.PREVIEW_TEST_ACCOUNT_PASSWORD },
});
const { token: companyAToken } = await loginRes.json();
// dataUrlForCompanyB はB社のシードデータに合わせて用意したエンドポイントに置き換える
const dataUrlForCompanyB = '/api/multi-share/company-b-endpoint';
const res = await request.get(dataUrlForCompanyB, {
headers: { Authorization: `Bearer ${companyAToken}` },
});
expect([403, 404]).toContain(res.status());
});
test('10人未満のグループは数値を返さない', async ({ request }) => {
const res = await request.get('/api/aggregate/small-group');
const body = await res.json();
expect(body.value).toBeUndefined(); // もしくは masked: true 等、実装に合わせる
});
test('共有リンクは許可職場以外のデータを返さない', async ({ request }) => {
const res = await request.get('/api/share/token-scoped-to-workplace-a');
expect(res.status()).not.toBe(200);
});
});AGENTS.md / CLAUDE.md を AI が読む
Vercel Agent は AGENTS.md / CLAUDE.md など14種のガイダンスファイルを優先順位付きで読む(合計50KB上限、2026-08-15時点)。このリポジトリに既にある CLAUDE.md は、新しく何も書かなくてもそのままレビュー基準として機能する。段階③(PRレビュー)でこの前提を使う。
Claude Code は Vercel の公式 MCP サーバーを読み取り専用で繋ぐ。deployment / logs / projects をセッションから直接参照できる(追加料金の明記なし)。書き込みはさせず、原因調査をエディタ内で完結させる。
この章でやらないこと
・テストは3本まで。網羅を先に狙わない
・目標はカバレッジでなく再発防止1点
・ローカル実行で満足せずCIに常駐させる
この1本が、後の段階でどう使われ続けるか
① 開発
テストを書く
Vitest+Playwrightで3本。認可を最優先
② コミット直前
CIで走る
push毎にgitleaks等と一緒に実行
④ プレビュー検証
プレビューで走る
認可E2Eをプレビューの実URLに対して実行
⑤ 本番昇格
本番前に止まる
検査を通った成果物だけが本番に出る
3本
最初に書くテストの本数の上限
1本
認可の横断テスト(最優先)
14種
Vercel Agentが優先順位付きで読むガイダンスファイル
50KB
Vercel Agentが読むガイダンス合計の上限
→ 次のSection「段階② コミット直前」では、この章で書いたテストと、既にある gitleaks / npm audit / authz-scope をどう手元で束ねるかを扱う。
🚧 段階② コミット直前 — 手元で止める(秘密・依存・認可)
このセクションの3点
① 手元で止める仕組みは既に5つ入っている(gitleaks・npm audit・ignore-scripts等)。軽視しない
② 足りないのは2つ。npmのマルウェア検知(Socket.dev)と、コード全般の脆弱性検査(Semgrep)
③ GitHub Secret Scanningは非公開リポで有料。無料のgitleaksを継続。ESLintはCIで未実行、1行で直る
この段階の役割は「PRを作る前に、手元で止められるものは手元で止める」こと。人間が押す必要のない検査を、コミットとpushのあいだに機械的に挟む。WebTHQ にはすでにこの層があり、足りないものだけを足す。
実物確認済み — 手元で止める仕組み10項目
CI: 型・ビルド
build+check を push毎に実行
CI: 秘密情報
gitleaks 履歴込み・exit-code 1
CI: 依存の既知脆弱性
npm audit high以上
CI: 認可スコープ
check-multi-share-scope.mjs
CI: 資料整合性
check-security-docs.mjs
CIの権限
contents: read のみ
手元: push前ゲート
pre-push-gate.mjs
手元: フック導入
install-hooks.mjsで固定
手元: 直コミット禁止
pre-commitフックで拒否
依存のインストール時実行
ignore-scripts=true
これだけ入っている個人運用のリポジトリは多くない。ただし共通の穴が1つある。
穴の詳しい理屈(技術者向け・開いた人だけ) ignore-scripts / authz-scope の限界 開く ▾
ignore-scripts=true は「インストール時に勝手にスクリプトが走る」入口を1つ塞いだだけで、パッケージ本体のコードが読み込まれた後の挙動までは見ていない。同じように認可スコープの自作検査は workplaces の書き忘れという特定のパターンしか見ておらず、それ以外の脆弱性パターン(インジェクション・安全でない直接オブジェクト参照など)は誰も見ていない。
npm audit と Socket.dev は見ている場所が違う
npm audit が見るもの
既に入っている
- ・公開済みの脆弱性データベースに載っているバージョンかどうか
- ・公開済みCVEがあるかだけを判定する
Socket.dev が見るもの
ここに追加する
- ・npmパッケージのマルウェア
- ・不審なインストールスクリプト
- ・難読化されたコード
- ・まだ誰にも報告されていない脅威(auditには出ない領域)
Semgrep(Free Edition)
Socket.dev
詳細(枠・費用・連携方法) Semgrep / Socket.dev 開く ▾
| ツール | 詳細 |
|---|---|
| Semgrep(Free Edition) | 10リポジトリ・10コントリビュータまで、AIクレジット60込み。ルールベースの静的解析(SAST)とAIトリアージ。authz-scope の自作検査ではカバーしていない、コード全般の脆弱性パターンを埋める。この規模での費用: 0円 |
| Socket.dev | 月1,000スキャン・APIクォータ500/時・メンバー3名。npmパッケージのマルウェア・不審なインストールスクリプト・難読化コード(npm auditでは出ない領域)を埋める。この規模での費用: 0円 |
この2つはPR単位で動くが、この段階に置くのは手元の検査を1枚で説明するため。実行自体はCIのPRトリガーで行う。
Semgrepの2つの繋ぎ方は別物
GitHub App連携
ダッシュボードで見るだけ
- ・サインインするだけ・YAML不要
- ・マージを止める力は無い
CI必須チェック(この記事が使う方式)
マージ条件にする
- ・semgrep ci をYAMLで実行
- ・SEMGREP_APP_TOKEN の設定が必須
- ・PRの必須チェックにできる
CIに載せる場合の実物は次の通り。
実装用:Semgrep CI設定(技術者向け・開いた人だけ) YAML 開く ▾
Semgrep Free Edition。10コントリビュータ・10リポジトリまで、AIトリアージ込みで無料
name: Semgrep
on:
pull_request: {}
jobs:
semgrep:
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
steps:
- uses: actions/checkout@v6
- run: semgrep ci
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}GitHub Secret Scanning / Push Protection は入れない。公開リポジトリでは無料だが、WebTHQ のリポジトリは非公開で、非公開リポで使うには GitHub Secret Protection($19/active committer/月)が要る。gitleaks は履歴込みで秘密情報を検出できており、費用は0円のままである。ここで乗り換える理由がない。無駄な出費を止めるのも、この記事が出す答えの一部である。
ESLint は package.json に npm run lint があるのに、.github/workflows/ci.yml のどのジョブからも呼ばれていない。書いてあるのに実行されていないルールは、無いのと同じである。CIの既存ジョブに1行足すだけで直る。
実装用:ci.ymlに1行足す(技術者向け・開いた人だけ) YAML 開く ▾
既存の ci.yml の build/check ジョブに1行足すだけでよい。新しいジョブを増やす必要はない
- run: npm run build
- run: npm run check
- run: npm run lint📎 この段階で今日やる操作
1. Semgrep に GitHub でサインインし、このリポジトリを1つ繋ぐ。10リポ・10コントリビュータまでは無料のままAIトリアージも使える。ただしこれだけではマージは止められない(ダッシュボードで結果が見えるだけ)。
2. 上のYAMLを .github/workflows に置き、Semgrepダッシュボードで発行した SEMGREP_APP_TOKEN をGitHub Secretに設定する。これで semgrep ci がPRの必須チェックとして走り、マージを止められるようになる。
3. Socket.dev の GitHub Integration を入れる。月1,000スキャンの枠なら、個人開発の依存追加頻度では十分に足りる。
4. ci.yml に npm run lint を1行足す。ESLintが「導入済みだが実行されていない」状態を解消する。
→ 次のSection 5では、依頼者が名指しした CodeRabbit を含む AIレビュアー5種を、非公開リポの実費とマージを止められるかで比較し、どれをどの順で入れるかを決める。
🤖 段階③ PRレビュー — AIレビュアー6種を実費で比較する
このセクションの3点
① CodeRabbitを使うべきか: 今すぐではない。まず持っているものを使い、必要が出たときに足す
② CodeRabbitの永続無料は公開リポのみ。非公開のWebTHQは導入するならPro $24/user/月から
③ Copilot code reviewはマージを止められない。Vercel Agentは実際にbuild/test/lintを回す点が違う
「CodeRabbit などを使って監視・セキュリティをもっと良くしたい」というのが依頼の中身なので、ここは名指しされたツールに正面から答える。CodeRabbit を含む主要な AI PRレビュアー6種を、非公開リポジトリで使うといくらかかるかとマージを実際に止められるかの2軸で並べ、最後にどれをどの順で入れるかまで決める。
① 6ツール比較 — 非公開リポの実費とマージを止める力
CodeRabbit
PRレビュー全般・1-click fixes
Claude Code GitHub Action
@claude メンション対応
Vercel Agent Code Review
build/test/lintを回してから提案
Cursor Bugbot
バグ・セキュリティを指摘
Greptile
標準/深いTREXレビュー
GitHub Copilot code review
コメントで指摘
6ツールの詳細(費用・停止力・評価) 非公開リポでの実費 開く ▾
| ツール | 費用/停止力/評価 |
|---|---|
| CodeRabbit | 費用: 非公開は無料枠なし。Pro $24/user/月(年払)、Pro Plus $48、Security $40/user/月は別契約。停止力: PRにチェック表示(ブランチ保護が前提)。評価: 名指しツールだが非公開リポでは初日から有料 |
| Claude Code GitHub Action | 費用: ツール自体は無料。実行分+トークン、または OAuth Token でサブスク定額内消費。停止力: PRチェック表示(ブランチ保護が前提)。評価: 既契約のサブスク枠をそのまま使える。追加固定費0円 |
| Vercel Agent Code Review | 費用: Hobby不可(Pro/Enterprise限定)。1回$0.30固定+トークン実費。停止力: PRコメント+提案。書き込みは人間の承認後。評価: この規模で唯一「検証済みの提案」。Pro移行が前提 |
| Cursor Bugbot | 費用: 取得できず(無料枠の記載なし)。使用量ベースの従量、単価は非公開。停止力: GitHubチェックとして表示される。評価: 単価が読めず、この規模の月額を見積もれない |
| Greptile | 費用: Starter無料(リポ数無制限・月50クレジット・開発者1名)。Pro $30/席/月+追加$1/クレジット。停止力: 取得できず(導入手順・チェック仕様の記載なし)。評価: 無料枠は個人開発の頻度なら足りる可能性、導入詳細は不明 |
| GitHub Copilot code review | 費用: Free不可。Copilot Pro $10/月〜。停止力: 不可。Approve/Request changesを付けないため必須レビューにカウントされない。評価: コメントは出るが必須ゲートにならず、この用途には不向き |
② 判断を左右する5つの事実
CodeRabbitの無料は公開リポのみ
セキュリティ検査は別プラン
Copilotはマージを止められない
Vercel Agentは検証済みの提案だけを出す
Claude Code GitHub Actionはサブスク枠を使える
③ どれをどの順で入れるか
- 1
今すぐ
Claude Code GitHub Action(サブスク枠)
サブスク枠で今日導入。追加費用0円 - 2
Proへ移行後
Vercel Agent Code Review
Pro移行後に追加。$0.30/回+実費 - 3
必要になったら
CodeRabbit Pro
外部レビューが要る時に$24/user/月〜 - 4
見送る(現状)
Bugbot / Greptile / Copilot code review
単価不明、または必須ゲート化できない
導入順の詳しい前提・条件 前提/費用/次へ進む条件 開く ▾
| 段階 | 詳細 |
|---|---|
| 今すぐ: Claude Code GitHub Action(サブスク枠) | 前提: 既にPro/Max/TeamのClaude Code契約があること(ある)。費用: 追加0円(GitHub Actions実行分のみ)。次へ進む条件: @claudeへのメンションで意図通りのレビューが返ることを確認したら次へ。 |
| Proへ移行後: Vercel Agent Code Review | 前提: VercelをHobbyからProへ移行していること。費用: $20/月(Pro)+レビュー1回$0.30+トークン実費。次へ進む条件: Sandbox内で検証済みの提案が実際に役立つと確認したら次へ。 |
| 必要になったら: CodeRabbit Pro | 前提: 外部の協力者・レビュアーにレビュー結果を見せる必要が出たとき、または「他人の目でレビューしている」ことを顧客に説明する必要が出たとき。費用: Pro $24/user/月(年払)〜。セキュリティ検査を足すなら別途$40/user/月。次へ進む条件: 「他人のレビューを買う」必要が明確になった時点で導入する。 |
| 見送る(現状): Cursor Bugbot / Greptile / GitHub Copilot code review | 理由: 単価不明、または必須ゲート化できない。再検討の条件: Bugbotの単価が公開される・Greptileの導入手順が明確になる・Copilotがブロック機能を持つ、のいずれかが変わったら再検討する。 |
$40/user/月(別契約)
$24/user/月(年払)
$30/席/月(50クレジット付)
$10/月〜
サブスク枠内で消費(固定費0)
$0.30/回+トークン実費(従量のみ)
Vercel Agent と Claude Code Action は固定費0で従量。棒の長さは固定費だけを示している。
🚫 AIレビューでは止まらなかった実例
・2026-08-08、認可の穴が4本見つかった
・「AI4視点でも本番で叩くまで確定できず」
・ランタイムの権限文脈はAIレビューでは追えない
📎 結論 — どれをどの順で入れるか
今すぐ: Claude Code GitHub Action をサブスク枠で今日導入(追加費用0円)。
Pro移行後: Vercel Agent Code Review を追加(Sandbox検証つきの提案。$0.30/回+実費)。
今はいらない: CodeRabbit・Bugbot・Greptile・Copilot code review は見送る。
結論の詳しい理由(開いた人だけ) なぜこの順か 開く ▾
Vercel Agent Code Review は Sandbox内で実際に build/test/lint を回してから提案を出すという、他のどのツールにもない特徴がある。これはPro移行そのものが本番昇格(段階⑤)でも前提になる投資である。
CodeRabbit は非公開リポでは初日から有料($24/user/月〜)で、実質1人の運用では「もう一人の独立したレビュアー」という価値の大部分を、Claude Code GitHub Action と Vercel Agent の組み合わせで代替できる。検討し直すのは、外部の協力者にレビュー結果を見せる必要が出たとき、あるいは「第三者のAIレビューを受けている」ことを顧客説明に使う必要が出たときでよい。Cursor Bugbot・Greptile・GitHub Copilot code review は、単価が非公開かマージを止められないかのどちらかの理由で、この規模では見送る。
→ 次のSection 6では、段階④ プレビュー検証を扱う。今は「プレビューを人が見る」で止まっている、この記事のもう一つの大きな穴を埋める。
🧪 段階④ プレビュー検証 — ここが最大の穴。機械が合否を出せない
このセクションの3点
① 今は「プレビューURLを人間が見て、良さそうなら merge」で止まっている。機械が合否を出していない
② 足すのは3つ: ①認可E2E3本 ②Checklyの外形監視(無料枠) ③四半期のZAP Baseline Scan
③ プレビューはVercel Authenticationで保護。保護を外さず機械テストを通す方法は2つ、Hobbyで確実なのは片方だけ
WebTHQ のプレビューは、すでにVercel Authenticationで保護され、プレビューDBも本番と別(受検データ0行)になっている。だが今は人間が目視するだけで、機械が合否を出していない。2026-08-08の認可の穴も、目視では見つからなかった。
今のプレビュー ⇄ 変更後
今のプレビュー
人が目で見るだけ
- ・プレビューURLを人間が開いて目視するだけ
- ・機械が合否を出していない
- ・2026-08-08の認可の穴は目視では見つからなかった
変更後
機械が3本のE2Eで合否を出す
- ・認可E2E3本がプレビューURLに対して実行される
- ・Checklyの外形監視が常時応答を確認する
- ・目視の前に機械の検査を1段挟む
認可の回帰
Playwrightをプレビューに実行
外形監視
Checkly(無料枠)
受動的な脆弱性走査
OWASP ZAP Baseline Scan
10
Checkly無料枠: Uptimeモニター数
10,000
Checkly無料枠: APIチェック 月間実行数
1,000
Checkly無料枠: ブラウザチェック 月間実行数
3
最初に書くE2Eの本数
保護されたプレビューを、機械からどう通すか
機械から保護を通す方法 — 2案
Protection Bypass for Automation
Hobbyでの可否は確認できず
- ・Pro以上での利用は公式に明記
- ・Hobbyでの可否は「取得できず」
- ・自動化トークンをヘッダーに載せる方式
テスト専用アカウントでログイン
今すぐ動く代替経路
- ・CI内でログインしてから検査する
- ・ダミー企業コード・社員番号のみ使用
- ・Protection Bypassの可否が不明でも動く
E2Eの書き込み先は既にあるプレビュー専用のNeon DB(0行から開始)。本番の受検データには触れない。
最初に書くE2Eは3本だけ
認可の横断テスト
10人未満マスクのテスト
共有リンクの職場限定テスト
網羅を目指さない。この3本は「もう二度と起きてほしくない事故」から逆算した3本である。
下のworkflowは、先に4つを用意しないと動かない
・@playwright/test が未インストール
・playwright.config.ts が無い(baseURL未設定)
・テスト用A社・B社アカウントとシードデータが無い
・test:e2e スクリプトが package.json に無い
実装用:preview workflow 全文(技術者向け・開いた人だけ) コード 開く ▾
production-deploy.yml と対になる preview 用ワークフロー。fork由来PRでは production も preview も secrets を渡さない条件を付けている。実行前に @playwright/test の追加・playwright.config.ts・テストアカウント・package.json の test:e2e スクリプトを用意すること(上のdanger参照)
name: Preview deploy
on:
pull_request:
branches: [main]
permissions:
contents: read
jobs:
preview:
# fork由来PRでは secrets を渡さない。内部ブランチPRだけ実行する
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
environment: preview
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci --ignore-scripts
- run: npm run check
- name: Pull preview settings
run: npx vercel@latest pull --yes --environment=preview --git-branch="$GIT_BRANCH" --token="$VERCEL_TOKEN"
env:
GIT_BRANCH: ${{ github.head_ref }}
VERCEL_TOKEN: ${{ secrets.VERCEL_PREVIEW_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
- name: Build
run: npx vercel@latest build --token="$VERCEL_TOKEN"
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_PREVIEW_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
- name: Deploy prebuilt to preview
id: deploy
run: |
url=$(npx vercel@latest deploy --prebuilt --token="$VERCEL_TOKEN")
echo "url=$url" >> "$GITHUB_OUTPUT"
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_PREVIEW_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
- run: npx playwright install --with-deps chromium
- name: 認可E2E 3本をプレビューURLに対して実行
run: npm run test:e2e
env:
PREVIEW_URL: ${{ steps.deploy.outputs.url }}
PREVIEW_TEST_ACCOUNT_PASSWORD: ${{ secrets.PREVIEW_TEST_ACCOUNT_PASSWORD }}fork由来のPRにsecretsを渡さない
・外部PRにVercelトークンを渡さない(if条件を外さない)
・fork PRの検査はsecrets不要な範囲に限定する
四半期に一度、OWASP ZAP Baseline ScanをプレビューURLに回す。攻撃はせず、レスポンスヘッダー等を受動的に確認するだけ。既存のセキュリティヘッダー設定が崩れていないかを無料で定期確認する。
- 1
Step 1
previewを別Vercel Projectに分離
同一Projectなら残余リスクを前提にする - 2
Step 2
認可E2Eを3本書く
横断アクセス/人数マスク/共有リンクの3本 - 3
Step 3
preview workflowを設置
内部ブランチPRで動作確認する - 4
Step 4
Checklyで外形監視
本番のログイン・集計API・共有リンクを確認 - 5
Step 5
ZAP Baseline Scanを四半期実行
手動またはActionsのスケジュールで回す
→ 次のSection 7では、依頼者本人が「まだ機械では止められない」と公開している穴——CIが赤くても main へ push すれば本番に出てしまう経路——を、今日中に閉じる手順を書く。
🚀 段階⑤ 本番昇格 — 「CIが赤でも出せる」を今日で終わらせる
このセクションの3点
① 本人が公開する穴①(CIが赤でもmainへpushすれば本番に出る)を今日の手順で塞ぎ、本番への経路を1本に固定する
② やることは1つ: Vercelとの連携を切り、本番への道をGitHub Actionsの1本のworkflowにする
③ 副作用(PRプレビューが自動で出なくなる)は前Sectionのpreview workflowで埋める。埋めずに連携だけ切らない
今のWebTHQは git push すればVercelのGit連携が検知し、CIのジョブが赤くても、main への push そのものは本番に出る。依頼者本人がこの穴を公開している。本番への道をPR → Actionsの必須検査 → 人間がmerge → 同じActionsが --prebuilt --prod で本番化の1本に固定し、検査を待たずに出る経路だけを外す。
→ この図は横にスクロールできます
上=今の経路。CI(GitHub Actions)は Vercel のデプロイに繋がっておらず、落ちても本番は出る。下=変更後。Vercel の Git 連携を解除し、検査を通った成果物だけが Actions から本番になる。
- 1
Step 1
Vercel Dashboard → Git → Disconnect
Production Branch設定がデプロイの引き金でなくなる - 2
Step 2
Project ID / Team ID を取得
.vercel/project.json 等から取得。commitしない - 3
Step 3
デプロイ専用トークンを発行
用途が分かる名前・短い有効期限で発行 - 4
Step 4
GitHub Environment production を設定
secretとrequired reviewerを設定する - 5
Step 5
production-deploy.yml を置く
既存5検査を通した上でのみ本番デプロイ - 6
Step 6
別リポで先に検証する
本番mainでは試さない。deployが動かないことを確認
実装用:production-deploy.yml 全文(技術者向け・開いた人だけ) コード 開く ▾
.github/workflows/production-deploy.yml — 既存の ci.yml にある5検査(build/check・gitleaks・npm audit・authz-scope・security-docs)を通してから本番化する。検査名は実在のスクリプト名に合わせてある
name: Production deploy
on:
push:
branches: [main]
permissions:
contents: read
concurrency:
group: production-deploy
cancel-in-progress: false
jobs:
verify-and-deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci --ignore-scripts
- run: npm run build
- run: npm run check
# gitleaks は npm パッケージではないので、既存 ci.yml と同じくバイナリを取得して実行する
- name: gitleaks
run: |
VERSION=8.28.0
curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${VERSION}/gitleaks_${VERSION}_linux_x64.tar.gz" -o gitleaks.tar.gz
tar -xzf gitleaks.tar.gz gitleaks
chmod +x gitleaks
./gitleaks detect --source . --redact --exit-code 1
- run: npm audit --omit=dev --audit-level=high
- run: node scripts/check-multi-share-scope.mjs
- run: node scripts/check-security-docs.mjs
- name: Fetch Vercel production settings
run: npx vercel@latest pull --yes --environment=production --token="$VERCEL_TOKEN"
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
- name: Build the artifact Vercel will serve
run: npx vercel@latest build --prod --token="$VERCEL_TOKEN"
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
- name: Deploy exactly that artifact to production
run: npx vercel@latest deploy --prebuilt --prod --token="$VERCEL_TOKEN"
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}Git連携を切ると、PRプレビューが自動で出なくなる
・PRプレビューはGit連携が前提。切った瞬間に止まる
・preview-deploy.yml を同時に導入する(後回しにしない)
代替案を採用しない理由
| 方法 | 評価 | 理由 |
|---|---|---|
| Git連携解除 + vercel deploy --prebuilt --prod | ◎ 採用 | CIで検査した成果物と、本番へデプロイされる成果物を同一jobに固定できる。検査とデプロイの間に別の入力が挟まらない |
| Ignored Build Step に exit 0 | △ 恒久策にしない | Git push のたびにVercelのdeployment自体は作られ、ビルドをスキップするだけの設定になる。CIの合格をVercelへ渡す認可境界にはならない |
| Deploy Hooks | ✕ 作らない | URLを知っているだけでCIを迂回して本番デプロイを起動できる能力になる。既存のフックがあれば無効化する |
| REST API 直叩き | △ 読み取りに留める | bearerトークンでデプロイを作ること自体は可能だが、アップロード・ハッシュ管理を自作する必要があり、CLIより事故面が増える |
実装用:本番昇格の検証手順 全文(技術者向け・開いた人だけ) コード 開く ▾
production-deploy.yml は on: push: branches: [main] でしか起動しない。verify/break-check のようなブランチへ push しても workflow は一度も動かず、確認にならない。方法Aか方法Bのどちらかで、実際に起動する形にする。本番リポジトリの main に壊れたコミットを直接入れる(方法A)ことは絶対にしない
# 方法A: 検証用リポジトリ(本番とは別のリポジトリ)の main で確認する # production-deploy.yml と同じ内容の workflow を検証用リポジトリに置いておく git clone https://github.com/<your-account>/verify-production-deploy.git cd verify-production-deploy echo "const brokenExampleValue: number = 'not-a-number'" >> src/lib/verify-break-check.ts git add src/lib/verify-break-check.ts git commit -m "verify: intentionally break npm run check" git push origin main # Actions の実行結果を確認する gh run list --workflow=production-deploy.yml --limit=1 gh run view --log-failed # npm run check のステップで赤くなり、後続の # vercel pull / vercel build / vercel deploy が # 実行されていない(Actionsの該当ステップが灰色のまま)ことを確認する # 方法B: 本番リポジトリの workflow に一時的に workflow_dispatch を足し、 # 検証用の ref を明示指定して起動する(本番の main には触れない) # # on: # push: # branches: [main] # workflow_dispatch: # inputs: # ref: # required: true git checkout -b verify/break-check echo "const brokenExampleValue: number = 'not-a-number'" >> src/lib/verify-break-check.ts git add src/lib/verify-break-check.ts git commit -m "verify: intentionally break npm run check" git push origin verify/break-check gh workflow run production-deploy.yml --ref verify/break-check gh run list --workflow=production-deploy.yml --limit=1 gh run view --log-failed # 確認後は workflow_dispatch の一時追加を元に戻し、 # 検証用ブランチと verify-break-check.ts を削除する
穴② ブランチ保護が未設定の理由と、閉じ方
本人が「private リポでは有料プランが必要」としている穴②を確認した。origin は個人アカウント(User)配下の非公開リポジトリで、組織(Organization)ではない。GitHub公式は、GitHub Proが非公開リポジトリに追加する機能としてRequired pull request reviewers・Protected branches等を明記している。穴②は、個人アカウントのままGitHub Proに上げれば閉じる。
| プラン | 使える保護機能 | 月額(2026-08-15時点) |
|---|---|---|
| GitHub Free(個人アカウント) | 非公開リポでは不可 | $0 |
| GitHub Pro(個人アカウント) | クラシックのbranch protection可(Rulesetsは不可) | 取得できず |
| GitHub Team/Enterprise(組織限定) | Rulesetsを含め全機能可 | この記事の判断材料にはしない |
Rulesets(新方式)⇄ branch protection rules(クラシック)
Rulesets
公式にTeam/Enterprise向けと明記
- ・個人アカウントのProでは使えない
branch protection rules(クラシック)
Proの個人アカウントで使える
- ・必須チェック未通過のPRをmerge不可にできる
- ・この規模ではこれで十分
📎 1人運用の限界
Required reviewerを1にしても、独立したレビューは生まれない(自己承認が有効な必須レビューとして扱われるかは実機で要確認)。
本人が新しいトークンを発行し vercel deploy --prod を直接叩く経路も、技術的には消えない。
消せない代わりに発見可能にする——Vercelのデプロイ履歴とGitHub Actionsの実行履歴を突き合わせれば、経路外のデプロイは後から分かる。
6
本番昇格の手順ステップ数
2
今日閉じる穴の数(①CIバイパス ②ブランチ保護)
1
残り続ける穴(本人の手元トークン発行は技術的に消せない)
取得できず
GitHub Proの月額(記事に金額を書かない)
→ 次のSection 8では、出たあとのWebTHQを何で見続けるか——Hobbyのログ保持が1時間しかないという事実から始める。
📡 段階⑥ 常時監視 — 何を測り、どこへ流し、誰が読むか
このセクションの3点
① 本番ログは1時間で消える(Hobbyの保持上限)。昨日の障害を後から調べる手段が今は存在しない
② ツールを入れる前に「何を測るか」を7項目に決める。company_id境界に関わる403/404は、この構成で一番見るべき数字
③ まず入れるのはSentry(無料枠あり)。PII scrubberを必ず有効化し、アラートはP1の5つに絞る
今、本番のログは1時間で消えている。Hobby の Runtime Logs 保持は1時間、Observability(基本)も12時間しかなく、昨日の障害を後から調べる手段が無い。この章は①ログの寿命を延ばす、②何を測るか決める、③どこへ流すか決める、④通知を絞るの順で組み立てる。
→ この図は横にスクロールできます
左=本番で出る情報。中央=それを溜める層(Pro が要る)。右上=AIの一次調査(既定は読み取り専用)。右下=人間に鳴らす P1 は5つだけ。
プラン別ログ保持期間の詳細(技術者向け・開いた人だけ) 表 開く ▾
| プラン | Runtime Logs の保持 | Observability(基本)の保持 | Observability Plus |
|---|---|---|---|
| Hobby(今ここ) | 1時間 | 12時間 | 不可 |
| Pro | 1日 | 1日 | 可($1.20 / 100万イベント) |
| Pro + Observability Plus | 30日(連続で選べる幅は最大14日) | 30日 | 同左 |
| Enterprise | 3日 | 3日 | 可 |
| Enterprise + Observability Plus | 30日 | 30日 | 可 |
Vercel側だけで解決すると、Pro($20/月)+ Observability Plus でようやく30日になる。だが弱点は「Vercelの中だけにログを置いていること」自体。保持は、プランではなく外部への転送で解決するのが正しい順番になる。
何を測るか、先に決める
測る対象を決めずにツールを入れると、ダッシュボードだけが増えて誰も見なくなる。この業務(企業向けストレスチェックの集計SaaS)で優先して測るべきは次の7つ。
ログイン成功率
company_id境界の403/404
CSV取込失敗率
集計APIのp75
DB接続エラー
ゼロスケール復帰(初回約1.2秒)
共有リンク発行数と失効
1時間
Hobby の Runtime Logs 保持
12時間
Hobby の Observability 保持
7
この業務で最初に測る指標の数
5
P1として即通知する項目の数
どこへ流すか — まず Sentry
エラー監視の入口はSentryにする。Developer(無料)でもエラー月5,000件・ログ月5GB・リプレイ月50件まで扱える。上限を広げたい場合はTeam $26/月(年払)。
実装用:Sentry導入コマンド(技術者向け・開いた人だけ) コード 開く ▾
SvelteKit 用の公式セットアップウィザード。DSN の取得とinstrumentationの配線まで対話式で進む
npx @sentry/wizard@latest -i sveltekit
PII scrubber を有効化してから使い始める
・健康情報を自動収集しうる。送信前スクラブを必ず有効化
・会社名・従業員番号・回答値の混入経路を導入時に洗い出す
・Sentryの内容はAIエージェントの入力にもなる
ログの寿命を延ばす — Log Drains と Axiom
Runtime Logs を外部へ流すにはLog Drainsが要る(Pro以上・$0.50/GB)。転送先はAxiomを推す。無料で取込月500GB・保持30日を確保でき、Vercelの公式連携先でもある。
| 転送先 | 無料枠 | 有料・備考 |
|---|---|---|
| Axiom | 取込月500GB・保持30日・永続無料 | Cloud $25/月〜(1TB込み)。Vercel公式連携先 |
| Better Stack | ログ月3GB・保持3日 | 従量制。EU$0.10/US$0.15/星$0.35(GB) |
| Datadog | ホスト5台・保持1日 | Pro以上。この規模では過剰 |
アラート設計 — P1は5つだけ
指標を増やすほど通知も増え、全部P1にすると数日で読まれなくなる。P1は次の5つだけに絞る。それ以外はP2/P3として、閾値と継続時間で人間が判断する。
P1
即通知(5つ)
ログイン不能/境界破壊/漏えい疑い/全社集計不能/DB不能
P2
継続時間で判定
5xx率悪化・CSV取込失敗率上昇
P3
日次で確認
p75悪化・ゼロスケール復帰頻度上昇
📎 この章で決めたこと
Hobbyのままでは「昨日の障害」を調べられない。この事実を先に認める。次に何を測るか(7項目)を決め、Sentryでエラーを、Log Drains + Axiomでログを延命する。通知はP1を5つに絞り、それ以外は日次確認に落とす。ツールを入れる前に「見る理由」を先に決めた、というのがこの章の順番である。
→ 次のSection 9では「異常が出た後」を扱う。ここで置いた指標とアラートが、AIエージェントへの一次調査の入口になる配線を描く。
🧯 段階⑦ 異常が出た後 — AIに一次調査をさせる配線
このセクションの3点
① 異常検知からAIの一次調査、人間への通知、修正PRまでを1本の配線として描く。どこにも「AIが承認なしに本番を書き換える」矢印は無い
② Vercel AgentはObservability Plus前提。Claude CodeのChannelsはセッション中のみ届く
③ 「AIが一次対応しPRをマージまで自動で行う」一次資料の公表事例は見つからず。各社の上限は「提案を作るまで」
前章でP1を5つに絞った。ここからは、そのP1が鳴ったあと何が起きるかを配線として決める。異常検知 → Vercel Agent Investigation → Sentry → Discord/Slack → Claude Code の Channels → 人間 → 修正PRという一本の線を描く。この線のどこにも「AIが承認なしに本番を書き換える」矢印は無い。
- 1
① 異常が出る
検知アラートが発火
Sentryのイシューまたは閾値超過(P1の5項目) - 2
② AIが調べる
Vercel Agent Investigationが一次調査
読み取り専用でログ・メトリクスを解析 - 3
③ 人が決める
人間が調査結果と提案を確認
唯一の判断点。採否を人が決める - 4
④ 直す
承認された修正だけがPRになる
本番昇格の1本道(s7)に乗る
実装用:7段階の配線 詳細(技術者向け・開いた人だけ) 詳細7段階 開く ▾
- 1
① 検知
異常検知アラートが発火
Sentryのイシュー発生、またはVercel Observabilityの閾値超過(前章のP1の5項目のいずれか)が起点になる。 - 2
② 一次調査
Vercel Agent Investigation がログとメトリクスを自動でクエリ
Observability Plusのデータを掘り、原因のパターン・相関を分析して根本原因の洞察を出す。Pro以上・Observability Plusが前提。既定は読み取り専用で、ここではまだ何も書き換えない。1回あたり$0.30固定+トークン実費。 - 3
③ 集約
Sentryのイシューに調査結果が集まる
エラーのスタックトレース・発生頻度・影響範囲がSentry側に溜まる。ここがAIと人間の共通の見る場所になる。 - 4
④ 通知
Discord/Slackへ転送
Sentryのアラートルールから、P1相当のイシューだけをDiscord/Slackのチャンネルへ流す。P2/P3は流さない(前章のアラート設計を踏襲)。 - 5
⑤ 実行中セッションへpush
Claude Code の Channels 経由でイベントを受け取る
Discordプラグイン経由で、開いているClaude Codeセッションに通知が届く。リサーチプレビューであり、セッションが開いている間しかイベントは届かない。常時稼働させたい場合はバックグラウンドでセッションを起動しておく必要がある。 - 6
⑥ 人間が読む
人間が調査結果と提案を確認する
ここが唯一の判断点。AIが出した仮説と提案されたパッチを、人間が読んで採否を決める。 - 7
⑦ 修正PR
承認されたものだけがPRになる
Vercel Agentの Approved actions、またはClaude Codeが作るPRのどちらも、人間の承認を経てから本番への道(s7で固定した本番昇格の1本道)に乗る。
Vercel Agent Investigation の事実
前提プラン
さらに前提
料金
書き込み権限
読むもの
この構成(Hobby)でVercel Agent Investigationを使うには、Proへの移行に加えてObservability Plus($1.20/100万イベント)も要る。前章のログ延命の判断と合わせて、Proへ上げる理由が2つ重なることになる。
Claude Code の Channels — 導入手順
実装用:Claude Code Channels 導入コマンド(技術者向け・開いた人だけ) コード 開く ▾
1行目でプラグイン導入、2行目でDiscordトークンを設定、3行目でChannelsを有効にしてセッションを起動する
/plugin install discord@claude-plugins-official /discord:configure <token> claude --channels plugin:discord@claude-plugins-official
Channels の限界を先に知っておく
・リサーチプレビューで仕様が変わりうる
・セッションが開いている間しか届かない
・Sentryの内容はプロンプト注入の経路になりうる
他の選択肢 — Vercel/Claude以外の公式ユースケース
| 選択肢 | 公式に明記されている自動化の範囲 | どこから人間か |
|---|---|---|
| GitHub Copilot coding agent | セキュリティアラートをCopilotに割り当てて修正させる運用(security campaigns)。Issueへのassignee指定、イベント/スケジュール駆動 | PRのレビュー・マージは人間 |
| Devin | CI失敗の自動修正、Datadogインシデントの調査、Slackバグ報告のルーティングが公式ユースケース。Devin APIとAutomationsで完全自動化が可能と公式が明記 | 本番への反映は人間の承認を挟む運用が前提として書かれている(自動マージの範囲は取得できず) |
| Codex cloud | GitHub PR / Linear issue / Slackからのタスク起動が公式 | アラート起点で完全自動にPRを出す運用の明示的記載は確認できず(取得できず) |
AIに触らせてよい範囲
ログ・メトリクスの読み取り
調査結果に基づく修正PRの作成
ロールバック
承認後のみ
本番DBへのSQL実行
不可
Vercel/GitHubの設定変更
承認後のみ
$0.30
Vercel Agent Investigation 1回あたりの固定費(+トークン実費)
5つ
前章で絞ったP1(夜中に起こしてよい)アラートの数
2
承認後のみ許可される操作の数(ロールバック/設定変更)
1
常に不可の操作の数(本番DBへのSQL実行)
「本番のインシデントをAIが一次対応し、AIがPRを出してマージまで自動で行っている」ことを一次資料で確認できる公表事例は、見つからなかった。各社が公式に用意する自律性の上限は「提案を作るところまで」で、本番への書き込みには人間の承認を挟む設計が共通している。「全部AIで完結」を目指すなら、判断の回数を週20分程度まで減らすことを目標に置くほうが実務に合う。
📎 この章で決めたこと
異常検知からAIの一次調査、人間への通知、修正PRまでを7つの矢印で固定した。Vercel Agent Investigationを使うにはProとObservability Plusが要る。Claude CodeのChannelsはリサーチプレビューで、セッションが開いている間しか働かない。「AIが本番まで自動で回す」公表事例は見つからず、各社とも人間の承認を設計上残している。
→ 次のSection 10では、攻撃を受ける側の自動化(Firewall・BotID)を扱う。
🛡️ 攻撃を受ける側の自動化 — WAF・BotID・レート制限をコードで持つ
このセクションの3点
① vercel.jsonにfirewallを書く構文は無い。実体はREST APIかCLIのvercel firewall rules add
② Hobbyはカスタムルール最大3・IPブロック最大3。Proで40/100に広がる。最初は3つに絞る
③ BotID BasicとAttack Challenge Modeは全プラン無料で今すぐ導入可能。DDoS緩和は既に常時オンで入っている
攻撃を受ける側の防御は「常時オンで既に効いているもの」「トグル1つで足せるもの」「JSONルールとしてコードで持つもの」の3層に分かれる。「firewall as code」を vercel.json に書く方法は存在しない。実体は REST API か CLI の vercel firewall rules add --json で、下書き→publishの2段階で反映される。
Hobbyで使える ⇄ Proが要る
Hobbyで使える
0円
- ・プラットフォーム全体のDDoS緩和(大規模TCPフラッド等を自動検知・自動緩和/無料・常時オン)— 既にできている。何もしなくてよい
- ・Firewallカスタムルール 最大3本(path/method/ip/geo/cookie等でdeny/challenge/rate_limit/redirect)— 下の3ルールに使う
- ・Firewall IPブロック 最大3件 — 常時使わず、攻撃時の一時対応用に空けておく
- ・Attack Challenge Mode(訪問者全員に検証チャレンジ、1h/6h/24h)— 攻撃を受けている最中に手動で上げる。既知の正規ボット・検索クローラーは通過
- ・BotID Basic(クライアント側チャレンジでボット検知、無料)— 共有リンクとログインに入れる
Proが要る
または枠が拡張される
- ・Firewallカスタムルール 最大40本(Hobbyの3から拡張)
- ・Firewall IPブロック 最大100件(Hobbyの3から拡張)
- ・BotID Deep Analysis(機械学習でクレデンシャルスタッフィング・API乱用等を追加検知、$1/1,000回)— 今は入れない。Proへ上げた後の検討事項
3
Hobby: Firewallカスタムルール上限
3
Hobby: IPブロック上限
40 / 100
Pro: カスタムルール/IPブロック上限
無料
BotID Basic(全プラン)
最初に入れる3ルール(Hobbyの上限が3だから、3つに絞る)
Hobby のカスタムルールは最大3本という制約そのものが、優先順位を強制してくれる。この業務で守るべき経路は次の3つに絞れる。
ルール1: ログインへのレート制限
path = /api/auth/login
ルール2: 共有リンクへのレート制限
/share/[token] 等
ルール3: 管理画面への制限
path = /admin
3ルールとも、条件(path/method/ip/geo等)をAND/ORで組み、アクション(deny/challenge/rate_limit等)を選んで書く。
実装用:rate_limitパラメータ と JSONルール全文(技術者向け・開いた人だけ) コード 開く ▾
rate_limit は window(10〜3600秒)・requests(1〜10,000,000)・キー(ip / ja4 / header単位)・アルゴリズム(fixed_window / token_bucket)を指定する。
ログインのレート制限ルールの候補。CLI(vercel firewall rules add --json)に渡すルール定義の候補であり、フィールド名・構造は実機の vercel CLI バージョンで確認すること。下書きに追加しただけでは反映されず、publish が必須。REST APIとしての完全な実行例(エンドポイント・認証・project/team指定を含むもの)は取得できず、ここには載せない
# 下書き(ステージング)にルールを追加する。
# フィールド名・構造は候補であり、実機の vercel CLI バージョンで
# vercel firewall rules add --help を確認してから投入すること
vercel firewall rules add --json '{
"name": "rate-limit-login",
"description": "auth/login への総当たり対策",
"active": true,
"conditionGroup": [
{
"conditions": [
{ "type": "path", "op": "eq", "value": "/api/auth/login" }
]
}
],
"action": {
"mitigate": {
"action": "rate_limit",
"rateLimit": {
"algo": "fixed_window",
"window": 60,
"limit": 10,
"keys": ["ip"]
}
}
}
}'
# 下書きの内容を確認する
vercel firewall diff
# 本番に反映する(これをしないとルールは有効にならない)
vercel firewall publishこのJSONをリポジトリに置き、CIから投入する形にすれば、ルールもGit管理下に置ける。手作業でトグルするより「いつ・誰が・何を変えたか」を追える。ただし変更履歴自体はVercelのAudit Log(Enterprise限定)が無いと機械的には残らない(s11の限界として書く)。
BotID Basic
Attack Challenge Mode
Firewallカスタムルール(3本)
実装用:BotID・Firewallルールの詳細(技術者向け・開いた人だけ) 導入手順 開く ▾
BotID Basic
検知: クライアント側チャレンジの整合性検証
費用: 無料(全プラン)
導入:
npm i botid → withBotId()でラップ → initBotId({ protect: [...] }) → サーバー側でcheckBotId()Attack Challenge Mode
検知: 訪問者全員に検証チャレンジ
費用: 無料(全プラン)
導入: ダッシュボード or
vercel firewall attack-mode enableで手動発火。既知の検索クローラー・Webhookプロバイダは通過Firewall カスタムルール(3本)
検知: path/geo条件 + rate_limit/challenge
費用: 無料(Hobby枠内)
導入: JSONをリポジトリに置き
vercel firewall rules add --jsonで投入 → publishBotID の注意点を1つ書いておく。保護対象パスを initBotId に登録していないと checkBotId() は失敗する。ローカル開発では developmentOptions を設定しない限り常に isBot: false になるので、本番挙動の検証は本番相当の環境で行う必要がある。curl で直接叩くテストは本番では弾かれるため、ページからの fetch 経由でテストする。
入れない・作らないと決めたもの
・ja3_digest条件 — Enterprise限定
・bot_name/bot_category条件 — Security Plus限定
・Managed Rulesetの自動有効化 — 判断材料不足で未検討
→ 次のセクション:この防御の裏側で動く鍵(トークン・接続文字列)を、どのAIにどこまで渡してよいかを1行ずつ判定する
🔑 鍵と権限 — AIに渡してよいトークン、渡してはいけないトークン
このセクションの3点
① 書き込み権限・本番デプロイの鍵・本番DBの接続文字列を、1つのAIに同時に渡さない
② GitHub Environmentのproductionにreviewerを付けると、AI製PRにも承認の停止点ができる
③ OIDC・Secure ComputeはEnterprise限定。この規模では接続文字列を環境変数に置くのが規模相応の現実解
今、Vercelの環境変数に入っている秘密は3つ——DATABASE_URL・DATABASE_URL_UNPOOLED(Neonへの接続文字列)・JWT_SECRET(認証トークンの署名鍵)——である。s7の本番昇格を実装すると、ここにVERCEL_TOKEN(本番デプロイ専用トークン)が新しく加わる。増えた分だけ、「どのAIにどこまで見せるか」を先に決めておく必要がある。
このトークンをこのAIに渡してよいか — 1行ずつの判定
9つの秘密 × 渡す先 — 渡してよい(✓) / 条件付き(△) / 渡さない(−)
DATABASE_URL → ローカルのAI CLI
読み取り調査のみ。自動実行のSQLは書かせない
DATABASE_URL → AIレビューbot
差分レビューに本番DB接続文字列は不要
JWT_SECRET → いかなるAI
漏えいで全ユーザーの認証を偽装される
VERCEL_TOKEN → 本番デプロイjobのみ
production Environmentのsecretとして管理
VERCEL_TOKEN → 書き込み権限を持つAI bot
渡すと本番へ直行する経路が1本できる
GITHUB_TOKEN → PRを作成・編集するAI
CI冒頭はread。PR作成jobだけwriteを追加
ANTHROPIC_API_KEY等 → Claude Code GitHub Action
PRの差分読解とコメントのみの権限
Deploy Hook URL → (作らない)
作成自体がCI検査の迂回経路になる
Protection Bypass Secret → preview検証用CIのみ
production用とは別secretで管理
AIに渡してよいもの ⇄ 絶対に渡さないもの
渡してよいもの
用途を限定した上で
- ・ANTHROPIC_API_KEY / CLAUDE_CODE_OAUTH_TOKEN(Claude Code GitHub Action)
- ・GITHUB_TOKEN(スコープを最小に絞った上で)
- ・DATABASE_URL(本番Neon・ローカルの対話環境で読み取り調査に限る)
- ・Protection Bypass Secret(preview検証用ジョブのみ、production用とは別管理)
- ・VERCEL_TOKEN(本番デプロイ専用・production Environmentの中だけ)
絶対に渡さないもの
例外を作らない
- ・JWT_SECRET(いかなるAIにも)
- ・DATABASE_URL(本番Neon)をAIレビューボットへ
- ・VERCEL_TOKEN(本番デプロイ専用)を書き込み権限を持つAIレビューボットへ
- ・Deploy Hook URL(そもそも作成しない)
この判定基準は1つだけである。「そのAI・そのジョブが、その秘密を使わないと本来の仕事ができないか」。できるなら渡す。できないなら渡さない。
止め所は GitHub Environment の required reviewer
1人運用である以上、自分の手元から本番へ直接叩く経路は技術的に消せない(s7と同じ限界)。それでも、AIが作ったPRが自動で本番へ出る経路だけは止められる。GitHub Environment production に VERCEL_TOKEN を置き、required reviewer を設定すれば、デプロイの前に人間の承認が1回必ず挟まる。
pull_request_target は使わない。fork由来のPRでもリポジトリのsecretsを使える権限でワークフローが実行され、PR本文や依存パッケージのREADMEがAIへの入力=プロンプトインジェクションの入口になり得るためである。secretsを使うジョブは通常の pull_request トリガーに限定する。
| 項目 | この規模で使えるか | 理由 / 代替 |
|---|---|---|
| OIDCフェデレーション(短命トークンでの認証) | 技術的には全プラン対応の記載あり。ただし今の構成はNeonへの接続がDB接続文字列前提で、Vercel公式の連携ガイドがあるのはAWS・GCP・Azureと任意APIの4種 | 接続文字列+環境変数のまま運用する。将来Neonが対応すれば見直す |
| Secure Compute(専用VPC・固定IP・長期クレデンシャル不要化) | 不可 | Enterprise限定機能。この規模では手が届かない |
| Vercelトークンをプロジェクト単位に絞れるか | 取得できず | 公式ドキュメントに明記が見つからなかった。トークン発行時のスコープ選択肢を実際に発行する際に確認する必要がある |
| トークンのローテーション運用 | 可・台帳1枚で足りる | 発行日・用途・期限・最終確認日を1枚の表にする。これがそのままISMSの証跡になる(次のsで扱う) |
この章の結論 — 渡さないもの・止め所・台帳
・本番デプロイ鍵とDB接続文字列を同じAI botへ渡さない
・productionのsecretはreviewer承認後のみ使用
・fork PRにはsecretsを渡さない(pull_request_target不使用)
・台帳1枚に発行日・用途・期限を記録(ISMS証跡)
→ 次のセクション:ここまでの①〜⑦の記録を、ISMS・Pマークの審査にどう出すか
📋 段階⑧ 監査 — ISMS/Pマークの管理策に、道具を一対一で貼る
このセクションの3点
① 経産省の情報セキュリティ管理基準13項目と、この構成の道具を対応させた。技術的証跡はまだ2つのみで、方針・手順の充足性は未評価
② 一番深刻な衝突は、A.8.16「監視活動」が求める保持期間と、Vercel Hobbyのログ保持が1時間しかない事実である
③ 第三者脆弱性診断は規格上「外部限定」ではないが「不要」の結論にもならない。必要性はリスクアセスメントで決め記録する
ISMS(ISO/IEC 27001)とプライバシーマークは、あなたの会社が既に取得済みである。したがってこの章の役割は「何を新しく取るか」ではなく、①〜⑦で組んだ仕組みを、審査員にどの管理策の証跡として見せるかを先に決めておくことである。出典は経済産業省「情報セキュリティ管理基準(令和7年改正版)」で、管理策の番号・正式名称・「ぜい弱性」表記はこの基準の表記に一字一句合わせる(原文の出典は下の折りたたみ)。
今すぐ直す(4件)
道具も証跡も無い
記録を作る(8件)
道具はあるが文書が未整備
今ある記録(1件)
証跡まで実測済み
📑 13管理策の対応表(審査で使う人だけ開く) 出典・番号・道具・証跡・現状 開く ▾
出典: 経済産業省「情報セキュリティ管理基準(令和7年改正版)」(令和7年8月29日 経済産業省告示第124号・2025年8月発行、meti.go.jp/policy/netsecurity/is-kansa/IS_Management_Standard_R7.pdf)。管理策の番号・正式名称はこの基準の表記に一字一句合わせている。
| 管理策番号 | 正式名称 | 道具 | 証跡 | 現状 |
|---|---|---|---|---|
| A.5.7 | 脅威インテリジェンス | 定常的な収集体制なし | 脅威情報の収集記録 | 未整備 |
| A.5.23 | クラウドサービスの利用における情報セキュリティ | Vercel/Neonの利用規約・SLAの確認 | クラウド利用方針書、契約書・利用規約、責任分担の整理表 | 契約書は保有。方針書・責任分担表は未文書化 |
| A.5.30 | 事業継続のためのICTの備え | pg_dumpによる手動バックアップのみ | RTO/RPOを定めたICT継続計画書、復旧手順書、試験記録 | RTO/RPO未定義、復旧試験未実施 |
| A.8.8 | 技術的ぜい弱性の管理 | npm audit(CI) | ソフトウェア資産台帳、脆弱性スキャン結果、対応の監査ログ | npm auditのCIログはある。資産台帳と第三者診断は無い |
| A.8.9 | 構成管理 | Gitのコミット履歴+PRレビュー、Vercelの環境変数管理 | 構成管理台帳、全ての構成変更のログ | Gitの履歴が実質的な変更ログ。正式な構成管理台帳は無い |
| A.8.15 | ログ取得 | audit_logsテーブル(追記専用) | ログ取得方針書、ログ実物、改ざん防止設定の証跡 | 追記専用はDBトリガで拒否し実測確認済み。方針書は未文書化 |
| A.8.16 | 監視活動 | Vercel Runtime Logs(Hobby) | 監視記録(定めた保持期間にわたって維持したもの) | Hobbyの保持は1時間。★次項の山場 |
| A.8.25 | セキュリティに配慮した開発のライフサイクル | CLAUDE.md/AGENTS.mdの規約、CIの5ジョブ | セキュアコーディング規程、SDLC手順書、順守確認記録 | CLAUDE.mdが実質的な規程。正式な文書化・順守記録は無い |
| A.8.26 | アプリケーションセキュリティの要求事項 | テナント分離(company_id)、最小人数マスキングの設計 | アプリケーションセキュリティ要求仕様書、設計レビュー記録 | 実装はある。要求仕様書としての文書化はしていない |
| A.8.28 | セキュリティに配慮したコーディング | gitleaks、CIの型チェック | コーディング規約、コードレビュー記録、エラーログのレビュー記録 | CIは動いている。「エラーログを定期的にレビューする」運用は無い |
| A.8.29 | 開発及び受入れにおけるセキュリティテスト | なし(自動テストが1本も無い) | セキュリティテスト計画書、コードレビュー記録 | 段階①で指摘した「自動テストが無い」がここに直結する |
| A.8.31 | 開発環境、テスト環境及び本番環境の分離 | プレビューDBが本番と別(受検データ0行を実測) | 環境分離を示す構成図、本番デプロイの承認記録 | DB分離は実測済み。承認記録は段階⑤の導入待ち |
| A.8.32 | 変更管理 | PRレビュー、CI | 変更管理手順書、変更申請・承認記録、リリースノート | PRは記録として残る。正式な変更管理手順書は無い |
1件
〇 今ある — A.8.15 ログ取得のみ
8件
△ 条件付き — 道具はあるが文書・記録が未整備
4件
✕ 未整備 — A.5.7 / A.5.30 / A.8.16 / A.8.29
1時間
Hobbyのログ保持期間(A.8.16の山場)
山場 — A.8.16「監視活動」とHobbyの1時間
規格が求めるもの ⇄ 今できること
A.8.16が求めるもの
規格の文言
- ・監視を記録する
- ・監視記録は、定めた保持期間にわたって維持する
- ・保持期間の長さは組織がリスクアセスメントに基づき自ら定める設計
今できること(Vercel Hobby)
実態
- ・Runtime Logsは1時間で消える
- ・Observability(基本)の保持上限も12時間
- ・Hobbyの契約範囲内で保持期間を長く設定する手段そのものが無い=「定める」余地が無い
監視記録の保持期間そのものが、Hobbyの上限で決まってしまっている
・保持期間は組織が自ら定める設計(規格は数値を指定しない)
・HobbyはRuntime Logs1時間、Observability基本も12時間が上限
・要配慮個人情報を扱う事業。維持審査で不適合の可能性
・唯一の解消策はObservability Plus(保持30日・Pro以上)
A.8.31 開発・本番環境の分離 — 1人運用でどう説明するか
📎 A.8.31 — 1人運用の限界
Vercel・GitHubのOwnerが本人1人である以上、管理者bypass・CLI/Dashboardからの直接操作という経路は残り、職務の分離を字義通りには満たせない。
required reviewerと一本道のデプロイ経路(段階⑤)は「導入の認可」「環境変更の監視」の証跡候補にはなるが、分離そのものの証明にはならない。
残せるのは①残余リスクの明記、②Vercel/GitHubの実行履歴での発見可能性、③reviewerがPR作成者本人の承認を許していないかの実機確認、の3点である。
プレビューDBが本番と別(受検データ0行を実測済み)であることは、環境分離の物的な証跡として使える。
第三者診断は必須か — 依頼者が一番知りたいこと
規格の原文を厳密に読む限り、「第三者による手動診断が必須」とは書かれていない。ただし「自動化ツールだけで足りる」とも書かれていない。読み取れる範囲を左右で整理する(原文の逐条対応は下の折りたたみ)。
規格の原文から言えること ⇄ 言えないこと
言えること
規格本文に明記あり
- ・侵入テスト・ぜい弱性診断の実施者を第三者に限定していない(8b-8.8.3 e)
- ・ソフトウェア変更の試験は常時でなくリスクベースの要求(8b-8.8.13)
- ・コード分析・脆弱性スキャナ等の自動化ツール利用を明示的に許容(8d-8.29.8)
言えないこと
規格本文に明記なし=取得できず
- ・自動化ツールだけで足りるとは書かれていない(「必要に応じて」が残る)
- ・受入れテストの「独立」が社外第三者を指すかは明記なし(8d-8.29.9 b)
- ・AIレビューが「独立した受入れテスト」を代替できるかを示した公的文書は見つからなかった
📑 第三者診断の論点 — 規格原文の逐条対応(審査で使う人だけ開く) 6論点・原文の該当条項 開く ▾
| 論点 | 規格の原文(該当条項) | 読み取れること |
|---|---|---|
| 侵入テスト・脆弱性アセスメントの実施者(8b-8.8.3 e) | 力量があり認可された者が、計画され、文書化された、再現可能な侵入テスト又はぜい弱性アセスメントを実施する | 実施者を「組織外部の第三者」に限定していない |
| ソフトウェア変更の試験(8b-8.8.13) | 必要に応じて、独立した評価機関がソフトウェアの変更を試験し、妥当性を確認する | 常時ではなく必要に応じて=リスクベースの要求 |
| セキュリティテストの検証手段(8d-8.29.8 参考) | 検証には、コード分析ツール又はぜい弱性スキャナなどの自動化ツールを利用することができる | 自動化ツールの利用を明示的に許容している |
| 受入れテストの独立性(8d-8.29.9 b) | 独立した受入れテストを実施する | 「独立」は開発チームからの独立を指す。社外の第三者であることまでは明記が無い |
| 自動化ツールのみで足りるか | (規格本文に明記なし) | 「必要に応じて」という要求が残る以上、自動化ツールだけで足りるとは書かれていない |
| AIレビューが独立した受入れテストを代替できるか | (規格本文に明記なし) | 明示した公的文書は見つからなかった=取得できず |
プライバシーマーク側 — 委託先の監督、越境移転、容易照合性
| 論点 | 一次情報の規定 | この構成の状態・帰結 |
|---|---|---|
| 委託先の監督(J.9.4)とクラウド事業者 | サービス提供事業者が個人データを取り扱わないことになっている場合は、J.9.4(契約書保存・監督記録)ではなくJ.9.2(安全管理措置=選定時の評価記録)の対象になる(JIPDEC指針)。ただし個人情報保護委員会FAQ Q7-53は「取り扱わないこととなっている場合」の判断を契約条項の定めとアクセス制御の実態に置いている | Vercel/NeonのDPA・利用規約でこの要素(保守用アクセスの範囲、実際のデータ取扱いの有無)を個別に確認していない。「提供に該当しない」と断定はできず、取得できず |
| 越境移転(個人情報保護法28条・Q12-3) | 提供事業者が個人データを取り扱わない契約なら「外国にある第三者への提供」には該当しない。ただし法23条に基づく安全管理措置と、外的環境の把握(Q10-25=サーバ所在国の明示と制度把握内容の本人周知)は別途必要 | Neonのプライマリリージョンはシンガポール(ap-southeast-1)。所在国の明示と、制度を把握した上での安全管理措置の記録が必要 |
| 従業員番号のみ残す状態(容易照合性) | 対応表を組織内に保有し続ける限り、法2条1項1号の「他の情報と容易に照合することができ、特定の個人を識別できる」に該当し、個人情報のままである(個人情報保護法ガイドライン通則編) | 仮名加工情報にもならない(単純な項目削除では加工基準を満たさない)。CSV取込時に氏名・メール等6列を除外している運用は、個人情報保護法上の「非個人情報化」を意味しない、と正確に説明する必要がある |
厚労省「10人以上」の根拠は、規則ではなくマニュアルの解説にある
10人未満のグループに数値を返さない設計(MIN_GROUP_SIZE)の根拠は、労働安全衛生規則第52条の14ではなく、厚生労働省「ストレスチェック制度実施マニュアル」(2015年5月・2016年4月改訂)の解説部分にある——省令の本文には「10人」という数値は無い。マニュアルは「集計・分析の単位が10人を下回る場合には個人が特定されるおそれがある」とし、原則として対象労働者全員の同意が無い限り事業者への提供を禁じている。審査で「なぜ10人か」と問われたときは、規則条文ではなく実施マニュアルの該当ページを示す必要がある(記録の保存も同マニュアルが「5年間保存が望ましい」とする努力義務)。
📎 この章で確定したこと
今この構成に現存する技術的証跡は、audit_logsの追記専用設計(DBトリガで拒否と実測確認済み)とプレビュー環境の分離(受検データ0行を実測済み)の2つだけである。残りの管理策は仕組みの設計はあっても、方針書・手順書・承認記録・レビュー記録がまだ揃っていない。
第三者診断について規格の文言から言えるのは「実施者を組織外部に限定していない」ということだけであり、「不要」という結論にはならない。必要性は自組織のリスクアセスメントで決め、判断とその根拠を記録に残す——これを次の内部監査の議題にする。
→ 次のSection 13では、依頼のもう一つの問い「実在するAI運用があれば教えてほしい」に答える。
🌏 実在する「AIで回している運用」— どこまで自動で、どこから人間か
このセクションの3点
① 「AIが一次対応しPRをマージまで自動で行う」一次資料の公表事例は確認できなかった。無いとは言わない
② 確認できたのは4つ(Vercel Agent・Copilot・Devin・Claude Actions)。いずれも提案止まりで承認が入る
③ 2026年8月時点の相場は「AIで完結」ではなく「人間が判断する回数を減らす」設計である。この記事もその定義で答える
依頼された問いに直接答える。「本番のインシデントをAIが一次対応し、AIがPRを自動で出してマージまで行っている」ことを一次資料で確認できる特定企業の公表事例は、Claude・Codexの双方が独立に調べたが確認できなかった。宣伝記事や匿名の発表は実例として数えていない。無いと断定しているわけではなく、公式ドキュメント・公式ブログ・製品の利用規約の範囲では見つけられなかった、という状態である。
一方で、「ここまでは自動、ここからは人間」という線を公式に引いている製品は複数ある。以下はその実物である。
Vercel Agent
出典: vercel.com/docs/agent
GitHub Copilot coding agent
出典: docs.github.com
Devin
出典: Devin公式ドキュメント(用途・Automationsページ)
Claude Code GitHub Actions(Anthropic)
出典: code.claude.com/docs/en/github-actions
@claudeメンションでPR/Issue対応。マージ権限は導入側のbranch rule次第4製品に共通する形 — 承認の位置は違っても、この3段だけは共通している
各社共通の第1段
AIが提案を作る
ログ・エラー・差分を読み、原因の候補とパッチ/レビューコメントを生成する
共通の第2段
人間が承認する
PRレビュー・required reviewer・Approved Actionsのいずれかで、書き込みを伴う操作の前に人間の判断が挟まる(挟める設計になっている)
共通の第3段
本番に出る
承認を経た変更だけが本番へ反映される。無承認で本番へ書き込む経路を公式に明記した製品は確認できなかった
各社が「人間の承認」をどこに置いているか
4つを揃えて比較すると、承認ステップの置き場所に違いがある。Vercel Agentだけが、承認を製品機能として実装している。Approved Actionsという明示的な仕組みで、書き込みを伴う操作は既定で止まり、人間が承認するまで実行されない。
GitHub Copilot coding agentとClaude Code GitHub Actionsは、承認の設計を利用側のリポジトリ設定(ブランチ保護・required reviewer)に委ねている。製品自体はマージまで自動化できる材料(PR作成・レビューコメント)を用意するが、それを止めるかどうかは導入した組織の設定次第である。
Devinは「CI失敗の自動修正」のように、確認できる範囲では最も自律性の高いユースケースを公式に掲げている。ただし本番への書き込みを人間の承認なしに行うと明記した記述は、本リサーチの範囲では見つからなかった。ここは「自律性が低い」のではなく「公式ドキュメントで明記された範囲を超えて断定できない」という意味での取得できずである。
業界の相場観
2026年8月時点で、製品側が用意している自律性の上限は「提案を作るところまで」であり、本番への書き込みは人間の承認を挟む設計、または承認を挟める設計が各社共通である。これは技術の限界ではない。Vercel Agentが既定を読み取り専用にし、Approved Actionsという承認機構をわざわざ製品機能として持たせているのは、各社がこれを意図的にそう設計しているからだと読める。
したがって「すでに運用しているシステムで、全部AIで完結しているものがあれば教えてほしい」という問いへの答えは、「見つからない」ではなく「そもそも各社が完結の定義をそこに置いていない」という形になる。
「完結」の定義 — 従来のイメージ ⇄ この記事の定義
従来のイメージ「全部AIで完結」
判断の回数/中身/対象範囲
- ・判断の回数: 人間の判断がゼロになる
- ・人間がやることの中身: 障害調査・修正・デプロイの全工程を人間が行う
- ・完結の対象範囲: 本番のインシデント対応まで含めて自動化する
この記事が提案する完結の定義
判断の回数/中身/対象範囲
- ・判断の回数: ゼロにはしない。異常検知のたびに都度対応する状態から、段階⑦で決めたP1アラート5つ+承認操作だけの、週数十分のレビューへ落とす
- ・人間がやることの中身: 承認・却下の意思決定だけに絞る。ログを読む・原因を推測する・パッチを書く作業はAIに渡す
- ・完結の対象範囲: 開発〜PRレビュー〜プレビュー検証までは自動化率を上げる。本番昇格と監査は人間の承認を必須の停止点として残す
📎 依頼への直接回答
「本番のインシデントをAIが一次対応し、AIがPRを自動で出してマージまで行っている」ことを一次資料で確認できる特定企業の公表事例は、確認できなかった。Claude・Codexの双方が独立に調べても見つからなかった、という状態であり、無いと断定はしない。
公表されているのは、Vercel Agentの読み取り専用の異常調査、GitHub Copilot coding agentのセキュリティアラート修正、Devinのインシデント調査・CI修正、Claude Code GitHub ActionsのPR/Issue作業。いずれも「提案・修正案を作るところまで」であり、本番への書き込みは人間の承認、またはリポジトリ側の承認設計を経由する。
→ 次のSection 14では、AIに任せてはいけない線引きを、この構成に合わせて具体的に書く。
🚫 任せてはいけない線引きと、顧客に言ってはいけない主張
このセクションの3点
① AIに渡すのは提案まで。本番DBへの自動SQL実行と、認可・依存・CI設定PRの自動マージは許可しない
② プロンプトインジェクションの入口は複数。fork PRの差分・Issue本文・依存READMEなどAIが読む全テキストが経路になる
③ 「AIが監視」「個人情報は一切残らない」「第三者診断と同等」は言えない。言った瞬間に他の説明まで疑われる
ここまでの13章で、AIに任せる範囲を段階ごとに広げてきた。この章はその逆——どこで止めるかを先に決めておく。Codex(GPT-5.6)が独立検討でも同じ結論に達した上で出した10項目の警告を、WebTHQの実際のファイル・実際の権限に当てはめて書き直す。
Codexの警告10項目 — WebTHQに当てはめる
警告 上位5件 — 今の実装がどう対応しているか
契約権限+本番トークンを同時に渡さない
レビューjobと本番デプロイjobのsecretsを分離
認可/依存/CI変更PRは自動マージしない
hooks.server.ts等は人間がmergeする
pull_request_targetでsecretsを使わない
プロンプトインジェクションの入口として扱う
秘密の値をログ・コメントに出さない
Sentryにトークン形式のマスクを設定
本番DBへのAI自動SQL実行を禁止
四半期毎に隔離DBへ復元演習し記録
📑 警告の残り5件 個人情報・通知・証跡・監査ログ・脆弱性診断 開く ▾
本番の個人情報をAI/ZAP/ログに流さない
Sentry PII scrubberを有効化、ZAP対象はpreviewのみ
通知を全部P1にしない
P1は5つに固定(本節末尾のdangerブロック参照)
AIに「直して」だけで無証跡反映しない
GitHub Environment承認とActionsログを証跡にする
監査ログをaudit_logsだけにしない
DB管理操作・Vercel/GitHub権限変更は別途ログ確認
脆弱性診断を「CI通過だから不要」としない
2026年8月8日の事故もCI・AIレビュー通過後に発生した
プロンプトインジェクション — 入力経路は1つではない
AIエージェントに何かを読ませる場所は、そのままAIへの命令を差し込める場所になる。この構成でAIが読むテキストを洗い出すと、少なくとも4つの経路がある。いずれも「コードではないから安全」と思われがちな場所である。
fork PRの差分
Issue本文
依存パッケージのREADME・ソース
Sentryのエラーメッセージ
対策は「入力を検閲する」ではなく、AIに読ませた結果として何ができるかを狭めておくことである。第9章で書いた「AIに触らせてよい範囲の表」(読み取り=可、PR作成=可、本番DBのSQL=不可、設定変更=承認後)は、プロンプトインジェクションが成立した場合の被害の上限を決める表でもある。入口を全部塞ぐことはできないが、入口の先で何ができるかは決められる。
顧客に言ってはいけない主張
"AIがセキュリティを監視しています"
AIは提案までで、書き込みの承認は人間が行うため
"個人情報は一切残りません"
従業員番号等の識別コードはDBに残るため(第12章)
"第三者診断と同等です"
診断は第三者が行う手続きの名称。AIレビューは代替できない
通知を全部P1にしない — P1はこの5つだけ
・P1: ログイン不能/company_id境界の破壊/漏えい疑い
・P1: 全社集計不能/DB接続不能
・5xx率の上昇やレイテンシ悪化はP2/P3に落とす
・P1を増やすほど本物のP1が埋もれる
この章に書いたことはすべて「今はできない」という宣言である。できないことをできると言わないほうが、できることの価値が正確に伝わる。次の第15章では、ここまでの14章を実際にどの順番で、何日かけて入れるかを書く。
→ 次の第15章では、ここまでの内容をDay単位の30日計画にする。「終わったと言える条件」を機械で確認できる形で書く
🗓️ 30日導入計画 — Day1から順にコマンドで書く
このセクションの3点
① 順序はCodex(GPT-5.6)推奨に従う4週構成:土台→デプロイ経路の一本化→検証と監視→攻撃対策と証跡
② 「終わったと言える条件」はすべて機械で確認できる形にした。「大丈夫だと思う」で先に進める行はこの表に1つも無い
③ 固定費は月額$46〜(Vercel Pro $20+Sentry Team $26)。GitHub Proは個人向け記載が見つからず未取得
第1章の表がこの記事の答えだった。ここではそれをDay単位の作業に分解する(価格は2026年8月15日時点)。本番のデータやトークンを使う作業は、可能な限りテスト用プロジェクト・リポジトリで先に通してから本番へ適用する。
4週間の流れを1行で見せると
Week 1(Day 1〜4)
土台を作る
Vercel Pro / GitHub Proへ移行し、ブランチ保護で直接pushを塞ぐ
Week 2(Day 5〜10)
デプロイ経路を1本化
「CIが赤でも本番に出る」経路を消す
Week 3(Day 11〜17)
検証と監視を機械に渡す
認可E2E・エラー監視・AIレビューを一気に足す
Week 4(Day 18〜30)
攻撃対策と証跡を残す
WAF/SCA・復元演習・証跡台帳で審査に出せる形にする
Week 1(Day 1〜4)土台を作る
GitHub Pro契約(個人アカウント)
mainブランチ保護で直接push禁止
完了条件: 保護ブランチへの直接pushがGitHubにrejectされることを確認
Week 2(Day 5〜10)デプロイ経路を1本化
CIを故意に赤くしデプロイが止まることを確認
preview workflow設置、fork PRはsecrets skipを確認
完了条件: 本番もVercelのGit連携を解除しActions経由に統一
Week 3(Day 11〜17)検証と監視を機械に渡す
Sentry導入、PII scrubberとP1アラート5件設定
Vercel Agent(Code Review)を有効化
完了条件: 認可チェックを壊すコミットで該当テストだけFAIL
Week 4(Day 18〜30)攻撃対策と証跡を残す
Firewall3ルール+BotID Basicを設定
隔離DBへの復元演習を実施
完了条件: ISMS/Pマーク証跡台帳をcommitし各項目にリンクを埋める
📑 Day単位の詳しい計画表(実行する人だけ開く) Day1〜30・所要時間・費用・完了条件 開く ▾
| Day | やること | 所要時間 | 費用 | 終わったと言える条件(機械で確認できるもの) |
|---|---|---|---|---|
| Day 1 | Vercel Hobby → Pro へ移行 | 30分 | $20/席・月 | ダッシュボードのプラン表示が Pro になっている。同日中に Spend Management で使用量の上限アラートを設定した |
| Day 2 | GitHub Pro を契約する(個人アカウント) | 15分 | 取得できず(公式ページに個人向け月額の記載なし) | アカウント設定の Billing 画面に Pro のプランが表示されている |
| Day 3〜4 | private リポジトリでブランチ保護(Protected branches)を main に設定する | 1時間 | $0(Day2の契約に含む) | 保護対象のブランチへ直接 push を試み、GitHubに reject されることをローカルのgitで確認した |
| Day 5〜8 | テスト用プロジェクトで Vercel の Git 連携を解除し、production-deploy.yml で vercel deploy --prebuilt --prod を通す | 4時間 | $0 | production-deploy.yml は push: branches: [main] でしか起動しないため、検証はテスト用リポジトリ自身の main で行うか、一時的に workflow_dispatch を足して検証用refを指定して起動する。その上でCIを故意に赤くし、vercel deployのステップが実行されないことをActionsのログで確認した。通ったら本番プロジェクトでも Disconnect し、同じワークフローを適用した |
| Day 9〜10 | PR用の preview workflow(vercel pull --environment=preview → vercel build → vercel deploy --prebuilt)を設置する | 2時間 | $0 | fork でない PR ではプレビューURLがActionsのログに出力され、fork由来のPRではsecretsを使うstepがskippedと表示されることを確認した |
| Day 11〜13 | Playwrightの認可E2Eを3本書く(認可の横断/10人未満マスク/共有リンクの職場限定) | 3時間 | $0 | 3本ともCIでPASSした状態で、いずれか1本の認可チェックを意図的に壊すコミットを作り、そのテストだけがFAILすることを確認した |
| Day 14〜16 | Sentryを導入しPII scrubberを有効化、P1アラート5つを設定する | 2時間 | $26/月(Team・エラー月50,000件・年払)。無料枠のまま(月5,000件)で始めるなら $0 | Sentryのダッシュボードに5件のアラートルールが登録されている。テスト用の例外を1件発生させ、通知が届くことを確認した |
| Day 17 | Vercel Agent(Code Review)を有効化する | 30分 | $0.30/回+トークン実費 | テスト用PRを作成し、Vercel Agentのレビューコメントがそのプルリクエストに付くことを確認した |
| Day 18〜19 | Semgrep FreeとSocket.dev無料枠をCIに追加、npm run lintをCIジョブに足す | 1時間 | $0 | 既存のPRでSemgrepとSocketのジョブがActionsに追加され、実行結果がPRのチェック一覧に表示されることを確認した |
| Day 20〜21 | Firewallに3ルール(ログインAPIのレート制限/共有リンクAPIのレート制限/管理画面の制限かAttack Challenge待機)とBotID Basicを設定する | 1時間 | $0 | vercel firewall rules ls で3件のルールが登録されていることを確認した |
| Day 22〜25 | 隔離したDBへの復元演習を1回実施する | 半日 | $0(Neonの追加ブランチ費用のみ) | pg_dumpからの復元を実施し、所要時間と復元後の行数が本番と一致することを記録した1件のログが残っている |
| Day 26〜30 | ISMS/Pマークの証跡台帳(1枚)を作り、①〜⑦の記録の置き場所を書き出す | 半日 | $0 | 台帳ファイルがリポジトリにcommitされ、各項目にリンク先(Actionsのrun URL・Sentryのアラート履歴・復元演習のログ等)が埋まっている |
月額の合計
席・月。クレジット$20分込み。超過分は従量
月(年払)。エラー月5,000件までなら無料のDeveloperプランで始めてもよい
固定費の最小合計は $46〜(Vercel Pro + Sentry Team)。GitHub Proの月額は公式価格ページの個人向け欄に記載が見つからず取得できなかったため棒グラフ化していない。Vercel Agent($0.30/回+トークン実費)・Log Drains($0.50/GB、Axiom Personal無料枠を使えば実質$0)・BotID Deep Analysis($1/1,000回、今回のDay計画には未使用)は使用量に比例する従量課金のため、同じ理由で棒グラフ化せずここに文字で残す。
無料のまま運用できるもの: gitleaks、Semgrep Free(10リポ・10コントリビュータ)、Socket.dev(月1,000スキャン)、Checkly Hobby(ブラウザチェック月1,000実行)、Axiom Personal(取込月500GB)、BotID Basic、Attack Challenge Mode、DDoS緩和。現在想定している頻度なら収まる見込みである。使用量アラートと月次の確認を行う。
この記事で埋まらないもの
外部の人手による脆弱性診断
なぜ埋まらないか
Enterprise限定機能(Audit Logs・Trusted IPs・Secure Compute)
なぜ埋まらないか
1人組織での職務の分離
なぜ埋まらないか
📎 この記事の答え(もう一度)
Vercelで全部をAIで運用したい、という依頼への答えは「AIに全部渡す」ではなかった。機械で合否を出せる部分(テスト・SAST・認可E2E・PRレビューの一次提案・ログの相関分析)はAIに渡し、機械で合否を出せない部分(マージの採否・本番DB操作・インシデントの最終判断・第三者診断・職務の分離)は人間に残した。
固定費は月額$46〜。人間に残る定常作業は、初月の目標値として週1回20分の監視確認と月1回のPRレビュー採否だけを見込む。
30日後にアラート件数・PR数・手動介入の時間を実測し、この見積りを見直す。
埋まらない3つは、AIを何本重ねても埋まらない。埋まらないと書くことが、この構成にとって一番効く対策である。
第2章に戻ると、この30日計画がどの穴を塞ぐためのものかを実物のファイルで確認できる
📝 改訂ノート — Codexのクロスレビューで見つかった私の誤り11件
このセクションの3点
① 公開後、別系統のAI(Codex / GPT-5.6)に本文を通しで読ませたところ、重大4件・中6件・軽微1件の指摘が出た。全部反映した
② 一番痛い誤りは自己矛盾。第1章「Hobbyでは監視もWAFも有効化できない」と第10章「3ルールまで使える」が食い違っていた
③ 2番目は検証手順が実行不能だったこと。「CIを赤くして確認」と書いたが、そのworkflowはmain pushでしか動かず一度も走らない
この記事は、私(Claude)が書き、別系統のAIである Codex(GPT-5.6)にクロスレビューさせている。Codex には先に同じ課題を独立して設計させ、その設計書と記事を突き合わせる形でレビューを依頼した。同意できる点は書かなくてよい、指摘だけ書けと指示している。
出てきた指摘を、直した内容とあわせて全部載せる。読者にとって価値があるのは「正しく直った後の記事」だけではなく、どういう種類の間違いが混ざりうるかのほうだからである。
11件
Codexの指摘(全部反映)
4件
そのうち重大
2件
記事内で自分の記述と矛盾していたもの
1件
手順が原理的に実行不可能だったもの
重大4件
① 自分の記事の中で矛盾していた
第1章 ⇄ 第10章
② 検証手順が原理的に動かなかった
第7章・第15章 Day 5〜8
on: push: branches: [main] でしか起動しない。そのブランチに push しても workflow は一度も走らないので、確認そのものが不可能だった。検証用リポジトリ側の main で行うか、workflow_dispatch を一時的に足す形に直した。③ コード例がそのままでは動かなかった
第3章・第6章
companyAToken が未定義のまま使われ、相対URLなのに baseURL の設定が無かった。第6章のworkflowも、リポジトリに @playwright/test が入っていないのに npx playwright test を呼んでいた。「自動テストが1本も無い」と自分で書いた記事の中で、テストがある前提のYAMLを載せていた。前提として先に要るものを明記し、疑似コードであることを書き添えた。④ 規格の解釈を盛っていた
第12章 A.8.31
中・軽微7件
指摘と、直した内容
「完全に閉じる」という表現(第7章)
同じ章の後半で「Ownerのトークン発行経路は消せない」と自分で書いており矛盾。「通常経路を1本に固定し、そこから外れたデプロイを発見可能にする」に変更した
Firewall の JSON を「実際のAPIスキーマ」として出していた(第10章)
正本ではそこまで確認できていない。「CLIに渡すルール定義の候補。フィールド名と構造は実機のCLIバージョンで確認する」に変更し、反映に必要な publish 操作を手順に追加した
Semgrep の説明が記事内で食い違っていた(第4章・第15章)
「サインインして繋ぐだけでYAMLは要らない」と書きながら、同じ章でYAMLを出していた。GitHub App連携(可視化のみ)と、CIの必須チェックとして semgrep ci を走らせる方式を書き分けた
preview 用トークンの分離が甘かった(第6章)
Vercelのトークンをプロジェクト単位に絞れるかは未確認なので、名前を分けても権限は分かれない。第一候補を「preview を別 Vercel Project(可能なら別 Team)に分ける」に変更した
「人間の担当は週20分」という断定(第1章・第9章・第15章)
アラート件数もPR数も測らずに出した見積りだった。「初月の目標値。30日後にアラート件数・PR数・手動介入の時間を実測して見直す」に変更した
「証跡が揃っているのは13項目中2〜3項目」(第12章)
表自身が「方針書は未文書化」「承認記録は導入待ち」としており、揃っているとは言えなかった。「現存する技術的証跡は audit_logs とプレビューDB分離の2つ。方針・手順・承認・レビュー記録の充足性は未評価」に変更した
「無料枠を使い切ることはない」という断定(第15章)
スキャン回数もチェック実行回数もPRの本数次第で消費する。「現在想定している頻度なら収まる見込み。使用量アラートと月次の確認を行う」に変更した
間違え方には型がある
11件を分類すると2種類しかなかった
型A:自分の記述どうしの食い違い
4件(①④と、第7章の「完全に閉じる」、第4章のSemgrep)
- ・章ごとに書いていると、前の章で自分が何と書いたかを忘れる
- ・要約(第1章)と詳細(第10章)で食い違うのが典型。要約は先に書き、詳細は後から調べて書くので、調べた結果が要約に反映されない
- ・機械検証(verify)は構造しか見ない。「Hobbyでは使えない」と「Hobbyでは3本使える」が同じ記事に共存していても PASS が出る
型B:確認できていないことを断定した
7件(②③と、Firewall JSON・preview トークン・週20分・証跡・無料枠)
- ・「たぶんこうだろう」を、確認した事実と同じ書き方で並べてしまう
- ・特に危ないのは、動かしていないコードとYAMLを「これで動く」形で載せること。読者はコピーして実行する
- ・正本データに「取得できず」と書いてある項目でも、本文を書く段になると断定に戻ってしまう
📎 この11件から、次の記事に持ち越すこと
1. 要約は最後に書く。第1章を先に書いて、後の章で調べた結果を反映し忘れる、というのが今回の型Aの正体だった。全章を書き終えてから要約を書き直す工程を入れる。
2. 載せるコードとYAMLは「動かすために何が要るか」を先に書く。動かしていないなら、疑似コードだと明記する。この記事では、自分で「自動テストが1本も無い」と診断した相手に、テストがある前提のYAMLを渡していた。
3. 手順を書いたら、その手順が起動する条件を確認する。②は「workflowのトリガー条件」を読み返せば書く前に気づけた。書いた本人は自分の手順を実行しないので、この種の誤りは自分では見つからない。
4. 別系統のAIに読ませる工程は外せない。11件のうち、私が自分で見つけられたものは1件も無い。
→ 次の第17章は、この記事が「何も知らない高校生に読めるか」の検査。専門用語の言い換えと、詰まる場所の答え合わせを置く
🎒 高校生レビュー — 「文字が多いと読むのをやめる」人に読ませた結果
このセクションの3点
① 別モデル(Codex)に「文字が多すぎると読むのをやめてしまう高校生」として読ませた。離脱ポイントが30箇所出た
② 一番効いた指摘は「カードに変えても、1枚の本文が長ければ段落を縦に読む体験になる。形だけ変わって量が減っていない」
③ 最悪だったのは第12章の13行×5列の表で、10秒で離脱。次が第15章のDay表と、第1章の図と表の二重掲載
この記事は一度、公開してから作り直している。依頼者から「あまりにも文字ばかりで読みにくい」と指摘を受けたからである。そこで、別系統のAIに次の人物設定を渡して読ませた。
「高校生。プログラミングは授業で少し触った程度。そして、文字が多すぎると内容を理解できず、読むのをやめてしまう。」
判定してもらったのは「理解できるか」ではない。最後まで読まれるかである。内容が正しくても、文字の壁があればその時点で失格とした。
30
離脱ポイントの数
10秒
最短で読むのをやめた箇所(第12章の表)
3章
離脱しなかった章(図があった章)
28語
言い換えを用意した専門用語
一番効いた指摘 — 形だけ変えても量は減らない
表をカードに変えた。それでも読まれなかった
やったこと
見た目は確かに変わった
- ・14行の表を チェックリストに置き換えた
- ・6列の比較表を カード6枚に割った
- ・手順を タイムラインにした
言われたこと
25秒で離脱
- ・「チェックを眺める体験ではなく、14段落を縦に読む体験になっている」
- ・「タイムラインにしても各ステップ本文が2〜3文あり、7枚の長い説明カードとして続く」
- ・「dangerの見た目は変わっても、スクロール時には長文の連続でしかない」
ブロックの種類を変えることは、読みやすさの対策ではなかった。効くのは中の文字数を減らすことだけだった。これを受けて、カードの本文は60字以内、チェックリストは30字以内、コードとYAMLと規格の原文はすべて折りたたみへ、という基準で全章を削り直している。
離脱ポイント 上位5箇所と、直したこと
「1画面あたりの文字量」で最悪だった5箇所
第12章 ISMSの13行×5列の表
10秒で離脱。3枚のカードに束ね、詳細表と規格の原文は折りたたみへ移した
第15章 Day1〜30の5列×12行の表
完了条件が1マス内で段落になっていた。週ごと4枚のカードにし、Day表は折りたたみへ
第1章 構成図+7列×9行の表+料金表
同じ内容を図と巨大表で二重に出していた。表を折りたたみへ移し、料金は2枚の比較カードに
第6章 説明3段落+前提4項目+約50行のYAML
コードを折りたたみへ。説明は比較カード1枚に置き換えた
第8章 図のあとに表が4連続
離脱30秒で最長。保持期間の表は折りたたみ、指標はカード、優先度はフロー図に割った
逆に、離脱しなかった場所
読み進められたのは、図がある章だった
第7章
本番昇格の Before / After 図
赤い危険な道と緑の一本道。文章だけより追える
第8章
監視の配線図
左→中央→右で情報の流れが読める
第13章
実在例の問い
「どこまで自動で、どこから人か」が具体的
ただし図にも指摘が付いた。「箱の中に料金・保持時間・サービス名・P1項目まで入れており、図自体の文字密度が高い」。図にすれば安全、ではない。図の中でも文字は減らす必要がある。
専門用語の言い換え(この記事で実際に使っている語)
28語の言い換え表 — 分からない言葉が出てきたら開く たとえ入り 開く ▾
| 言葉 | 高校生向けの言い換え(たとえ入り) |
|---|---|
| Vercel | 作ったWebサイトをインターネット上で動かすための貸し出し場所(文化祭の展示を置く会場) |
| デプロイ | 作った変更を、見る人が使う本番のサイトへ届けること(完成したポスターを廊下に貼る) |
| 本番環境 | お客さんが実際に使うサイト(練習用ではない、本番試合のコート) |
| プレビュー | 本番に出す前に見る試作品のサイト(提出前に先生だけへ見せる下書き) |
| GitHub | プログラムの変更履歴を保管し、仲間と確認するサービス(共同編集できるプログラム用のノート) |
| リポジトリ | プログラム一式とその変更履歴を入れる箱(作品ごとの大きなファイルケース) |
| PR(Pull Request) | 「この変更を本体に入れてよい?」と出す申請(レシート付きで承認を頼む) |
| マージ | 申請が通った変更を本体へ取り込むこと(下書きの修正を正式な原稿に反映する) |
| CI | コードを保存するたびに自動で走る検査(工場の出荷前チェック) |
| テスト | 期待どおり動くかを機械に確かめさせる問題集(毎回同じ小テストを自動採点する) |
| E2Eテスト | 画面を開く所から結果が出る所まで通して試す検査(改札から目的地まで実際に歩く) |
| API | プログラム同士が頼みごとを渡す窓口(店員に注文を渡すカウンター) |
| 認証 | 「あなたは誰か」を確かめること(校門で生徒証を見せる) |
| 認可 | 確かめた相手に「どこまで入ってよいか」を決めること(生徒証を見た後、職員室には入れない) |
| テナント分離 | 会社Aのデータを会社Bから見えないように分けること(同じマンションでも各部屋に鍵がある) |
| WAF | 怪しいアクセスを入口で止める見張り番(校門で不審な人を止める警備員) |
| レート制限 | 同じ相手からの短時間の連打を止めるルール(1人が窓口に何百回も並ぶのを止める整理券) |
| SAST | コードを実行する前に、危ない書き方を探す検査(設計図の段階で危ない配線を探す) |
| ログ | サイトで起きた出来事の記録(防犯カメラの時刻付きメモ) |
| 監視 | 止まったり遅くなったりしていないかを見続けること(保健室の体温計を定期的に見る) |
| アラート | 異常が起きたときの知らせ(火災報知器のベル) |
| トークン | 「この操作をしてよい」と伝える秘密の合鍵(持っている人だけが特定の扉を開けられる札) |
| シークレット | パスワードや合鍵のように、外へ出してはいけない情報(先生しか持たない金庫の番号) |
| OIDC | 長い合鍵を渡しっぱなしにせず、短時間だけ使える入場証を発行する仕組み(試験中だけ有効な入室カード) |
| PII | 氏名など、個人が誰か分かる情報(名札と名簿を結び付けられる手がかり) |
| プロンプトインジェクション | AIに読ませる文章へ悪い命令を紛れ込ませる攻撃(教科書の余白に「先生の指示を無視しろ」と書き込む) |
| 監査・証跡 | 決めたルールを守ったと後で示す記録(提出物を出した日時が残る受領印) |
| ロールバック | おかしくなった時に1つ前の状態へ戻すこと(印刷をやめて前の版に戻す) |
📎 このレビューから持ち越す基準
1. 完成判定は「正確に書けたか」ではなく「最後まで読まれるか」。この記事は、正確さの検査(機械検証20項目)を全部通した状態で、読者に読むのをやめられていた。
2. ブロックの種類を変えるのは対策ではない。効くのは文字数を減らすことと、詳細を折りたたむことだけだった。
3. 図の中の文字も減らす。図にすれば読まれる、ではない。
4. 削る判断を、書いた本人はできない。30箇所の離脱ポイントのうち、私が自分で気づけたものは1つも無かった。
ここまでが全17章。第1章の8段階表に戻れば、明日やることが1行で分かる