[Feature] Agent 节点工具调用策略:按命令前缀/路径声明 allow·deny·ask 规则,高危操作拦截或转人工审批

Offen
#301 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Anfängerfreundlichkeit
15/100
Issue-Typ
Feature
Klarheit
Größtenteils klar
Aktivitätsstatus
Aktiv
Tech-Stack
go
Bereich
backend, security

Rechercherichtung

This is design work spanning several subsystems, so read the referenced files first: internal/runtime/hooks.go (materializeAgentHooks), internal/domain/agent.go (AgentHook), internal/engine/node_outcome.go (waiting_approval), and the provider files for Claude Code, CodeBuddy and Codex. Agree on the policy model and the three-level merge order with a maintainer before coding. Done means the acceptance checklist in the issue passes, starting with the check endpoint and policy unit tests.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

背景与借鉴来源

无人值守的 Agent 节点在沙箱里执行 shell 和文件写入。沙箱能隔离宿主,但挡不住在工作区和已授权的远端上做的高危操作:git push --force、删分支、rm -rf 仓库目录、改 CI 配置或 migrations/、kubectl/terraform apply、curl … | sh 等。主流 Agent 都在「全放开」和「每步都问」之间加了一层声明式工具调用策略:

  • openai/codex(https://github.com/openai/codex ,约 135k★,当天仍有提交):codex-rs/execpolicy 用 prefix_rule(pattern=[...], decision=allow|prompt|forbidden, justification=...) 按命令前缀判定;forbidden 时把 justification(如「请用 jj 代替 git」)回给模型;规则自带 match/not_match 样例,加载时当单测校验。
  • google-gemini/gemini-cli(https://github.com/google-gemini/gemini-cli ,约 109k★,当天仍有提交):Policy Engine 用 TOML 规则(toolName、commandPrefix/参数匹配、decision = allow|deny|ask_user、priority),用户级、管理员级多层合并,优先级高的规则生效。
  • OpenHands/software-agent-sdk(https://github.com/OpenHands/software-agent-sdk ,OpenHands 约 93k★,SDK 当天仍有提交):security/confirmation_policy.py 提供 AlwaysConfirm/NeverConfirm/ConfirmRisky(threshold),按动作风险等级决定是否要人工确认。
  • anthropics/claude-code(约 155k★):permissions.allow/deny/ask 支持 Bash(git push:*)、Edit(./migrations/**) 这种细粒度规则,PreToolUse hook 可返回 permissionDecision: deny。

LoopForge 现状与不足

  1. 所有执行器都强制全放开:
    • internal/runtime/provider_claude.go 的 Prepare 固定改成 --permission-mode bypassPermissions;
    • internal/runtime/provider_codebuddy.go 的 isolateCodeBuddyFlagsWithSource 固定加 -y 和 bypassPermissions;
    • internal/runtime/provider_codex.go 在 docker/bwrap 下改成 --sandbox danger-full-access。
      这对无人值守是必要的,但结果是 SOP 节点里任何命令都不会被拦下,平台也没有统一的地方补拦截。
  2. 只能靠每个 Agent 自己写 hook 脚本:domain.AgentHook(internal/domain/agent.go)+ internal/runtime/hooks.go 的 materializeAgentHooks 支持 PreToolUse 脚本,但要每个角色手写 shell/python、不同 CLI 的输入输出格式各不相同、没有平台/项目级统一配置、没法审计「拦了什么」。Main Bot 的 PreToolUse 拦截(internal/httpapi/assistant_provider.go、assistant_engine_cli.go)只用于助手会话,不覆盖 SOP 节点。
  3. 没有「需要人工确认」这条路:引擎已有 waiting_approval(internal/engine/node_outcome.go)和干预点 HumanInterventionPoint,但干预点只能挂在 before_execution/after_execution/before_publish 阶段,不能「执行到某条高危命令时」暂停等人批。
  4. 现有相关 issue 都不覆盖这块:#226 管沙箱出网域名,#227 管推送前密钥扫描,#258 管停滞/打转,#223 管 Token 预算。

建议方案

  1. 策略模型(internal/domain 新增 ToolPolicy,归 CatalogRepo 管理):规则字段
    tool(shell/edit/write/mcp:<server>/<tool>)、commandPrefix(按 token 前缀,支持备选)、pathGlob(文件类工具)、decision(allow/deny/ask)、priority、justification、examples.match/notMatch。
    作用域:平台默认 → 项目 → Agent 角色,按优先级合并;平台可标记某些 deny 规则为「不可被下层覆盖」。
  2. 内置默认规则集(可关):git push --force*/git push * :branch、rm -rf / 及工作区根、curl|wget … | sh、改 .github/workflows/**、.gitlab-ci.yml、migrations/** 等给出 deny 或 ask 建议值。
  3. 统一执行点:在 materializeAgentHooks 阶段为每个节点自动注入一个平台 PreToolUse 守卫(复用 Main Bot 守卫的做法),守卫读物化后的策略 JSON 做判定,按 Claude Code / CodeBuddy / Codex 各自的 hook 协议返回结果;不支持 hook 的执行器(opencode、cursor 等)在节点详情里标「策略未生效」,项目可配置「要求策略生效,否则拒绝运行」。
  4. 三种结果的处理:
    • deny:拒绝该调用,把 justification 作为拒绝原因回给模型,让它换做法;
    • ask:拒绝本次调用并结束当前轮,节点进入 waiting_approval,审批卡片展示命令、工作目录、命中规则;批准后通过 resume 会话放行该命令(一次性 allow token),拒绝则把原因作为反馈继续;
    • allow:放行。
  5. 审计:每次命中写 policy.decision 事件(规则 ID、工具、命令摘要、结果),节点详情和运营分析里可查「被拦/被审批」的次数。
  6. 策略测试:保存策略时校验 examples;提供 POST /api/tool-policies/check 输入命令返回命中结果,便于配置前试跑。

验收标准

  • 可以在平台、项目、Agent 三级配置策略,合并顺序和「不可覆盖」标记有单测覆盖;保存时 examples.match/notMatch 不符会报错。
  • Claude Code、CodeBuddy、Codex 三种执行器下,节点执行 git push --force origin main 时被拦截,模型能收到 justification,事件里有 policy.decision=deny。
  • ask 规则命中时节点进入 waiting_approval,审批卡片能看到命令和命中的规则;批准后该命令得以执行、节点继续;拒绝后原因作为反馈回到 Agent。
  • 不支持 hook 的执行器在节点详情显示「策略未生效」;开启「要求策略生效」时这类节点启动即失败并给出明确提示。
  • 未配置任何策略、且关闭内置默认规则时,现有节点行为和测试结果不变。
  • check 接口对给定命令返回命中的规则和最终结果。
Vorherrschende Sprache
Go
Sterne
141
Forks
28
Ø Merge
1 T. 15 Std.
Gemergte PRs (30 T.)
113

Entwicklungsumgebung

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus Tencent/LoopForge

Alle Issues in Tencent/LoopForge

Ähnliche Issues

Weitere Issues zu Go

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.