⏱️ この記事を3行でまとめると
① 🔓 第3段階で固めたDataset境界へ正規Guestを実際の業務routeから通し、Guest Demoを一歩前へ進めました。
② 🛡️ 商品表示・商品POST・売上POST・Dashboard・AI promptまで実request経路で確認し、Guest A / BやAdmin間で越境しないことを検証しました。
③ 🧪 pytestは195→201件へ。Codexは使わずChatGPTと相談しながら一つずつ確認し、積み上げてきた自動点検が開発速度にも返ってきたと実感しました。
はじめに
本業でトラックドライバーをしながら、Python / Flaskを中心にWebアプリケーションを個人開発しています。
現在育てているのが、ベーカリー向け売上管理システム sales_data_app です。
商品登録、日々の売上入力、Dashboardでの集計・ランキング、AIによる売上分析などを行えるシステムとして開発しています。
そして現在は、将来このシステムを第三者にも実際に触ってもらえるようにするため、ゲストデモの実装を段階的に進めています。
🔰 pytestやこのシリーズを初めて読む方へ
この記事では pytest を使って、
Guest AがGuest Bのデータを見られないか
不正な商品IDを送っても書き換えられないか
DashboardやAIへ他Guestのデータが混ざらないか
といった、**「起きてほしくない事故」**を自動で確認しています。
pytest は、
PythonのコードやWebアプリが、想定した通りに動くかを自動で確認するためのテストツール
です。
pytestそのものがまだよく分からない方は、こちらの第1段階から読むと流れを追いやすいです。
👉[📝pytestを「事故防止台帳」として育てる 第1段階:3件の簡単なテストを9件の回帰テストへ強化した記録]
もちろん、この第4段階の記事から読んでも追えるように、専門用語はできるだけその場で補足していきます。
前回の第3段階では、
Guestを業務routeへ通す前に、Admin / GuestごとのDataset境界を固める
ところまで進めました。
第3段階終了時点は、
195 passed
です。
ただし、第3段階終了時点では、Guestを商品登録・売上入力・Dashboardなどの業務routeへはまだ通していません。
第3段階までは、
Guestを通す前に、越境できそうな場所を先に潰す
段階でした。
そして今回の第4段階。
いよいよ、
Guestを実際の業務routeへ通します。
📌 この記事での現在地
第3段階までは、
Guestをまだ業務routeへ通さない
↓
Product / DailySales / Dashboard / AI / seed
のDataset境界を先に固める
という段階でした。
今回は、
正規Guestを実際のrouteへ通す
↓
実際のHTTP requestを流す
↓
それでもAdminや他Guestへ越境しないか確認する
段階です。
Guestの有効期限・cleanup・AI利用回数制限などはまだ残っているため、ゲストデモそのものが完成したわけではありません。
ここでいう route は、
商品登録画面、売上入力画面、Dashboard、APIなど、Webアプリ内の入口・処理経路
くらいの意味です。
そして Dataset は今回のシステムでは、
AdminやGuestごとに分けたデータの区画
として使っています。
また、この記事で何度も出てくる HTTP request は、
ブラウザなどからWebアプリのサーバーへ送る「画面を見たい」「データを保存したい」といった要求
くらいの意味です。
今回の開始時点は、
195 passed
最終結果は、
201 passed in 23.83s
でした。
第4段階で増えたpytestは6件です。
ただし、今回も件数を増やすこと自体が目的ではありません。
テーマはこれまでと同じです。
「このGREENは、どの事故を防いでいるのか?」
目次
📌 この記事も長めです。
第4段階では、Guestを実際のrouteへ通したあと、商品・売上・Dashboard・AIまで一つずつ越境確認を行っています。
初めて読む方は上から順番に、前回の続きから読む方や気になる部分だけ確認したい方は、以下のリンクから移動できます。
- 第4段階でやることとまだやらないこと
- 第3段階までで「部屋の境界」は作った
- 第4段階の流れ
- まずGuestを業務routeへ通す
- login_requiredだけでは弱かった
- admin_or_guest_requiredを追加する
- ここからは「Guestを通した状態」で越境を確認する
- 1 Guest AとGuest Bの商品表示を分離
- 一瞬「越境した?」と思う結果が出た
- 原因はproduction codeではなくテスト側だった
- 2 商品POSTの越境を防ぐ
- 3 売上POSTの越境を防ぐ
- 4 Dashboard APIの越境を確認する
- 5 Dashboard HTMLも確認する
- 6 AI promptへ他Guestのデータを混ぜない
- 第4段階のpytest推移
- 実装よりテストの方が多くなった
- 今回はCodexを使わなかった
- 安全確認を自動化していたから速かった
- pytestは目視確認をなくすためではない
- 第4段階で追加した6件
- 第4段階を終えて
- 次は第5段階
💡 目次へ戻りたいとき
目次のリンクから各見出しへ移動したあと、もう一度目次へ戻りたい場合は、ブラウザの「戻る」ボタンを使うと早いです。
マウスに「前のページへ戻る」ボタンがある場合は、それを使うとさらにスムーズです。
スマホ・タブレットならスワイプで目次に戻れます。
第4段階でやることとまだやらないこと
第3段階までに、
Product
DailySales
Dashboard
Dashboard API
AIへ渡す売上データ
seed
をDataset単位へ分離しました。
今回の第4段階では、
/
商品登録・一覧
/input
売上入力
/dashboard
Dashboard
/api/dashboard-data
Dashboard API
/api/ai-advice
AI advice
/api/greeting
Greeting API
を正規Guestから利用できるようにします。
そして、
Guest A → Guest B
Guest A → Admin
Guest B → Guest A
へ越境できないことを、実際のrequest経路で確認します。
一方、まだ以下には進みません。
Guestの有効期限
30分無操作判定
last_activity_at
cleanup
Guestデータ削除
AI利用回数制限
第4段階のテーマは、
Guestを通すこと
だけではありません。
Guestを通しても境界が壊れないこと
です。
第3段階までで「部屋の境界」は作った
Datasetを初心者向けに考えるなら、
利用者ごとの「部屋」
というイメージが分かりやすいと思っています。
PostgreSQL
│
├─ Admin Dataset
│ └─ Product
│ └─ DailySales
│
├─ Guest Dataset A
│ └─ Product
│ └─ DailySales
│
└─ Guest Dataset B
└─ Product
└─ DailySales
第3段階では、
- Product
- DailySales
- Dashboard
- Dashboard API
- AI分析
- seed処理
などが、現在のDatasetを基準に動くよう確認しました。
つまり、
Guest A
↓
Guest A Datasetだけ
Guest B
↓
Guest B Datasetだけ
Admin
↓
Admin Datasetだけ
という内部の境界はかなり固まっています。
pytestも、
181 passed
↓
195 passed
まで増えました。
ただし、第3段階ではまだ、
Guest A本人が
実際のHTTP requestを送る
ところまでは進んでいません。
ここまで来て、ようやく次の問いに進めます。
境界を作ったのは分かった。
では、実際にGuestをrouteへ通しても本当に大丈夫なのか?
第4段階では、この確認に進みます。
💡 RED / GREENって何?
この記事では、
RED
= pytestが失敗している状態
GREEN
= pytestが成功している状態
という意味で使っています。
例えば、
「この操作は拒否されるはず」
↓
実際には通ってしまった
↓
pytest失敗 🔴 RED
問題を修正
↓
期待した通り拒否された
↓
pytest成功 🟢 GREEN
という流れです。
単にGREENを見るだけではなく、何が原因でREDになり、何を直したことでGREENへ変わったのかも確認しながら進めています。
第4段階の流れ
今回の流れを簡単にすると、こうなりました。
開始
195 passed
│
├─ Guestをrouteへ通す
│
│ login_requiredへ変更
│ ↓
│ 2 failed, 193 passed 🔴
│ ↓
│ 原因を確認
│ ↓
│ admin_or_guest_required追加
│ ↓
│ 195 passed 🟢
│
├─ Guest A / Bの商品表示確認
│ ↓
│ 196 passed 🟢
│
├─ 商品POST越境確認
│ ↓
│ 197 passed 🟢
│
├─ 売上POST越境確認
│ ↓
│ 198 passed 🟢
│
├─ Dashboard API分離
│ ↓
│ 199 passed 🟢
│
├─ Dashboard HTML分離
│ ↓
│ 200 passed 🟢
│
└─ AI prompt分離
↓
201 passed 🟢
今回は、第3段階のようにproduction codeのDataset queryを次々と修正するというより、
Guestを通す
↓
実際のrequestを投げる
↓
境界を1つ確認
↓
GREEN
↓
次へ進む
という流れになりました。
ここでいう production code は、
テスト専用のコードではなく、実際のアプリ本体で動くコード
という意味です。
まずGuestを業務routeへ通す
第3段階終了時点では、業務routeに、
@admin_required
が付いていました。
つまり、
Admin → 通る
Guest → 通らない
状態です。
Guest Demoとして第三者に触ってもらうには、
Admin
Guest
の両方を通せる必要があります。
そこで最初に考えたのが、
@login_required
へ変更することでした。
login_required はFlask-Loginが提供する、
ログイン済み利用者だけをrouteへ通すための仕組み
です。
一見すると、
Admin → authenticated
Guest → authenticated
なので、これで良さそうに見えます。
authenticated は、
その利用者が認証済みである状態
くらいの意味です。
しかしpytest全体を実行すると、
2 failed
193 passed
になりました。
REDです。
login_requiredだけでは弱かった
改めて考えると、
ログイン済み
と、
このアプリが正式に認めているAdmin / Guest
は同じではありません。
login_required が主に確認するのは、
現在の利用者が認証済みか
です。
しかし今回必要なのは、
現在の利用者がAdminUserまたはGuestUserなのか
という確認です。
例えば、テスト上で未知の認証済みprincipalを作った場合、
authenticated = True
なら login_required を通過できる可能性があります。
ここでいう principal は、
現在アクセスしている利用者を表す認証主体
くらいの意味です。
Datasetを利用するrouteでは、その後に、
require_current_dataset()
が呼ばれるため、そこで正規のDatasetを解決できなければ止まります。
しかし、
/api/greeting
のようにDatasetを必要としないrouteでは、その防御まで到達しません。
⚠️ 「ログイン済みだから通してよい」とは限らない
今回必要なのは、
ログインしているか
だけではなく、
正規Adminなのか
正規Guestなのか
まで確認することでした。
認証済みという条件だけでは、今回の業務route用ゲートとしては不足していました。
admin_or_guest_requiredを追加する
そこで、
def admin_or_guest_required(view_function):
"""Adminまたは正規Guestだけが業務routeへアクセスできるようにする。"""
@wraps(view_function)
@login_required
def wrapped_view(*args, **kwargs):
principal = current_user._get_current_object()
if not isinstance(principal, (AdminUser, GuestUser)):
abort(403)
return view_function(*args, **kwargs)
return wrapped_view
を追加しました。
これで、
AdminUser
↓
通す
GuestUser
↓
通す
それ以外の認証済みprincipal
↓
403
となります。
対象routeは、
/
/input
/dashboard
/api/dashboard-data
/api/ai-advice
/api/greeting
です。
Datasetを利用するrouteでは、このあとさらに、
require_current_dataset()
で現在のDatasetを解決します。
つまり、
認証
↓
正規Admin / Guestか確認
↓
current Datasetをサーバー側で解決
↓
業務処理
という順番です。
🔐 認証とDataset認可は別々に確認する
今回の構造では、
誰なのか
↓
Admin / Guest判定
どのデータ区画を使うのか
↓
Dataset判定
を分けています。
正規Guestだからといって、好きなDatasetを自由に指定できるわけではありません。
利用するDatasetは、サーバー側で現在の identity から判断します。
ここでいう identity は、
現在アクセスしているのが、どのAdmin / Guestなのかを識別するための情報
くらいの意味です。
ここからは「Guestを通した状態」で越境を確認する
第3段階までは、
内部のDataset queryが正しく分離されているか
をかなり確認していました。
query はここでは、
データベースから、どのデータを取得・操作するか指定する処理
くらいの意味です。
第4段階では、もう一段外側へ出ます。
つまり、
実際のHTTP request
↓
認証
↓
route
↓
Dataset解決
↓
query
↓
response
まで通して確認します。
response は、
requestを受け取ったサーバーが、ブラウザなどへ返す結果
です。
ここからGuest AとGuest Bを実際に作り、
別々の利用者としてアクセスさせます。
内部のqueryだけを見て、
たぶん分離できている
と判断するのではなく、
Guest Aとして実際にアクセスする
↓
Guest Bのデータが見えない
ところまで確認します。
1 Guest AとGuest Bの商品表示を分離
まずは一番基本的な表示です。
Guest A Dataset
└─ GUEST_A_PRODUCT
Guest B Dataset
└─ GUEST_B_PRODUCT
という状態を作ります。
Guest Aで / を開いた場合、
GUEST_A_PRODUCT
↓
見える
GUEST_B_PRODUCT
↓
見えない
という状態である必要があります。
実際のHTTP requestを通したテストを追加し、
196 passed
となりました。
第3段階では内部queryのDataset境界を確認しました。
今回はさらに外側から、
Guest login
↓
route
↓
current Dataset
↓
Product query
↓
HTML response
まで通して確認しています。
一瞬「越境した?」と思う結果が出た
このテストを作っている途中、少し気になる結果が出ました。
Guest AとGuest Bの2つのtest clientを利用したところ、
Guest Bでアクセスしているのに、Guest Aの利用者情報が残っているように見える
状態が出ました。
test client は、
実際のブラウザを使わずに、pytestからWebアプリへrequestを送るためのテスト用ブラウザのようなもの
です。
一瞬、
Guest A
↓
Guest B request
↓
Guest Aのidentityを再利用?
となり、
「Dataset境界を越えた?」
と疑いました。
ただし、ここですぐproduction codeを修正するのは危険です。
本当にアプリ側のバグなのか。
それともテスト環境側の問題なのか。
REDが出たからといって、
RED
↓
production codeが悪い
と決めつけることはできません。
調べていくと、今回の原因はpytest fixture側でした。
原因はproduction codeではなくテスト側だった
fixture は、
テストで何度も使う準備処理をまとめた仕組み
くらいの意味です。
今回のfixtureでは、大まかに、
with app.app_context():
db.create_all()
yield app
db.session.remove()
db.drop_all()
という形で、テスト中のapp contextを保持していました。
app context はFlaskで、
現在どのアプリケーションの処理をしているのかを管理するための実行環境
くらいのイメージです。
Flask-Loginの current_user は、Flaskの g へキャッシュされます。
そのため、2つのtest clientを同じ外側app context内で続けて利用すると、
Guest A request
↓
current_userがgへ入る
Guest B request
↓
同じ外側app context
↓
Guest Aのcurrent_userを再利用したように見える
という、テスト特有の状態が起きました。
そこで各requestを、
with flask_app.app_context():
response = guest_a_client.get("/")
のように、新しいapp context内で実行する形へ変更しました。
すると、
1 passed
になりました。
production codeは変更していません。
🔎 REDだからといって、すぐアプリ本体を直さない
今回のREDは、
アプリ本体のDataset境界が壊れていた
のではなく、
テスト環境のcontextが残っていた
ことが原因でした。
テストはアプリを疑うための道具ですが、
テストコード自身も疑う必要がある
と改めて感じた場面でした。
2 商品POSTの越境を防ぐ
次は、表示ではなく書き込みです。
Guest AからGuest Bの商品IDを直接POSTしてみます。
POST は、
Web画面などからサーバーへ「この内容を保存・更新したい」とデータを送るrequest
です。
例えば、
Guest A
↓
Guest Bの商品IDを指定
↓
商品更新POST
です。
画面上でGuest Bの商品が見えなくても、
product_id
を直接送れば更新できるなら安全ではありません。
期待する結果は、
Guest A
↓
Guest B product_idをPOST
↓
400 または 403
↓
Guest A商品 変更なし
Guest B商品 変更なし
です。
ここでも重要なのは、
拒否されたか
だけではありません。
失敗したあとDBへ副作用を残していないか
まで確認します。
副作用 はここでは、
本来変更されてはいけないDBデータが、途中まで書き換わってしまうこと
くらいの意味です。
結果、
197 passed
となりました。
3 売上POSTの越境を防ぐ
次は /input です。
Guest Aから、
Guest Bの商品ID
quantity = 999
のような売上POSTを送ります。
期待する動作は、
Guest A
↓
Guest Bの商品へ売上入力
↓
拒否
↓
DailySales全体に変化なし
です。
第3段階では、Dataset境界を内部queryレベルで固めました。
今回は、
Guestのログイン状態(session)
↓
実際のHTTP POST
↓
sales route
↓
Dataset確認
↓
DB
まで通して確認します。
ここでいう session は、
ログインしている利用者などの状態を、複数のrequestをまたいで保持する仕組み
くらいの意味です。
結果、
198 passed
となりました。
表示だけではなく、
書き込み経路でもDataset境界を越えられない
ところまで確認できました。
4 Dashboard APIの越境を確認する
次は集計です。
第3段階でも確認しましたが、Dashboardでは、
別Datasetの数字だけが静かに混ざる
問題がありました。
Productそのものが分離できていても、集計queryでDataset条件を付け忘れれば、
Guest A Sales
+
Guest B Sales
がDashboard上で合算される可能性があります。
そこで今回も、混ざったらすぐ分かる値を使います。
Guest A
├─ A専用商品: 11個
└─ クロワッサン: 10個
Guest B
├─ B専用商品: 987654個
└─ クロワッサン: 90個
Guest AのDashboard APIでは、
A専用商品
↓
見える
B専用商品
↓
見えない
だけでなく、
クロワッサン
10個 → 正しい
100個 → 出てはいけない
ことも確認します。
つまり、
Guest A 10
+
Guest B 90
=
100
というDataset越境集計が起きていないかを見ます。
結果、
199 passed
です。
⚠️ 商品名が見えなくても、数字だけ混ざる可能性がある
例えば同名商品なら、
Guest Bの商品名が表示された
とは見えません。
画面には自然な、
クロワッサン 100個
としか出ない可能性があります。
そのため今回も、同名商品をわざと別Datasetへ作って確認しています。
5 Dashboard HTMLも確認する
Dashboard APIが正しくても、
/dashboard
側が別のqueryや処理経路を利用していれば、HTMLへ他Datasetのデータが混入する可能性があります。
そのため、
/api/dashboard-data
だけではなく、
/dashboard
そのものも確認しました。
Guest AのDashboard HTMLに、
Guest Bの商品
Guest B専用の大きな数量
Dataset間で合算された値
が含まれないことを確認します。
結果、
200 passed
となりました。
6 AI promptへ他Guestのデータを混ぜない
最後はAIです。
今回かなり重要だと思っていた部分です。
画面やDashboardへGuest Bのデータが表示されなくても、
Geminiへ送るpromptへ混ざっていたら情報漏えいになります。
今回も実際のGemini API通信は行わず、mockを使います。
mock は、
本物の外部APIを呼ばず、何を渡そうとしたか確認するための代役
です。
例えば、
Guest A
A専用商品: 12
クロワッサン: 10
Guest B
B専用商品: 876543
クロワッサン: 90
とします。
Guest AからAI adviceを実行したとき、
A専用商品
12
クロワッサン 10
はpromptへ入ってよい。
しかし、
B専用商品
876543
クロワッサン 100
は入ってはいけません。
実際にGemini clientへ渡そうとした contents を確認し、
Guest Aのデータ
↓
含まれる
Guest Bのデータ
↓
含まれない
ことを確認しました。
結果、
201 passed
です。
🤖 AI画面だけでなく「送信直前」を確認する
AI機能では、
画面に他Guestデータが出ていない
だけでは不十分です。
今回確認したのは、
Geminiへ送信しようとした最終prompt
です。
実際の外部通信前のデータを確認することで、他Datasetの情報が混ざっていないことをテストしています。
第4段階のpytest推移
今回の増え方はこうなりました。
| 確認内容 | 全pytest |
|---|---|
| 第4段階開始 | 195 |
| Guest A / Bの商品表示 | 196 |
| 商品POST越境防止 | 197 |
| 売上POST越境防止 | 198 |
| Dashboard API分離 | 199 |
| Dashboard HTML分離 | 200 |
| AI prompt分離 | 201 |
最終結果は、
201 passed in 23.83s
です。
今回も、
201件まで増やした
ことが主目的ではありません。
Guestを実際のrouteへ通した状態で、
見る
書く
集計する
AIへ渡す
という各経路から他Datasetへ越境しないことを、一つずつ確認した結果です。
つまり、
pytestが6件増えた
というより、
新しく6件の事故防止項目が
台帳へ追加された
という感覚に近いです。
実装よりテストの方が多くなった
今回のproduction code側で大きかった変更は、
admin_or_guest_required追加
↓
Guest Demo対象routeのdecoratorを変更
です。
ここでいう decorator は、
routeの手前に付けて、ログイン必須・権限確認などの処理を追加する仕組み
くらいの意味です。
今回なら、
@admin_or_guest_required
を付けることで、
AdminUserまたはGuestUserだけを通す
という条件をrouteへ追加しています。
一方、その後のテストでは、
Guest A / Bの商品表示
商品POST
売上POST
Dashboard API
Dashboard HTML
AI prompt
session改ざん
まで確認しました。
つまり、
Guestを通すコードを書くことより、通したあとに何が起こらないかを確認する方へ多く時間を使った
段階です。
ゲストデモでは、むしろこの順番でいいと考えています。
動いた
↓
完成
ではなく、
動いた
↓
越境しないか確認
↓
既存機能を壊していないか確認
↓
GREEN
までを一つの作業として扱います。
今回はCodexを使わなかった
そして第4段階が終わりそうになった頃、ふと気づきました。
「あれ?今回、Codex使ってないじゃん」
第3段階では、Codexをかなり活用しました。
問題をREDで再現
↓
Codexでproduction codeを修正
↓
pytestでGREEN確認
↓
最後にproduction code全体を出口監査
という流れです。
一方、第4段階ではCodexによる実装支援を使いませんでした。
ChatGPTと相談しながらコードを書き、
VS Codeのターミナルで、
変更
↓
pytest
↓
1 passed
↓
結果を目視確認
↓
次の変更
と、一つずつ手動で進めていました。
それでも、第4段階は約2時間で完了しました。
前回の第3段階は、開始から正式完了まで約1時間42分でした。
ただし、
⚠️ 速度比較のために行ったものではありません
第3段階と第4段階では、
作業内容
追加したpytest数
production codeの修正量
が異なります。
最初から、
Codexあり
vs
Codexなし
を比較するために進めたわけでもありません。
第4段階が終わりそうになってから、
今回Codex使っていなかった
ことに気づいただけです。
そのため、単純な性能比較として扱うものではありません。
それでも、自分の開発記録として面白かったのは、
今回はCodexを使わなかった。それでも開発速度は大きく落ちなかった。
という点でした。
安全確認を自動化していたから速かった
なぜ、ターミナルで一つずつ手動確認しながら進めても、それほど時間が掛からなかったのか。
自分の中では、これまで積み上げてきたpytestの存在がかなり大きかったと思います。
以前なら、コードを変更するたびに、
商品登録画面を開く
↓
操作する
↓
売上入力画面を開く
↓
操作する
↓
Dashboardを見る
↓
認証を見る
↓
DBを見る
↓
修正する
↓
もう一度最初から確認
という作業が必要でした。
今は違います。
今回変更した箇所
↓
対象pytest
関連する機能
↓
関連pytest
最後
↓
pytest全体
という形で確認できます。
今回も小さな確認ごとに、
1 passed
を目視しながら進めました。
最後には、
pytest -q
を実行し、
201 passed in 23.83s
を確認しています。
つまり、
安全確認を省略して速く進めたわけではありません。
これまでAIも使いながら、
毎回人間が繰り返していた安全確認をpytestへ移してきた
ことで、今回の確認速度につながりました。
自分の中では、
「AIエージェントを使ったから速かった」のではなく、
「AIエージェントも使いながら安全確認を自動化してきたから速かった」
という感覚に近いです。
これまで積み上げてきたpytestという安全網が、
次の開発を速くするための資産
として返ってきたように感じました。
pytestは目視確認をなくすためではない
ただし、自動テストが増えたからといって、
人間は何も確認しなくていい
とは考えていません。
今回も、
pytestを実行
↓
結果を見る
↓
想定した結果になっているか確認
↓
次へ進む
という形で、自分自身でも一つずつ結果を目視確認しました。
本業のトラック運転でも、
決められた点検
安全装置
確認手順
があるからといって、
最後に自分の目で周囲を確認しなくてよいわけではありません。
自動化できる確認は仕組みに任せる。
そのうえで、
今回どこを変えたのか
どこが危ないのか
テスト結果は本当に意図したものか
は人間が見る。
自分にとってpytestは、
目視確認をなくすためのものではなく、目視確認する場所を絞るためのもの
になってきました。
🚛 安全確認を減らすのではなく、役割を分ける
繰り返し確認できる部分
↓
pytest
今回変更した部分
想定外の挙動
最終判断
↓
人間
という役割分担です。
安全確認を省略したから速いのではなく、安全確認を自動化してきたから速い。
今回かなり実感できた部分でした。
第4段階で追加した6件
今回、第4段階で新しく増えたpytestは6件です。
Guest A / Bの商品表示 +1
商品POST越境防止 +1
売上POST越境防止 +1
Dashboard API分離 +1
Dashboard HTML分離 +1
AI prompt分離 +1
────────────────────────────
合計 +6
結果として、
195 passed
↓
201 passed
となりました。
ただし、自分としては、
6件増えた
という数字より、
実際のGuest request
商品書き込み
売上書き込み
Dashboard
AI
まで事故防止台帳の対象を広げられたことを重視しています。
第4段階を終えて
第3段階では、
Guestを通す前に
内部のDataset境界を固める
ところまで進めました。
今回の第4段階では、
実際にGuestを通す
↓
HTTP requestを通す
↓
商品表示を確認する
↓
POSTを試す
↓
Dashboardを確認する
↓
AI promptを確認する
ところまで進みました。
最終結果は、
201 passed in 23.83s
です。
✅ 第4段階で確認できたところ
正規Guestの業務routeアクセス ✅
未知principalの拒否 ✅
Guest A / Bの商品表示分離 ✅
商品POST越境防止 ✅
売上POST越境防止 ✅
POST失敗時のDB不変 ✅
Dashboard API分離 ✅
Dashboard HTML分離 ✅
同名商品の越境合算防止 ✅
AI promptへの他Guest混入防止 ✅
Admin昇格防止 ✅
pytest 201件 ✅
第3段階が、
ゲートを開ける前の安全確認
だとすれば、
第4段階は、
実際にゲートを開けて
境界が守られるか確認した
段階です。
今回一番印象に残ったのは、
「Guestが動いた」ことだけではありません。
Guestを実際に通した状態で、
他Guestの商品は見えない
他Guestの商品は更新できない
他Guestへ売上入力できない
Dashboardへ混ざらない
AI promptへも混ざらない
ところまで確認できたことです。
そしてもう一つ。
第4段階が終わりかけたところで、
「そういえば今回、Codex使ってないな」
と気づきました。
それでも大きく速度が落ちなかった。
これまで、
面倒でもpytestを増やす
↓
GREENでも疑う
↓
弱い条件を探す
↓
安全確認を自動化する
という下積みを続けてきた効果が、今回かなり見えた気がします。
安全確認を省略して速く進めるのではなく、安全確認を自動化したから速く進められる。
今回の第4段階は、そのことを実感できた段階でもありました。
次は第5段階
第2〜4段階の変更はmainへ統合しました。
第4段階まで統合したmainでも、
201 passed
を確認しています。
そして最新mainから、
feature/guest-demo-stage5
ブランチを作成しました。
次は第5段階です。
まだ、
Guest期限切れ
30分無操作
last_activity_at
cleanup
Guestデータだけの安全な削除
AI利用回数制限
などが残っています。
ゲストデモは、かなり実際に触れる形へ近づいてきました。
ただし、
動くようになった
↓
公開
とはしません。
ここからも、
新しい機能を追加
↓
新しい事故候補を考える
↓
pytestへ追加
↓
GREEN確認
を繰り返します。
引き続き、
安全第一⛑️
で進めます。
👤ゲストデモモード搭載シリーズ
第1段階
既存AdminデータをDatasetへ移行し、Guest領域を作る前の土台を整えました。
第2段階①
Guestを入れる前にAdminを守り、Guest identityとDataset認可の土台を作りました。
第2段階②
Guest用Datasetをサーバー側で安全に発行し、Guest identityと結びつけたうえで、181件GREENでも最後に安全条件を再監査しました。
第3段階
Guestを業務routeへ通す前に、Product・DailySales・Dashboard・API・AI・seedのDataset境界を固め、pytestを181件から195件へ強化しました。
第4段階(※この記事です)
正規Guestを実際の業務routeへ通し、商品・売上・Dashboard・AIまで実request経路でDataset越境が起きないことを確認しました。
✅️pytest強化シリーズ
