FR-166.1 · 設計文件 v2 · 2026-10-29(D1~D10 定案;27 張卡 10 批)
FR-166 收尾後 PM 提六條回饋;每條先找既有機制再決定怎麼接,沒有一條另起爐灶
PM 看完 FR-166 手測版提六點:證據檔只准線上看、下載要獨立權限且出貨全鎖;離線還剩幾天能登入要顯示;CINC profile 推到 Agent 要看得到有沒有成功、能補推;工具帳密要能從主系統設定但資料仍存 Agent;要有操作與事件日誌可瀏覽;登入後沒得切語言。本文件把六條各自對到既有機制:下載權限點掛在 jedi-file-upload 的簽票那一層一處生效;profile 照弱點資料庫的心跳同步模型;主系統設定工具帳密走測試連線同一條直連通道當場存;稽核改接 Python logging 管線(jedi-common 的 system_logs、標準庫 QueueHandler),不再自寫 jsonl;剩餘天數與語言切換是純畫面。所有下載出口與 FR-169 的檔案下載加密接在一起。
狀態:v2 定案、實作完成待收尾|日期:2026-10-29|母卡 CM-3199、子卡 CM-3200~CM-3222、CM-3282~CM-3285|前作 FR-166(主控台、D23 離線權限同主系統、HTML 預覽)、FR-156(弱點資料心跳同步)、FR-157(工具帳密搬進 Agent)、FR-033(主系統稽核事件管線)|並行 FR-169(下載檔加密) 開發 branch:五個 repo 皆在
feature/FR-139;runner 開工git branch --show-current再確認,不對就停下問,不切
🔴 這份是設計決策,不是現況。 上線後的畫面與 API 現況看 SPEC 頁。
| 日期 | 變更 | 對應 |
|---|---|---|
| 2026-10-29 | 初版:PM 六條回饋 → D1~D8,17 張卡 6 批;同日開卡 | 母卡 CM-3199,子卡 CM-3200~CM-3216 |
| 2026-10-29 | v2:D1/D2 改分模組能力點;D5 改直連當場存;新增 D9(離線超過天數 AD 也鎖)、D10(日誌覆蓋率與匯出);工具頁改名「Agent 掃描工具設定」並重做;與 FR-169 加密接齊 | 子卡 CM-3217~3222、CM-3282~3285 |
PM 2026-10-28 看完 FR-166 手測版後的六條原話與決策者補充:
| # | PM 原話 | 決策者補充(2026-10-29) |
|---|---|---|
| 1 | Agent 檔案的地方也是只能預覽、下載拔掉;所有報告不要讓下載只能預覽;下載要可以設定成權限點,目前全部都鎖起來 | 全系統所有證據檔案下載都收進權限點,不限 Agent;不能預覽的格式就不給看 |
| 2 | 離線情況下還剩幾天就不能再離線登入,要顯示在儀表板 | — |
| 3 | CINC Auditor profile 推到 Agent 也要讓 Agent 知道有更新成功,也要可以補更新 | 比照弱點資料庫那套 |
| 4 | 掃描工具設定檔本機還是要留機制給 user 從主系統設定,讓人遠端幫忙設置不透過 Agent 畫面,但資料還是存在 Agent | 等於在主系統開放編輯權限;Agent 離線直接說連不上 |
| 5 | 要有日誌管理,記錄 user 的操作行為跟 log audit,要有 UI 可瀏覽 | 只記操作與事件,系統 log 先不要;比照主系統 system_logs;用 logging 機制,本機有範例,不要硬刻 |
| 6 | 登入後沒有 i18n 切換功能 | — |
system_logs 表,欄位與主系統同一份;主控台多「日誌」分頁可依人、事件、日期篩,可匯出 CSV。預覽、進頁、開工具表單、開執行紀錄詳情也記;升級時舊版 jsonl 稽核一次搬進表。回傳主系統的機制不變,游標改自增 id。flowchart LR
subgraph 主系統
FU[jedi-file-upload 簽票<br/>action=preview/download]
CAP[(各模組 download 能力點<br/>認領者自己查)]
HB[心跳回應<br/>profiles 清單+補更新旗標]
DP[資料面直推 8443<br/>PUT/DELETE /detection/credentials]
SL[(system_logs)]
end
subgraph Agent
PC[profile_cache 既有取檔]
PS[profile_sync 照 vulndb_sync]
CS[credential_store]
AP[audit() → Filter → Queue → DBLogHandler 子類]
SQ[(SQLite system_logs)]
UI[主控台:預覽/剩餘天數/日誌/語言]
end
CAP --> FU
HB --> PS --> PC
DP --> CS
AP --> SQ --> |心跳 console_events| SL
主系統與 Agent 之間有兩條路:Agent 出站的心跳(每 60 秒拉一次,profile 清單、補更新旗標夾在回應裡),以及主系統連進 Agent 資料面 8443 的直推(mTLS+綁定 agent 身分的短效 JWT,回應比對 Agent 指紋)。要當場知道結果的動作(測試連線、取證據檔、設定與清除工具帳密)走直推;狀態同步走心跳。直推的前提是主系統連得到 Agent 的 8443:落地版同在客戶內網一定通,SaaS 版要客戶開放。
| # | 決策 | 定案 | 理由 | 被排除 |
|---|---|---|---|---|
| D1 | 下載權限點掛哪一層 | 掛在 jedi-file-upload 簽票端點+認領者:簽票分 action=preview|download,下載端點只收 download 票;登記表多一個 FILE_ACTION_DOWNLOAD 動作,每類檔案的認領者(證據、SSP 佐證、意見回饋附件…)在 download 時自己決定要不要多看一顆能力點。看不到的檔一律 404,看得到但不能下載 403 FILE_UPLOAD_403002 |
主系統所有檔案下載都走 /file/download/<uid> 一條路,票是唯一門;但「哪些檔算客戶資料」只有認領它的模組知道,全局一顆守門會把公版範本也鎖掉 |
全局一顆 各模組 download 能力點(能力點名撞三段約束,且分不出客戶資料與公版);前端逐處擋(漏一處就是洞);另開第二條下載端點 |
| D2 | 能力點命名與預設 | 每類資料用自己模組的 download/export 動作:下載 7 顆(grc.job-evidence.download、grc.audit.download、oscal.ssp.download、detection.source-scan.download、evidence.classification.download、workspace.feedback.download、detection.remote-agent.download-files),匯出補 2 顆只擋 read 的客戶資料(grc.audit.export、grc.risk.export);角色設定頁多一欄「下載/匯出」讓管理員逐模組決定;出貨全部不綁任何角色,Administrator 靠 *.*.* 自然持有。判準:內容是客戶自己的資料就鎖;產品帶來的公版/範本、各種匯入範本、管理功能匯出不擋。13 類上傳檔鎖 9 開 4(資源庫建議附件、框架 PDF、檢測規則包、系統共用資產開放)。上傳者本人永遠能下載自己上傳的檔(比 upload_files.created_user),但仍要先看得到;範本 SSP 的佐證文件只鎖下載、預覽照舊 |
PM 原話「目前全部都鎖起來」;管理員要能分模組開,一顆全系統的做不到;上傳者拿不回自己的檔不合理 | 一顆全系統 各模組 download 能力點;綁預設角色;連匯入範本一起鎖 |
| D3 | Agent 主控台的下載 | 票上新範圍 download-files ↔︎ detection.remote-agent.download-files(主控台檔案頁全是掃描報告,整頁視同證據;網路除錯報告一樣鎖);離線操作者同樣照 D23 由心跳算;檔案頁補預覽端點走既有 inline_policy;不能 inline 的格式(svg、xhtml)不給看 |
與 D23 同一份真相;預覽機制 FR-166 已有 | 給 svg 另開消毒預覽 |
| D4 | profile 同步模型 | 照弱點資料庫:心跳回應附 profiles[](現行版本 uid/version/sha256/file_uid),Agent 比對本機快取、背景拉、下次心跳回報每支狀態;主系統存 agent_profile_states;「補更新」=心跳旗標讓 Agent 清冷卻立刻檢查;主控台「立即檢查」同 vulndb 那顆 |
掛點(heartbeat_extras)與 Agent 端流程(vulndb_sync)都現成;取檔與快取 profile_cache.py 現成,只差「主動比對」這一步 |
主系統主動推(主系統連不進 Agent);改掉派工時 lazy 拉(沒壞) |
| D5 | 主系統設定/清除工具帳密的通道 | 直連 Agent 資料面:主系統 PUT/DELETE Agent 的 /detection/credentials,與測試連線同一道 mTLS+JWT+回應指紋比對;Agent 照工具目錄 schema 驗欄位(與主控台存檔同一套),不合回 400 不存;回來的狀態當場寫回 remote_agents.configured_tools。帳密不寫 tenant_detection_tool_configs、不進派工單;帶帳密只走加密通道;Agent 離線回 409;稽核 6086/6087 method=remote 不帶值 |
測試連線本來就直推,設定若改等心跳,同一頁兩種速度、使用者以為壞了;測試連線能通的環境設定就能通 | 走 credential_handover 派工單等心跳(要輪詢、最多等一分鐘);主系統存一份再同步(第二份真相);離線排隊(使用者不知道何時生效) |
| D9 | 離線超過天數時 AD 登入 | 一起鎖,不留例外;只剩本機管理員能登,連回主系統才能再用。原因碼沿用 method_blocked,擋在送 AD 之前 |
斷線越久名單越可能過時(撤銷收不到),AD 密碼對不代表授權還有效 | AD 不受天數限制(FR-166 D17,推翻) |
| D10 | 日誌覆蓋與匯出 | 舊 console-audit.jsonl 啟動時一次搬進表(冪等);預覽記自己的碼 6230(與下載 6088 分開,主系統「檔案離開 Agent」統計不被預覽灌水);進頁 6231、開工具表單 6232、開執行紀錄詳情 6233(同一對象 5 分鐘內只記一次);匯出 CSV 6236,守「看日誌」範圍+download-files、走 FR-169 加密。6230~6236 只留本機 |
換表前寫在 jsonl 的紀錄不搬,日誌分頁就看不到升級前的操作;「看」類動作要留紀錄才查得到誰看過客戶資料 | 前端切頁主動打 API 記進頁(要多一支 API,先不做) |
| D6 | Agent 稽核的架構 | 接 Python logging 管線:入口只有 jedi-remote-agent 既有 audit(logger, event_name, event_code, **fields);ConsoleActorFilter 從 flask.g.console_session 補操作者(背景執行緒補 system);jedi-common SecretMaskingFilter 遮密;QueueHandler→QueueListener→DBLogHandler 子類寫 SQLite system_logs(表、DTO、service 用 jedi-common 現成);心跳回傳改讀表、游標改自增 id |
41 個呼叫點現在手傳 actor、哪些回傳是寫死集合、sink 只有 jsonl,加一個 sink 就改 record();logging 天生就是「一入口多 sink 中間掛 filter」,主系統已這樣用 |
自寫 SQLite audit 模組(第二套管線);只改 jsonl 成寫表(架構不變) |
| D7 | 資料庫 | 留 SQLite,不起 Postgres | 123 密集手測三天稽核 61 筆;WAL+busy_timeout 已設;QueueListener 讓寫表永遠單執行緒;多一個容器牽動安裝/升級/wipe/診斷包全部腳本 | Postgres(反悔條件:多台共用狀態或跨 Agent 集中查,後者已靠心跳回傳做到) |
| D8 | jedi-common 版本 | Agent 釘 0.0.31 不升;DBLogHandler 用薄子類補「只放行帶 event_code、缺欄補 None」兩段(1.3.6 原生有),升版即刪 |
jedi-file-upload 0.0.22 也釘舊版,兩個一起升牽動範圍不小,與本案無關 | 本案順便升 |
全部開卡前實查(2026-10-29)。
| 主題 | 既有機制 | 位置 | 缺什麼 |
|---|---|---|---|
| 下載出口 | 主系統所有檔案下載走 /file/download/<uid>?st=,票由 /file/access-token/<uid> 簽,守門=file_access_guard(簽章票或 JWT)+file_ownership_guard(歸屬),無能力點 |
jedi-file-upload/api/routes/upload_file_route.py 141、160;宿主接線 core/plugins/file_upload.py 351 |
票不分用途;FileUploadAdapters 沒有下載守門欄 |
| 前端下載呼叫 | 10 處:signedDownloadUtil.js(簽票唯一入口)、JobExecutionDrawer.vue 1434、RoundEvidenceView.vue 80、SystemFeedbackView/Form.vue、EvidenceFilePreviewDialog.vue 135、useSbomViewer.js、useScanFileDownload.js;Agent 執行紀錄 AgentLocalRunsView.vue 213 |
FE repo | 都沒有 v-can |
| Agent 主控台下載 | 檔案頁 files_download 守 files 範圍;報告預覽走 inline_policy+CSP sandbox(FR-166);runs.js canDownload 看 files/net-diag |
core/console/files.py 169、console/views/Files.vue 90、console/runs.js 82 |
檔案頁無預覽;範圍不分瀏覽與下載 |
| 能力點 ↔︎ 票範圍 | CONSOLE_SCOPE_CAPABILITIES 五列、OFFLINE_OPERATOR_SCOPE_CAPABILITIES 四列 |
jedi_remote_agent/plugin/contract.py 44、52 |
缺 download |
| 離線天數 | 心跳下發 offline_login_days;Agent heartbeat_status.offline_days();總覽 banner 已顯示「已離線 n 天/上限 N」 |
console/views/Overview.vue 141 |
沒算剩餘、沒有卡 |
| 弱點資料同步(範本) | 心跳附加 vulndb(heartbeat_extras 鉤子)→ Agent vulndb_sync.observe 比對→背景下載→回報 vulndb_date;主控台 POST /vulndb/check 只清冷卻喚心跳 |
core/plugins/_agent_vulndb.py、evidence-agent/core/vulndb_sync.py、ops_routes.py 104 |
— |
| profile 取檔 | 派工時 _resolve_profile → profile_cache 按 sha256 命中或拉;原子解壓 |
evidence-agent/core/profile_cache.py 115~250 |
沒有「主動比對清單」;主系統沒有每台 Agent 的狀態 |
| 帳密交接 | credential_handover 工單(升級搬家用):主系統從雲端密文解出 fields 進單,Agent put_if_absent 存本機、回執工具代號 |
jedi_detection/app/service/credential_handover_service.py;evidence-agent/core/credential_handover.py |
只有搬家;當場設定另走直推(D5) |
| 主系統直推 Agent | 測試連線 AgentProbeClient、取證據檔 RemoteAgentAdapter:mTLS+綁定 agent 身分的短效 JWT;Agent 資料面 /blob、/detection 前綴由 data_plane_auth 守門 |
jedi_detection/infra/detection_tools/connector/agent_probe_client.py;infra/upload_file/remote_agent_adapter.py;evidence-agent/core/data_plane_auth.py |
沒有設定帳密的端點 |
| 檢測工具頁 | tool-plugin-manage enable=0(FR-166 隱藏);ToolPluginManage.vue 766 行 |
scripts/sql/2026-10-28-fr166-hide-tool-plugin-manage-menu.sql |
翻回並改用途 |
| 主系統稽核管線 | logger.info(extra={event_code}) → CustomFormatter 補操作者 → DBLogHandler 只放行帶事件碼 → public.system_logs;套件 audit() helper |
jedi-common 1.3.6 logger/;jedi_remote_agent/common/audit.py |
— |
| Agent 稽核 | audit.record(action, actor, **fields) 寫 jsonl;REPORTED_ACTIONS 11 種隨心跳回傳;ISO 微秒游標;_MASKED_KEYS 自遮;41 個呼叫點手傳 actor |
evidence-agent/core/console/audit.py 155;logging 只有 basicConfig |
整段換管線 |
| Agent SQLite | jedi-common init_db,WAL+busy_timeout 5s,local_db 版本表 v2 四張表 |
core/app_factory.py 38、91;core/local_db/migrations.py |
v3 加 system_logs |
| jedi-common 0.0.31 | DBLogHandler.emit 直接讀 record.user_uid/event_code、不過濾;CreateSystemLogDTO/system_log_service.add_system_log(@transaction)現成;session_context 是 ContextVar,listener 執行緒自開 scope 沒問題 |
Agent venv jedi_common/logger/db_log/ |
過濾與補欄要子類 |
| 主控台語言 | 登入頁有 toggleLocale;殼只有深淺色與登出;翻譯檔中英齊 |
console/Login.vue 200、console/Shell.vue 55 |
殼沒鈕、沒記住 |
| 主站日誌頁(範本) | UserLogs.vue 讀 api_logs:act_time/level/user_name/url/method/source_ip |
src/views/action-log/UserLogs.vue |
— |
票分用途。 GET /file/access-token/<uid>?action=preview|download,省略=preview(舊前端不壞)。票的 scope 字串在既有 file_access_scope 後接 :download,下載端點 file_access_guard 只收帶 :download 的票,pdf-preview 端點兩種都收。簽 download 票前先跑 adapters.download_guard(宿主注入,None 時不擋)。
認領者各看自己那顆。 登記表 FILE_ACTION_DOWNLOAD;主系統 core/plugins/_file_ownership.py::assert_download_capability 一支共用:上傳者本人直接放行,否則查該模組的 download 能力點;9 類認領者各自呼叫它。能力點 migration 照 FR-166 形狀但第三段「預設角色授權」整段不寫。匯出端點照既有 @require_capability("<模組>.export") 形狀補 2 顆。
Agent 端:票範圍 download-files;files_download、netdiag 報告、runs 報告三條下載都改這個範圍;新增 GET /console/files/<uid>/preview 走 inline_policy。主系統「Agent 掃描執行紀錄」報告下載端點 _ADMIN_CAPABILITIES 改 detection.remote-agent.download-files。
前端:signedDownloadUtil.fileDownloadUrl 帶 action=download;下載鈕顯示條件=「持該模組 download 能力點,或是自己上傳的」,各頁帶各自那顆;共用預覽框由呼叫端給能力點;匯出鈕看各自 export 顆;主控台檔案頁改「預覽」為主、下載鈕看 me.scope 含 download-files。
陷阱:Agent 驗票見到不認得的範圍整張拒收,所以 Agent(A2 套件+A5)要先認得 download-files,主系統才可以簽;升級順序 Agent 先。
總覽卡:剩餘 = offline_login_days − offline_days,只在 net === OFFLINE 顯示;≤0 紅字+「只剩本機管理員可登入」。資料心跳已下發、Agent /console/state 已回,純畫面。到期後離線密碼與 AD 一起鎖(D9):Agent operator_session_valid 不分登入方式都看 offline_login_disabled(),登入當下與每個請求重驗走同一支;登入頁兩個分頁一起灰。
照 vulndb_sync.py 逐段對應:
| vulndb | profile |
|---|---|
心跳回應 vulndb:{bundle_date,sha256,size} |
profiles:[{uid,version,sha256,file_uid}](只含 is_current) |
observe() 比日期 |
observe() 逐支比 profile_cache.is_cache_valid(cache_dir, sha256) |
| 背景執行緒下載+驗章+原子切換 | 背景執行緒呼叫既有 profile_cache._populate_cache(抽成公開介面,不複製) |
回報 vulndb_date/vulndb_sync_error |
payload profiles:[{uid,version,sha256,state,error}] |
主系統 remote_agents.vulndb_* 三欄 |
新表 agent_profile_states(一台多支) |
主控台 POST /vulndb/check 清冷卻 |
POST /profiles/check 同款;主系統「補更新」=心跳回應帶 profiles_check:true 旗標(照 restart 旗標形狀) |
失敗冷卻同 vulndb,避免每次心跳重拉。
主控台總覽「檢測基準」卡:Agent profile_sync.summary() 回 {total, ok, error, last_synced_at, listed},取得時間用快取完成標記檔的 mtime(重啟不丟);卡片顯示「N 天前更新/M 支基準 K 支失敗」,主系統沒下發清單時顯示「主系統未提供」;「立即檢查更新」與弱點資料卡共用 useSyncCheck;健康區 profiles 燈超過 7 天或有失敗轉黃。
頁面:主系統「合規與稽核 → Agent 掃描工具設定」(route agent-tool-credentials,門檻 detection.remote-agent.configure)。左欄選 Agent(連線中/離線、已設定 n/N 支、最近心跳);右欄是那台每支工具一張卡:已設定/未設定、設定時間、設定方式(由主系統設定/Agent 主控台)、最近測試結果。只列租戶啟用、要帳密的工具。卡片標題列一顆「⋮」功能選單:
| 動作 | 彈窗 | 走哪條路 | 能力點 |
|---|---|---|---|
| 設定 | 照工具 schema 出表單,按「儲存」;已設定時提示會整組覆蓋 | POST /remote-agents/{uid}/tool-credentials → 主系統直推 Agent PUT /detection/credentials |
detection.remote-agent.configure |
| 測試連線 | 要連目標主機的工具從設備清冊挑;有兩組憑證的工具先選組 | 既有 POST /detection-tools/configs/{uid}/test-connection 帶 agent_uid,Agent 用本機帳密測、結果記回心跳 |
detection.plugin.update |
| 清除 | 確認窗說明之後派工會因未設定而失敗 | DELETE /remote-agents/{uid}/tool-credentials → 直推 DELETE /detection/credentials |
detection.remote-agent.configure |
頁頂「管理啟用的工具」對話框是租戶層開關:關掉的工具整個停用,這頁不列、任務設定也選不到。
直推流程:
is_online false → 409 FILE_AGENT_409003,不打 Agent。工具目錄不認得 → 404。infra/remote_agent/agent_credential_client.py 以 mTLS+短效 JWT 打 Agent;帶帳密的 PUT 在非 full 模式直接拒(不走裸 http);回應比對 X-Agent-Fingerprint,不符拒用並稽核 6081。/detection/credentials 走 credential_handover.store(照工具目錄 schema 用 secret_form.validate 驗、寫 credential_store、稽核 6086/6087 method=handover);欄位不合回 400,訊息只有欄名。status 寫回 remote_agents.configured_tools(assign_fields),畫面當場翻面;下一次心跳照常以 Agent 自報值覆蓋。AGENT_CREDENTIAL_SET/AGENT_CREDENTIAL_CLEARED method=remote,只帶工具代號。離線與舊版 Agent:右欄整頁鎖(離線說明連不上、舊版說明請先升級),每 30 秒重抓 Agent,連回自動解鎖;填到一半斷線會關彈窗。
業務碼 ──audit(logger,"AGENT_X",AgentEventCode.AGENT_X,**fields)──▶ logger "agent"
│
ConsoleActorFilter(補 user_uid/user_nickname/login_method/source_ip;無 request→system)
SecretMaskingFilter(jedi-common)
│
QueueHandler(請求不等 DB)
│ 專屬執行緒
QueueListener ──▶ AgentDBLogHandler(DBLogHandler)
只放行 event_code≠None/''/'-';缺欄補 None
system_log_service.add_system_log(@transaction 自開 scope)
│
SQLite system_logs
│
心跳 console_events:select id>cursor and event_code in REPORTED
ack → cursor=max(id)(自增 id,重啟不重送)
audit("credential_set", g.console_session.sub, tool=code) 改成 audit(logger, "AGENT_CREDENTIAL_SET", AgentEventCode.AGENT_CREDENTIAL_SET, tool=code)。actor 參數消失。AgentEventCode 旁一個 REPORTED 集合),不再是 audit.py 另一個集合。AGENT_LOGOUT、AGENT_CREDENTIAL_TESTED、AGENT_PASSWORD_CHANGED、AGENT_HEARTBEAT_LOST、AGENT_HEARTBEAT_RESTORED、AGENT_VULNDB_UPDATED、AGENT_PROFILE_UPDATED、AGENT_LOCAL_SCAN_REFUSED、AGENT_LDAP_CHANGED、AGENT_STORAGE_CHANGED、AGENT_SUPPORT_BUNDLE_DOWNLOADED,從 6207 起。delete where act_time < now-180d。core/console/audit_import.py 啟動時把舊 console-audit.jsonl(含 .1)照時間排序一次寫進表,35 個舊動作名對到事件碼、對不到的記 6235;同一交易寫一列 6234 當冪等標記,寫完才把檔改名 .imported;act_time 原樣保留到微秒,主系統以 at 去重不會重複。audit_once 同一 session 同一對象在窗內只記第一筆(只在真的記了才更新時刻)。GET /console/api/logs/export 同一組篩選、不分頁、上限 50,000 列,CSV 帶 BOM、以 = + - @ 開頭的儲存格加單引號;守「看日誌」範圍+download-files 兩層;走 file_protect.send_protected(FR-169)。AgentDBLogHandler 只存在因為 0.0.31 的 emit 不過濾且直讀 record.user_uid;檔頭註解只寫這一句與「升 jedi-common ≥1.3.6 即刪」。QueueListener 執行緒上呼叫 add_system_log,@transaction 能自開 session_scope(session_context 是 ContextVar,新執行緒為空,應可);不行就在 handler 內顯式 with session_scope()。Login.vue 的 toggleLocale 抽成 useLocale.js(localStorage 記住,照 theme.js 形狀),殼頂欄與登入頁共用。
gen_permission_matrix.py 重產矩陣讓 FE 角色矩陣多一欄「下載/匯出」。send_protected:主控台檔案、網路除錯報告、診斷包、日誌匯出,主系統 Agent 執行紀錄報告;預覽不加密。AGENT_CONSOLE_TICKET_SCOPE_UNKNOWN(請升級 Agent),不混進「無效或過期」。SecretMaskingFilter;A3 突變:把 filter 拿掉,含 password= 的測試要紅。path/line_no 這種程式座標給使用者。批(Stage)=工作坊同時開幾個小弟一起跑的那一組:同一批不改同一個既有檔、不依賴對方產出。底表在 handoff/cards.py,兩個斷言已過。
登記型檔只讓一張卡碰:manifest.tsv/event_code.py/remote_agent.py adapters(B1、B2、B3 各在不同批);console/routes.py(A6);enroll.py(A7);Shell.vue 與 i18n key(F1 先登記「日誌」項,F3 只新開 view);capabilities.js 由 B1 重產、F2 commit。
套件異動:jedi-file-upload 1.4.0、jedi-remote-agent 1.9.0、jedi-detection 1.7.0、jedi-issue 1.4.0(意見回饋附件認領者),皆已發版、BE 已釘。批 10 與手測直修只動 Agent、BE、FE,沒有新套件版本。
表中 B3/F5 兩列寫的是開卡範圍(派工單+等心跳);行為以 D5 直連為準,見 §5.4。
| 批 | 主題 | 卡 | repo | reuse/extend/new+理由 | 改哪些既有檔 | 新開哪些檔 | 依賴 | 驗收 |
|---|---|---|---|---|---|---|---|---|
| 1 | 下載權限點 | A1 jedi-file-upload:簽票分 preview/download 兩種用途、下載端點只收 download 票、宿主可注入下載守門 | jedi 套件 | extend:UploadFileAccessTokenRoute 加 `?action=preview |
download(預設 preview,舊前端不壞);FileUploadAdapters加一欄download_guard(宿主注入,None=不擋);UploadFileDownloadRoute` 驗票時只收 action=download 的票;不另開第二條下載端點 |
jedi_file_upload/api/routes/upload_file_route.py 141(簽票)、160(下載)、jedi_file_upload/plugin/contract.py 125(FileUploadAdapters)、jedi_file_upload/api/guards.py 42(file_access_guard 傳 action) |
— | |
| 1 | 下載權限點 | A2 jedi-remote-agent:主控台票新範圍 download-files(A2b 對到 detection.remote-agent.download-files);AgentEventCode 補本機事件碼;console_event 收 event_code |
jedi 套件 | extend:plugin/contract.py 的 CONSOLE_SCOPE_CAPABILITIES 與 OFFLINE_OPERATOR_SCOPE_CAPABILITIES 各加一列;common/code.py AgentEventCode 從 6207 起加碼;heartbeat_console.ingest_console_events 收的事件多一個 event_code 鍵(沒帶仍照 action 對照,舊 Agent 不壞) |
jedi_remote_agent/plugin/contract.py 44、52、jedi_remote_agent/common/code.py 89、jedi_remote_agent/app/service/heartbeat_console.py 87 |
— | tests:持有 各模組 download 能力點 的票帶 download-files;離線操作者範圍含它;ingest_console_events 帶 event_code 的事件原碼寫入、只帶 action 的照舊;新碼 6207~ 不與主專案 event_code.py 撞號(開卡已查最大 6206) |
|
| 1 | Agent 日誌 | A3 Agent 稽核改走 logging 管線:system_logs(SQLite)+QueueHandler+操作者過濾器+DB handler 過渡子類;41 個呼叫點改用套件 audit() | evidence-agent | reuse:入口用 jedi-remote-agent common/audit.py::audit(logger, event_name, event_code, **fields);表/DTO/service 用 jedi-common 0.0.31 logger/db_log/system_log;標準庫 QueueHandler+QueueListener。new(過渡層,升 jedi-common 即刪):DBLogHandler 薄子類(只放行帶 event_code、缺欄補 None)。new:ConsoleActorFilter(從 flask.g.console_session 補 user_uid/user_nickname/login_method/ip,背景執行緒補 system)。刪:audit.py 的 jsonl 寫入、ISO 游標、local_rows、REPORTED_ACTIONS/_MASKED_KEYS |
core/console/audit.py 155(整支改寫:record→委派 audit();pending/ack 改讀表、游標改自增 id)、core/local_db/migrations.py(v3:system_logs 表,欄位照 jedi-common model)、core/app_factory.py 24(logging 接線一處)、core/console/heartbeat.py 51、core/console/{routes,ops_routes,scan_routes,netdiag_routes,tools,files,runs_routes,ldap_routes,local_auth,local_auth_routes}.py、core/{console_allow_cidr,local_state_cli,ldap_source}.py(41 處呼叫改簽名、拿掉 actor 參數) |
core/audit_pipeline.py(filter、queue、handler 子類、install()) |
— | 登入/設帳密/手動掃描後 sqlite3 data/agent.db 'select event_code,user_name,message from system_logs' 有列且密碼欄為 ***;心跳 console_events 帶 event_code、ack 後游標前進(重啟不重送);背景執行緒事件 user_name=system;把 filter 拿掉 → 測試紅(突變);grep -rn 'console-audit.jsonl' core/ 為 0;寫表失敗只進 app log、請求不失敗;180 天清理在心跳跑一次/天 |
| 1 | profile 同步 | A4 jedi-detection:Agent×profile 取得狀態表、心跳附加欄位 provider、代設帳密的 handover 單(overwrite) | jedi 套件 | extend:新表 agent_profile_states(agent_id, profile_version_id, sha256, synced_at, error) 照套件既有 migration 形狀;credential_handover_service.start_for_agent 加 tools=/overwrite= 參數(代設走同一支,不另開 service);心跳附加欄位 profiles 的 provider 放套件(主專案接線) |
jedi_detection/app/service/credential_handover_service.py 91、116、jedi_detection/migrations/(新號) |
jedi_detection/domain/detection_tools/entity/agent_profile_state_entity.py、jedi_detection/infra/detection_tools/model+repo(agent_profile_state)、jedi_detection/app/service/agent_profile_sync_service.py(current_profiles_for_heartbeat()、record_agent_state()) |
— | DEV 套套件 migration 後 \d 新表有 RLS 四指令與 (agent_id, profile_version_id) 唯一鍵;current_profiles_for_heartbeat() 只回 is_current 版本的 {uid, version, sha256, file_uid};start_for_agent(tools=[x], overwrite=True) 建的單 params 帶 overwrite;既有 handover tests 綠 |
| 1 | 語言切換 | F1 主控台殼層:登入後語言切換、總覽「離線登入剩餘天數」卡、選單登記「日誌」分頁(先指向佔位) | FE | extend:Shell.vue 頂欄把 Login.vue 既有的 toggleLocale 搬成共用(state.js 或新 useLocale.js,localStorage 記住,照 theme.js 形狀);Overview.vue 的 banner 既有 offline_days/offline_login_days 算剩餘天數加一張卡(照 overviewHealth.js 既有卡形狀);登記型檔集中:Shell.vue 選單本卡一次加「日誌」項並佔 i18n key,F3 只新開 view |
console/Shell.vue 201、console/Login.vue 200(toggleLocale 改呼叫共用)、console/views/Overview.vue 141、console/router.js(logs 路由指向 Placeholder.vue)、i18n zh-tw/en agent-console.json |
console/useLocale.js |
— | 登入後右上角有地球鈕,切換後重整仍是該語言;總覽有「離線登入還能用 N 天」卡:N=上限−已離線天數、≤0 紅字並寫「只剩本機管理員與 AD 可登」、在線時卡不顯示;側欄多「日誌」項(點進去是佔位);grep border-left console/ 為 0 |
| 2 | 下載權限點 | A5 Agent 端:檔案與報告下載只認 download-files 範圍、檔案頁補預覽端點、不能 inline 的格式不給看 | evidence-agent | extend:files.py 的 files_download 改 require_session('download-files')、新增 files_preview 走既有 inline_policy(照 runs_routes 預覽端點形狀,不複製);netdiag_routes 報告下載同樣改範圍;local_login.py 認得新範圍(票上帶不認得的範圍整張拒收,先認再用) |
core/console/files.py 169、core/console/netdiag_routes.py(report 下載)、core/console/runs_routes.py(報告下載)、core/console/local_login.py(範圍白名單) |
A2、A3 | curl 8444:票無 download-files 時 GET /console/files/<uid>/download 403、/preview 200 且 HTML 回應帶 Content-Security-Policy: sandbox;svg 預覽 415;主系統票帶 download-files 時 200;tests 含突變(把範圍檢查拿掉要紅) |
|
| 2 | Agent 日誌 | A6 Agent 日誌查詢 API:依人/事件碼/日期分頁讀本機 system_logs | evidence-agent | reuse:jedi-common system_log_service.get_system_log_list(curr_page, page_size, <strong>filters) 已有分頁與篩選,端點只做參數解析與序列化;守門 require_session(('configure','files','run-local-scan','net-diag')) 唯讀;登記型檔**:routes.py 只加一行掛 blueprint |
core/console/routes.py 212(掛一行) |
core/console/log_routes.py |
A3 | GET /console/logs?page=1&size=50&user=local-admin&event_code=6093&from=…&to=… 回 {items, total},欄位 act_time/user_name/event_code/message/method;無 session 401;message 裡沒有密碼(A3 已遮) |
| 2 | profile 同步 | A7 Agent profile 同步:心跳收 profiles 清單比對本機快取、背景補拉、回報每支狀態;主控台「立即檢查」 | evidence-agent | reuse:取檔與快取用既有 core/profile_cache.py(_populate_cache、is_cache_valid),不另寫下載;流程照 core/vulndb_sync.py 形狀(observe→比對→背景執行緒→回報→冷卻),request_check() 同款;登記型檔:enroll.py 掛一個 observer+payload 加一欄 |
core/enroll.py 287(payload 加 profiles)、362(observer 一行)、core/console/ops_routes.py(POST /console/profiles/check 照 vulndb/check 形狀) |
core/profile_sync.py |
A4 | 心跳回應帶 profiles:[{uid,version,sha256,file_uid}] 時,本機沒有的在背景拉、拉完 marker sha256 一致;下次心跳 payload `profiles:[{uid,version,sha256,state:ok |
| 2 | 代設工具帳密 | A9 Agent 收代設帳密:handover 單帶 overwrite 時蓋掉本機既有值 | evidence-agent | extend:credential_handover.store 讀 task.get('overwrite'),True 走 credential_store.put(既有)而非 put_if_absent;回報 summary 多 overwritten |
core/credential_handover.py 20 |
A4 | tests:overwrite=False 既有不蓋(stored/skipped 同今天);overwrite=True 蓋掉並回 overwritten;log 只帶工具代號;稽核 AGENT_CREDENTIAL_SET method=handover |
|
| 2 | 下載權限點 | B1 主系統:EventCode 鏡像 6207~6217、console sink 收 event_code(下載守門改由 B4 分模組做) | BE | extend:migration 照 2026-10-27-fr166-agent-standalone-capabilities.sql 形狀但不綁預設角色;core/plugins/file_upload.py adapters 多注入 download_guard=require_capability('file.download');core/plugins/remote_agent.py _ADMIN_CAPABILITIES 的 RemoteAgentLocalRunReportRoute.get 改 各模組 download 能力點;common/enum/event_code.py 鏡像 A2 新碼;core/plugins/_agent_console_audit.py 收 event_code;跑 scripts/deliverables/gen_permission_matrix.py 重產 FE capabilities.js(FE 檔由 F2 commit) |
core/plugins/file_upload.py 351、core/plugins/remote_agent.py 186、common/enum/event_code.py 198、core/plugins/_agent_console_audit.py 25、scripts/sql/manifest.tsv |
scripts/sql/2026-10-29-fr166-1-file-download-capability.sql |
A1、A2 | DEV 套 migration:select count(*) from role_capabilities rc join capabilities c on c.id=rc.capability_id where c.name like '%.download' 為 0(Administrator 靠 *.*.*);無此能力點的帳號 GET /file/access-token/<uid>?action=download 403、?action=preview 200;Agent 執行紀錄報告下載端點同樣 403/200;BE 重啟實打;守衛測試綠;回寫明講「出貨基線待重產」 |
| 4 | profile 同步 | B2 主系統 profile 同步接線:心跳附加 profiles、心跳回報入表、profile 頁查每台 Agent 取得狀態、補更新端點 | BE | extend:core/plugins/remote_agent.py heartbeat_extras 加 A4 的 provider(照 _agent_vulndb.py 形狀新開 _agent_profile_sync.py);心跳 payload profiles 入表走套件 service;新端點 GET /detection-profiles/<uid>/agents(每台 Agent:version、sha256、synced_at、error)與 POST /remote-agents/<uid>/profiles/check(經心跳要求 Agent 立即檢查,照 restart 旗標形狀);守門 detection.profile.read/detection.remote-agent.configure |
core/plugins/remote_agent.py 319(heartbeat_extras 加一項)、186(兩端點登記) |
core/plugins/_agent_profile_sync.py、api/remote_agent/routes/agent_profile_sync_route.py |
A4、A7 | DEV:上傳新版 profile → 123 Agent 下次心跳拉到 → agent_profile_states 有列、GET …/agents 看得到 ok;按補更新 → 心跳回應帶旗標 → Agent 清冷卻;BE 重啟實打;守衛測試綠 |
| 3 | 下載權限點 | A1b jedi-file-upload:登記表加 FILE_ACTION_DOWNLOAD、拆掉全局 download_guard 插槽 |
jedi 套件 | extend:domain/ports.py 多一個動作常數;FileUploadAdapters 拿掉 A1 的全局插槽(守門責任下放認領者) |
jedi_file_upload/domain/ports.py、plugin/contract.py、api/routes/upload_file_route.py |
A1 | tests:download 票簽發前呼叫認領者的 assert_can_access(file, FILE_ACTION_DOWNLOAD);沒有認領者的檔 404 |
|
| 3 | 下載權限點 | A2b jedi-remote-agent:download-files 範圍對到 detection.remote-agent.download-files、CAPABILITIES 申報它 |
jedi 套件 | extend:plugin/contract.py 對照表改一列、能力點清單加一顆(含 home_route) |
jedi_remote_agent/plugin/contract.py |
A2 | tests:持該顆者票帶 download-files;守衛測試「套件宣告的能力點都在 seed」綠 |
|
| 6 | 下載權限點 | B4 主系統:7 顆客戶資料下載能力點 migration、9 類認領者下載時看自己那顆、上傳者本人免、範本 SSP 佐證只鎖下載 | BE | new:core/plugins/_file_ownership.py::assert_download_capability 一支共用;extend:9 支認領者各加一行呼叫;event_code.py 鏡像 6218~6227 |
core/plugins/file_upload.py、各模組 ownership 檔、common/enum/event_code.py、scripts/sql/manifest.tsv |
scripts/sql/2026-10-29-fr166-1-download-capabilities.sql |
A1b、A2b、B1 | 無能力點帳號對他人證據 ?action=download 403、preview 200;對自己上傳的 download 200;role_capabilities 對 7 顆為 0 |
| 6 | 下載權限點 | A2c jedi-remote-agent:AgentEventCode 補登 6218~6227 十個 Agent 本機事件碼 |
jedi 套件 | extend:common/code.py 加十列(A3 暫定的碼正式登記) |
jedi_remote_agent/common/code.py |
A3 | tests:碼不撞、主專案鏡像一致 | |
| 7 | 下載權限點 | B5 主系統匯出端點補 export 能力點:稽核計畫、POA&M、風險總表、原始碼掃描檔原檔 | BE | extend:各端點 @require_capability("<模組>.export");migration 2 顆 |
api/project/routes/ap_export_route.py、api/project/routes/poam_objective_route.py、api/governance/routes/risk_register_route.py、manifest.tsv |
scripts/sql/2026-10-29-fr166-1-export-capabilities.sql |
B4 | 無 grc.risk.export 帳號 POST /governance/risks/export 403 GRC_403022;管理員 200 xlsx |
| 8 | 下載權限點 | F6 主站匯出鈕看各自 export 能力點(稽核計畫/POA&M/風險總表) | FE | extend:三處匯出鈕加 v-can;capabilities.js 重產 |
三個 view、src/config/capabilities.js |
B5 | 無能力點看不到匯出鈕;有則照常 | |
| 7 | 下載權限點 | F2 全系統下載鈕分模組看各自 download 能力點、上傳者本人免:主站 10 處+Agent 執行紀錄頁+主控台檔案頁改預覽、執行紀錄對話框下載鈕;commit 重產的 capabilities.js | FE | extend:主站 signedDownloadUtil.fileDownloadUrl 簽票帶 action=download、filePreviewUrl 帶 preview;10 處下載鈕統一 v-can="各模組 CAP.<模組>_DOWNLOAD"(PrimeVue Menu 項用既有 useMenuItemsCan);主控台 Files.vue 下載鈕改看 me.scope 含 download-files、加「預覽」鈕 reuse ReportPreviewDialog(svg/xhtml 不給看、顯示「此格式僅能下載」);Runs.vue 對話框下載鈕同範圍;runs.js canDownload 改認 download-files |
src/utils/signedDownloadUtil.js 44、src/components/grc/JobExecutionDrawer.vue 1434(超標 3179 行:只改一行加 v-can)、src/components/grc/evidence-view/RoundEvidenceView.vue 80、src/views/feedback/system/SystemFeedbackView.vue 60、src/views/feedback/system/SystemFeedbackForm.vue 240、src/views/evidence-classification/components/EvidenceFilePreviewDialog.vue 135、src/composables/useSbomViewer.js 26、src/composables/useScanFileDownload.js 19、src/views/remote-agent/AgentLocalRunsView.vue 213、src/config/capabilities.js(B1 重產,本卡 commit)、console/views/Files.vue 90、console/views/Runs.vue 185、console/runs.js 82 |
B1、A5 | 無 各模組 download 能力點 的角色:主站 10 處下載鈕全部不見、預覽照常;主控台檔案頁只有預覽、報告對話框無下載;有能力點的角色全部回來;`grep -rn 'DOWNLOAD_FILE|openFileDownload|fileDownloadUrl' src/ | |
| 4 | Agent 日誌 | F3 主控台「日誌」分頁:依人/事件/日期篩,欄位比照主站使用者日誌頁 | FE | reuse:表格與篩選列照主站 src/views/action-log/UserLogs.vue 的欄位與寫法,分段用 SegmentButtons;資料來源 A6 端點;事件碼顯示用既有 i18n lang.event_code.*(grep 確認主站有);只新開 view,不碰 Shell.vue(F1 已登記) |
console/router.js(logs 指向新 view) |
console/views/Logs.vue、console/logsApi.js |
A6、F1 | 分頁對 123 實際有列;篩人/事件/日期區間有效;message 不顯示密碼;grep border-left 為 0;表格一格一值 |
| 5 | 代設工具帳密 | B3 主系統代設 Agent 工具帳密端點:在線才收、建 overwrite handover 單、主系統不落地;檢測工具頁 route 翻回並改名 | BE | extend:新端點 POST /remote-agents/<uid>/tool-credentials {tool, fields} 走 A4 start_for_agent(tools=[tool], overwrite=True),fields 只進派工單 payload(既有 build_payload 從雲端密文讀 → 本卡加「一次性 fields 直接進單」分支,不存 tenant_detection_tool_configs);Agent 離線(is_online 為 false)回 409 GRC_409xxx;守門 detection.remote-agent.configure;稽核 AGENT_CREDENTIAL_SET method=remote;migration 把 tool-plugin-manage 翻回 enable=1、名稱改「Agent 掃描工具設定」、綁 configure 能力點 |
core/plugins/remote_agent.py 186(端點登記)、common/code/grc_error_code.py、scripts/sql/manifest.tsv |
api/remote_agent/routes/agent_tool_credentials_route.py、scripts/sql/2026-10-29-fr166-1-tool-page-agent-credentials.sql |
A4、A9 | 在線 Agent:POST 後 123 下次心跳收到單、本機值被蓋、回執 overwritten;離線 Agent 409;select * from tenant_detection_tool_configs 沒新增列;system_logs 有 6086 method=remote 且 message 無帳密;選單翻回且改名;守衛測試綠;回寫明講「出貨基線待重產」 |
| 5 | profile 同步 | F4 主站 profile 頁:每個版本展開「Agent 取得狀態」表+「補更新」鈕 | FE | extend:ScanToolResourcesView.vue(82 行)加一個子元件掛點;新元件 ProfileAgentStates.vue 讀 B2 端點,表格一格一值(Agent 名、版本、同步時間、狀態 Tag),補更新鈕 v-can="CAP.DETECTION_REMOTE_AGENT_CONFIGURE" |
src/views/plugin/ScanToolResourcesView.vue 82、src/config/api/api.js、i18n |
src/views/plugin/components/ProfileAgentStates.vue |
B2 | 上傳新版後表格顯示 123 從「待更新」變「已取得」;按補更新有 toast、Agent 下次心跳拉;離線 Agent 顯示「離線」不報錯;grep border-left 為 0 |
| 8 | 代設工具帳密 | F5 主站「Agent 掃描工具設定」頁:選 Agent、選工具、填帳密、送出;離線直接說連不上 | FE | extend:ToolPluginManage.vue 766 行超標:只留殼與路由,新邏輯進新元件 AgentCredentialSetter.vue;工具表單 reuse 既有 tool_schemas/config_field_schema 的表單渲染(grep 主控台 SecretForm.vue 與主站既有工具表單,二擇一抽共用、不第三份);送出後顯示「已送出,等 Agent 下次心跳(最多 N 秒)」、輪詢 handover 進度(既有 credential_handover 欄) |
src/views/plugin/ToolPluginManage.vue 766(淨減)、src/config/api/api.js、i18n、src/router(頁名) |
src/views/plugin/components/AgentCredentialSetter.vue |
B3、F2 | 選離線 Agent 送出 → 409 toast「這台現在連不上」;在線送出 → 幾十秒內狀態變「Agent 已收」;主系統 DB 無帳密;wc -l ToolPluginManage.vue 比 766 小;表單不自刻第三份;grep border-left 為 0 |
| 9 | 文件 | D1 SPEC 與手冊補到現況:下載權限點、profile 同步、代設帳密、Agent 日誌、剩餘天數、語言切換;FE 角色矩陣多一顆 | BE | extend:docs/spec-site/current/evidence/agent-console.md、remote-agent-manage.md、scan-tool-resources(profile 頁)對應頁各加段+檔頭變更紀錄一行;手冊 docs/user-manual/agent/13-standalone-operation.md 13.x 補操作;docs/claude/reference_permission_system_sop 若列能力點清單補 各模組 download 能力點 |
docs/spec-site/current/evidence/agent-console.md、docs/spec-site/current/evidence/remote-agent-manage.md、docs/user-manual/agent/13-standalone-operation.md |
F2、F3、F4、F5 | 六個主題各有一段;grep -n '原本|第 [0-9] 棒|這次' 命中 0;SPEC 頁 build 過 |
|
| 10 | 檢測基準+AD 鎖 | A10 Agent:總覽「檢測基準」摘要與燈;離線超過天數 AD 登入一併鎖(D9) | evidence-agent | extend:profile_sync.summary()、overview._profiles_lamp;local_auth.operator_session_valid 拿掉 AD 例外 |
core/profile_sync.py、core/profile_cache.py、core/console/overview.py、core/console/local_auth.py、core/heartbeat_status.py |
— | AD 登入過期後 401、已登入被踢;local-admin 照登;總覽 info.profiles 與 profiles 燈有值 |
|
| 10 | 檢測基準卡 | F7 主控台:總覽「檢測基準」卡+立即檢查+燈;離線鎖定時 AD 分頁一起灰 | FE | extend:useVulndbCheck 泛化成 useSyncCheck 兩張卡共用 |
console/views/Overview.vue、console/Login.vue、console/opsApi.js、console/overviewHealth.js、i18n |
console/useSyncCheck.js(改名) |
A10 | 卡片顯示 N 天前/M 支 K 失敗;「主系統未提供」;文案不再說 AD 不受限 |
| 10 | Agent 日誌 | A11 Agent:日誌覆蓋率——舊 jsonl 一次匯入、預覽記 6230、進頁/開工具表單/開執行紀錄詳情 6231~6233(D10) | evidence-agent | new:audit_import.py;extend:audit.audit_once、各分頁 API 掛 page_viewed |
core/console/audit.py、files.py、tools.py、runs_routes.py、scan_routes.py、log_routes.py…、core/app_factory.py |
core/console/audit_import.py |
— | 123 升級後多 61 筆舊紀錄、jsonl 改名 .imported;走一圈每步一筆 |
| 10 | 工具設定頁 | F8 主站「Agent 掃描工具設定」頁重做:左選 Agent、右列工具卡、離線整頁鎖、拆舊目錄 | FE | new:AgentPicker、AgentToolCard、EnabledToolsDialog、agentToolCards.js;刪 DetectionToolCards.vue 等五檔 |
AgentCredentialSetter.vue、ToolPluginManage.vue、i18n |
見左 | — | 版面照雛形;離線鎖;舊目錄不見 |
| # | 步驟 | 期望 |
|---|---|---|
| 1 | 用沒有任何 download/export 能力點的角色登主站 | 他人上傳的證據、SSP 佐證、SBOM、掃描檔、意見回饋、Agent 執行紀錄的下載鈕全部不見,自己上傳的仍可下載;預覽照常;稽核計畫/POA&M/風險總表匯出鈕不見 |
| 2 | 同角色跳轉 Agent 主控台檔案頁 | 只有預覽;svg 顯示「此格式僅能下載」且無下載鈕 |
| 3 | 給該角色對應模組的 download/export 顆 | 該模組的下載鈕回來;直接打 ?action=download 簽票 200;拿 preview 票打下載端點 403 用途不符 |
| 4 | 123 拔網路 | 總覽「離線登入還能用 N 天」卡出現,N=租戶設定−已離線天數;超過天數後離線密碼與 AD 分頁一起灰、AD 登入 401,本機管理員照登 |
| 5 | 主站上傳新版 profile | profile 頁該版本展開:123「待更新」→ 下次心跳後「已取得」;按補更新 → Agent 立即檢查;主控台總覽「檢測基準」卡顯示幾天前更新 |
| 6 | 主站「Agent 掃描工具設定」對 123 的 Nmap「⋮ → 設定」、儲存、再「⋮ → 測試連線」 | 儲存當場成功、卡片翻成已設定;欄位不合當場報哪一欄;測試連線結果寫進「最後測試」;123 主控台工具頁看到同一設定時間;主系統 DB 無帳密 |
| 7 | 123 離線時打開那台 | 右欄整頁鎖並說明連不上;連回 30 秒內自動解鎖 |
| 8 | 做完 1~7 開主控台「日誌」 | 每一步都有列(含預覽、進頁、開工具表單)、操作者正確、密碼欄 ***;升級前的舊紀錄也在;「匯出 CSV」跳一次性密碼、下載加密檔;主站使用者日誌頁看到回傳的那幾筆 |
| 9 | 登入後切英文、重整 | 仍是英文 |
| 10 | 主系統升級後、Agent 未升時從主系統開主控台 | 登入頁說「這台 Agent 版本比主系統舊,請升級」,不是「入場券無效」 |
download-files,舊 Agent 整張拒收,持有者登不進主控台。與 FR-166 P3-0b 同一個坑。action 預設 preview,只有 FE 的 fileDownloadUrl 一處改帶 download;其他簽票呼叫者行為不變。/data/content/cache/:正式版靜 compose 掛可寫 volume;用源碼直接跑的開發機要自己把這個目錄給 Agent 帳號寫入權,否則每支 profile 回報 PermissionError。DBLogHandler.emit 整支 try/except 走 handleError,1.3.6 有、0.0.31 沒有,子類要補。JobExecutionDrawer.vue 3179 行:F2 只改一行加 v-can,不碰其他。設計決策與拆卡;開工後現況看 SPEC 與手冊;每棒做了什麼看 handoff/FR-166.1-LOG.md。