0
✦ 品質
🛡 セキュリティ
⚙ 保守性
📋 概要
羽田空港の公式フライト情報APIからダイヤを取得し、FIDS風UIで表示するPython製Webアプリ。fetch_haneda.py でデータ取得・flights_data.js 生成、server.py でローカルHTTPサーバーを提供し、GitHub Actions + Vercel で自動デプロイする構成。
🎯 今すぐ直すべき3点
-
server.py do_POST 内の subprocess.run([sys.executable, 'fetch_haneda.py'], check=True) はローカルホスト限定とはいえ外部プロセス起動をHTTPリクエストで直接トリガーしている。少なくとも SSRF的な悪用を防ぐため、バインドアドレスを明示的に 127.0.0.1 に限定する(socketserver.TCPServer のバインドを ('127.0.0.1', PORT) に変更)。現状は ('', PORT) 相当でLAN全体に公開される可能性がある。↗
-
fetch_aircraft.py get_key() 関数が aerodatabox_key.txt / key.txt をカレントディレクトリから open() で読み込んでいるが、ファイルパスのバリデーションが一切ない。server.py 経由で実行される際に cwd=ROOT が指定されているため現状は限定的だが、キーファイルのパーミッションを 600 に設定する旨をREADMEに明記し、.gitignore に aerodatabox_key.txt / key.txt を追加してAPIキーの誤コミットを防ぐ対策を施す。↗
-
fetch_haneda.py call() 関数が urllib.request.urlopen(req, timeout=30) の例外(HTTPError, URLError, JSONDecodeError)を一切キャッチしていない。APIが503/403を返した場合やネットワーク断でスタックトレースが flights_data.js の上書き前に発生し、既存データが破損するリスクがある。try/except で HTTPError・URLError・JSONDecodeError を捕捉し、既存ファイルを保持したまま終了するフォールバック処理を追加する。↗
🔍 検出された問題 (5件)
🟥 Critical
📄 server.py
server.py がLANインターフェース全体にバインドされている可能性
socketserver.TCPServer のバインドアドレスが明示されておらず、デフォルトの 0.0.0.0 でLAN全体に公開される。do_POST は /api/update への POST で fetch_haneda.py を subprocess 実行するため、同一ネットワーク上の第三者が意図せず外部APIへのリクエストを大量トリガーできる。ローカルツールであっても 127.0.0.1 への明示バインドは必須。
🟧 Warning
📄 fetch_aircraft.py
APIキーファイルの誤コミットリスク
fetch_aircraft.py の get_key() が aerodatabox_key.txt / key.txt をカレントディレクトリから読み込むが、.gitignore にこれらのファイルが含まれているか確認できない(evidence_coverage が subset のため断定不可)。キーファイルが誤ってコミットされた場合、RapidAPI の無料枠が第三者に消費される。.gitignore への追記とREADMEへのパーミッション設定手順の明記が必要。
🟧 Warning
📄 fetch_haneda.py
fetch_haneda.py の call() でHTTPエラー・ネットワーク例外が未処理
urllib.request.urlopen が HTTPError(403/503等)やタイムアウトを送出した場合、例外がそのまま上位に伝播し flights_data.js の書き込みが中断される。部分書き込み中に例外が発生すると既存の有効なデータが破損し、アプリが空白表示になる危険がある。
🟧 Warning
📄 server.py
server.py の run_update() が fetch_haneda.py を check=True で実行しているが例外メッセージが不明瞭
subprocess.run(..., check=True) は CalledProcessError を送出するが、do_POST の except Exception as e でキャッチして f'{type(e).__name__}: {e}' をそのままHTTPレスポンスに含める。CalledProcessError の str() はコマンドライン全体を含むため、内部パス情報がクライアントに漏洩する可能性がある。
🟨 Suggestion
📄 server.py
fetch_haneda.py と fetch_aircraft.py の責務が server.py から subprocess 経由で結合されている
run_update() が subprocess.run でPythonスクリプトを別プロセス起動しており、同一Pythonインタープリタ内で関数として呼び出せるにもかかわらず二重起動のオーバーヘッドが発生している。モジュールとして import して直接呼び出す設計にすれば、エラーハンドリングの粒度も向上する。
✅ 良い点
- server.py の do_POST が _lock.acquire(blocking=False) + UPDATE_INTERVAL チェックで二重実行と過剰リクエストを429で弾いており、外部APIへの負荷制御がコードレベルで強制されている点が実用的かつ誠実な設計。
- tests/test_units.py が convert() の正常系・境界値(change_time が定刻と同値の場合)・APIがnullを返すパターン・空レコードの4ケースをカバーしており、非公開APIの仕様変更によるサイレント破壊を検知する目的が明確に達成されている。
- fetch_haneda.py の convert() 関数が or {} / or [] / isinstance チェックを多用してAPIレスポンスのnull・型不一致を防御的に処理しており、テストケース test_null_fields_from_api がそれを裏付けている。
🔧 リファクタ提案
- server.py の socketserver.TCPServer を ('127.0.0.1', PORT) に明示バインドし、run_update() 内の subprocess.run を fetch_haneda.main() / fetch_aircraft.main() の直接呼び出しに置き換えることで、プロセス間通信のオーバーヘッドとエラー情報の損失を同時に解消する。
- fetch_haneda.py の call() 関数に try/except (urllib.error.HTTPError, urllib.error.URLError, json.JSONDecodeError) を追加し、失敗時は既存の flights_data.js を保持したまま sys.exit(1) するフォールバックを実装する。
- fetch_aircraft.py の load_data() が open() でファイルを直接読み込んでいるが、with 文を使っていない箇所(open(fn).read())がある。全ファイル操作を with 文に統一し、ファイルディスクリプタリークを防ぐ。
🔒 セキュリティ注意点
- server.py がデフォルトで 0.0.0.0 にバインドされる可能性があり、LAN内の第三者が /api/update POST を叩いて外部APIへのリクエストをトリガーできる。明示的に 127.0.0.1 へバインドすること。
- fetch_aircraft.py の get_key() が読み込む aerodatabox_key.txt / key.txt が .gitignore に含まれていない場合、APIキーがリポジトリに誤コミットされるリスクがある。.gitignore への追記と key.txt のパーミッション 600 設定を徹底すること。
📤 PRコメント出力
このレビューをGitHub PRコメントとして貼り付けられるMarkdown形式で出力します。