permgate

package
v0.20.0 Latest Latest
Warning

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

Go to latest
Published: Nov 7, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package permgate 工具调用许可判定链:谁在什么模式下对什么输入得到 allow/ask/deny。对标 ZCode permission/service.ts 的优先级状态机——顺序是 踩坑固化的,别调换:

requiresUserInteraction → ask(交互型工具天然要用户)
alwaysAsk 硬阻断段 → disallowed/project-deny 仍压过「问」(被硬禁的
  工具不能退化成「弹窗一点就能跑」)
alwaysAsk 会话授权段 → 命中即放行(钥匙是本会话的授权,不看模式)
alwaysAsk 只读拦截段 → 只读档的非只读工具直接拒(不给「问」的机会)
disallowed → deny
project deny → deny
配置白名单 → allow(break-glass 位次,issue #58:运维显式加白是「比模式
  更强的信任」,压过只读档与 project ask;硬禁仍在它前面——白名单不是
  绕禁的后门)
只读拦截 → deny(只读档的非只读工具直接拒——「禁」压过「问」)
yolo → 放行(alwaysAsk 与一切「禁」都在它前面——yolo 跳过的是「问」不是「禁」)
project ask → ask
只读模式 → 只读工具放行、其余拦下
project allow → allow
预批钩子 → allow(WebFetch URL 白名单类)
兜底 → 会话授权、只读工具放行,其余 ask

「只读拦截」段是「只读模式」段的前置影子:只读档对非只读工具是「禁」不是 「问」——它必须压过 alwaysAsk 与 project ask 两处「问」,否则只读退化成 「换个姿势问」(issue #24)。它与后段同 RuleID/Reason,审计口径不变; mode 之间互斥,故它与 yolo 段无交集。唯一的例外是配置白名单(#58 的 break-glass):只读档默认禁写,但运维对单个工具的显式加白压得过模式档 (下游不再需要在 permgate 之外私设一层本地 override,授权真相只有一份)。

与 agentkit policy(操作审计门:四模式裁决矩阵)正交:policy 裁「业务操作 该不该做」,permgate 裁「这次工具调用要不要人确认」。

规则内容匹配(对标 matchesRuleContent):精确 / `prefix:*` 前缀(prefix 或 prefix+空白开头——空白含换行,换行同属命令分隔)/ `*` 通配(跨行透明)。 匹配对象从工具输入提取(command/url/file_path/path/pattern/patch_text 字段 或字符串输入本身);类型化输入(map[string]string、struct 及其字段/json tag) 同样参与提取(#65/#72:此前这些形态静默落空,内容级 deny 对类型化调用方 全部失配——fail-open)。

复合命令(#62/#71):command 形态的匹配对象先按 shell 操作符(`&&` `||` `;` `|` 换行,引号内不拆)拆段,段级命中的量词按规则极性取 fail-closed 侧 ——allow/会话授权要求**每段**都命中(`git status && curl evil` 不得搭 `git status:*` 的车),deny/ask 只要**任一段**命中(复合命令里混进一段 危险命令即拦)。不追求完整 shell 语法:命令替换(`$(…)`、反引号)等真 AST 形态归 tools/bashguard,本包只做 stdlib 操作符切分,拆不动的形态宁可 让 allow 失配(落 ask),不得让操作符后的命令搭车放行。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Behavior

type Behavior string

Behavior 判定行为。

const (
	Allow Behavior = "allow"
	Ask   Behavior = "ask"
	Deny  Behavior = "deny"
)

type Capability

type Capability struct {
	// ReadOnly 只读工具(读后无副作用)。
	ReadOnly bool
	// AlwaysAsk 工具自报必须逐次确认(不可被模式/白名单绕过,只可被硬阻断
	// 与会话授权短路)。
	AlwaysAsk bool
	// RequiresUserInteraction 用户交互型工具(AskUserQuestion 类)。
	RequiresUserInteraction bool
}

Capability 工具能力自报(注册期声明)。

type Decision

type Decision struct {
	Behavior Behavior
	RuleID   string
	Reason   string
}

Decision 判定结果(RuleID 结构化审计)。

type Mode

type Mode string

Mode 会话模式。

const (
	// ModeDefault 正常模式(兜底:只读放行、其余问)。
	ModeDefault Mode = "default"
	// ModeYolo 直通模式(跳过确认——但压不过 alwaysAsk 与硬禁)。
	ModeYolo Mode = "yolo"
	// ModeReadOnly 只读模式(plan 类:只放行只读工具)。
	ModeReadOnly Mode = "read_only"
)

type Rule

type Rule struct {
	// ToolName 工具名;Edit 规则同时匹配 Write(写面等价,对标 ZCode 特例)。
	ToolName string
	// Content 输入内容模式(command/url/路径):空 = 该工具全部调用;
	// "git status:*" 前缀(空白边界,命令形态专用);含 * 通配;否则精确等值。
	// ⚠ 路径规则用 wildcard 形态("/repo/data/*")而非前缀形态——前缀边界是
	// 空白/制表符,对路径子树形同虚设;路径 subject 匹配前会 filepath.Clean
	//(`..` 穿越不命中),符号链接围栏归执行器。
	Content string
}

Rule 单条许可规则。

type Ruleset

type Ruleset struct {
	Allow []Rule
	Ask   []Rule
	Deny  []Rule
}

Ruleset 三档规则集。

type Service

type Service struct {
	// AllowedTools 配置级白名单(工具名集合)。break-glass 位次(#58):
	// 运维显式加白压过只读档与 project ask,但压不过 disallowed/project deny。
	AllowedTools map[string]bool
	// DisallowedTools 配置级黑名单(压过 yolo、alwaysAsk 的确认段与白名单)。
	DisallowedTools map[string]bool
	// ProjectRules 项目/产品级规则集。
	ProjectRules Ruleset
	// Preapprove 预批钩子(WebFetch URL 白名单类):返回非空 ruleID 即放行。
	// 判定位次在项目 allow 之后、配置白名单之后(plan 拦截压得过预批)。
	Preapprove func(ctx context.Context, tool string, input any) (ruleID string, ok bool)
	// contains filtered or unexported fields
}

Service 许可判定器。零值可用(全部走兜底档)。

并发契约(issue #66):Check/AllowForSession/ResetSession/Update/SessionAllows 之间并发安全——Check 全程只读锁内快照,Update 在锁内整体换配置。导出的 配置字段(AllowedTools/DisallowedTools/ProjectRules/Preapprove)视为**装配期 字段**:直接赋值只允许发生在并发使用开始前;运行期热更新一律经 Update 换**新值**(不得原地改切片元素——快照共享底层数组,原地改与并发读仍构成 竞争),也不得在 Update 回调里再调本包方法(非重入锁,会死锁)。

func (*Service) AllowForSession

func (s *Service) AllowForSession(tool, content string)

AllowForSession 会话级授权登记(用户对 ask 选择「本会话总是允许」时调用)。 同 (tool, content) 重复登记折叠(#70):规则表=授权真相——N 次「总是允许」 不该积累 N 条相同规则(线性膨胀稀释审计面)。

func (*Service) Check

func (s *Service) Check(ctx context.Context, tool string, input any, mode Mode, cap Capability) Decision

Check 判定一次工具调用。input 为工具入参(string、map[string]any、 map[string]string 或 struct 等类型化形态——内容字段按 subjectKeys 名单提取)。 分段优先级见包注释——顺序是踩坑固化的,别调换。

func (*Service) ResetSession

func (s *Service) ResetSession()

ResetSession 会话结束清空会话授权(实例消亡语义的显式形态)。

func (*Service) SessionAllows added in v0.20.0

func (s *Service) SessionAllows() []Rule

SessionAllows 本会话已授权清单快照(#70 审计面):锁内深拷贝,调用方可安全 遍历/导出;空清单返回 nil。

func (*Service) Update added in v0.20.0

func (s *Service) Update(fn func(*Service))

Update 运行期配置热更新(#66):fn 在锁内拿到 Service 本体,对配置字段 **整体赋新值**;与并发 Check 安全交错(Check 持锁内快照)。约束见类型注释。

Jump to

Keyboard shortcuts

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