FR-190 · 需求討論稿 · 2026-11-09(v1 待審)
把 Agent 主控台 7 個大範圍拆成「每個功能 × 檢視/設定/執行/下載」26 顆能力點;主系統角色設定頁逐顆給;同步機制沿用、不重做
Agent 主控台現在只有 7 個權限範圍,一個「設定」包了 9 個頁面、一個「下載」包了 5 種檔。管理員想讓某個角色「可以下載掃描報告、但不能下載證據檔」做不到,想讓人「只管 LDAP、不碰工具帳密」也做不到。本案把這 7 個範圍拆成 11 個功能 × 最多 4 個動作=26 顆能力點,全部放進主系統既有的能力點表,角色設定頁逐顆勾;Agent 收到的票與離線名單照既有管道帶過去,同步機制一行不改。三邊(主系統、jedi-remote-agent、Agent)改成共用一份清單,不再各自硬寫。決策者已裁:顆粒做滿 26 顆、舊 Agent 收到不認得的權限就丟掉而不是拒收、主系統派的掃描紀錄歸「掃描 · 檢視」。
Agent 主控台是裝在客戶機器上的管理畫面。誰能進去、進去能做什麼,由主系統決定:使用者在主系統點「進入主控台」時,主系統看他持有哪些 Agent 能力點,把對應的「權限範圍」寫進一張五分鐘有效的入場券,Agent 驗票後照票上的範圍開頁面、擋 API。斷線時用的離線操作者名單,也是主系統每次心跳依該使用者當下的能力點算好下發。
這套機制是對的,問題只在顆粒。 現在只有 7 個範圍:
| 範圍 | 主系統能力點 | 實際蓋到的東西 |
|---|---|---|
configure |
Agent 設定 | 工具帳密、LDAP、金鑰換發、授權上傳、離線登入設定、Agent 名稱、主系統位址、儲存設定、連線與換主系統、三種「檢查更新」、診斷包、主系統派的任務紀錄 |
files |
Agent 檔案 | 檔案列表、預覽、日誌頁 |
run-local-scan |
Agent 獨立掃描 | 掃描頁的看+執行+手動掃描紀錄 |
net-diag |
Agent 網路除錯 | 除錯頁的看+執行+除錯紀錄 |
download-files |
Agent 下載檔案 | 證據檔下載、掃描報告原檔、除錯報告、日誌匯出、診斷包 |
restart |
重啟 Agent | 重啟 |
update |
更新 Agent 版本 | 線上換版、離線上傳換版 |
🔴 三個做不到的事
download-files。configure。而且 主系統派下來的掃描紀錄要有「設定」權限才看得到,有掃描權限的人反而看不到。原因只是當初沒有一顆對應的能力點,隨手掛在設定底下。
另一個隱性問題:範圍清單在三個地方各寫一份——Agent 的 CONSOLE_SCOPES、jedi-remote-agent 的 CONSOLE_SCOPE_CAPABILITIES、主控台前端 router.js 每頁的 scope。三邊靠人工對齊,少一邊就是「票上有、Agent 不認」,整張票被拒。
整案一句話:7 個範圍拆成 26 顆能力點,三邊改讀同一份清單,角色頁逐顆給,同步機制不動。
| 階段 | 做什麼 | 產出 | 完成怎麼判定(決策者檢查法) |
|---|---|---|---|
| P0 契約 | 在三邊共用的 jedi-agent-protocol 套件寫下 26 顆的清單(功能、動作、顯示名、離線可不可下放) |
套件新版本 | 開套件檔看到 11 個功能 × 動作的表;三邊鏡像測試綠 |
| P1 四邊接上 | 主系統 BE(能力點 migration、舊轉新、管理端點守門換顆、角色樹子頁)、主系統 FE(角色頁文案、離線操作者標籤)、jedi-remote-agent(宣告 26 顆、簽票、離線名單)、Agent 後端(約 60 條路由守門換顆、不認得的範圍丟掉)、主控台前端(選單與按鈕依新顆顯示、舊版橫幅) | 五個 repo 各一批 commit | 對照雛形第 1~4 頁:角色頁看到「Agent 管理 › Agent 主控台」子頁底下 26 顆;給一個角色只勾「檔案 · 檢視」+「掃描 · 下載」,用該角色進主控台:檔案頁只有預覽、掃描紀錄有下載鈕、其餘頁不出現 |
| P2 收口 | 兩支套件發版、主系統與 Agent 改回釘版、Agent 出 image、SPEC 與手冊 | 版號、image、文件 | 用釘版 wheel 起主系統 HEAD 正常;手冊「角色權限」一節列 26 顆 |
依賴:P1 前要先開一張環境卡(主系統與 Agent 開發期改走本機路徑裝套件),否則 P1 的卡 import 到的是舊發行版、測試假綠。
測試前提:Agent 一定要升到新版
26 顆新權限的守門寫在新版 Agent 裡,舊版 Agent 不認得新名字。要驗這個功能,測試用的 Agent 必須先裝新版。這點不管怎麼設計都一樣。D2 決定的是另一件事:客戶現場還沒升的舊 Agent,使用者是「完全登不進」還是「登得進但只有舊功能」。
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
participant Admin as 管理員
participant Main as 主系統
participant Agent as Agent
participant User as 稽核員
Admin->>Main: 角色設定頁勾 3 顆(掃描檢視/掃描下載/檔案檢視)
User->>Main: Agent 管理頁點「進入主控台」
Main->>Main: 逐顆查持有的能力點 → 票上寫 3 個範圍
Main-->>User: 五分鐘票
User->>Agent: 帶票登入
Agent->>Agent: 認得的範圍留下、不認得的丟掉並記數(D2)
Agent-->>User: 側欄只出現有「檢視」的頁;下載鈕看「下載」顆
Note over Main,Agent: 離線路:每次心跳主系統重算該使用者的範圍 → 整份名單下發
Main->>Agent: 心跳回應帶離線操作者名單(含 3 個範圍)
Agent->>Agent: 覆蓋名單;縮權的人踢掉已登入 session
D1 顆粒做滿:11 個功能 × 最多 4 個動作,共 26 顆
動作只有四種,全部是角色頁已經認得的詞:檢視(頁面出現、唯讀 API)、設定(改這頁的設定)、執行(跑掃描、跑除錯、重啟、換版)、下載(把檔帶走)。
| 功能 | 檢視 | 設定 | 執行 | 下載 |
|---|---|---|---|---|
| 檔案 | 列表、預覽、上傳者清單 | 證據檔原檔 | ||
| 掃描 | 工具、目標、基準、紀錄(含主系統派的,D3) | 執行、取消、重送結果 | 掃描報告原檔、工具 log | |
| 網路除錯 | 目標、紀錄、預估、報告預覽 | 執行、重送 | 除錯報告 | |
| 日誌 | 查日誌 | 匯出日誌 | ||
| 工具設定 | 看已設定(不回密碼) | 改帳密、測試連線、清除 | ||
| LDAP | 看設定 | 改來源、改本機設定、測試、重新信任 | ||
| 金鑰 | 看金鑰狀態 | 換發 | ||
| 授權 | 看授權狀態 | 上傳授權檔、線上啟用 | ||
| 維運 | 服務狀態、離線登入設定、儲存設定 | 改名稱、改主系統位址、改儲存、改離線登入、三種「檢查更新」 | 重啟 | 診斷包 |
| 更新 | 看版本、檢查新版 | 線上換版、離線上傳換版 | ||
| 連線設定 | 看註冊狀態 | 註冊、探測、換主系統 |
理由:拆一半等於再做一次;四個動作是角色頁現成的欄,管理員不用學新東西。被排除:只拆下載那一顆(工作量三分之一,但「設定」包九頁的問題還在)。
D2 舊 Agent 收到不認得的權限:丟掉,不拒收
現況是票上有一個 Agent 不認得的範圍,整張票作廢、登不進。改成:不認得的丟掉,認得的照常給,主控台頂部顯示一句「這台 Agent 版本較舊,有 N 項權限尚未支援,升級後生效」。
理由:丟掉只會「少拿權限」不會「多拿」,安全上沒有風險;換來的是主系統可以先升、Agent 慢慢跟,現場不會因為漏一台 Agent 就整台登不進。被排除:維持拒收(升級順序變硬性、錯誤訊息只有一句「需要升級」)。
影響:Agent 的 TicketScopeUnknown 錯誤路徑拿掉;/api/me 多回「丟掉了幾個」給前端顯示橫幅;離線名單同樣過濾、不報錯(現況已是如此)。
D3 主系統派下來的掃描紀錄歸「掃描 · 檢視」
執行紀錄頁的掃描紀錄不分來源(本機手動、主系統派工)都歸「掃描 · 檢視」看、「掃描 · 下載」帶走報告。網路除錯紀錄歸「網路除錯 · 檢視/下載」。
理由:對使用者它們都是掃描結果,差別只在誰按的鈕,不該用兩顆權限管。被排除:維持掛在設定底下(只管帳密的人看得到所有派工結果,反而不合理)。
D4 角色設定頁怎麼排這 26 顆
現在 Agent 的 11 顆全部平鋪在「檢測 › Agent 管理」這一頁底下,與「新增/檢視/修改/刪除 Agent」四顆混在一起。26 顆再平鋪會是 30 個勾,看不懂。
角色樹已經支援「內頁當子頁」(FR-132 做的 tree_page)。三個排法:
建議:A。一層子頁夠分清「管 Agent 清單」與「進主控台做事」,前綴讓 26 顆掃得過去;B 要為主系統沒有的 11 個畫面各造一列 ui_routes,太重。開卡前要驗:ui_routes 加一列 is_menu=false、tree_page=true 但主系統沒有對應畫面,前端路由守衛不會因此出錯。對照雛形第 1 頁。
D5 舊 7 顆怎麼退場
主系統能力點表現在有 7 顆舊的(configure、browse-files、run-local-scan、net-diag、download-files、restart、upgrade)。
role_capabilities、route_capabilities、role_capability_patterns 的列——這三張表對能力點沒有外鍵,要手清)。新顆的 legacy_name 記舊名。展開對照(舊 → 新):configure → 工具/LDAP/金鑰/授權/維運/連線六組的檢視+設定,另加「掃描 · 檢視」(D3 後派工紀錄歸這裡);browse-files → 檔案 · 檢視、日誌 · 檢視;run-local-scan → 掃描 · 檢視+執行、日誌 · 檢視;net-diag → 除錯 · 檢視+執行、日誌 · 檢視;download-files → 檔案/掃描/除錯/日誌四顆下載,維運 · 下載只給同時持有 configure 的角色(診斷包現況要兩顆都有);restart → 維運 · 執行;upgrade → 更新 · 檢視+執行。
建議:A。出貨前無客戶、每版可直接升級由 migration 保證;留一堆退役顆是第二套真相。展開會讓少數角色「多一點」(持 configure 的多看到手動掃描紀錄)、「少一點」(持 download-files 但沒 configure 的拿不到診斷包,與現況一致)——都寫進 migration 檔頭。
D6 離線操作者不下放哪些
FR-166 定的:離線操作者不給「重啟」「換版」(不可逆、只給從主系統進來的人)。對到新顆就是 維運 · 執行、更新 · 檢視、更新 · 執行 不下放。
另外三顆要不要也不下放:連線設定 · 設定(註冊、換主系統——斷線時改主系統位址是「自救」還是「風險」?)、金鑰 · 設定(換發要連主系統,斷線時按了也沒用)、維運 · 設定 裡的「改主系統位址」。
建議:維持 FR-166 的線,只不下放維運 · 執行與更新兩顆;其餘照使用者持有的下放。斷線時「換主系統位址」正是離線操作者存在的理由之一(FR-166 D14 主系統搬家)。清單上每顆加一個「離線可下放」旗標,放在共用清單裡,jedi-remote-agent 從旗標推導,不再另外手寫一張表。
D7 主系統這邊也有幾個端點要換顆
主系統「Agent 執行紀錄」頁的三個下載端點(報告原檔、報告檢視、工具 log)現在守 download-files;代設工具帳密守 configure;補更新基準守 configure;重啟守 restart。
建議:執行紀錄下載依紀錄種類換成「掃描 · 下載」或「除錯 · 下載」;代設工具帳密 → 「工具設定 · 設定」;補更新基準 → 「維運 · 設定」;重啟 → 「維運 · 執行」;Agent 清單可見(_AGENT_LIST)改成「持有任一顆 Agent 主控台檢視」也看得到;簽票端點改成「持有 26 顆任一」。
D8 票上怎麼寫 26 個範圍
票是 RS256 JWT,現在 7 個範圍約 1.8 KB,Agent 登入入口的 body 上限 8 KB。
files.download),估 2.5 KB,Agent 端 require_session("files.download") 一對一,不需要任何對照表。建議:A。8 KB 餘裕夠,可讀性在除錯時值錢。
D9 要不要跟主系統的對應功能連動(決策者 2026-11-09 問)
管理員的痛點是「主系統勾了掃描設定,Agent 這邊還要再勾一次」。三個做法:
detection.profile.update 就自動有「掃描 · 執行」。管理員只勾一次。對照表(主系統功能 ↔︎ Agent 主控台功能):
| Agent 主控台功能 | 主系統對應能力點 | 關係 | 出貨預帶給 |
|---|---|---|---|
| 掃描 · 檢視/執行/下載 | detection.profile.*、detection.scan-zone.*、grc.job.* |
只相關:主系統定義基準與目標、派任務;Agent 在機器上跑 | 稽核員:檢視+下載;IT Manager:三顆 |
| 工具設定 · 檢視/設定 | detection.plugin.*;主系統「Agent 掃描工具設定」頁現守 configure |
等價:代設帳密=在主控台改帳密 → D7 該頁改守「工具設定 · 設定」 | IT Manager |
| LDAP · 檢視/設定 | system.ldap-config.* |
只相關:主系統 LDAP 是全租戶登入、Agent LDAP 是那台離線登入 | IT Manager |
| 授權 · 檢視/設定 | platform.license.* |
只相關:平台層 vs 每台一份 | IT Manager |
| 更新 · 檢視/執行 | system.product-update.* |
只相關:各自不可逆(FR-172) | 只給 Administrator |
| 維運 · 四顆 | system.storage-config.*、現有 remote-agent.restart |
儲存只相關(MinIO vs 本機路徑);重啟等價於現有顆 | IT Manager;執行只給 Administrator |
| 日誌 · 檢視/下載 | 無(主系統日誌頁無獨立能力點;log-forwarding 是轉送設定) |
無對應 | IT Manager |
| 檔案 · 檢視/下載 | grc.job-evidence.download |
只相關:主系統按專案守、Agent 是這台全部不分專案(FR-166 刻意分開) | 不預帶(延續 FR-166.1 零角色) |
| 網路除錯 · 三顆 | 無 | 無 | IT Manager |
| 金鑰 · 檢視/設定 | detection.remote-agent.update(主系統換發憑證端點現守這顆) |
等價 → D7 改守「金鑰 · 設定」 | IT Manager |
| 連線設定 · 檢視/設定 | detection.remote-agent.create(註冊碼) |
相關:同一流程兩端 | IT Manager |
建議:B。A 會讓風險面不同的兩件事綁死——能編全租戶基準的顧問不該因此能在客戶機器上開掃描,現場 IT 能跑掃描也不該因此能改基準;主系統現有 Agent 顆本來就獨立於其他功能,沿用。C 是現況痛點。B 的「比照帶入」對照表就是上表,放在 protocol 清單每顆的 mirrors 欄,前端不另寫一份。對照雛形第 1 頁標題列。
| 元件 | 現況 | 本案動作 |
|---|---|---|
主系統能力點表 capabilities |
三段名 模組.資源.動作,有 license_module、legacy_name、home_route_name 欄;套件宣告由 flatten_pkg_migrations.sh 攤成 _capabilities.sql 每次升級重跑 |
沿用。26 顆由 jedi-remote-agent 的 CAPABILITIES 宣告,攤平自動進表;角色授權展開與刪舊顆另寫一支主線 migration |
簽票 RemoteAgentConsoleTicketRoute |
逐顆 capability_checker,持有的寫進 scope |
沿用,清單換成 26 顆 |
離線名單 OfflineOperatorService._scopes_for |
每次心跳依使用者當下能力點算,整份下發 | 沿用,對照表換成「清單中離線可下放的」 |
Agent 驗票 sync/domain/agent_auth.py |
不認得的範圍整張拒 | 改:丟掉並記數(D2) |
Agent 守門 console/api/*.py 約 60 條 require_session |
7 個範圍名 | 改名:一對一換成新顆;runs_routes 的來源判斷改歸掃描(D3) |
Agent shared/constants.py CONSOLE_SCOPES |
硬寫 7 個 | 改:從 jedi-agent-protocol import |
jedi-remote-agent contract.py 三張表 |
CAPABILITIES 11 顆、CONSOLE_SCOPE_CAPABILITIES、OFFLINE_OPERATOR_SCOPE_CAPABILITIES 硬寫 |
改:三張表全部從 protocol 清單推導,不再手寫 |
jedi-agent-protocol |
事件碼、錯誤碼、指令、設定、事件、信任錨;沒有權限範圍 | 新增 console_scopes 模組:資源、動作、顯示名、離線可下放旗標;三邊鏡像測試 |
主控台前端 console/router.js |
每頁 scope 硬寫、isVisible 任一命中 |
改名+各 view 的 canDownload/canConfigure 換新顆;/api/me 回丟掉的數量 → 橫幅 |
主系統 _ADMIN_CAPABILITIES |
約 40 個端點守舊 7 顆 | 改:D7 對照 |
角色頁 PermissionMenuTree |
選單頁 → 子頁(tree_page)→ 能力點三層;動作欄順序 ACTION_ORDER 已有 execute、export,沒有 download |
補 download 進排序;D4 子頁一列 ui_routes |
gen_permission_matrix.py 空殼判定 |
掃主系統與 jedi 套件原始碼有沒有人守;沒掃 Agent repo | 補:清單來自 protocol 套件(pip 裝在主系統 venv 裡掃得到),守門在 Agent 要標「Agent 端守門」而非空殼 |
FE i18n permission-tree.json/remote-agent.json |
11 顆標籤與說明、5 個 scope_* 文案 |
換 26 顆標籤與說明 |
| 離線操作者對話框 | 唯讀顯示該使用者的範圍 tag | 沿用,標籤換新 |
Agent 守衛測試 test_fr166_guards.py |
ops 路由逐支以單一 scope 打一次對表 | 擴:對表換 26 顆、涵蓋全部 blueprint |
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
P[jedi-agent-protocol<br/>console_scopes:26 顆清單<br/>資源/動作/顯示名/離線可下放]
P --> R[jedi-remote-agent<br/>CAPABILITIES 宣告<br/>簽票範圍<br/>離線名單範圍]
P --> A[evidence-agent<br/>CONSOLE_SCOPES<br/>require_session 守門<br/>不認得的丟掉]
R --> M[主系統 BE<br/>_capabilities.sql 攤平進表<br/>_ADMIN_CAPABILITIES 守門<br/>角色授權展開 migration]
M --> F[主系統 FE<br/>角色頁 26 顆<br/>離線操作者標籤<br/>capabilities.js 重產]
A --> C[主控台 FE<br/>router.js 每頁 scope<br/>按鈕看各顆<br/>舊版橫幅]
不新增任何表。 變動只有三處:
capabilities 多 26 列、少 7 列(D5)。module=agent(新模組,角色樹第一層多一組「Agent」)、resource_type=files 等 11 種、action 四種、license_module=remote-agent-manage 不變、home_route_name 指向 D4 的子頁。ui_routes 多一列:remote-agent-console,is_menu=false、tree_page=true、pid=remote-agent-manage(D4 A 案)。scope 欄值從 7 個短字串換成 files.download 形式,欄位型別不變。命名規則:票上的範圔字串=能力點名去掉 agent. 前綴。Agent 端不需要任何對照表。
模組為什麼是 agent 不是 detection(開卡後資安審查補):出貨 seed 四個系統角色帶 detection.*.*/detection.*.read 萬用字元,放 detection 底下新裝客戶的稽核主管會自動拿到全部 26 顆、唯讀角色拿到 11 顆檢視。FR-166 的 7 顆已踩在這個洞上,本案一併補掉。
| 方案 | 為什麼不 |
|---|---|
只拆 download-files 成 4 顆,其餘不動 |
「設定」包九頁的問題還在;下次再拆等於再做一次三邊同步 |
| 在 Agent 端自己做角色與權限表 | Agent 單租戶、無使用者表,主系統已是權限真相來源;兩套真相是 FR-048 收斂掉的病 |
| 票上帶位元遮罩縮小體積 | 8 KB 餘裕夠(D8),可讀性除錯時值錢 |
| 舊顆保留標退役 | 第二套真相;矩陣產生器與角色頁都要多一個狀態 |
| 維持「不認得的範圍整張拒收」 | 升級順序硬性 Agent 先;現場漏一台整台登不進;丟掉不會多給權限 |
prototype/index.html:第 1 頁角色設定頁、第 2 頁稽核員看到的主控台、第 3 頁舊 Agent 橫幅、第 4 頁離線操作者對話框。handoff/cards.py 先驗批次再寫),開 Notion 母卡與子卡。批 1 固定是環境卡。