Skip to content

feat(orchestration): permissions 规则 YAML 化(#4 / ADR-0011 D-8b) - #15

Merged
mirror29 merged 1 commit into
mainfrom
feat/permissions-yaml-d8b
May 27, 2026
Merged

feat(orchestration): permissions 规则 YAML 化(#4 / ADR-0011 D-8b)#15
mirror29 merged 1 commit into
mainfrom
feat/permissions-yaml-d8b

Conversation

@mirror29

Copy link
Copy Markdown
Owner

Summary

PermissionEngine 的 allow/ask/deny 规则从 defaults.ts 硬编码 TS 数组搬到外置 YAML(config/permissions.default.yaml),解决 issue #4 的 4 个痛点:改权限不再要发版 / 多环境差异化可行 / audit 追踪独立 / 兑现 ADR-0011 §规则文件示例的设计承诺。

加载优先级(loadDefaultPermissions):

INALPHA_PERMISSIONS_FILE env  →  config/permissions.default.yaml  →  DEFAULT_PERMISSIONS 常量

失败语义:env 指定路径 或 默认 yaml 文件存在时,加载失败 strict throw 带文件路径与 zod 字段诊断;仅"env 未设 + 默认 yaml 不存在"才回退常量并 console.warn 一次——对应 issue #4 验收第 4 条 "YAML 解析失败 / schema 不匹配时启动失败并打印明确错误"。

改动

新增(4 文件)

  • packages/orchestration/config/permissions.default.yaml — 1:1 等价于 DEFAULT_PERMISSIONS,带 inline comment 复述设计意图(含 paper.promote_candidate MVP allow workaround 注释 + sandbox timeoutMs<=60000 predicate)
  • src/permissions/schema.ts — zod PermissionConfigSchema,只校结构;规则字符串语法由 parseRule 抛错
  • src/permissions/yaml_loader.tsloadPermissionConfigFromFile / resolveDefaultYamlPath / loadDefaultPermissions;路径用 import.meta.url 解析不依赖 cwd(规避 vitest / mastra dev 漂移)
  • tests/permissions-yaml-loader.test.ts — 9 case,覆盖等价性 / env override / 6 条 strict throw 路径

修改(4 文件)

  • src/mastra/wired-tools.tsbuildDefaultPermissionEngine() 改用 loadDefaultPermissions()
  • src/permissions/index.ts — 多导出 loadDefaultPermissions / loadPermissionConfigFromFile / resolveDefaultYamlPath / PermissionConfigSchemaDEFAULT_PERMISSIONS 保留作 builtin fallback + 现有测试基线
  • package.json / pnpm-lock.yaml — 加 yaml@^2.9.0(ISC license,与 AGPL-3.0 兼容)

验收对应(issue #4

  • 1. yaml 内容等价于 defaults.ts — 测试 default yaml 加载后逐字段等于 DEFAULT_PERMISSIONS 常量 deep equal pass
  • 2. 默认行为不变permissions.test.ts / wired-tools.test.ts / strategy-authoring.test.ts / sandbox.test.ts 5 个文件 113/113 通过
  • 3. INALPHA_PERMISSIONS_FILE env 切换生效 — 测试 env 指向自定义 yaml 时结果反映该文件而非默认 pass
  • 4. 解析失败 strict throw — 覆盖文件不存在 / 非法 YAML / 缺 defaultMode / 枚举不匹配 / allow 不是数组 / 顶层不是 object 6 条路径

Test plan

  • pnpm -C packages/orchestration typecheck — clean
  • permissions 相关 5 测试文件 113/113 通过
  • bash scripts/check-consistency.sh — 失败 0
  • 可选:INALPHA_PERMISSIONS_FILE=/tmp/custom.yaml bash scripts/dev.sh 验证 mastra :4111 启动加载自定义 yaml

不在范围(out-of-scope)

  • user / project / local 三层 yaml merge(D-8 简化,留给后续 ADR-0011 §三层 merge 完整版)
  • 规则内容调整(本 PR 只搬运不重设计)
  • pnpm permissions:explain CLI(可后续 chore;engine 已有 list() 方法支撑)
  • hot reload(yaml 变更要重启,符合 D-8b 最简实现)

关联

🤖 Generated with Claude Code

把 PermissionEngine 的 allow/ask/deny 规则从硬编码 TS 数组搬到外置 YAML,
解锁运维不发版调权限 + dev/staging/prod 差异化 + audit 追踪独立化。

加载优先级(loadDefaultPermissions):
  INALPHA_PERMISSIONS_FILE env  →  config/permissions.default.yaml  →
  DEFAULT_PERMISSIONS 常量(仅默认 yaml 缺失时兜底)

失败语义:env 指定路径 / 默认 yaml 文件存在时,加载失败 strict throw
带文件路径与字段诊断;仅"env 未设 + 默认 yaml 不存在"才回退常量并
console.warn 一次——对应 issue #4 验收第 4 条。

新增:
  - packages/orchestration/config/permissions.default.yaml(1:1 等价于
    DEFAULT_PERMISSIONS,带 inline comment 复述设计意图)
  - src/permissions/schema.ts(zod 校验结构)
  - src/permissions/yaml_loader.ts(loadPermissionConfigFromFile /
    resolveDefaultYamlPath / loadDefaultPermissions;路径用 import.meta.url
    解析不依赖 cwd)
  - tests/permissions-yaml-loader.test.ts(覆盖等价性 / env override /
    4 条 strict throw 路径)

接入:wired-tools.ts buildDefaultPermissionEngine 改用 loadDefaultPermissions;
DEFAULT_PERMISSIONS 常量保留作 builtin fallback 与现有 4 个测试基线。

验证:pnpm typecheck 通过;permissions 相关 5 个测试文件 113/113 通过;
check-consistency.sh 失败 0。workflows.hello 的并行 timing flake 与本 PR 无关
(重跑通过)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying inalpha-web with  Cloudflare Pages  Cloudflare Pages

Latest commit: f3d6b3d
Status: ✅  Deploy successful!
Preview URL: https://27b09791.inalpha-web.pages.dev
Branch Preview URL: https://feat-permissions-yaml-d8b.inalpha-web.pages.dev

View logs

Comment on lines +14 to +15
allow: z.array(z.string()),
ask: z.array(z.string()),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[medium] askdeny 未设 .optional().default([]),导致自定义 YAML 若省略空数组就会报 schema mismatch: ask: Required。这个 PR 的核心用例是允许运维写自己的 YAML,严格要求三个数组全写会增加配置成本。建议:

Suggested change
allow: z.array(z.string()),
ask: z.array(z.string()),
ask: z.array(z.string()).optional().default([]),
deny: z.array(z.string()).optional().default([]),

这样 PermissionConfigParsed 推断类型不变(string[]),loadPermissionConfigFromFile 返回的对象仍满足 PermissionConfig。— 依据 CLAUDE.md §9 可维护性:面向运维的配置接口应降低必填门槛

@claude

claude Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Review(CLAUDE.md §3 / §3.1 / §3.2 / §4 / §7–9)

整体质量高:错误语义设计清晰(env 指定路径 strict throw / 默认 yaml 不存在 warn+fallback)、测试覆盖 9 case、import.meta.url 路径计算在 rootDir:"./src" + outDir:"./dist" 下验证正确。


必修

无 critical / major 级别问题。


可选优化

  • PermissionConfigSchemaask / deny 改为 .optional().default([])(见 inline 评论)。自定义 YAML 省略空数组会命中 schema mismatch: ask: Required,对运维不友好;三段式 fallback 链的设计意图是降低配置门槛,schema 也应保持一致。

LGTM,合并后 console.warn fallback 路径在默认 yaml 已存在的情况下永远不会触发,可后续再考虑移除 _warnedFallback 状态(当前无影响)。

@mirror29
mirror29 merged commit cbd6f25 into main May 27, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] 权限规则 YAML 化(ADR-0011 / D-8b)

1 participant