ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Atuin AI 工具与权限系统完全指南:permissions.ai.toml 配置、作用域规则与安全实践

Atuin AI 工具与权限系统完全指南:permissions.ai.toml 配置、作用域规则与安全实践 Atuin AI 工具与权限系统完全指南permissions.ai.toml 配置、作用域规则与安全实践【免费下载链接】atuin✨ Making your shell magical项目地址: https://gitcode.com/gh_mirrors/at/atuinAtuin AI 是 Atuin 项目内置的 AI Agent它通过AtuinHistory、AtuinOutput、Read、Write、Shell等客户端工具与你的系统交互——在帮你回忆历史命令、分析文件内容、修改配置或执行多步操作时每个工具都可以被允许allow/ 拒绝deny/ 询问ask。本文基于官方文档 docs/docs/ai/tools-permissions.md并结合仓库源码crates/atuin-ai/src/permissions/与crates/atuin-ai/src/tools/系统讲解权限文件的位置与查找顺序、规则优先级、五种工具的作用域写法、Shell 命令通配符语义以及能力开关配置。读完本文你将能写出精确、安全、可复用的permissions.ai.toml在不失控的前提下把 AI 的动手能力交给它。权限系统总览Atuin AI 采用**默认询问ask-first**的设计默认情况下AI 在调用任何客户端工具前都必须先征得你的许可。你可以通过一个称为permission file权限文件的 TOML 配置来改变这一默认行为——把高频、低风险的操作用allow自动放行把危险操作用deny直接拦截剩下的保持ask由你逐次确认。从源码看整个判定链路清晰且分层收集PermissionWalker从 AI 的当前工作目录出发沿目录逐级向上查找权限文件并追加全局权限文件walker.rs解析每个文件被解析为RuleFileContent { permissions: { allow, deny, ask } }每条规则解析为Rule { tool, scope }file.rs、rule.rs裁决PermissionChecker按文件从深到浅、文件内 ask → deny → allow的顺序逐一匹配命中即返回结果全部未命中则默认Askcheck.rs入口PermissionResolver负责组装 walker 与 checker并把每次工具调用ClientToolCall转成PermissionRequest进行裁决resolver.rs。裁决结果PermissionChecker::check的返回类型PermissionResponse只有三种取值check.rs结果含义触发条件Allowed直接放行命中 allow 规则且未被更优先的 ask/deny 拦截Denied直接拒绝命中 deny 规则且未被更优先的 ask 覆盖Ask弹窗询问命中 ask 规则或所有文件都无匹配规则权限文件位置、查找顺序与优先级文件位置与查找顺序权限文件有两种放置位置项目级任意项目目录下的.atuin/permissions.ai.toml。当 AI 想要运行某个工具时Atuin AI 会检查它的工作目录并向上逐级检查所有父目录直到文件系统根目录全局级Atuin 配置目录下的permissions.ai.toml默认是~/.config/atuin/permissions.ai.toml。源码与文档完全对应PermissionWalker::walk通过self.start.ancestors()枚举当前目录到根目录的每一级并行检查每个目录下是否存在.atuin/permissions.ai.toml最后单独检查全局文件walker.rs。路径拼接逻辑见 writer.rspub fn project_permissions_path(project_root: Path) - std::path::PathBuf { project_root.join(.atuin).join(permissions.ai.toml) } pub fn global_permissions_path() - std::path::PathBuf { atuin_common::utils::config_dir().join(permissions.ai.toml) }也就是说一个项目可以同时拥有项目根级与各子目录级多层权限文件再加上一份全局文件共同参与裁决。文件格式权限文件是一个 TOML 文件固定包含[permissions]表表内三个数组[permissions] allow [ # rules for automatically allowed tools ] deny [ # rules for automatically denied tools ] ask [ # rules for tools that require asking for permission ]每个数组元素是一条规则字符串。从源码看rule.rs规则由正则^(\w)(?:\((.*)\))?$解析Tool或Tool(scope)例如Read、Read(**/*.md)、Shell(git commit *)。ask数组在文档示例中不常出现但它是完整格式的一部分需要时同样可用。文件级优先级越深越优先位于文件系统更深处的权限文件优先于更上层的权限文件。例如当前工作目录下的权限文件允许某工具那么即使父目录的权限文件拒绝它也会以工作目录的为准放行。这一语义在源码中有明确的注释支撑Files are in order from deepest to shallowest, so we can stop at the first matchcheck.rs——walker 收集时按深度排序walker.rschecker 按此顺序遍历命中第一个匹配文件即终止即使后续文件存在相反规则也不再考虑。文件内优先级ask deny allow在同一个权限文件内部ask规则优先于deny规则deny规则优先于allow规则。例如某文件既有一条允许某工具的规则又有一条对该工具询问的规则则 AI 会先弹出询问而非直接放行。这与 check.rs 的实现完全一致对每个文件依次遍历ask→deny→ 检查allowall_covered_by命中即返回。默认行为无匹配即询问如果所有权限文件中都没有匹配的规则Atuin AI 默认询问用户后再执行工具PermissionResponse::Askcheck.rs。这是安全兜底即使你从未配置过任何权限文件AI 也绝不会在未经确认的情况下擅自执行工具。权限作用域Permission Scopes大多数规则都可以限定作用域到特定路径或其他上下文。对于文件操作类规则作用域是一个匹配文件路径的 glob 模式。例如你可以允许 AI 读取某个目录下的文件同时禁止读取其他目录。作用域写在工具名后的括号里例如Read(**/*.md)—— 匹配当前目录及子目录下的所有 Markdown 文件Read(.secret/**)—— 匹配.secret目录下的所有文件缺省 glob如Read—— 匹配所有文件。从源码看path_matches_scope的匹配逻辑很宽容tools/mod.rs相对路径会先解析为绝对路径再做匹配非绝对路径的 scope 会依次尝试文件名匹配完整绝对路径匹配相对当前工作目录匹配三种方式路径中的\会归一化为/以兼容 Windows。这意味着*.md、crates/**/*.rs、src/*.rs这类写法都能按直觉工作。完整示例配置官方文档给出如下示例允许 AI 读写当前项目内所有 Markdown 文件因为 Write 隐含 Read见下文但拒绝访问任何.env文件对其他文件AI 会在读写前向你询问。[permissions] allow [ Write(**/*.md) ] deny [ Read(.env) ]这是一个非常典型的最小信任 明确例外配置日常只写文档敏感文件直接封死其余情况保持人工确认。工具详解Atuin AI 的客户端工具通过统一的ClientToolCall枚举管理tools/mod.rs每个工具类别对应唯一的权限规则名。特别要注意的是Edit编辑文件与Write写入文件共享Write规则名——一个 Write 权限同时覆盖字符串替换式编辑和整文件创建/覆盖tools/mod.rs。AtuinHistory搜索历史命令AtuinHistory工具允许 AI 搜索你的 Atuin 历史找出相关命令。它只读不会修改任何数据。当你问我之前跑过什么命令我的某个命令为什么失败了时AI 可能会请求使用它。权限规则与作用域AtuinHistory配置开关ai.capabilities.enable_history_search见 settings 文档示例权限文件[permissions] allow [AtuinHistory]AtuinOutput读取命令输出AtuinOutput工具允许 AI 读取历史命令的已捕获输出。它同样只读适用于那条命令跑出了什么结果或排查失败命令。前提条件命令输出捕获依赖 daemon 与 pty-proxy 的正确搭建详见 Reading Command Output相关组件文档见 pty-proxy 与 daemon。权限规则与作用域AtuinOutput配置开关ai.capabilities.enable_history_output见 settings 文档示例权限文件[permissions] allow [AtuinOutput]Read读取文件Read工具允许 AI 读取系统上的文件。当你请它分析文件内容、帮你修改文件、或提出最好看看文件内容才能回答的问题时它都可能被请求使用。除文本文件外Read 也支持读取目录列表源码中目录会返回Directory contents:形式的清单见 tools/mod.rs。权限规则与作用域Read(glob_pattern)。例如Read(**/*.md)允许读取当前目录及子目录下所有 Markdown 文件缺省 globRead匹配所有文件。配置开关ai.capabilities.enable_file_tools见 settings 文档——该开关同时启用Read与Write两个工具。示例权限文件[permissions] allow [Read(**/*.md)] deny [Read(.secret/**)]⚠️ 警告Write 隐含 Read为防止意外数据丢失Atuin AI 在写入文件前必须先读取该文件的内容。这意味着任何允许Write工具作用于某文件或某组文件的规则都会自动允许Read作用于同样的文件。例如你配置了Write(**/*.md)即使没有显式的Read(**/*.md)规则AI 也能读取当前目录及子目录下所有 Markdown 文件。这一点在源码的ReadToolCall::matches_rule中直接体现规则工具名为Read或Write都会命中tools/mod.rs。Write创建与编辑文件Write工具允许 AI 创建和编辑系统上的文件。当你请它更新某个工具的配置、或协助排查问题时它可能被请求使用。Editedit_file与Writewrite_file共用Write规则名作用域匹配逻辑也一致tools/mod.rs。权限规则与作用域Write(glob_pattern)。例如Write(**/*.md)缺省 globWrite匹配所有文件。配置开关ai.capabilities.enable_file_tools见 settings 文档。示例权限文件[permissions] allow [Write(**/*.md)] deny [Write(.secret/**)] 备注文件备份在同一个会话session中Atuin AI 首次写入某个文件时会先创建该文件的备份。备份存放于 Atuin 数据目录下按会话隔离目录内有一份 manifest 文件将原始文件路径映射到备份文件路径并记录快照时间与字节数snapshots.rs。从源码看备份目录的实际结构为data_dir/ai/snapshots/session_id/备份文件名是对原路径做百分号编码/→%2F、\→%5C后生成的扁平文件名便于直接用ls浏览如/Users/me/.config/foo.toml对应Users%2Fme%2F.config%2Ffoo.tomlmanifest.json中的每个条目包含original_path、snapshot_at与size_bytes三个字段snapshots.rs。同一会话内重复写入同一文件不会重复快照幂等。官方文档同时说明未来会提供更方便的数据恢复手段。Shell执行命令Shell工具允许 AI 在你的系统上执行 shell 命令。当你请它直接跑一条命令来达成目的、协助调试失败命令、或执行多步工作流时它都可能被请求使用。权限规则与作用域Shell(command pattern)。例如Shell(git *)允许任何以git开头的命令缺省命令模式Shell匹配所有命令。配置开关ai.capabilities.enable_command_execution见 settings 文档。示例权限文件[permissions] allow [ Shell(git add *), Shell(git commit *) ]Shell 作用域的通配符语义Shell规则中的命令模式是针对命令的各个词word进行匹配的*通配符出现的位置不同行为也不同模式匹配不匹配*任意命令—git commit *git commit、git commit -m msggit、git pushls*ls、ls -a、lsofcatgit * --amendgit commit --amend、git rebase --amendgit commitgit commitgit commitgit、git push、git commit -m msg注意ls *带空格与ls*不带空格的区别空格分隔的形式使用词边界匹配——ls *匹配ls和ls -a但不匹配lsof紧贴的形式使用前缀匹配——ls*能匹配上述全部包括lsof。源码any_subcommand_matchesshell.rs按顺序处理几种情况空串/*全匹配xxx *结尾的词边界前缀匹配xxx*结尾的前缀/glob 匹配含*的中间通配每个*匹配零到多个词以及无通配符的精确/前缀匹配。这些语义都有大量 rstest 参数化测试用例背书如ls_word_boundary、ls_glob_prefix、middle_wildcard_amend等见 shell.rs。allow/ask与deny的无通配符差异对allow和ask规则无通配符的模式如git commit是精确匹配——只有当命令的词完全一致时才命中。想让git commit带任意参数都放行请写git commit *对deny规则无通配符的模式如rm是前缀匹配——任何以该前缀开头的命令都会命中。也就是说deny [Shell(rm)]会同时拒绝rm、rm -rf /和rm ./README.md。写 deny 规则时务必小心不带显式通配符的 deny 覆盖面比你想的更大。这一差异在源码中体现为any_subcommand_matches的prefix_bare参数allow 走严格精确路径prefix_bare: falsedeny/ask 走宽泛前缀路径prefix_bare: true并明确注释了denyingrmalso blocksrm -rf /的意图shell.rs。复合命令的处理当 AI 运行复合命令例如git add . npm test时Atuin 会先把它解析成一个个子命令。只有所有子命令都被允许整条命令才会自动放行否则就会落入询问流程。例如git add . npm test必须同时被Shell(git add *)和Shell(npm test)两条规则覆盖才能自动通过。解析实现位于 shell.rs启用tree-sitter特性时bash/sh/zsh/dash/ksh 用 tree-sitter-bash 解析、fish 用 tree-sitter-fish 解析能够识别/||/;/管道、命令替换$(...)、子 shell( ... )、if/for/while/case等结构在无法交叉编译的平台或未知 shell如 nushell上回退到按、||、;、|切分并取每段首词的简化策略parse_fallback。all_covered_by明确要求每个子命令都必须被至少一条规则单独覆盖且解析为空时不做事后放行tools/mod.rs。⚠️ 警告复合命令需要谨慎官方文档明确提示Atuin 的命令解析并非完美存在无法正确识别子命令的边界情况某些 shell 上的解析能力也有限。因此不建议用宽泛模式如Shell(*)放行复合命令——一个解析失误就可能把一条本应被拦截的rm -rf放进 allow 集合。能力开关在配置层面控制工具曝光除了权限文件Atuin AI 还提供一组[ai.capabilities]配置用于控制哪些能力会写入发送给 LLM 的上下文——LLM 只会请求它知道存在的工具。四个开关默认均为true详见 settings 文档配置项默认值控制的工具enable_history_searchtrueAtuinHistoryenable_history_outputtrueAtuinOutput依赖 pty-proxy 与 daemonenable_file_toolstrueRead与Writeenable_command_executiontrueShell示例关闭历史搜索能力[ai.capabilities] enable_history_search false能力开关与权限文件是两层互补的防线前者决定 LLM 是否知道某工具存在、是否会请求调用后者决定即使它请求了该次调用是否放行。此外settings 文档 中还提到一个全局yolo模式默认false开启后自动放行所有权限检查但它不会启用任何被关闭的能力只是绕过权限裁决。请谨慎使用yolo。实战建议与常见陷阱结合文档与源码这里总结几条最实用的配置建议从最小允许开始默认的 ask-first 行为是最安全的状态。先按需添加少数几条allow再逐步观察日志权限命中时会输出Permission ALLOW by rule ...之类的 debug 日志见 check.rs补全规则而不是一开始就写宽泛通配。把.env、密钥、~/.ssh等敏感路径写进deny文档示例中的deny [Read(.env)]思路可推广——用deny做安全兜底永远比依赖AI 不主动去读可靠。用文件级优先级做项目覆盖全局如果你在全局文件里 deny 了某工具但某个可信项目确实需要它可以在该项目根目录的.atuin/permissions.ai.toml里用更深的文件覆盖注意文件内ask deny allow的优先级不会因为深度而改变深文件整体先于浅文件生效。allow写精确、deny写前缀记住不对称语义——allow中git commit只放行精确命令需要参数请写git commit *deny中rm会连带拦截rm -rf /。这正是允许从严、拒绝从宽的安全姿态。对复合命令保持警惕宽泛的Shell(*)加上不完美的命令解析是权限体系最大的潜在漏洞。如果确实需要放行多步工作流请用 tree-sitter 能可靠解析的/;结构并确保每个子命令都有独立规则覆盖。通过权限文件.atuin/permissions.ai.toml与全局~/.config/atuin/permissions.ai.toml、能力开关[ai.capabilities]与工具作用域三者的组合你可以把 Atuin AI 从每步都要确认的助手调教成该放手时放手、该拦截时绝不手软的可靠自动化伙伴。【免费下载链接】atuin✨ Making your shell magical项目地址: https://gitcode.com/gh_mirrors/at/atuin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表