VFKさんが来る 建設アシスト 品質・セキュリティ改善 総括

朝は京橋川を散歩させて、シャワーを浴びて五日市の病院に、帰りに元宇品の森でキクを散歩させていたらVFKさんから電話、昼は近くの『はる』でお好み焼きを食べて、晩秋には北海道へJeepでキャラバンすることで盛り上がる・・・夕方に、贈り物がしたいということなので、洋酒の酒店に行く、ウイスキーが好みだそうで2種類を購入、TAMにも一本贈り物として頂いた

朝は甲斐犬のキクを京橋川で散歩 夏の日差しが暑い

建設アシスト 品質・セキュリティ改善 総括

1.目的

建設アシストは、現場マネジメントDXの実践アプリケーションで、本プロジェクトの目的は以下の3点

  • 大手組織のセキュリティ審査に耐えるシステムにする 複数テナント(会社)が同居するSaaSとして、テナント間のデータ分離を構造的に保証する
  • AIに投げる情報の管理と漏洩リスクの低減 工事情報・現場情報をAI APIに送信する以上、何をどう送り、何を記録するかを一元的に管理できる構造にする
  • 今後の機能追加に耐える保守性の確保 一人開発で継続的に機能を追加していくため、重複コード・デッドコードを排除し、「1箇所直せば全体に効く」構造を作る
2.出発点の課題(Fable 5による全体検証の結果)

セキュリティ(フェーズ1)

  • Critical 7件・High 12件。中心はIDOR(他社データへの越境アクセス)で、工程表・安全パトロール・RA・施工計画書の主要機能に集中していた
  • テナント分離がコントローラの手動認可(authorizeProject)に全依存しており、
    1箇所の実装漏れがそのままデータ漏洩に直結する構造だった
  • 当時の評価:「現時点では大手組織のセキュリティ監査に耐えられない」

保守性(フェーズ2)

  • AI呼び出しが8箇所に散在し、URL・タイムアウト・エラー処理がコピペ重複
  • 工程表のJS約4,100行がBladeにインラインで埋め込まれ、CSP強化の障害に
  • テナント設計が未完了のモデル(company_id未設定)が多数
  • デッドコード(未完成のWord/Excel出力サービス、旧版施工計画書、孤立したAIサービス等)が大量に残存。

バグ(フェーズ3)

  • 確定バグ14件。空CSVで法規制マスタが全削除される致命的バグ、工程表の無限ループ、祝日計算誤りによるCPMの1日ズレ等
  • トランザクション欠落が主要機能に多数(途中失敗で中途半端なデータが残る)
  • 同時編集の保護が皆無(後勝ち上書きで先の編集が無警告で消える)。
VFKさん、久しぶりにJeepで
アイリッシュウイスキー バスカー シングルモルト
3.緊急対応

Critical IDOR 8件をabort_ifによる親子一致確認で全件修正
空CSV全削除・無限ループ等の確定バグ、トランザクション欠落4件を修正
本番.envのログレベルも是正し、AIレスポンスのログ蓄積を停止した。

結果: 即時の攻撃可能な穴は全て塞がれた。ただしこの時点では
「穴を1つずつ塞いだ」状態であり、構造的な保証はまだなかった

4.テナント分離の構造化

BelongsToTenantグローバルスコープを設計し、全36モデル(company_id直持ち10・Project木経由13・多段経由13)に段階適用した
これによりModel::find($id)の段階で他社データが自動的にnullになり、コントローラで認可を忘れてもデータが漏れない構造が完成した
既存の手動認可は多層防御として残置

結果: 「テナント分離はどう担保していますか」という審査質問に「モデル層のグローバルスコープで全クエリに自動適用」と答えられる状態になった

途中の重要な学び: 適用初日にAuth::check()の無限再帰によるメモリ枯渇が発生。テスト(actingAs)では検出できず、実機経路で初めて顕在化した・・以降、全フェーズで「実機相当検証(セッション復元経由・低メモリ制限)」を標準手順に組み込んだ

5.AI呼び出しの集約

8箇所に散在していたAI呼び出しをAnthropicClientサービスに集約
cURL直書きを全廃し、用途別のモデル・タイムアウト・トークン数をconfig一元管理にした。AIレスポンスの本文ログ出力を全削除し、ログには用途と長さのみを記録する方針に統一した

移行調査の過程で、8箇所のうち3箇所は呼び出し元が消えた孤立コードと判明し
削除。品質検証では、PDF様式取込でhaikuが「令和8年→和6年」「最大積載荷重→
最大建築面積」等の危険な誤読をすることが実測で確認され、安全書類系はsonnetを使う用途別モデル切り替えの妥当性が裏付けられた

結果: AIへの送信内容・記録・コストが1箇所で管理できる構造になり、「AIに投げる情報の管理」という当初目的の技術基盤が完成した

10.今後の留意点
  • テストを回帰防止網として維持する・・TenantIsolationTest(33件)とptimisticLockTest(26件)は、今後の機能追加時に必ず実行する・・新しいモデルを追加したらBelongsToTenantの分類(A/B/C/D)を判断してトレイトを適用し、テストも追加する・・・これを怠ると二重防御が一重に戻る
  • 新しい保存エンドポイントには楽観ロックを最初から組み込む・・withOptimisticLockトレイトとoptimistic-lock.jsが共通基盤として存在するので、新機能では最初から使う・・特に「全削除→全挿入」型の保存は409時の保護を必ずテストする
  • fetch実装時の定型ルールを守る・・Acceptヘッダー必須・応答とレコードの対応付け・保存の直列化・・楽観ロック導入で確立したこの3点は、今後のAjax実装全般の規約とする
  • デプロイ手順の遵守・・git pull → migrate → キャッシュ再構築 → composer install の順序・・・特にcomposer installの省略は今回autoload起因の500を招いた・・DBパスワード等の変更時は.envとキャッシュの両方を必ず確認する
11.残課題(急がない)
  • CSP unsafe-inlineの除去: JS外部化で道筋はついたが、残るインラインscriptの整理が必要CSP完全化は審査対策の最終ピース
  • バー・矢線の右クリック編集統一: アノテーションで統一した操作体系を工程表の主要素にも広げる(別起票済み)
  • 旧版施工計画書のテーブル最終整理: コードは削除済み
    本番データ208件を含むテーブルの扱いは将来のマイグレーションで対応
  • PHPUnit 12対応: doc-comment警告のattribute書式への移行(動作影響なし)
6.工程表の近代化

Bladeに埋め込まれていた工程表JS約4,300行を外部ファイル化し、CSP強化(unsafe-inline除去)への道筋をつけた。あわせてUX課題に着手した

  • 自動保存(2分・変更検知)と保存ボタンの点滅フィードバック
  • 工程表選択モーダルの改善(別種件数表示・キャンセルで工事管理へ)
  • ネットワーク/バーチャートで別々だったモーダルUI・操作体系の統一
  • アノテーション・フリー線のアーキテクチャをイベント委譲方式に統一し、
    共通モジュール(schedules-common.js)に抽出

調査の過程で、バーチャート側はテキストボックスの移動もフリー線の 端点編集も未実装だったことが判明し、ネットワーク同等の機能を新規実装した

結果: 両工程表の操作が統一され、今後の機能追加は共通モジュールの
1箇所修正で両画面に反映される。重複コード約550行を削減

7.同時編集の保護

updated_atベースの楽観ロックを設計し、共通基盤(D-0)→工程表(D-1)→施工計画書(D-2)→現場帳票(D-3)→監査系(D-4)→必須化(D-5)の6フェーズで段階導入した。競合検出時は保存を一切書き込まず、競合モーダルで「最新を読み込む/編集内容を退避(JSONダウンロード)」を提示する

特に危険だった「全削除→全挿入」型の保存(環境側面・監査チェックシート)と「payload外id削除」型(監査指摘→是正処置のcascade連鎖消滅)は、409時に削除処理が一切実行されないことをテストで担保した

結果: 複数ユーザーの同時利用で編集が無警告で消える構造が解消された・・・導入中に発見した「遅延レスポンスによる別レコードのトークン汚染」というSPA特有の落とし穴も修正し、再現テストとして固定化した

8.コードベースの清掃

デッドコードを体系的に削除した・・・ompdf/Puppeteer(サーバーPDF生成・未使用)、未完成のWord/Excelサービス3本、孤立AIサービス2本、旧版施工計画書(ルート13本・コントローラ約1,000行・ビュー4本)、空モデル2本等、累計で約6,000行以上を削除README・CLAUDE.mdも実態に合わせて更新した

9.定量的な成果
指標開始時完了時
Critical脆弱性 7件0件
確定バグ14件0件
テナント分離 手動認可のみ 36モデルに自動スコープ+手動認可の二重防御
AI呼び出し8箇所散在・cURL混在1サービスに集約・config一元管理
同時編集保護なし(後勝ち上書き)全主要機能で楽観ロック必須
自動テスト26件59件(テナント分離33+楽観ロック26)
Blade内インラインJS工程表約4,300行外部化完了
削除したデッドコード約6,000行以上
ブックマークする パーマリンク.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

  • 2026年8月
     12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31