本卡為 FR-083 母案。掃
jedi-ai-dashboard(套件 34 檔 + BE 宿主接線 18 檔)。只掃不修,修正卡另開、由 PM 統一安排。建議 D2(宿主)先跑——理由見下。
系統裡有一個「AI 儀表板」:使用者用自然語言問問題(例如「列出所有專案的進度」),AI 會自己決定要呼叫系統裡的哪一支查詢功能,把查到的資料拿去設計版面,做成圖表顯示。
這一棒要回答的是:AI 能呼叫的那些查詢功能,有沒有做權限檢查?查到的資料會不會被送到公司外面?使用者能不能用自然語言誘導 AI 去查他本來看不到的東西?
① FR-079 已經證明這條路有洞,但我們只驗證了 27 支裡的 1 支。
FR-079 的 F13 查到「AI 儀表板可以直接呼叫公告查詢,不經過網頁那層的任何權限檢查,而且部門過濾永遠失效(呼叫端寫死 params={})」。當時只追了公告那一支。
這次盤點發現:di_containers/dashboard_apis/ 底下有 14 支申報檔,合計申報了 27 支 API——
participant(專案成員) 7 支 ← 「你在這個專案能幹嘛」的資料源
auth(認證) 4 支 ← get_users / get_tenants / get_roles / get_org_units
flow_engine 3 支
oscal / project / survey 各 2 支
bulletin / feedback / device / system_menu /
system_config / module_frame / user_auth_provider 各 1 支
────
27 支
auth.get_users、auth.get_tenants、auth.get_org_units 全部在這條旁路上——那是全站使用者名冊、租戶清單、組織架構。還有 26 支從未驗證過。
② 查到的資料會原文送給第三方 LLM。 F13 已確認「結果前三筆原文送第三方」。27 支 API 的回傳內容都可能經這條路出去。
③ 使用者的自然語言會決定 AI 呼叫哪支 API。 domain/service/dashboard_generation_domain_service.py(329 行,套件最大檔)與 app/service/ai_dashboard_app_service.py(258 行)負責「AI 選哪支 API、怎麼組版面」——提示詞注入的天然位置:能不能用文字誘導 AI 去選一支本來不該給這個使用者的 API?
依 FR-079 換來的判準先查「這支有沒有宿主那一半」——有,而且宿主那半邊是主角不是配角:
套件本體 jedi_ai_dashboard/ + harness/ 34 檔 2,296 行
BE 宿主接線 api/ai_dashboard/ 105 行
di_containers/ai_dashboard/ 153 行
di_containers/dashboard_apis/ 14 支申報檔、27 支 API
------------------------------------------------
18 檔 約 800 行
兩邊都夠大、且 scanRoot 只能指一個目錄,所以必須分開。 這與 FR-082(jedi-ai-bot 宿主僅 3 檔 89 行,併進卡片背景即可)不同。
api/ai_dashboard/、di_containers/ai_dashboard/、di_containers/dashboard_apis/。27 支申報 API 的守門形狀全在這裡。建議先跑。jedi_ai_dashboard/ + harness/。AI 怎麼選 API、怎麼呼叫、怎麼把結果送給 LLM。為什麼 D2 先跑:F13 已經證明那半邊有洞,而 27 支 API 的權限形狀是本 arc 的核心問題。D1 跑第二棒時可以帶著 D2 的結論去看「AI 的選擇邏輯會不會放大那些洞」。兩棒的發現要放在一起對(FR-078 N1/N2、FR-081 I1/I2 的經驗)。