dsh-root-temp-guard:把「臨時文件進 tmp」從約定變成執行期攔截

前言

在 DeepSeek Harness(DSH)裏跑智能體時,工具層可以寫文件、跑 shell。很多倉庫會在 AGENTS.md 或團隊規範裏寫一句:臨時目錄、日誌、探針文件不要堆在倉庫根目錄,統一放進 tmp/<任務名>/。規範寫在文檔裏,模型或腳本仍可能在根目錄創建 _tmp_probe/、build.log、.tmp 等條目,事後要靠人工或 CI 清理。

dsh-root-temp-guard 是 DSH Host 側的工作流類插件,在工具調用管線裏攔截「在工作區根目錄創建臨時目錄 / 臨時文件」,並可在回合結束時把漏網的根目錄臨時項移入隔離目錄。下面介紹它的定位、三層機制、安裝方式與配置要點。

這是什麼

維護者 lizhijie429,倉庫 lizhijie429/dsh-root-temp-guard,npm 包名 dsh-root-temp-guard(資料中版本 0.6.0),許可證 MIT。DSH 引擎要求:>=0.2.1-0 <0.3.0。

一句話定位:在 Host 插件層把「臨時產物統一放臨時目錄」的項目約定,從文字規則升級爲執行期攔截;工作區根目錄隨會話解析(session-root aware),規則與文案可配置。

務必區分邊界:這是衛生 / 約定守衛,不是安全邊界。文件類工具走參數解析與 fs-intent 兩層判定,命令類只做啓發式文本匹配;惡意或複雜 shell 仍可繞過,真正邊界仍是 DSH 沙箱。

社區目錄頁:SkillHub 插件頁(與 DeepSeek / 幻方無官方從屬,屬社區收錄)。

核心功能:三層攔截

插件 README 將機制歸納爲三層,且三層在插件內部異常時均爲 fail-open(放行並寫日誌,不卡死工具調用)。

1、工具參數層

通過 ctx.tools.guard() 在工具執行前運行,結合工具參數與會話當前工作目錄(workingDirectory.get(session))判定。即便模型先 working_directory { cd: "tmp" } 再寫 ../_tmp_x,也會按真實 cwd 解析並攔截。

2、已解析目標層

監聽 DSH 的 fs/write-intent / fs/edit-intent waterfall(write、edit、str_replace_editor 均會觸發),在路徑解析完成、寫盤前判定。該層使用 realpath 身份,因此通過 tmp/link 等 junction/symlink 把根目錄臨時項藏進允許的 tmp/ 也會被拒絕。

3、回合結束清掃

監聽 session/event 的 turn/start / turn/end:把本輪新出現且名字像臨時項的根目錄條目移動(不刪除)到 tmp/_quarantine/<timestamp>-<name>,便於人工恢復。這是對命令類啓發式繞過的兜底;turn/start 之前已存在的條目不會被被動處理。

默認覆蓋的工具類型(資料原文):

  • 文件類:write、edit、str_replace_editor(view 只讀放行)
  • 命令類:pwsh、bash、terminal_send(解析 command / text;workdir 按當前 cwd,cd / Set-Location 後的相對路徑按新目錄解析)

默認規則示例:根下的 _tmp_probe/、scratch/、test-out/、_tmp_notes.md、build.log、x.tmp 等會拒絕;配置的統一臨時目錄(默認名 tmp)下的路徑允許;工作區外路徑不干預,交給沙箱策略。

安裝與啓用

本插件是 DSH profile 組合包(bundle):package.json 的 dsh.bundle.patch 指向 cordis.patch.yml,安裝後 DSH 會自動插入 root-temp-guard 行(默認 tmpDirName: tmp、quarantine: strict)。

CLI profile(推薦)

npm 發佈後,在 web / headless 等由 CLI 管理的 profile 上執行:

dsh plugin --profile web add dsh-root-temp-guard

安裝後可用下面命令確認 patch 是否生效:

dsh --profile web --dump-config | Select-String -Context 0,6 'dsh-root-temp-guard'

發佈前從本地目錄安裝(資料示例,無構建步驟):

dsh plugin --profile web add "file:$env:USERPROFILE\.dsh\plugins\dsh-root-temp-guard"

桌面端 profile

desktop profile 由 Electron 管理,dsh plugin 不直接改它。需在 %USERPROFILE%\.dsh\profiles\desktop\cordis.patch.yml 末尾按絕對路徑插入 root-temp-guard 條目(字段見 README「方式二」)。純 config 改動在默認 patchReload: live 下可熱生效;改 index.mjs / lib/guard.mjs 可能受 ESM 緩存影響,需重啓 DeepSeek Harness。

臨時驗證(不改 profile)

dsh headless --patch <含 root-temp-guard insert 的 yaml> "hello"

安裝插件會以當前 DSH 進程權限運行 Host 代碼;啓用前應自行查看倉庫源碼與 MIT 許可證,確認符合你的環境策略。

典型配置

config: 塊全部可選。常見字段如下(默認值以 README 爲準):

字段 默認 說明
enabled true 總開關
mode deny deny 拒絕;warn 只記 would-deny 並放行(灰度)
tmpDirName tmp 統一臨時目錄名(單路徑段)
allowRootNames [] 額外放行的根目錄名
quarantine strict 回合結束清掃;off 關閉
reasonTemplate 見 README 拒絕文案,支持 {name}、{tmpDir}

在 profile 的 cordis.patch.yml 裏按 id: root-temp-guard 覆蓋 config 會整體替換該行的 config。資料中的灰度示例:

- insert:
    - id: root-temp-guard
      name: 'C:\Users\<你>\.dsh\plugins\dsh-root-temp-guard\index.mjs'
      config:
        mode: warn
        tmpDirName: scratchpad
        reasonTemplate: '臨時產物請寫入 {tmpDir}/<任務名>/,不要污染倉庫根目錄:{name}'

日誌默認寫在 <插件目錄>/state/root-temp-guard.log,超過 5MB 會輪轉一次爲 .1。拒絕、隔離移動、掛載/dispose 等事件會寫入該文件。

適用場景與注意

適合誰

  • 已在 AGENTS.md 或團隊規範里約定「臨時文件進 tmp/」,希望 Host 層自動擋掉根目錄 _tmp*、.log、.bak 等常見污染。
  • 需要先用 mode: warn 觀察誤報,再切 deny 上線的工作流團隊。

不要指望它做什麼

  • README「已知限制」明確:node -e "fs.mkdirSync(...)"、複雜拷貝、管道、別名、腳本間接建目錄等可繞過命令類啓發式。
  • 無 session 的 agentless 調用拿不到工作區上下文,守衛直接放行。
  • 子代理 / workflow / PTC 機制上走同一註冊表,但未做端到端集成驗證。
  • 其它插件直接調用 ctx.fs 且不觸發 intent 的路徑不在 fs-intent 層覆蓋範圍內;可通過 extraWriteTools / extraShellTools 擴展工具名。

非法配置會寫 config.warning 到日誌,而不是靜默失效。

結尾

dsh-root-temp-guard 把倉庫根目錄臨時項的約定落到 DSH 工具管線:參數守衛、寫盤 intent、回合隔離清掃三層配合,配置驅動且隨會話工作區根切換項目。若你的 profile 已由 CLI 管理,優先用官方 npm 安裝命令接入 bundle。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜