# ADR-0022 服务管理的技能目录在沙箱中只读可见;Codex 的禁止规则绕开可读路径 - 状态:Accepted · 日期:2026-10-25 · 补充 ADR-0010、ADR-0017 ## 背景 实施自定义技能时发现两个问题,也影响已有的第三方技能: 1. 内置全局禁止项包含 `{dataDir}/data`(数据库、版本库、MCP 数据都在这里),而第三方技能与自定义技能的生效目录 `data/community-skills`、`data/custom-skills` 也在其中。 - Claude 的 Read 等工具经过 `checkAccess`,全局禁止项优先于可读路径,所以读不到技能的参考文档。 - Codex 的沙箱同样禁止。 - SKILL.md 本身由引擎进程读取,所以技能看起来"能触发",但参考文档和脚本用不了。 2. Codex(0.164)的文件权限中,父目录为 deny 时子路径的 read 无效,write 有效。已实测:父 deny + 子 read,读取被拒;父 deny + 子 write,写入正常。 - 因此宽松模式下 `softDeny` 中的服务目录(`/srv/agent-server`)会让 Codex 读不到其中的本地技能目录、Python 运行环境与官方技能目录。 - 当前工作区可写,不受影响。 ## 决策 - `checkAccess` 对服务管理的技能目录(`managedSkillRoots()`:第三方、自定义技能的生效目录)只放行读取,并且先于全局禁止项判断。data 下的其他内容仍然禁止,写入仍然禁止。 - Claude 的 Bash 沙箱:`denyRead` 中的 data 目录与 `allowRead` 中的技能目录同时存在时,更具体的 allowRead 生效(已实测)。无需改动。 - Codex 的权限表:要禁止的目录(全局禁止项、宽松模式的 softDeny)如果包含必须可读的路径(表中所有 read 项),不再禁止该目录本身,而是逐层展开,逐个禁止通往可读路径以外的其他条目(`denyAround`)。 - 已在生产 Codex 上验证:可读路径能读、不能写,同级条目被拒。 - 展开在每次对话时计算。之后新出现的条目要到下一次对话才被禁止;这些目录只由服务写入。 ## 后果 - 第三方技能与自定义技能的参考文档、脚本、模版在两个引擎中都可用 - 宽松模式下 Codex 可以使用本地技能目录与 Python 运行环境 - 自定义技能的版本库(`data/custom-skill-store`)、数据库等仍不可见 ## 后续(2026-10-26) 技能生效目录已从 `data/` 移到顶层 `{dataDir}/managed-skills/{community,custom}`,不再位于全局禁止的 `data/` 之内(systemd `ReadWritePaths` 相应加入该目录,启动时自动搬迁旧目录)。文件库、上传暂存与技能来源缓存仍在 `data/` 下,对 Agent 不可见。`checkAccess` 的只读放行保留:即使追加的全局禁止项覆盖了这些目录,技能仍然可读。