Skip to content

fix(infra): ローカル開発の CORS 許可を localhost:8601-8610 に広げる (#1160) - #1161

Merged
takaokouji merged 1 commit into
developfrom
topic/autopilot-1160
Aug 30, 2026
Merged

takaokouji merged 1 commit into
developfrom
topic/autopilot-1160

Conversation

@smalruby3-editor-bot

Copy link
Copy Markdown

概要

ローカルの dev server は 8601 から順に使う(scratch-gui = 8601 / Admin SPA = 8602)。devpod で worktree を並行起動すると 8603 以降も割り当たるが、各 API の CORS 許可はポートが 1〜2 個に固定されていたため、別ポートで立てた途端にローカルから API を呼べなくなっていた。

実際に Admin SPA を 8601 で起動して詰まった:

Access to fetch at 'https://stg.admin.api.smalruby.app/admin/me' from origin 'http://localhost:8601'
has been blocked by CORS policy

Closes #1160

変更

ファイル 内容
infra/{admin,classroom,bug-report}/lib/cors-origins.ts 新規。ポート範囲の生成・ローカル判定・ステージ別の解決を行う純粋関数
同 lib/*-stack.ts 既定オリジンの組み立てを resolveCorsOrigins() に置き換え
同 lambda/tests/cors-origins.test.ts 新規。17 ケース
docs/admin/README.md ローカル開発の手順に「8601〜8610 のどれでもよい」を追記
  • 非 prod の既定 = 本番オリジン + http://localhost:8601〜8610。HTTP API v2 の allowOrigins は完全一致でポートにワイルドカードが使えないため列挙する。
  • prod の既定 = 本番オリジンのみ(localhost を含めない)。classroom / bug-report は既定が stage を見ておらず prod でも http://localhost:8601 を許可していたので、その footgun も直した。
  • prod ガード: CORS_ALLOWED_ORIGINS に localhost / 127.0.0.1 / [::1] が残ったまま prod へ deploy しようとしたら stack が throw する。CORS は「開発中に緩めて戻し忘れる」が起きやすいので、範囲を広げるなら検知する側を対で入れるべきと判断した(既存の DEV_BYPASS_TOKEN prod ガードと同じ思想)。

現行デプロイの挙動は変わらない: classroom / bug-report は .env.<stage>(gitignored)が既定を上書きしているため。admin だけは .env に指定が無く既定がそのまま効くので、stg 再デプロイで 8601〜8610 が有効になる。

検証

プロジェクト tsc --noEmit npm test cdk synth stg cdk synth prod
smalruby-admin ✅ 91 passed(既知の 1 suite は下記) ✅ ✅
smalruby-classroom ✅ 287 passed / 18 suites ✅ ✅
smalruby-bug-report ✅ 70 passed / 3 suites ✅ ✅

synth 済みテンプレートで許可オリジンを確認済み(stg に 8601〜8610 が入り、prod には入らない)。

既知の失敗(本 PR と無関係): cold cache で smalruby-admin の handler-notifications.test.ts が TS2451 で落ちる。これは develop 既存の問題で、修正は未マージの PR #1156 に入っている。重複修正は #1146 でコンフリクトを生んだので、本 PR では触っていない。

マージ後に必要な運用作業(この PR には入らない)

  1. AdminStack-stg を再デプロイ(既定が効くのは admin のみ)。
  2. classroom / bug-report で範囲を効かせたい場合は、.env.stg の CORS_ALLOWED_ORIGINS を更新して stg 再デプロイ(gitignored なのでリポジトリからは変えられない)。
  3. prod の再デプロイは不要(prod の許可オリジンは変わらない)。

レビュー観点

  • prod に localhost が漏れない設計になっているか(既定・env・ガードの 3 経路)
  • ポート範囲の列挙で API Gateway の CORS 設定量が過大になっていないか(10 個)
  • 3 プロジェクトに同じヘルパを複製している点(各 infra が独立 npm パッケージのため。コメントで明記)

dev server は 8601 から順に使う(gui=8601 / Admin SPA=8602)が、devpod で
worktree を並行起動すると 8603 以降も割り当てられる。許可オリジンが 1〜2 個に
固定されていたため、別ポートで立てた途端にローカルから API を呼べなくなっていた。

非 prod の既定に 8601-8610 を並べる。HTTP API v2 の allowOrigins は完全一致で
ポートにワイルドカードが使えないため列挙する。

あわせて classroom / bug-report の既定が stage を見ておらず prod でも
localhost:8601 を許可していたのを stage 対応にし、CORS_ALLOWED_ORIGINS に
localhost が残ったまま prod へ deploy しようとしたら throw するガードを足す
(既存の DEV_BYPASS_TOKEN の prod ガードと同じ考え方)。実デプロイは各
.env.<stage> が上書きしているので現行の挙動は変わらない。

Closes #1160

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@smalruby3-editor-bot

Copy link
Copy Markdown
Author

🤖 敵対的レビュー(自己レビュー): Must 0 件 / Question 2 件 / FYI 3 件

観点は正確性・セキュリティ・再利用/簡潔性・.claude/rules 準拠・テスト/DoD 整合。変更が infra/** なので .claude/rules/infra/development.md(stage 解決順・.env symlink 運用・prod ガードの慣行)と smalruby-classroom.md を読んで照合した。

synth 済みテンプレートで実際の許可オリジンを検証

cdk synth の出力から AllowOrigins を抽出して数えた(この PR の主張が本当かを、コードではなく成果物で確認する):

プロジェクト stg prod
smalruby-admin 11 個(https://smalruby.app + localhost:8601〜8610) 1 個(localhost なし)
smalruby-classroom 3 個(.env.stg 由来・変化なし) 2 個(localhost なし)
smalruby-bug-report 4 個(.env.stg 由来・変化なし) 2 個(localhost なし)

prod にローカルオリジンが 1 つも入らないことを 3 プロジェクトとも確認した。classroom / bug-report の stg が変わらないのは .env.stg が既定を上書きしているためで、PR 本文の記載どおり。

ハンドラ側との整合も確認

CORS_ALLOWED_ORIGINS は Lambda env にも渡り、ハンドラは includes(origin) の完全一致で判定し、非許可時は CORS_ALLOWED_ORIGINS[0] にフォールバックする。今回の並び順は本番オリジンが先頭のままなので、フォールバック値は変わらない(https://smalruby.app)。ここが逆順だと非許可オリジンに http://localhost:8601 を返す実装になっていた。

Question(人間の判断が要る)

[Question] prod ガードは、既存環境の deploy を突然失敗させうる。 CORS_ALLOWED_ORIGINS に localhost が入ったまま prod へ deploy すると throw する。このコンテナ内の .env.prod(admin / classroom / bug-report)は 3 つとも localhost 無しで、現状の prod deploy は止まらないことを確認済み。ただし .env.prod は gitignored で開発者ごとに存在するため、手元の prod env に localhost を書いている人がいると deploy が止まる。意図した安全側の挙動ではあるが、マージ時に一言周知したほうがよい。

[Question] ヘルパとテストを 3 プロジェクトに複製している。 各 infra が独立した npm パッケージで共有モジュールを持てないための妥協で、ファイル冒頭に「変更するときは揃えること」と書いた。将来ズレる余地は残る(例: 一方だけ範囲を広げる)。共有パッケージ化する価値が出るのは infra が増えたときなので今回は複製で通したが、別案があれば従う。

FYI(対応不要と判断)

[FYI] resolveCorsOrigins は重複除去をしない。 既定経路では本番オリジン(https)とローカル範囲(http)が重ならないので重複は生じない。env で重複を書いた場合はそのまま通るが、CORS の挙動は変わらない。

[FYI] stg の CORS 設定が 11 origins に増える。 API Gateway の制限には遠く、synth も通る。ワイルドカードが使えない以上、列挙以外の選択肢が無い。

[FYI] cold cache で smalruby-admin/handler-notifications.test.ts が TS2451 で落ちる。 develop 既存の問題で、修正は未マージの PR #1156に入っている。同じ修正を二重に入れると #1146 と同じマージコンフリクトを作るので、本 PR では触っていない。

DoD 照合

  • Admin SPA を 8601〜8610 のどのポートで立てても stg の Admin API を呼べる(synth で範囲を確認。実地確認は stg 再デプロイ後)
  • prod の許可オリジンに localhost が入らない(既定・env・ガードの 3 経路をテストで固定)
  • ポート範囲の unit テスト(範囲の端・件数・prod で含まれないこと・env 優先・prod ガード)計 17 ケース
  • cdk synth stg / prod ともに 3 プロジェクトで成功
  • npm test: classroom 287 / bug-report 70 / admin 91(既知の 1 suite は上記 FYI)
  • docs/admin/README.md に 8601〜8610 を反映

@takaokouji
takaokouji merged commit 4d0c1f9 into develop Aug 30, 2026
13 checks passed
@takaokouji
takaokouji deleted the topic/autopilot-1160 branch August 30, 2026 00:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(infra): ローカル開発の CORS 許可を localhost:8601-8610 に広げる

1 participant