WebAuthn認証をCIで自動テスト:仮想認証器とMailpit連携で実現するE2E【第2回】

この記事で得られること WebAuthn(パスキー)認証をCI環境でテストする方法 OTPメール取得の自動化(Mailpit API連携) 並列E2Eテストでのメール競合を防ぐテクニック 日本語UIを直接テストするlocale-specific testing はじめに 第1回では、マルチテナントSaaS「Saru」の全体像と自動化戦略を紹介した。今回は、その自動化の核となるE2Eテストの実装詳細を掘り下げる。 特に難しいのが認証フローのテストだ。Saruでは2種類の認証方式を採用している: ポータル 認証方式 難しさ System / Provider OTP + パスキー メール取得、WebAuthn Reseller / Consumer Keycloak OAuth 外部IdP連携 これらをすべてCIで自動テストする方法を解説する。 1. WebAuthn仮想認証器:パスキーをCIでテスト パスキー認証の課題 WebAuthn(パスキー)は物理的なセキュリティキーや生体認証を使う。普通に考えると、CI環境でテストするのは不可能に思える。 解決策:Chrome DevTools Protocol (CDP) の仮想認証器 Playwrightでは、CDPを通じて仮想的な認証器を作成できる。これにより、物理デバイスなしでWebAuthnのフルフローをテストできる。 注意: CDP仮想認証器はChromium系ブラウザ限定の機能。Safari(WebKit)やFirefoxでは使用できない。クロスブラウザ対応が必要な場合、WebAuthnテストはChromiumでのみ実行し、他ブラウザでは認証済み状態をモックする等の対策が必要になる。 実装コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import { test, expect, type BrowserContext } from '@playwright/test'; test('should complete signup with Passkey registration', async ({ page, context }) => { // 仮想認証器を有効化 const cdpSession = await context.newCDPSession(page); await cdpSession.send('WebAuthn.enable'); // 仮想認証器を追加 await cdpSession.send('WebAuthn.addVirtualAuthenticator', { options: { protocol: 'ctap2', // CTAP2プロトコル transport: 'usb', // USB接続をエミュレート hasResidentKey: true, // パスキー対応 hasUserVerification: true, // 生体認証をエミュレート isUserVerified: true, // 常に認証成功 automaticPresenceSimulation: true, // 自動応答 }, }); // ... サインアップフローを実行 ... // Passkey登録ボタンをクリック await page.getByRole('button', { name: 'Passkey' }).click(); // 仮想認証器が自動的に応答し、登録が完了する await expect(page.getByText('Passkey registered')).toBeVisible(); // クリーンアップ await cdpSession.send('WebAuthn.disable'); }); transport設定とサーバー設定の整合性 WebAuthn仮想認証器を設定する際、サーバー側の設定との整合性が重要になる。 ...

January 13, 2026 · 4 分 · ko-chan

1人では保守できない複雑さに自動化で挑む:マルチテナントSaaS開発記【第1回】

この記事で得られること 「1人で作れる規模」を超えたシステムに挑む際の考え方 複雑なマルチテナントシステムの設計概要 手動テストゼロを実現する自動化戦略 はじめに 「1人で保守できないものは作るな」 ソロ開発の鉄則だと思う。でも、あえてその限界に挑戦してみたくなった。 AIコーディングエージェント(Claude Code、GitHub Copilot等)を数カ月実務で使ってきて、「これなら1人でも複雑なものを作れるかもしれない」と思い始めた。ただし条件がある。徹底的な自動化だ。 このブログでは、マルチテナント型サブスクリプション管理システム「Saru」の開発記録を残していく。複雑なシステムを1人で作り切るために、何を自動化し、どう設計したかを共有する。 なぜ「保守できない複雑さ」に挑むのか AIコーディングエージェントで「ちょっとしたもの」ではなく「本格的なもの」を作ってみたい 1人では普通作れない規模のシステムに、自動化でどこまで対抗できるか試したい 失敗しても学びになる。成功すれば再現可能なノウハウになる Saruの複雑さ 4階層のアカウント構造 一般的なSaaSは「管理者 → ユーザー」の2階層。Saruは4階層ある。 階層 役割 説明 System プラットフォーム管理 全体を統括 Provider サービス提供 SaaSや商品を提供 Reseller 販売代理 Providerのサービスを販売 Consumer 購入・利用 サブスクリプションを購入 さらに: ResellerがPROVIDE権限を持つと独自サービスも提供可能 ConsumerがPROVIDE権限を持つとCreator(個人事業者)になれる この柔軟性が複雑さの源泉であり、差別化ポイントでもある。 4ポータル × 4API 各階層に専用のフロントエンドとAPIがある。 ポータル API ポート System Portal system-api 3001 / 8080 Provider Portal provider-api 3002 / 8081 Reseller Portal reseller-api 3003 / 8082 Customer Portal customer-api 3004 / 8083 ポータルは動的サブドメインで分離(例: provider-xxx.example.com) ...

December 20, 2025 · 2 分 · ko-chan