本卡屬 FR-166(母卡 CM-3109),批 6。repo:agent。只改 evidence-agent。由首腦在驗收 P1-3/P1-7b/P2-5/P2-8a/P1-8 時陸續發現、沒有任何卡負責的 Agent 端缺口,一次收掉。
前面幾批交出來的 Agent 主控台有幾個接縫沒人接:手動掃描、網路除錯、重啟三個功能在真機上沒人拿得到權限;主系統清單看不到 Agent 有沒有同步;從主系統跳進來不會自動跳設密碼框;狀態列沒有最後心跳時間;總覽缺時鐘偏差燈;主控台存過儲存設定後沒辦法改回安裝時的設定;argon2 是別的套件順帶裝進來的。本卡一次補齊。
repo:~/Projects/Billows/Audit-Manager/evidence-agent
改:core/agent_auth.py(CONSOLE_SCOPES)
改:core/console/heartbeat.py(fields 加 sync_state)
改:core/console/routes.py 的 /api/me(加 offline_password_set)
改:core/console/local_auth_routes.py 的 /console/state(加 last_heartbeat_at、cloud_url)
改:core/console/overview.py+core/clock_skew.py(時鐘燈)
改:core/console/ops_routes.py+core/storage_settings.py(DELETE /storage)
改:pyproject.toml(argon2-cffi 明確宣告)
agent_auth.CONSOLE_SCOPES 加 run-local-scan、net-diag、restart。這三個 scope 的 API(P2-2/P2-5/P2-8a)已經做好,現在是任何登入方式都拿不到。local-admin 的 claims 會自動吃到;離線操作者照名單範圍過濾的邏輯不用改。測試:local-admin session 有三個新 scope;入場券帶新 scope 不再被拒。console/heartbeat.fields() 加 sync_state:synced/unsynced,用 offline_operators.synced()(P1-3 已備好)。主系統 P0-6 已在收這欄。GET /console/api/me 對名單內的離線操作者多回 offline_password_set: bool(local_credentials.has_password(sub));local-admin 與名單外的人不回這個欄位。P1-7b 前端只在值明確是 false 時才跳設密碼框。GET /console/state 多回 last_heartbeat_at(heartbeat_status.last_ok_at(),epoch 秒,沒成功過回 null)與 cloud_url(設定裡的主系統網址,只給 origin)。clock_skew 現在只寫 log,請在心跳 observer 算出偏差時把最近一次結果記在模組裡(已有 compute_skew/is_skewed,不另寫),overview._lamps 加一盞 clock(偏差超門檻=warn)。DELETE /console/api/ops/storage(scope configure):清掉 credential_store 的 _storage,回到安裝時的設定並重載,回 200 {source:"install"};記稽核 storage_reset。解決「主控台存過儲存設定後,CLI configure-storage 會被蓋掉,而且沒辦法改回」。P2-8b 前端會照這個契約加按鈕。新 DELETE 入口要在 P3-7 守衛第 5 條清單表態(屬「要擋」或「豁免」,寫理由)。argon2-cffi (>=25.1,<26)。照 BE 規則只能 poetry update argon2-cffi 指名更新;Nexus 帳密不通時,改 pyproject 並回寫卡在哪,不要裸跑 poetry lock。test_fr166_guards.py 綠。/console/api/scan/tools、/console/api/netdiag/targets、/console/api/ops/status 都不再 403。sync_state;/console/state 有 last_heartbeat_at、cloud_url;名單內操作者的 /console/api/me 有 offline_password_set。DELETE /console/api/ops/storage 後 GET /storage 的 source 變 install。