fix(t213): 診斷檔遮蔽引擎錯誤訊息裡的本機絕對路徑
engine.detail/engine.last_error 在同步引擎沒在跑時,會把 collector 開機 橫幅的完整原文帶出來(direct.go RunDirect 的「監看 %s → %s」那行),其中 含監看資料夾的絕對路徑(如 /Users/xxx/Desktop/...)。這是上一輪(第二/ 三輪)已發現但標記「附帶發現、未修」的洞——首頁在同一狀態下本來就會顯示 同一句話(不動,留給另案判斷),但診斷檔現在會被匯出成檔案交給外部人看, 風險層級跟留在托盤畫面上不同,這輪把它遮掉。 新增 redactLocalPaths(),只在 buildDiagnosticsPayload() 組裝 engine 欄位時 套用:把訊息裡看起來像本機絕對路徑的片段換成「…/<路徑最後一截>」, http(s) URL 先放行原文(避免 URL 裡的 / 被誤判成本機路徑)。只動 diagnostics_export.go 這一端,不改 describeStatus()/collectorFailure()/ direct.go 的訊息本身——那些同時是首頁托盤畫面在用的同一組憑據。 擴充 diagnostics_engine_e2e_test.go(真執行檔+真 supervisor 子行程,零 網路零帳號):監看資料夾改用真實絕對路徑,證明子行程停擺後整份匯出 JSON 找不到該路徑,同時 last_error/detail 仍讀得出「引擎沒在跑、以及為什麼」 (含監看資料夾的名字)。另加 8 個 redactLocalPaths 純函式單測。 go build/go vet/go test ./...(collector+arcrun-app+supervisor 三個 package)全綠;diagnostics_stage_manual_test.go 維持預設 SKIP,本輪未碰 網路/stage。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,8 +18,10 @@ package main
|
||||
// 不需要任何雲端憑證,任何機器上都能跑、都穩定。
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -42,12 +44,23 @@ func TestDiagnosticsEngine_ReflectsRealSupervisorLifecycle(t *testing.T) {
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
|
||||
// t213 phase 4:監看資料夾要是一個**真的絕對路徑**,才能重現「collector 開機橫幅把
|
||||
// 監看路徑印進 stderr → supervisor 記成 LastError → 診斷檔把它原樣帶出去」這個洞
|
||||
// (見 direct.go RunDirect 的「監看 %s → %s」那行;leo 08-08 附帶發現、本輪要修的問題)。
|
||||
watchDir := filepath.Join(home, "知識庫")
|
||||
if err := os.MkdirAll(watchDir, 0o755); err != nil {
|
||||
t.Fatalf("建監看資料夾失敗:%v", err)
|
||||
}
|
||||
|
||||
// 需要至少一個帳號:LoadDirectConfig 會拒絕零帳號的設定(「缺必填欄位:accounts」,
|
||||
// 連迴圈都進不去),但這個帳號**不必連得上**——cypher_url 刻意指向一個解析不出來的
|
||||
// 網址,驗證的是「心跳(LastSync)跟著子行程死活走」這條機制,不是雲端連線本身。
|
||||
cfg := &directConfig{
|
||||
Manifest: filepath.Join(home, ".arcrun-rag", "manifest.json"),
|
||||
Accounts: []accountCfg{{CypherURL: "https://example.invalid.test", Namespace: "test", APIKey: "test"}},
|
||||
Accounts: []accountCfg{{
|
||||
CypherURL: "https://example.invalid.test", Namespace: "test", APIKey: "test",
|
||||
WatchFolders: []string{watchDir},
|
||||
}},
|
||||
}
|
||||
if err := saveCfg(cfg); err != nil {
|
||||
t.Fatalf("存設定失敗:%v", err)
|
||||
@@ -110,4 +123,29 @@ func TestDiagnosticsEngine_ReflectsRealSupervisorLifecycle(t *testing.T) {
|
||||
t.Fatal("情境二:alive=false 時 headline 不該是空的——這是給人看的『還在不在跑』答案")
|
||||
}
|
||||
t.Logf("✅ Q2 證據鏈完整:pending 不變的情況下,alive/last_sync/seconds_since_last_sync 三者都反映了子行程真的停了")
|
||||
|
||||
// ── t213 phase 4(leo 08-08 附帶發現、本輪要修)──
|
||||
// alive=false 這個狀態下,engine.detail/engine.last_error 過去會帶出 collector 開機
|
||||
// 橫幅的完整原文,其中含監看資料夾的絕對路徑(見 direct.go RunDirect 的
|
||||
// 「監看 %s → %s」那行)。這裡的 watchDir 就是刻意設成真實絕對路徑,用來重現這個洞:
|
||||
// 驗證整份匯出 JSON 裡找不到它,同時確認「引擎沒在跑、以及為什麼」仍然讀得懂
|
||||
// (不能把資訊遮成啞巴——資料夾最後一截「知識庫」要還在)。
|
||||
if strings.Contains(string(stoppedJSON), watchDir) {
|
||||
t.Fatalf("情境二:整份診斷檔仍然帶出監看資料夾的絕對路徑 %q:%s", watchDir, stoppedJSON)
|
||||
}
|
||||
if strings.Contains(string(stoppedJSON), home) {
|
||||
t.Fatalf("情境二:整份診斷檔仍然帶出本機家目錄路徑 %q:%s", home, stoppedJSON)
|
||||
}
|
||||
if containsAbsPath(string(stoppedJSON)) {
|
||||
t.Fatalf("情境二:整份診斷檔(掃全文,不只 engine 兩個欄位)仍有本機絕對路徑殘留:%s", stoppedJSON)
|
||||
}
|
||||
reason := stoppedOut.Local.Engine.LastError + stoppedOut.Local.Engine.Detail
|
||||
if reason == "" {
|
||||
t.Fatal("情境二:alive=false 時 last_error/detail 不該兩個都是空的——『為什麼沒在跑』答不出來了")
|
||||
}
|
||||
if !strings.Contains(reason, "知識庫") {
|
||||
t.Fatalf("情境二:遮蔽把資訊遮成啞巴了——連監看資料夾叫什麼名字都看不出來:last_error=%q detail=%q",
|
||||
stoppedOut.Local.Engine.LastError, stoppedOut.Local.Engine.Detail)
|
||||
}
|
||||
t.Logf("✅ t213 phase 4:路徑遮掉了,但『引擎沒在跑、以及為什麼(監看的是「知識庫」資料夾)』還讀得懂")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user