A capability-based security gate for AI agent tool-call interception, with session-scoped policies and default-deny enforcement
OS 概念 → PromptGate 映射
capability(能力令牌) → 只有持有能力的 Agent 才能调用对应工具
seccomp(系统调用过滤) → 策略声明"允许哪些工具调用",其余默认拒绝
cgroup(资源配额) → token 消耗预算 + 调用次数限制
/proc(可观测性) → 每次判定的审计日志,可追溯可导出
进程地址空间 → Session 绑定能力,会话结束能力回收| 项目 | 定位 | 关系 |
|---|---|---|
| MoonPermit | 计划编译最小权限 + 运行时检查 | 互补:MoonPermit 管"这次任务需要什么权限",PromptGate 管"这个环境允许什么操作" |
| MoonPod | 通用策略执行与审计引擎 | 互补:MoonPod 覆盖文件/命令/网络通用策略,PromptGate 专注于 Agent 工具调用的能力边界 |
IDE 中的 AI 助理被授予限制能力:
allow: (read_file, read, "workspace/**")
allow: (run_shell, execute, "moon*")
deny: (read_file, read, "*.env")
deny: (run_shell, execute, "rm*")
当 LLM 试图读取 .env 时 → Deny(审计记录:匹配 deny 规则)
当 LLM 运行 moon test 时 → Allow
当 LLM 运行 rm -rf 时 → Deny(审计记录:匹配 deny 规则)租户 A:capabilities 绑定 db/tenant_a/*
租户 B:capabilities 绑定 db/tenant_b/*
每个租户的 Agent session 拥有独立的 Gate + Budget + AuditTrail。
租户 A 调用 db/tenant_b/data → Deny(资源不匹配任何 allow 规则,default-deny)allow: (api_call, get, "ci.example.com/status/*")
allow: (api_call, post, "ci.example.com/deploy/*")
ask: (api_call, post, "ci.example.com/deploy/production/*")
deny: (api_call, delete, "ci.example.com/*")
部署到 staging → Allow(自动)
部署到 production → AskUser(需要人工确认)
删除服务 → Deny(审计记录中永久保留)# 克隆仓库
git clone https://github.com/zyyaa125/PromptGate.git
cd PromptGate
# 检查
moon check --deny-warn
# 测试(48 个测试用例)
moon test --deny-warn
# 运行示例
moon run examples/code_assistant// 创建策略
let json = "{\"version\":\"1\",\"rules\":[{\"rule_type\":\"allow\",\"tool\":\"read_file\",\"action\":\"read\",\"resource\":\"workspace/**\"}]}"
let gate = try! @promptgate.load_policy(json)
// 创建 session
let budget = @promptgate.Budget::new(max_calls=Some(100L), max_tokens=None, window_seconds=None)
let session = @promptgate.Session::new(id="agent-1", gate=gate, budget=budget, expires_at=None)
// 工具调用判定
let (session, verdict) = session.gate_call("read_file", "read", "workspace/main.mbt")
// verdict == Verdict::Allow
// 查看审计日志
let entries = session.audit_entries()
// entries[0].verdict == "allow"moon fmt --check # 格式检查
moon check --deny-warn # 类型检查(0 错误)
moon test --deny-warn # 48 个测试全部通过
moon run examples/code_assistant # 输出 5 条判定结果 + 审计日志PromptGate Code Assistant Demo
================================
call: read_file(workspace/src/main.mbt) -> Allow
call: read_file(.env) -> Deny
call: run_shell(moon test) -> Allow
call: run_shell(rm -rf /) -> Deny
call: api_call(api.github.com/gists) -> AskUser
Audit Trail:
------------
#0: read_file workspace/src/main.mbt => allow (matched allow rule)
#1: read_file .env => deny (default-deny or matched deny rule)
#2: run_shell moon test => allow (matched allow rule)
#3: run_shell rm -rf / => deny (default-deny or matched deny rule)
#4: api_call api.github.com/gists => ask_user (matched ask-user rule)
remaining budget: 95 callsPolicy (JSON) → CapabilitySet → Gate → Session {
gate_call(tool, action, resource):
1. Budget.consume() → 超出配额则 Deny
2. Gate.judge() → Allow / Deny / AskUser
3. AuditTrail.record() → 记录决策
}
模块依赖关系:
capability.mbt ← 数据模型
capability_set.mbt ← glob 匹配 + deny-first 判定
gate.mbt ← Allow/Deny/AskUser 三层判定
policy.mbt ← JSON 策略加载 + 验证
budget.mbt ← 调用次数/token 配额
audit.mbt ← 环形缓冲审计日志
session.mbt ← 整合以上全部模块pub(all) suberror PolicyError {
InvalidJson(String)
MissingField(String)
UnknownVersion(String)
EmptyRules
}fn AuditEntry::new(tool : String, action : String, resource : String, verdict : String, reason : String) -> AuditEntryfn AuditTrail::record(self : AuditTrail, tool : String, action : String, resource : String, verdict : String, reason : String) -> AuditTrailfn CapabilitySet::match_(self : CapabilitySet, tool : String, action : String, resource : String) -> MatchResultpub struct Session {
id : String
gate : Gate
budget : Budget
audit : AuditTrail
created_at : Int64
expires_at : Int64?
} derive(Eq, Debug)fn glob_match(pattern : String, value : String) -> BoolInstall
Download zipA capability-based security gate for AI agent tool-call interception, with session-scoped policies and default-deny enforcement