本卡屬 FR-169(母卡 (建卡後補 Case No)),卡 B1,批 2。只改 BE(主 repo,Repo 欄空著)。依賴:P1。

這張卡做什麼(白話)

主系統這邊把套件接起來,並做「看得到效果」的最小一段:①一支共用 helper send_protected,所有匯出端點之後都呼叫它——讀前端送來的密碼 header、查安全政策開關、呼叫套件加密、寫一筆稽核、回檔並加不可快取的 header;②安全政策多一個布林鍵「檔案下載保護」(預設開)——型別與預設寫在 jedi-iam 套件裡(它管所有安全政策鍵),所以這張卡會動到 jedi-iam;③心跳回應多帶這個開關值給 Agent;④新稽核事件碼 FILE_DOWNLOADED;⑤先把「稽核計畫匯出」與「結案報告匯出」兩個端點改走 helper,讓決策者在 DEV 看到第一個加密檔。三支既有端點各自抄了一份 _send_attachment,本卡抽成一份。

reuse/extend/new

new:common/util/file_protect.py 的 send_protected(buf, filename, mimetype, *, request, watermark_actor)——讀 header X-File-Password、查開關、呼叫套件、寫稽核、回 send_file+Cache-Control: no-store+X-Filename+X-File-Protected;取代各端點手寫的 _send_attachment(ap_export、ssp_export、mf_ssp_export 三支已各有一份,本卡抽成一份)。extend:jedi-iam security_policy.py BOOL_KEYS/_STATIC_DEFAULTS 加 FILE_DOWNLOAD_PROTECTION=True(套件改動,開發期 path dependency);core/plugins/remote_agent.py heartbeat_extras 加 file_protect_heartbeat_extra;event_code.py 加 FILE_DOWNLOADED;ap_export_route.py、closing_report_route.py 改呼叫 helper

在哪裡

repo:~/Projects/Billows/Audit-Manager/compliance-manager-be
改既有:jedi-iam/jedi_iam/domain/security_policy.py(BOOL_KEYS、_STATIC_DEFAULTS)
改既有:pyproject.toml(jedi-file-protect pin、jedi-iam path 開發期)
改既有:common/enum/event_code.py
改既有:core/plugins/remote_agent.py(heartbeat_extras)
改既有:api/project/routes/ap_export_route.py
改既有:api/closing_report/routes/closing_report_route.py
改既有:app/system_config/service/security_policy_app_service.py(開關關閉寫稽核 SECURITY_POLICY_UPDATED 帶 file_download_protection=False)
新開:common/util/file_protect.py
新開:core/plugins/_agent_file_protect.py(心跳 extra:`{"file_protect": {"enabled": bool}}`)
新開:test/test_file_protect_helper.py

怎麼做

驗收(首腦照這個驗)

DEV 重啟後:GET /ap/<uid>/export?format=docx 不帶 header 回 400(GRC_400xxx 新碼「缺少檔案密碼」),帶 X-File-Password 回 docx 且 Word 要密碼、回應 header 有 Cache-Control: no-store 與 X-File-Protected: 1;format=zip 回 .7z 且 7-Zip 要密碼、X-File-Needs-7zip: 1;結案報告 pdf 同;稽核事件頁出現 FILE_DOWNLOADED(使用者、檔名、encrypted=true)且 payload 無密碼;grep -rn X-File-Password log/app.log 為 0;安全政策 PUT FILE_DOWNLOAD_PROTECTION=false 後同端點不帶 header 直接給明文、事件 encrypted=false;心跳回應 data.file_protect.enabled 跟著變;守衛測試綠;回寫明講 jedi-iam 已改、發版前要確認

必讀