permgate

package
v0.2.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 13, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

blacklist.go —— 黑名单硬规则与命令类判据。

职责:

  • 持有内置黑名单模式表(自 internal/agentd/approver.go 迁入)
  • 引号字面量剥离与执行包装器识别
  • judgeCommand:命令类请求(bash 及其余工具)的判定

边界:

  • 不认识工具名、不碰路径:路由在 permgate.go,路径判定在 path.go

path.go —— 写文件目标路径的范围归属判定。

职责:

  • 把可能是相对路径、可能经软链的目标路径归一化为真实绝对路径
  • 判定它是否落在任务范围(Workdir 或 TaskDir)的子树内

边界:

  • 只读文件系统(EvalSymlinks 探测),不创建、不修改任何东西
  • 不认识工具名、不做黑名单匹配

已知残余风险(TOCTOU):判定通过后、executor 实际写入前,软链可能被换掉。 闭合它需要在 executor 侧持有文件句柄,而写入动作发生在 agent 进程里, 超出 handoff 的可控范围——spec §5.4 明确接受此风险。

Package permgate 提供权限请求的结构化判据。

职责:

  • 把一次权限请求判成三个出口之一:AutoAllow(立即放行)、Consult (交廉价模型审批者)、Escalate(直接升级人工协调者)
  • 承载全部判定规则:黑名单模式匹配、引号剥离、执行包装器识别、 写文件目标路径的范围归属

边界:

  • 纯计算,无 I/O:不写 store、不碰 adapter、不发网络请求(EvalSymlinks 的文件系统只读探测除外,它是路径判定的必需品)
  • 无 deny 权:出口里没有「拒绝」——拒绝只有人能做,与 approver 同源
  • 不做状态迁移、不建工单:调用方(manager)据 Verdict 决定后续动作

为什么判据要独立成包:三个 adapter(claude/grok/opencode)的权限载荷形态 完全不同,但判据必须只有一份——判据分散到 adapter 里,就会重演「opencode 有 external_directory、claude 和 grok 没有」这种各家一套的漂移。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func HasExecWrapper

func HasExecWrapper(s string) bool

HasExecWrapper 判断命令是否含执行包装器(sh -c / bash -c / eval / xargs / 通用 -c/-e/-E 执行标志等)。

func InScope

func InScope(path string, scope Scope) (in bool, base string, err error)

InScope 判定目标路径是否落在任务范围内。

参数:

  • path: 目标路径,可为相对路径(按 scope.Workdir 解析)
  • scope: 任务范围;其中为空的基准目录被跳过,不参与判定

返回:

  • in: 是否落在范围内
  • base: in=true 时命中的基准目录(归一化后),供日志说明「凭哪条放行」
  • err: 路径归一化失败;调用方须按 fail-closed 处理为升级人工

注意:

  • 用 filepath.Rel 判归属而非字符串前缀——strings.HasPrefix("/repo-evil/x", "/repo") 为真,前缀匹配会把仓库外的路径判成内部
  • 对已存在的最长前缀求 EvalSymlinks——目标文件常常尚不存在(Write 新建), 不解软链则 `ln -s ~ /repo/link` 之后写 /repo/link/.ssh/authorized_keys 直接绕过

func StripQuoted

func StripQuoted(s string) string

StripQuoted 把成对引号内的内容清空,保留引号本身。

参数:s 为原始命令串 返回:剥离后的串,如 `git commit -m "去掉 rm -rf 分支"` → `git commit -m ""`

注意:

  • 不做完整 shell 解析。反斜杠转义(`"it\"s"`)会让本函数提前认为引号闭合, 结果是**剥得更少**——剥得少意味着更可能仍然命中黑名单、更可能 Escalate, 方向是安全的,因此接受
  • 未闭合引号:引号之后的内容全部丢弃

Types

type Action

type Action int

Action 是一次权限裁决的出口。

const (
	// AutoAllow 立即放行:不建工单、不发事件、不唤醒任何人。
	// 只可能出自 write/edit 路由(目标路径全部落在任务范围内)。
	AutoAllow Action = iota
	// Consult 交廉价模型审批者裁决(今天未命中黑名单时的默认路径)。
	Consult
	// Escalate 直接升级人工协调者(今天黑名单命中时的路径)。
	Escalate
)

func (Action) String

func (a Action) String() string

String 给出日志可读的短标签。

type Gate

type Gate struct {
	// contains filtered or unexported fields
}

Gate 持有编译后的黑名单,是判据的唯一入口。

func New

func New(patterns []string, log *slog.Logger) (*Gate, error)

New 构造判据网关。

参数:

  • patterns: 用户自定义黑名单(config.ApproverConfig.Blacklist);内置 黑名单自动前置,无需调用方传入
  • log: 包日志入口;nil 时用 slog.Default()

返回:

  • 可用的 Gate;任一正则编译失败即返回错误(配置错误应在启动期暴露)

注意:

  • **无论审批者是否启用都必须构造**。AutoAllow 是第 0 层静态判据、不是 审批者的职权;漏构造会让未配置审批者的部署被工作区内的每次写入淹没

func (*Gate) Judge

func (g *Gate) Judge(req Request, scope Scope) Verdict

Judge 判定一次权限请求(spec §3.4 的路由 + §7 的 fail-closed 表)。

参数:

  • req: 结构化后的权限请求
  • scope: 本任务的合法作用范围

返回:Verdict,调用方据 Action 决定后续动作

路由:

  • write / edit → 路径归属判定,**并且**对 Text 跑一次黑名单(路径本身 可能命中,如 Write: /etc/sudoers);两项是与关系
  • bash → 对 Command 做命令类判定
  • 其余 → 对 Text 做命令类判定

注意:

  • Truncated 一律直接 Escalate 且不再往下判:看到的是不完整的描述, 危险片段可能落在截断之外,黑名单与模型都不可信
  • 本方法**永不因失败而返回 AutoAllow**(spec §7)

type Request

type Request struct {
	Tool      string   // 归一化工具名,取 executor.PermTool* 常量
	Text      string   // 权限描述全文(与工单同源)
	Command   string   // Tool=bash 时的完整命令串
	Paths     []string // Tool=write|edit 时的目标路径(可为相对路径)
	Truncated bool     // 描述含 executor.TruncationMarker
}

Request 是结构化后的权限请求。

Text 与 Command 不是重复:Text 是给人看的全文(与工单同源,形如 "Bash: xxx"),Command 是命令类工具的纯命令串。bash 路由判 Command, 其余路由退回判 Text。

type Scope

type Scope struct {
	Workdir string
	TaskDir string
}

Scope 是本任务的合法作用范围。

两处都是 handoff 分配给该任务的空间:Workdir 是它要改的仓库/worktree, TaskDir 是 agentd 给它的 0700 私有目录。写这两处不该叫醒任何人。

type Verdict

type Verdict struct {
	Action Action
	Reason string
	Rule   string
}

Verdict 是裁决结果。

  • Reason: 可读理由,进日志与审计
  • Rule: 因黑名单而 Escalate 时命中的规则原文;其余情形为空

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL