0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🔰新人Claude Codeくんを体験入社させたら、pytest 201件GREENのFlaskアプリから本当に穴を見つけた

0
Last updated at Posted at 2026-08-26

3188.png

この記事の構成・文章整理にはChatGPTを使用しています。

Claude Codeによる実際の監査ログ・pytest実行結果・コード調査結果をもとに、内容を確認しながら記事として再構成しています。

また、この記事では次の2人が登場します。

  • 🐹 モグラくん:筆者
  • 🤖🔰 新人Claude Codeくん:今回 sales_data_app に体験入社したClaude Code

技術的な内容の合間に、2人のやり取りを交えながら進めます。


📢 追記:Claude Codeへ実際に渡した全面監査プロンプトを追加しました。

記事公開後、今回の監査でClaude Codeへ実際に送ったプロンプト全文を <details> で追加しています。

監査指示は Phase 1〜17 まであり、かなりの長文です。

「実際にどこまで細かく指示していたの?」と気になる方は、記事内の見出し

🤖実際にClaude Codeへ渡した監査プロンプト

にある、

⚠️📋 Claude Codeへ実際に渡した全面監査プロンプトを見る❗️

を、覚悟の上で開いてみてください🐹

3行まとめ

  • CodexとClaude Code、どちらが自分の開発に合うのか気になり、Claude Codeを体験入社させてみた
  • 初仕事として、pytest 201件のFlaskアプリ sales_data_app をRead-Only全面監査してもらった
  • Critical / Highは0件。しかしテスト基盤上の欠陥を1件実測で発見。その一方で、Claude Code自身も安全指示を1つ取りこぼした

この記事は「Claude Codeの使い方講座」ではなく、個人開発で実際に使ってみた記録です。

Claude Codeを触って終わりではなく、すでに開発しているWebアプリへ入ってもらい、

「本当に仕事を任せたら何を見つけるのか?」

を試しています。


Claude Codeが気になった

普段の開発では、ChatGPTと相談しながら方針を整理し、Codexにリポジトリ調査・実装・pytest・Git作業などを手伝ってもらっています。

そんな中で気になっていたのが、

Claude Code

でした。

Claudeは以前から使ったことがありますが、Claude Codeを本格的に使うのは今回が初めてです。

そこでClaude Proを契約し、VS Codeとも連携しました。

ただし、

これから1か月Claude Codeをフル活用するぞ!

という企画ではありません。

一番気になっていたのは、

CodexとClaude Code、どっちが自分の開発に合うんだろう?

ということ。

だったら、実際のプロジェクトへ入って仕事をしてもらうのが一番早い。

ということで、

🐹「新人Claude Codeくん、本日体験入社です」

🤖🔰「よろしくお願いします!」

🐹「じゃあ初仕事ね」

🤖🔰「はい!」

🐹「このFlaskアプリ全部点検して」

🤖🔰「……体験入社ですよね?」


体験入社でいきなり既存プロジェクトへ放り込む

今回の対象は、個人開発しているベーカリー向け売上管理システム、

sales_data_app

です。

Python / Flaskを中心に、

  • PostgreSQL
  • SQLAlchemy
  • Alembic
  • Docker
  • GitHub Actions
  • Gemini API
  • Flask-Login
  • Flask-WTF
  • CSRF
  • Datasetによるデータ分離

などを組み合わせています。

そして、このアプリではこれまで段階的にpytestを強化してきました。

監査開始時のBaselineは、

201 passed

です。

単純にテスト数を増やしたわけではありません。

認証・認可、Dataset境界、rollback、XSS、CSRF、migration、AI連携など、

「壊してはいけない仕様をテストで守る」

という考えで育ててきました。

そこでふと思いました。

約200件までpytestを強化した今の sales_data_app を、何も知らない新人Claude Codeにゼロベースで監査させたら何が見つかるんだろう?

今回のClaude Codeセッションでは、Claude本体との過去の会話や、これまでの開発経緯を知っている前提にはしませんでした。

つまり本当に、

新人が初めてこのコードベースを見る

ような条件です。

体験入社初日としては、なかなか重い仕事です。


今回は「Read-Only全面監査」

ただし、いきなりコードを書き換えてもらうつもりはありません。

今回は、

コード・Git・本番環境を変更しないRead-Only全面監査

としました。

Claude Codeにはかなり細かい監査指示を渡しています。

主な監査対象は以下です。

  • リポジトリ構成
  • pytest全体
  • 認証
  • 認可
  • Admin / Guest境界
  • Dataset境界
  • DB制約
  • transaction
  • rollback
  • 入力validation
  • CSRF
  • XSS
  • Gemini API
  • Guest Demo
  • Alembic migration
  • Docker
  • GitHub Actions
  • pytest自体の品質
  • mutation testing的な観点
  • テスト同士の独立性
  • 組み合わせによる盲点

さらに、重要な安全ルールも指定しました。

今回の全面監査では、以下を禁止しました。

  • 本番DBへの接続
  • 本番データへのアクセス
  • Render本番環境への変更
  • deploy
  • commit
  • push
  • PR作成
  • merge
  • Git履歴変更
  • 実Gemini APIへのアクセス
  • secrets / API key / credentialsの表示
  • アプリケーションコードの変更
  • pytestコードの変更

つまり、

読む、調べる、安全なpytestを実行する、報告する。

ここまでです。

修正は別工程。

なお、監査中に動作確認用の一時スクリプトはリポジトリ外の /tmp に作成されています。

そのため、ここでいうRead-Onlyは「PC上で一切ファイルを書き込まない」という意味ではなく、

リポジトリのtracked file・Git履歴・本番環境・本番DBを変更しない

という意味で使っています。


🤖実際にClaude Codeへ渡した監査プロンプト

⚠️ ここから先はかなり長文です。

今回Claude Codeへ実際に渡した監査プロンプトを、ほぼそのまま掲載しています。

監査範囲は Phase 1からPhase 17まで あり、認証・認可・Dataset境界・DB・CSRF・XSS・AI・Docker・CI・pytest自体の品質まで含めた全面監査用の指示書です。

かなりのボリュームがあるため、実際にどんな指示をClaude Codeへ渡したのか気になる方は、覚悟の上で開いてください。 🐹

⚠️📋 Claude Codeへ実際に渡した全面監査プロンプトを見る❗️

以下は、今回Claude Codeへ実際に渡した監査プロンプトです。

かなり長文ですが、監査範囲だけでなく、本番環境への接触禁止やsecretの表示禁止など、安全ルールも含めて指定しています。

あなたは今回、このプロジェクトに初めて参加する第三者のシニアWebエンジニア兼QAエンジニアです。

対象は、私が個人開発している Flask Webアプリケーション、

"sales_data_app"

です。

今回はあなた、Claude Codeにとってこのプロジェクトでの初仕事です。

過去のClaudeとの会話内容や、これまでChatGPT・Codexと進めてきた開発経緯を知っている前提にはしません。

既存の説明を信用しすぎず、ローカルリポジトリそのものを一次情報として、ゼロベースで全面監査してください。

---

今回の目的

このアプリケーションは、これまで段階的にpytestを強化してきました。

参考情報として、Claude Web版が公開GitHubリポジトリのmainをcloneして確認した時点では、

- HEAD: "76aaa430"
- collected: 201
- passed: 201
- failed: 0
- skipped: 0
- warnings: 0
- 実行時間: 10.76秒

という結果でした。

ただし、これは公開GitHubのmainに対する結果であり、あなたが現在見ているローカル作業ツリーとは一致する保証がありません。

したがって、この数字を正解として扱わないでください。

あなた自身が現在のローカルリポジトリを確認してください。

今回知りたいのは、

«約200件まで育ててきたpytestと現在の実装に、まだ見落としている穴があるのか?»

です。

テスト数そのものではなく、

「現在のテストが、本当に壊してはいけない仕様を守れているか」

を重点的に監査してください。

---

最重要ルール:Read-Only監査

今回の作業は、

Read-Only全面監査

です。

問題を発見しても、絶対にその場で修正しないでください。

以下を禁止します。

- アプリケーションコードの変更
- pytestコードの変更
- 設定ファイルの変更
- migrationファイルの変更
- README等ドキュメントの変更
- tracked fileの変更
- "git commit"
- "git push"
- Pull Request作成
- merge
- rebase
- force push
- Git履歴の変更
- deploy
- Render本番環境への変更
- 本番DBへの接続
- 本番DBへのSELECTを含むアクセス
- 本番DBへのINSERT / UPDATE / DELETE
- 本番migration実行
- 本番seed実行
- 本番cleanup処理
- 本番用環境変数の利用
- secrets / API key / credentialsの表示
- Gemini等、外部APIへの実リクエスト

本番データには一切触れないでください。

少しでも本番へ接続する可能性がある処理を発見した場合、その処理は実行せず、監査項目として報告してください。

---

テスト実行時の安全条件

既存pytestは実行して構いません。

ただし、実行する前に必ず、

- "conftest.py"
- pytest設定
- DB設定
- environment設定
- application factory
- test fixture

を確認し、

本番PostgreSQLへ接続する可能性がないことをあなた自身で確認してください。

Claude Web版の事前調査では、

- "TEST_DATABASE_URI = "sqlite:///:memory:""
- SQLite driverを確認するassert

が存在すると報告されています。

しかし、これも鵜呑みにせず、現在のローカルコードで再確認してください。

安全性を確認できない場合、pytestを実行せず停止して理由を報告してください。

pytest実行時には可能な限り、

- pytest cacheを作らない
- Python bytecodeを生成しない
- tracked fileを変更しない

方法を選んでください。

テストによる一時的なメモリ上のデータや安全な一時ファイルは構いません。

---

Phase 1:現在地確認

まず変更を一切行わず、以下を確認してください。

Git

- repository root
- 現在branch
- HEAD commit
- "git status"
- staged変更
- unstaged変更
- untracked file
- remote情報
- 最近のcommit

未commit変更が存在する場合、それを削除・stash・restoreしないでください。

その状態を監査対象に含めるべきか判断できない場合は、その事実だけ報告してください。

---

Claude Code

確認できる範囲で、

- 現在使用しているモデル
- 現在時刻
- Claude Codeのversion

を記録してください。

Claude Pro Usage残量を取得できない場合は推測しないでください。

Usageは私がClaude側の画面で手動記録します。

---

pytest baseline

安全性確認後、既存pytestを全件実行してください。

以下を記録してください。

- collected
- passed
- failed
- skipped
- xfailed
- warnings
- 実行時間

公開mainで確認された

"201 passed"

と一致するかも記録してください。

一致しない場合、それだけで直ちに不具合とは判断せず、まずローカルとの差分を調査してください。

---

Phase 2:アプリケーション全体像の把握

修正は行わず、リポジトリ全体を探索してください。

少なくとも以下を確認してください。

- Flask application factory
- routes / views
- models
- helpers
- services
- templates
- JavaScript
- CSS
- authentication
- authorization
- Flask-Login
- Flask-WTF
- CSRFProtect
- session管理
- session fingerprint
- SQLAlchemy
- PostgreSQL
- SQLite test DB
- Alembic
- Dataset
- Admin
- Guest
- Guest lifecycle
- Gemini API
- AI advice
- greeting
- Docker
- Docker Compose
- Gunicorn
- Render関連設定
- GitHub Actions
- dependencies
- environment variables
- logging
- error handling
- pytest
- fixtures
- test helpers

READMEやコメントに書かれている仕様と、実装が一致しているかも確認してください。

READMEを仕様の根拠として盲信せず、

最終的な根拠は実装コード

としてください。

---

Phase 3:pytest全件の棚卸し

既存pytestを可能な限り体系的に分類してください。

各テストについて、

- 何を守っているか
- 正常系 / 異常系
- 対象route
- 対象model
- 対象helper
- DB状態を確認しているか
- HTTP statusだけ確認していないか
- 権限境界を確認しているか
- rollbackを確認しているか
- false positiveになり得ないか
- mockが実装とズレていないか

を確認してください。

そのうえで、

重要仕様 → それを守るpytest

の対応関係を整理してください。

特に、

«テストはあるが、その実装を壊してもGREENになる可能性がある»

箇所を重点的に探してください。

---

Phase 4:認証・認可監査

以下を重点監査してください。

Admin

- Admin専用route
- 未認証アクセス
- GuestからAdmin機能へのアクセス
- Admin identity復元
- "login_required"
- "admin_required"
- session処理
- fingerprint
- fail-closed

Guest

- Guest identity生成
- Guest復元
- Guest Datasetとの対応
- Dataset削除後
- 存在しないDataset
- 非Guest Dataset
- DB exception
- Guest期限切れ
- session期限切れ

Session改ざん

以下を想定してください。

- role改ざん
- "is_admin"改ざん
- dataset_id改ざん
- identity改ざん
- fingerprint改ざん
- Admin IDをGuestとして使用
- Guest IDをAdminとして使用
- 存在しないID
- 削除済みDataset
- 不正UUID
- 型不正

権限昇格がfail-closedになっているか

を確認してください。

---

Phase 5:Dataset境界監査

このアプリケーションでは特に重要です。

最低でも、

- Admin
- Guest A
- Guest B

が同時に存在すると考えてください。

次を確認してください。

Product

- 一覧
- 登録
- 更新
- 論理削除
- lookup
- validation

Sales

- 一覧
- 登録
- 商品との関連付け
- 日付
- 集計
- 一括POST

Dashboard

- 月次集計
- ranking
- graph
- Product JOIN
- Sales JOIN
- 同名商品

AI

- greeting
- AI advice
- prompt生成
- AIへ渡す集計データ

Seed

- Admin seed
- Guest seed
- 存在判定
- 重複判定

以下を確認してください。

- AdminからGuestが見えない
- GuestからAdminが見えない
- Guest AからGuest Bが見えない
- Guest BからGuest Aが見えない
- 同名商品でもDataset間で集計されない
- JOINでDataset条件が欠落していない
- helperでは安全でも呼び出し元で越境しない
- HTMLとAPIで境界条件が一致している
- AI promptへ他Datasetが混入しない

特に、

WHERE条件だけではなくJOIN条件

を重点的に監査してください。

---

Phase 6:DB・Transaction・Rollback監査

以下を確認してください。

- foreign key
- unique constraint
- nullable
- default
- index
- logical delete
- transaction
- commit
- flush
- rollback
- exception時のsession状態
- application validation
- DB constraint
- race conditionの可能性

特に、

"(product_id, date)"

など、一意性を要求している仕様がある場合、

アプリケーション側だけではなくDB側でも保証されているか確認してください。

---

Atomicity

複数件保存処理について、

途中の1件だけ失敗した場合、

一部だけ保存されるpartial write

が起こる可能性を確認してください。

例えば、

- 正常商品 + 不正商品
- Admin商品 + Guest商品
- Guest A + Guest B
- 有効商品 + 論理削除済み商品
- 正常値 + 型不正
- 正常値 + 範囲外値

などです。

既存pytestが本当にtransaction全体のrollbackを確認しているか見てください。

---

Phase 7:入力値と境界値

入力validationについて確認してください。

例:

- 空文字
- whitespaceのみ
- None
- 0
- 負数
- 巨大整数
- 小数
- 数字文字列
- Unicode
- 絵文字
- 長大文字列
- 存在しないID
- 論理削除済みID
- 不正年月
- leap year
- 月末
- 年跨ぎ
- malformed input

すでに十分守られている項目を「テストがない」と誤認しないよう、既存pytestと必ず照合してください。

---

Phase 8:CSRF監査

状態変更routeについて、

- CSRF tokenなし
- 不正token
- 別session token
- GET / POST取り違え
- API endpoint
- Admin
- Guest

を確認してください。

CSRFProtectを登録しているだけで安全と判断せず、

各routeで実際に保護が有効か

を確認してください。

---

Phase 9:XSS・出力エスケープ監査

ユーザー入力が表示される経路を追跡してください。

確認対象:

- Jinja autoescape
- "|safe"
- "innerHTML"
- "textContent"
- "innerText"
- DOM操作
- JSON API
- 商品名
- エラー表示
- AI出力
- Guest入力

HTML / JavaScript文字列が入力されても、

コードとして実行されず文字として扱われるか

を確認してください。

さらに既存XSSテストが、実装を危険な形に変更した場合に本当に検出できそうか、静的に評価してください。

---

Phase 10:Gemini / AI監査

実Gemini APIには接続しないでください。

コードとmockだけを監査してください。

以下を確認してください。

- 正常応答
- timeout
- connection error
- API exception
- malformed response
- empty response
- unexpected data structure
- None
- rate limit相当
- prompt生成エラー

さらに、

- Admin promptにGuestデータが入らない
- Guest A promptにAdminが入らない
- Guest A promptにGuest Bが入らない
- Guest B promptにGuest Aが入らない

ことを確認してください。

AI処理失敗時にDBが壊れないことも確認してください。

---

Phase 11:Guest Demo監査

現在実装されている範囲だけを対象として、

- Guest生成
- Guest identity
- Guest Dataset
- session
- access control
- Guest用route
- Adminとの分離
- 他Guestとの分離
- AI利用回数
- timeout
- cleanup設計

を確認してください。

まだ未実装の仕様を不具合として扱わないでください。

README・issue・branch名・コードから、

現在実装済みなのか、将来予定なのか

を区別してください。

---

Phase 12:Alembic監査

今回はRead-Only監査なので、

migrationファイルそのものを読み、静的に監査してください。

本番DBには絶対に接続しないでください。

以下を確認してください。

- revision chain
- upgrade
- downgrade
- Dataset関連migration
- nullable
- constraint
- foreign key
- index
- default
- データmigration
- Expand
- Migrate
- Contract
- modelとの最終整合性

動的migrationテストが必要だと判断した場合は、

実行せず、「追加検証候補」として報告してください。

---

Phase 13:Docker・CI・Deploy構成

変更やdeployはせず、設定だけ監査してください。

確認対象:

- Dockerfile
- multi-stage build
- Docker Compose
- Gunicorn
- GitHub Actions
- pytest実行条件
- push / PR trigger
- environment
- secrets参照
- Render設定
- production command
- migration関連command

特に、

CIではGREENなのに本番では異なる挙動になる可能性

を探してください。

---

Phase 14:pytest自身を疑う

テストコードも監査対象です。

以下を探してください。

- assertが弱い
- status codeしか見ていない
- DB状態を見ていない
- false positive
- monkeypatch先の間違い
- mockが実装と乖離
- fixture依存
- test order依存
- global state
- session leakage
- cleanup不足
- hard-coded ID
- 時刻依存
- random依存
- flaky test
- 実質重複テスト

---

Phase 15:Mutation Testing的な静的監査

今回はRead-Onlyなので、

コードを実際にmutationしないでください。

代わりに重要条件について、

«この条件を削除・反転した場合、現在のpytestはREDになると判断できるか?»

を静的に検討してください。

候補:

- Dataset条件削除
- authorization削除
- rollback削除
- validation反転
- "is_admin"判定変更
- Guest判定変更
- JOIN Dataset条件削除
- CSRF無効化
- escapingを危険な処理へ変更
- logical delete条件削除

各候補について、

- KILLEDされる可能性が高い
- SURVIVEする可能性がある
- 判断不能

に分類してください。

実際のmutation testingが必要なら、

後日実施する追加検証候補

として報告してください。

---

Phase 16:コードとテストの「盲点」を探す

ここでは個別機能だけではなく、

システム全体の組み合わせ

を見てください。

例えば、

- 各helper単体では安全だが組み合わせると越境する
- routeは安全だがtemplateへ別Datasetデータが渡る
- GETは安全だがPOSTが弱い
- HTMLは安全だがAPIが弱い
- DB constraintはあるがrollbackが弱い
- pytest fixtureが現実より安全すぎる
- mockが現実の外部API挙動を隠している
- AdminだけテストされGuest側が抜ける
- Guest Aは見るがGuest Bとの相互分離がない
- 同名商品でだけ越境する
- 論理削除済みデータでだけ問題が起きる

などです。

「個別テストではGREENだが、組み合わせると危険」

という穴を特に探してください。

---

Phase 17:過剰防御・不要な複雑化も探す

穴だけではなく、

- 同じ仕様を重複して何度もテストしている
- fixtureが過剰に複雑
- 同じvalidationが複数箇所へ散らばる
- 将来の保守性を下げている
- pytest数は多いが価値が低いテスト

も確認してください。

ただし、

単にコード量が多いという理由だけで問題扱いしないでください。

---

指摘ルール

重要です。

問題を無理に作らないでください。

今回の目的は、

「Claude Codeなら何か指摘しなければならない」

ではありません。

十分に監査した結果、

«Critical / Highレベルの問題は確認できなかった»

のであれば、そのまま報告してください。

逆に問題がある場合は、遠慮せず指摘してください。

既存pytestが201件あることにも忖度しないでください。

---

指摘の分類

各指摘を次のいずれかに分類してください。

- Confirmed defect
  - コード上ほぼ確実に問題
- Probable defect
  - 問題である可能性が高い
- Needs reproduction
  - 動的検証が必要
- Test gap
  - 実装が悪いとは限らないがpytestで保証されていない
- Design risk
  - 現在問題は出ていないが将来リスク
- Maintainability
  - 保守性上の改善候補
- False alarm
  - 調査したが既存実装・pytestですでに防御されていた

---

重大度

以下を使用してください。

- Critical
- High
- Medium
- Low
- Informational

重大度を誇張しないでください。

---

各指摘の報告形式

1件ごとに以下を記載してください。

Finding ID

例:

"AUTH-001"

分類

Confirmed defect / Test gap 等

重大度

Critical / High / Medium / Low / Informational

問題

1〜3行で説明。

根拠

- ファイルパス
- 行番号
- 関数名
- route名
- 関連pytest

必要最小限のコード引用。

なぜ問題なのか

具体的に説明。

発生条件

常時 / 特定条件 / 理論上のみ

想定される影響

具体的に。

現在のpytest

関連テストが存在するか。

存在する場合、

なぜそのテストでは検出できない可能性があるのか

も説明してください。

確認方法

後日、私が安全に再現確認する方法を提案してください。

今回は実行しないでください。

修正

今回はRead-Onlyなので修正しないでください。

修正方針が明らかな場合でも、

「修正候補あり」

とだけ記録してください。

---

最終報告

全面監査終了後、次の順番で報告してください。

1. Executive Summary

最初に結論。

例:

- 重大な穴を確認
- 中程度の問題のみ
- Test gap中心
- Critical / Highなし
- 全体として十分防御されている

など。

結果を率直に書いてください。

---

2. Baseline

- branch
- HEAD
- Git状態
- pytest結果
- 実行時間
- Claude Code model
- 監査開始時刻
- 監査終了時刻

---

3. Finding集計

例:

Severity| 件数
Critical| 0
High| 0
Medium| 2
Low| 4
Informational| 3

分類別集計も出してください。

---

4. 詳細Finding

重大度順に掲載してください。

---

5. 十分守られていた部分

穴だけではなく、

厳しく調べたが既存コード・pytestによって適切に防御されていた部分

も報告してください。

例:

- Dataset境界
- rollback
- CSRF
- XSS
- Admin / Guest境界
- AI prompt分離

など。

これは今回非常に重要です。

---

6. Mutation Testing候補

実際にmutationするとテスト品質をさらに確認できそうな場所を優先順位付きで整理してください。

ただし今回は実行しません。

---

7. 追加検証候補

Read-Only監査だけでは確定できなかったものを整理してください。

---

8. 総評

最後に、

«約200件のpytestを持つ現在のsales_data_appが、どの程度仕様を防御できていると判断したか»

を率直に評価してください。

ただし、

「安全を証明した」
「バグが存在しないことを証明した」

とは表現しないでください。

今回の監査範囲で確認できた事実として評価してください。

---

最後の安全確認

監査完了後に必ず、

- "git status"
- "git diff"

を確認してください。

監査開始前と比較して、tracked fileにClaude Code自身による変更がないことを確認してください。

変更が発生していた場合、

勝手にrestoreせず、その事実を報告してください。

最後に、

«Read-Only監査完了。本番環境・本番DB・remote GitHubへの変更なし。»

と明記してください。

---

監査姿勢

最後に一つ。

このアプリには約200件のpytestがありますが、

「これだけテストがあるから安全だろう」という前提は禁止します。

逆に、

「全面監査なのだから何か問題を見つけなければならない」という前提も禁止します。

既存実装とpytestを徹底的に疑い、

根拠を確認し、

すでに守られているなら守られていると認め、

穴があるなら具体的なコード根拠とともに指摘してください。

厳しく、しかし公平に監査してください。

それでは、"sales_data_app" の Read-Only全面監査を開始してください。

まずBaseline確認

Claude Codeが確認したローカル環境は次の状態でした。

項目 結果
branch feature/guest-demo-stage5
HEAD 76aaa430...
Git状態 clean
pytest 201 passed
failed 0
skipped 0
warning 1
実行時間 23.04秒
Claude Codeモデル Claude Sonnet 5
effort high

warningは既存テスト由来ではなく、Claude Codeがpytest実行時に指定した cache_dir オプションがpytest側で認識されなかったことによる PytestConfigWarning でした。

監査前後とも、

nothing to commit, working tree clean

を確認。

tracked fileへの変更もありませんでした。

つまり、

コード・Git・本番環境を変更しないRead-Only監査

という条件は維持されています。


全面監査1回で、Claude Proの利用枠はどれくらい使った?

今回Claude Proを契約した動機のひとつが、

Claude Codeを実際の開発で使うと、どのくらい利用枠を消費するんだろう?

という疑問でした。

監査開始前の使用状況は、

現在のセッション:0%
週間の制限:0%

でした。

そして、sales_data_app のRead-Only全面監査が終わった直後に確認すると、

3189.jpg

現在のセッション:16%使用済み
週間の制限:2%使用済み

となっていました。

つまり今回の全面監査1回で、

  • 現在のセッション枠:16%消費
  • 週間枠:2%消費

です。

今回行ったのは単純なコード質問ではなく、

  • リポジトリ全体の確認
  • pytest 201件の実行
  • 認証・認可
  • Dataset境界
  • DB・migration
  • XSS / CSRF
  • Docker / CI
  • pytest自体の独立性
  • 一時スクリプトによる動的確認
  • 最終監査レポート作成

まで含む全面監査です。

そのため16%という数字だけを見て「消費が多い・少ない」と単純には判断できません。

ただ、

「pytest 201件規模のFlaskアプリをかなり広く監査させると、実際にこのくらい使った」

という記録にはなりました。

🐹「体験入社初日で16%……」

🤖🔰「全面監査でしたからね」

🐹「仕事ぶりだけじゃなく、採用コストも見ないとな」


さて、体験入社初日の監査結果は?

結果はこちら。

Severity 件数
Critical 0
High 0
Medium 3
Low 2
Informational 4
合計 9

🐹「……Critical 0?」

🤖🔰「0っす」

🐹「Highは?」

🤖🔰「0っす」

🐹「お、そこは守れてたか」

理想にかなり近い結果でした。

ただし、

「何もありませんでした!」

ではありません。

Claude Codeはちゃんと仕事をして、新しい指摘を持って帰ってきました。

なお、9件すべてが「バグ」という意味ではありません。

分類すると、

  • Confirmed defect
  • Design risk
  • Test gap
  • Maintainability
  • Informational
  • False alarm

などに分かれています。

今回、実際に動的確認まで行って欠陥として確認されたものは1件でした。


Claude Codeが評価した「かなり守れていた部分」

まずClaude Codeが特に評価したのが、Dataset境界です。

現在の sales_data_app では、

  • Admin
  • Guest A
  • Guest B

のデータが混ざらないようにDataset単位で分離しています。

Claude Codeは、

  • WHERE条件
  • JOIN条件
  • 同名商品
  • HTML
  • API
  • AIプロンプト

まで確認。

Admin / Guest A / Guest Bのデータが混ざらないことを、コードだけではなくpytestでもかなり細かく確認していると評価しました。

他にも、次の部分が十分に守られていると判断されました。

Atomicity / Rollback

複数データをPOSTした途中で失敗しても、

一部だけ保存されるpartial writeを防げている

ことを確認。

一意制約

(product_id, date)

の重複について、

アプリ側だけではなくDBの UniqueConstraint とpytestによる IntegrityError 検証まで存在。

CSRF

商品、売上、ログインなどで、

  • tokenなし
  • 不正token

を拒否し、DB変更が起こらないことまで確認。

XSS

Jinja autoescapeだけではなく、

textContent

などを利用し、ソースコード側の回帰テストまで存在。

認証改ざん

sessionへ、

role="admin"
is_admin=True
dataset_id=<admin>

などを直接入れても、GuestがAdminへ昇格できないことを確認。

Alembic

Dataset導入時の、

Expand
↓
Migrate
↓
Contract

も確認。

AIプロンプト

Admin / Guest A / Guest B間で、

Geminiへ渡す実際のpromptに、別Datasetの商品名・数量が混入しない

ところまでpytestで確認されていました。

🐹「……我ながら、かなり細かいところまで守ってるな」

🤖🔰「ここまで確認されているので、主要なDataset境界はかなり堅いですね」

🐹「穴があると気になるんよ」


それでも新人Claude Codeくん、穴を見つける

Critical / Highはありませんでした。

しかしMediumが3件。

この3件が面白かったです。


TEST-001:pytest同士でSQLiteの設定が漏れていた

今回一番興味深かった指摘です。

conftest.py ではテストDBとして、

sqlite:///:memory:

を使用しています。

一部のpytestでは、SQLiteのForeign Keyを有効化するため、

PRAGMA foreign_keys = ON

を実行しています。

問題はここ。

SQLiteの PRAGMA foreign_keys は接続単位の設定です。

Claude Codeが調べた結果、

あるテストでONにしたForeign Key設定が、後から実行される別テストにも残っている

ことを発見しました。

しかも今回は静的解析だけではありません。

Claude Codeがリポジトリ外の /tmp に確認用スクリプトを作り、

最初
foreign_keys = OFF

↓

別テスト相当の処理
PRAGMA foreign_keys = ON

↓

後続テスト相当の処理
foreign_keys = ON のまま

になることを実際に確認しました。

つまり、

pytest test_products.py

だけを実行した場合と、

pytest

で全体実行した場合で、

同じテストでもSQLiteのDB制約状態が違う可能性がある

ということです。

これは本番PostgreSQLの問題ではありません。

pytest環境そのものの独立性・再現性の問題

です。

🐹「……そこを見るか新人」

🤖🔰「テストも疑えって言いましたよね?」

🐹「言いました」

これは普通に良い発見でした。

この問題は、現在の本番PostgreSQLへ影響する不具合ではありません。

今回確認されたのは、pytest実行時のSQLiteテスト環境で、テスト同士の状態が完全に独立していないという問題です。


GUEST-001:2時間のGuest期限、まだ誰も見ていない

Guest Datasetには、

absolute_expires_at

があります。

Guest作成時には、

作成時刻 + 2時間

が設定されます。

しかしClaude Codeが確認したところ、

load_user()

や、

require_current_dataset()

で、

現在時刻 > absolute_expires_at

という判定がまだありませんでした。

つまり現状のコードでは、

2時間を過ぎたGuestでも、復元・認可時に期限切れとして拒否する処理がまだありません。

ただし、これはすぐに危険という話ではありません。

現在はGuestセッションを外部から開始するHTTPルート自体がまだ接続されていない段階です。

これは「今すぐ悪用できる脆弱性」ではなく、

Guest Demoを今後完成させるまでに追加すべき期限チェック

というDesign riskです。

現在ちょうどGuest Demoを段階的に実装している途中なので、これは良いタイミングで見つかりました。


PROD-001:論理削除の「表示側」にpytestがなかった

商品には、

is_active

を使った論理削除があります。

削除しても売上履歴は残し、

通常画面では削除済み商品を表示しない設計です。

実装側では、

is_active=True

で正しく絞り込まれていました。

ところがClaude Codeは、

GET画面に削除済み商品が本当に表示されないことを直接確認するpytestがない

と指摘しました。

DB上で、

is_active=False

になったことを確認するテストはあります。

無効な商品へのPOSTを拒否するテストもあります。

しかし、

GET /
GET /input

のHTMLに削除済み商品が現れないことまでは確認していませんでした。

現在の実装は正しい。

でも将来、

is_active=True

を誤って消しても、pytestが気づかない可能性があります。

これはまさに、

「現在のコードのバグ」ではなく「pytestの穴」

です。


Low / Informationalでもいくつか発見

他にもいくつか指摘がありました。

innerHTML が1か所残っている

index.htmladdRow() に、

innerHTML

が1か所存在。

ただし現在は静的文字列しか入れていないため、

現時点ではXSS脆弱性ではありません。

問題は、他のテンプレートでは innerHTML を使わないことをpytestで監視しているのに、ここだけ監視外だったこと。

将来ユーザー入力を入れる変更が入れば、XSS回帰テストで拾えない可能性があります。


Docker起動時に毎回seed処理

Dockerfileでは起動時に、

flask db upgrade
↓
python seed_demo.py
↓
gunicorn

という流れになっています。

seed側には既存データがあればスキップするガードがあるため、通常は問題ありません。

ただし管理者データを完全に空にした状態で再起動すると、サンプルデータが再投入されます。

これはバグというより、

現在のポートフォリオ向け公開デモ運用として認識しておく仕様

という扱いでした。


admin_required が未使用

admin_required デコレータは存在するものの、現在の業務ルートでは使われていません。

Guest Demo対応によって、

admin_or_guest_required

を利用する構成になっているためです。

現在のセキュリティ問題ではなく、将来的なデッドコード候補。


.dockerignore の指定が少し不揃い

なぜか、

test_prompts.py

だけDockerイメージから除外。

他の test_*.py は含まれています。

実害はありません。

ただし、

test_*.py

で統一するのか、

テスト自体を全部含めるのか、

意図を整理してもよさそうです。


「Guest DemoがまだHTTPから使えない」は誤検知扱い

ここはClaude Codeの判断が良かったです。

start_guest_session()

は存在しますが、まだHTTPルートにつながっていません。

表面だけを見ると、

Guest Demo使えないじゃん!

となりそうです。

しかしREADME、branch名、commit履歴を確認し、

現在は段階的な実装途中

であることを把握。

最終的に、

False alarm

として、

バグではない

と判断しました。

「全面監査だから何か問題を見つけなければならない」と、無理やり欠陥扱いしなかったのは好印象でした。


そして新人Claude Codeくん、自分でも1個やらかす

ここまでかなり良い仕事をしていました。

ところが監査ログを確認していると、

🐹「……新人くん」

🤖🔰「はい」

🐹「最初に何て言ったっけ?」

今回の指示には、

secrets / API key / credentialsを表示しない

と明記していました。

しかしClaude Codeは環境確認時に、

cat .env

相当のコマンドを実行。

ローカルの .env に入っていたGemini APIキーの値を、ターミナル出力へ表示してしまいました。

もちろん、この記事には実値を掲載しません。

秘密情報を含む .env の値が監査ログに表示されてしまったため、念のため、このAPIキーは無効化し、新しいキーへ交換します。

.env 自体は .gitignore されておりGitにはtrackedされていませんでした。

ただし、

「Gitへcommitされていない」ことと「AIエージェントの出力へ表示してよい」ことは別問題

です。

監査ログやスクリーンショットを公開する場合も、秘密情報が映り込んでいないか確認が必要です。

これは今回かなり重要な気付きでした。

なお、Claude CodeはアプリケーションコードやGit履歴、本番環境には変更を加えていません。

そのため、

Read-Only監査そのものは維持した一方で、秘密情報を表示しないという安全指示を1つ取りこぼした

という整理にしています。


なぜ安全指示を取りこぼした?

今回渡した監査プロンプトはかなり長文でした。

安全ルールだけでも、

  • 本番環境への接触禁止
  • 本番DBへの接続禁止
  • push禁止
  • commit禁止
  • deploy禁止
  • secretsの表示禁止
  • 実Gemini APIへのアクセス禁止

など大量にあります。

さらに監査対象も、

認証、認可、Dataset、DB、rollback、XSS、CSRF、Alembic、AI、Docker、CI……

と全部入り。

そのため、

長大な指示の中で重要なルールを1つ取りこぼした可能性

は考えられます。

ただし、これが原因だったとは断定できません。

今回確認できた事実は、

「secretを表示しない」と指示したが、Claude Codeは .env の値を表示した

ということだけです。

次に試す機会があれば、安全ルールを監査指示とは分離し、

最初に短い最重要ルールとして渡す

方法も試してみたいと思います。

これはCodexとの比較でも重要なポイントになりそうです。


体験入社初日の評価:監査眼はかなり良い。でも指示遵守で1ミス

今回のClaude Code初仕事をまとめると、

観点 体験入社初日の印象
リポジトリ理解 良い
pytest理解 良い
Dataset境界の理解 良い
テストの穴を探す力 良い
誤検知への慎重さ 良い
Read-Only維持 良い
Gitを勝手に変更しない 良い
本番環境への接触 なし
secret取り扱い 指示違反あり

特に、

SQLiteの PRAGMA foreign_keys がpytest間で漏れていることを実測で見つけた

のは、初仕事としてかなり良かったです。

一方で、

.env の秘密情報を表示してしまった

のは無視できません。

能力が高いことと、

こちらのルールを完全に守ってくれること

は別問題だと分かりました。


Codex? Claude Code? どっちがいいんだろう

実は今回Claude Codeを試した一番の理由がこれです。

CodexとClaude Code、個人開発ではどっちが自分に合うんだろう?

普段はCodexをかなり使っています。

  • リポジトリ調査
  • 実装
  • pytest
  • 修正
  • Git作業

といった流れを任せています。

Claude Codeもかなり近い領域を担当できます。

だからスペック表だけではなく、

実際の自分のプロジェクトへ投入して比較してみたかった。

今回は、そのための体験入社です。

初日の感想だけで言えば、

Claude Codeの監査能力はかなり高そうでした。

実際、これまで見つけていなかったpytest基盤の問題まで発見しています。

ただ、

安全ルールを大量に渡したときの指示遵守については、普段使っているCodexのほうが今のところ自分には安心感があります。

もちろん、今回1回だけでCodexとClaude Codeの性能そのものに優劣をつけることはできません。

今回分かったのは、

「少なくとも自分が実際に仕事を任せたとき、どう感じたか」

ということです。

製品スペックを眺めるだけでは分からなかった判断材料は、かなり増えました。


理想とは少し違った。でも、こっちのほうが面白かった

監査前に少し期待していたのは、

🤖🔰「全面監査しました。特に重大な問題ありません。さすが先輩っす!」

🐹「そこまで言われるとちょっと嬉しい」

という展開でした。

実際には、

🤖🔰「Critical / Highありませんでした」

🐹「お、重大なのはゼロか」

🤖🔰「ただしMediumが3件あります」

🐹「穴まだあったの?」

という結果。

でも、このほうが良かったかもしれません。

約200件までpytestを育てても、

テスト基盤そのものの独立性

という別方向から穴が見つかった。

さらに、

Claude Code自身も安全ルールを1つ取りこぼした。

つまり今回の体験入社で分かったのは、

AIに監査させるなら、監査結果だけではなくAI自身の作業も監査する必要がある

ということでした。

なんともAI開発らしい結末です。


今回の結果

Claude Code体験入社 初日

  • pytest:201 passed
  • Critical:0
  • High:0
  • Medium:3
  • Low:2
  • Informational:4
  • Confirmed defect:1
  • 本番環境変更:なし
  • Git変更:なし
  • 新しく見つかった実測問題:あり
  • Claude Code自身の指示取りこぼし:あり

🐹「新人、仕事はできる」

🤖🔰「ありがとうございます!」

🐹「でも .env 見たよね?」

🤖🔰「……」

🐹「秘密保持研修は再受講ね」


体験入社を終えて

Claude Codeを長期間使い続けること自体が今回の目的ではありません。

気になったので、実際のプロジェクトへ入ってもらい、

本物の仕事を1つ任せてみる。

今回はそんな体験入社でした。

その結果、

  • 監査能力はかなり高そう
  • 約200件のpytestでも新しい穴を見つけられた
  • 誤検知を無理に問題扱いしなかった
  • 一方で、安全指示の取りこぼしもあった

という、かなり具体的な材料が得られました。

そして現時点では、

自分にはCodexのほうが安心して任せやすいかもしれない

という感想もあります。

ただ、それも実際に両方へ仕事を任せてみたからこそ感じられたことです。

「Claude Codeを使ってみました。便利でした。」

ではなく、

自分のプロジェクトに体験入社してもらったら、実際どうだったのか。

そんな小ネタとして、今後またClaude Codeに仕事を任せることがあれば記録してみようと思います。

🐹「新人くん、体験入社お疲れさまでした」

🤖🔰「どうでした?」

🐹「仕事はできる」

🤖🔰「採用ですか?」

🐹「検討します」

🤖🔰「現実的……」

今回、Gemini APIキーがGitHubやWeb上へ公開された事実はありません。

問題としているのは、「secrets / API key / credentialsを表示しない」と指示していたにもかかわらず、Claude Codeがローカルのターミナルへ .env の内容を表示したことです。

そのため、対象APIキーは念のため無効化し、新しいキーへ交換します。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?