給執行 session 的 prompt。前置:FR-048 主體已完工(SUMMARY
2026-07-07-FR-048-SUMMARY.md)。 本批是收尾後的裸奔稽核(5 群 subagent + 主導逐條驗 code)挖出的真漏網—— 大多數 agent 報的裸奔是誤判(只看 route 沒追 service 層守門),以下是通過驗證的真缺口。
【接手主題】FR-048 Phase 2b-4 — 收掉裸奔稽核確認的 4 個寫入面真漏網
必讀:
docs/features/FR-048-2607-unified-auth-guard/endpoint-authz-matrix.md(軸模型、既有守門 pattern)common/authz/(canonical:assert_project_manager / assert_project_participant / require_capability)【branch】fix/v1.8.0-bugs,禁止切 branch。不動 jedi-* 套件。守門一律 common.authz canonical。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 【鐵則:先驗 live 再改(每條都要)】
修 bug 前先驗真實狀態(DB/FE/呼叫路徑),不要憑本 prompt 直接刻。每條的驗證步驟已列在下方。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
現況(已驗):app/task_survey/service/question_answer_service.py(update_task_survey_answer:61 / checkpoint:168 / patch:314)、task_survey_service.py(update_task_survey:71 / update_task_survey_configure:529)、question_answer_history revert——service 完全無身分檢查,任何登入者可改任何人的填答。route 只有 @jwt_required。
定調(D10):填答 = 被指派者本人(assignee);configure/管理類 = manager。
先驗:
compliance-manager-fe grep 對應 api。task_assignee_domain_service(task_survey_service.py:37),grep 既有 TaskAssigneeQueryEntity 用法找反查(禁重複造輪)。task_survey 有 task_id → task_assignees 有 project_id + user_id。改:
ForbiddenError。若 D10 允許 manager 代填,manager 也放行(比照 AR override)。assert_project_manager。GRC_NOT_PROJECT_PARTICIPANT)。現況(已驗):api/grc/routes/poam_route.py:73 PUT 呼叫 app/grc/service/poam_service.py:96 update_poam——此 service 零守門(grep assert_project_manager = 0)。注意這跟已守的 poam_app_service.py(v2,有 _check_manager)是兩個不同 service,route 用的是沒守的這個。
先驗:
poam_route.py 這條 PUT 是 live(FE 有在用?還是 v1 殘留)——grep FE + 看 api/grc/__init__.py 有無註冊。若 dead 就標 dead 不改。ap_uid → 怎麼 resolve project_id(看 poam_app_service 或 audit_round 既有反查)。改(若 live):update_poam 開頭 resolve project → assert_project_manager。若同 service 有其他寫入 method(create/delete poam)一併檢視補齊。
現況(已驗):api/report/routes/scheduler_report_route.py — preview(:69)有 @require_capability("report.read"),但 file-list(:44)POST 只有 @jwt_required,不一致。路徑已消毒(_safe_report_path),風險低但該對齊。
改:file-list 掛同款 @require_capability("report.read")(或與 preview 一致的守門)。
疑點:report.read 在任何 migration seed 都找不到(grep -rn "report" scripts/sql/*.sql 無)。若它不在 DB 既有 121 顆 capability 裡,則 preview(及本批要加的 file-list)的 @require_capability("report.read") 會把 super_admin 以外所有人擋掉(break-glass 才進得去)= 現行 preview 可能已壞。
先驗(DEV DB):
SELECT name, is_platform FROM public.capabilities WHERE name LIKE 'report%';
(用 cmmgr,連線資訊查 .env DB_SECRET / CLAUDE.md DB 環境清單;跑 SQL 前正確 source .env)
處置:
report.read 存在 → 沒事,file-list 直接掛。report.read(幂等 migration,配 Administrator,只套 DEV,STG/POC 列交付)。先回報 user 選哪個,別自己拍板 seed。━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 【驗證 + 收尾】
python -m pytest test/ -q --continue-on-collection-errors,comm 比對,新增失敗 0)。【手測 checklist 必含】非 assignee 帳號改別人填答 → 403;assignee 本人 → 正常;report 預覽/檔案清單 admin 能開、一般帳號行為一致。