審計與覆蓋
每次閘門決策都會寫入日誌。受信任的工作流可在策略層豁免。緊急停止開關用於事故響應,始終留下操作記錄。
上週一,你嘗試運行的某個腳本被攔截了。隱約記得點過"取消",但具體是哪個腳本?又或者,你有一條從頭到尾經過審查的自動化流程,每次運行時卻仍會彈出同樣的確認問題。能不能讓閘門直接放行?
本頁介紹三個操作員級別的控制手段:查看歷史決策、配置單工作流豁免,以及緊急停止開關。
設計理念:可見、可攔截、始終審計
以下三條屬性貫穿閘門的每條代碼路徑:
- 可見。 每次閘門決策(拒絕 / 確認 / 放行)都會寫入一條審計記錄,無一例外。操作員可隨時回溯。
- 可攔截。 受信任的工作流可通過
script_risk_policy預先批准特定腳本體。豁免本身也會寫入一條審計記錄,可區分"因策略獲批"與"腳本本身乾淨"這兩種情況。 - 始終審計。 就算在事故響應期間設置了
DISABLE_SCRIPT_RISK_GATE=1,每次被旁路的調用也會寫入一條標記bypassed_by="env_global"的記錄。任何使用模式都不會讓閘門保持沉默。
為什麼這樣設計? 信任來自透明,而非單純的嚴格。只會攔截的閘門最終會被繞過:有人設置了那個環境變量然後忘記了。一個提供清晰旁路路徑、同時記錄每次使用的閘門,既足夠靈活(真實工作流可以順利運行),也保持問責(事故發生後可以還原現場)。
查看決策記錄:minara script-risk list / show
先從"今天剛發生了什麼"入手:
# 所有工具最近 50 条决策
minara script-risk list
# 最近 24 小时内的拒绝记录
minara script-risk list --verdict=reject --since=2026-05-14
# 特定会话的所有决策
minara script-risk list --session=abc-123
# 特定工作流定义内的所有决策
minara script-risk list --workflow=wf_daily_rebalance
# 按工具过滤
minara script-risk list --tool=execute_code
# 查看某条决策的完整详情(所有 finding、所有证据行)
minara script-risk show <decision-id>
# 机器可读格式
minara script-risk list --verdict=confirm --json各標誌可組合使用。目的是取證:當你想了解昨天哪些腳本被攔截時,從寬泛的 --verdict=reject 開始,再逐步縮小範圍(--session、--workflow、--tool、--since)。
HTTP 等效接口提供相同的數據結構:
GET /v1/admin/script-risk/decisions?verdict=reject&tool=terminal&since=…&limit=…
GET /v1/admin/script-risk/decisions/<id>如果你把網關暴露給除自己以外的人,請在反向代理層對該接口加以保護。
審計記錄包含什麼、不包含什麼
每條決策都會記錄:
- 決策時間戳、工具名稱、工具調用 ID(已知時)、會話 ID
- 裁定(拒絕 / 確認 / 放行)及 findings 數組;每個 finding 包含類別、單行描述、屏蔽後的證據文本,以及在腳本體中的行號
body_sha256:被分析腳本體的哈希值user_decision(execute / cancel / timeout):當流程經過確認彈窗時記錄bypassed_by(env_global / workflow_policy / null):當流程通過顯式策略放行時記錄
明確不記錄:
- 腳本體本身
- 匹配到脫敏規則的原始私鑰、Authorization 頭、Cookie 值或 Bearer token
- 腳本的 stdout / stderr
為什麼不記錄完整腳本體? 含有私鑰的腳本一旦持久化,審計日誌就變成了第二條洩漏通道。存儲
sha256可以回答"之前是否見過這個腳本?"(是/否);屏蔽後的證據可以回答"哪條規則觸發了、匹配的內容大致是什麼?";兩者都不需要把密鑰複製到長期存儲的表中。代價是:事後無法逐字節回放腳本體。換來的是一份可以安全備份、共享和 grep 的審計日誌。
工作流豁免:script_risk_policy
典型場景是這樣的:你有一個定投 (DCA) 工作流,每天調用 minara swap USDC ETH 100。腳本是你自己寫的,也經過了審查,體內容不會變化。每次運行都要確認,純屬摩擦。
在工作流定義內配置:
script_risk_policy:
approved_body_sha256:
- "abc123…" # 你审查过的脚本的 sha256
allowed_categories:
- fund_moving_cli # 该工作流被明确允许
# 调用 minara swap通過 workflow_activate 激活工作流(該操作本身是涉及資金的兩步確認)後,策略即註冊生效。此後,當該工作流運行匹配的腳本體時,YELLOW 級別的 finding 會靜默降級。審計記錄中會寫入 bypassed_by="workflow_policy",事後仍可看出閘門未攔截的原因。
適用場景:
- 體內容穩定的預審腳本(哈希校驗將你鎖定在特定版本)
- 特定業務工作流中,某類已知操作本就是其核心目的(閃兌的定投工作流;調用 approve 的再平衡工作流)
不適用場景:
- 通用的萬能工作流。策略應足夠精確,一句話就能說清楚"這條豁免是為什麼而設"。
- 對所有類別全部放行。那等於對一個工作流徹底關閉閘門。
- 每次運行時動態生成體內容的腳本。體內容變化後 sha256 不匹配,策略會靜默失效(失敗時保持關閉,本身沒問題,但你增加了複雜度卻毫無收益)。
為什麼策略可以旁路 YELLOW 而不能旁路 RED? YELLOW 表示"合理但有風險":
minara swap是真實的操作,確實有人可能想自動化它。策略正是用來表達"是的,這個特定工作流被允許執行該類操作"的。RED 表示"沒有合理的業務理由"。批量刪除、IMDS 數據外洩、內聯私鑰,這些情況不存在合法的工作流場景。如果你的工作流觸發了 RED,解決辦法是修改工作流腳本,而非放寬策略。RED 被設計為策略不可旁路。
全局緊急停止開關:DISABLE_SCRIPT_RISK_GATE
設置環境變量 DISABLE_SCRIPT_RISK_GATE=1 會完全跳過閘門,RED 和 YELLOW 均直接放行。每次旁路仍會寫入一條審計記錄,標記 bypassed_by="env_global"。
每年應僅使用數次的場景:
- 生產事故響應。 一個真實的誤報正在阻斷正常業務,需要十分鐘時間發佈修復。設置環境變量、完成恢復操作、取消設置,然後提交 issue 收緊觸發規則。
- 完全隔離的 CI。 回測、端到端測試、迴歸測試套件;所有調用方可證明為非交互式,測試環境處於沙盒中。
永遠不應使用的場景:
- "確認彈窗太煩了":那正是安全機制在發揮作用。
- "我在給團隊運行 agent,不想審查策略":這會讓整個團隊暴露在攻擊者能繞過第一層防禦的風險中。
- 寫進 shell profile 然後忘記。下一個無關的會話會繼承它。
從審計角度,可以這樣發現濫用:
minara script-risk list --json \
| jq '.decisions[] | select(.bypassed_by == "env_global")'如果在你記憶中的時間窗口之外看到 env_global 旁路記錄,說明環境變量在某處被設置了,而你並沒有意識到。
完整環境變量參考見環境變量 → DISABLE_SCRIPT_RISK_GATE。
操作員職責
第 4 層(閘門)、第 3 層(涉及資金的確認)和第 2 層(OS jail)承擔了大量工作,但無法替代一些不可省略的操作員規範:
- 每個 Minara 實例對應一名操作員。 Minara 為單用戶交易場景設計,不支持多租戶 SaaS。團隊共享的 Web UI 不在支持範圍內;每位操作員應運行自己的實例。
- 私鑰存放在
.env中,不進代碼庫。 且.env應設置為chmod 600。閘門可以在運行時阻止第 4 層讀取未授權文件,但無法阻止你在 shell 中執行cat .env。 - 看到 RED 時,不要嘗試旁路。 停下來想想:為什麼自己運行的腳本觸發了高置信度的惡意模式?95% 以上的情況不是誤報,那是閘門在履職。
- 看到 YELLOW 時,閱讀證據。 花兩秒鐘讀一下匹配行,這正是彈窗存在的意義。憑肌肉記憶點"執行",只會讓自己成為最薄弱的一環。
- 永遠不要把
MINARA_SKIP_FUND_CONFIRM=1或DISABLE_SCRIPT_RISK_GATE=1寫入.zshrc、.envrc或 systemd unit。 如果某個腳本確實需要,就為那條命令單獨內聯設置,完成後立即取消。 - 審計日誌的備份很重要。
script_risk_decisionsSQLite 表是取證鏈的一部分,應像對待日誌一樣對待它。