10 Decisions中文
10 · 决策与满足
规范来源:
capability-language-core-v1.md§9(9.1 reason ordering)、§10、Appendix A 本页是便于阅读的指南。若出现冲突,以规范为准。 状态:预览版——不用于生产环境。
速览
Authorize(grants, operation) → Decision 产生三值 verdict:allow / deny / allow_unresolved。Satisfy(evidence_set, requirement)(§10)产生证据侧的二值报告:SATISFIED / UNSATISFIED。两者都是确定性、fail-closed 的,并携带稳定的 reason code。Appendix A 展示了消费者如何绑定这套共享词汇。
1. Authorize——授权侧(§9)
Decision = { verdict: "allow"|"deny"|"allow_unresolved",
reason: string|null,
unresolved: string[] } // additive, §8.4
算法(后续内容沿用 §9.1's layer order,但不代表优先级):
| 步骤 | 检查 | 解析为 |
|---|---|---|
| 0. 预检查 | grant 集合缺失或为空 → capability_not_authorized(§9.1 layer 10),早于任何 operation 检查,即使 operation 也缺失 |
decide-016:{} grants + {} op → capability_not_authorized,而不是 missing_capability_id |
| 1. Operation 验证 | id 缺失或无效——报告具体的 layer 1 代码,绝不合并 | missing_capability_id decide-017;unsupported_wildcard decide-018;invalid_capability_id decide-025 |
| 2. 查找覆盖 grant | 通过 Entails(§6.1);没有覆盖项 → capability_not_authorized(§9.1 layer 10) |
decide-002 |
| 3. 求值约束 | 按覆盖 grant 逐个处理,依据 §8.1 | unknown_constraint / invalid_constraint / {type}:violated / 遗留义务(§8.4) |
| 4. 聚合(多 grant,§9.1) | 任一覆盖并允许即可 → allow;合并判定为 allow 的覆盖 grant 的 residual union;全部拒绝 → 取规范顺序中第一个覆盖 grant(§9.1),结果确定 | decide-029、decide-030、decide-035 |
| 5. Verdict | 有非空 residual 的 allow → allow_unresolved;无 residual 的 allow → allow |
decide-020 |
预检查是唯一的优先级规则:缺失或为空的 grant 集合会以 capability_not_authorized(layer 10)拒绝——调用方如果两个输入都未传入,得到的就是这个 reason,而不是 missing_capability_id。operation 缺失则解析为 missing_capability_id(layer 1)。语言修订不匹配(§12.1)会在每一层之前解析为 unsupported_language_revision。
2. 多 grant 聚合(§9.1)
Authorize 处理的是有序 grant 列表;授权结果与顺序无关,只有 reason 的选择使用输入顺序:
- 任一覆盖并允许的 grant 都允许(窄 grant 绝不能 deny 宽 grant 允许的 operation)——
decide-029。 - 遗留义务 = 同时覆盖、判定为 allow 的 grant 之间的
unresolved并集(规范化后排序)。在 params/约束层被拒绝的覆盖 grant 不贡献任何内容——它没有授权,因此其遗留义务也不会被携带(decide-035:两个 grant,network + time,都为 allow → 以allow_unresolved携带并集)。 - 没有 grant 覆盖 →
capability_not_authorized;operation 的第 1 层错误始终先于任何覆盖/聚合处理。 - 所有覆盖 grant 都在 params/约束层被拒绝 → deny,reason = 规范顺序中第一个覆盖 grant 的 layer 5–11 拒绝结果(输入列表顺序;MUST NOT 按哈希/迭代顺序选择)——
decide-030。
Op-ID 验证错误会传播其具体的 layer 1 代码(missing_capability_id / unsupported_wildcard / invalid_capability_id),绝不使用笼统代码,也绝不变成 capability_not_authorized;只有覆盖失败(layers 3–4 and 10)才归并为 capability_not_authorized。grant 中出现格式错误的 id,会使该 grant 无法匹配:Entails 会将它的 layer 1 代码作为 false 的 reason 报告,但 Authorize 会把不匹配归并到覆盖失败(capability_not_authorized)——不会暴露 grant 自身的代码。
3. Resolved Reason Ordering(§9.1,规范)
单一报告的 reason 是固定顺序中第一个适用的层(适用于 Entails、Intersect、Authorize):
| # | 层 | Reason code |
|---|---|---|
| 1 | CapabilityId 有效性 | invalid_capability_id、missing_capability_id、unsupported_wildcard |
| 2 | Params 归一化 | invalid_params_duplicate_key、invalid_params_number、invalid_params_size、invalid_params_binding |
| 3 | 命名空间(scheme + action Class) | different_namespace |
| 4 | 路径覆盖(同一命名空间) | literal_mismatch、wildcard_requires_trailing_segment |
| 5 | 显式空边界 | empty_bound_denies_class |
| 6 | null 值 | invalid_params_null |
| 7 | 参数存在性(双向) | params_missing、undeclared_param |
| 8 | 枚举成员资格与基数 | not_in_enum、params_cardinality |
| 9 | 边界比较 | params_exceed_grant、params_out_of_range、params_not_multiple |
| 10 | 覆盖为空 | no_overlap、absent_source、capability_not_authorized |
| 11 | 约束求值 | unknown_constraint、invalid_constraint、{type}:violated |
Resolve(§8.5)是决策之后的处理,不是某一层:它消费一个 Decision,绝不重新运行 Authorize;它只引入 invalid_resolution / invalid_timestamp 以及已履行的 {type}:violated,并且只在 allow_unresolved 输入上引入。
4. Satisfy——证据侧(§10)
Satisfy(evidence_set, requirement) → Satisfaction
Satisfaction = { verdict: "SATISFIED"|"UNSATISFIED", reason: string|null }
算法:(1) 按各自的原生规则验证每个 evidence 工件;(2) 每个所需 evidence 角色都已填写;(3) 通过 Match(§6.4)将每个工件精确绑定到 action;(4) 求值 freshness、consumption 和 role 约束(§8.2 evidence-side grammar:varwof/evidence-v1:freshness:sec:<n>)。如果某个已识别约束的求值属于 enforcement point(consumption),其结果为 unknown,在顶层产生 UNSATISFIED;(5) 所有角色都已填写并绑定 → SATISFIED;(6) 任一角色未填写、未绑定或被违反 → UNSATISFIED。
三态求值,二值报告。 已识别的证据侧约束以三态求值(satisfied / violated / unknown),但报告是二值的:顶层的 unknown MUST 产生 UNSATISFIED,绝不产生 SATISFIED。证据侧没有 allow_unresolved;unresolved 只用于授权侧(§8.4、§11)。结果确定性、fail-closed,并具有稳定的 reason code(§10)。
5. 消费映射(Appendix A)
Appendix A 是信息性内容——符合 CLC-A 不依赖任何 consumer profile:
| Consumer | 语法 | 绑定 | Verdict |
|---|---|---|---|
| AIC-JWT DA | capability[].id |
Entailment(§6.1) | Decision(§9) |
| EMILIA AEB | AEG capability_class | Match(§6.4)+ Entailment(§6.1) | SATISFIED(§10)+ Decision(§9) |
| RAR authorization_details | type="capability"(RFC 9396) |
Entailment(§6.1) | Decision(§9) |
| 委托链 | 每个 hop 声明的集合 | Intersection(§7) | Decision(§9) |
| 委托包含关系 | 父级和子级边界 | Contains(§13) |
Containment verdict(§13) |
委托链和包含关系这两行绝不能混淆:交集回答整条链的有效权限,包含关系回答每一跳的 child ⊆ parent;必须留在父级范围内的 hop 要用 Contains(§13)检查——参见 12-containment。
防混用清单
- [ ] grant 侧预检查(layer 10)先于 operation 验证(layer 1):grant 缺失 + operation 缺失 →
capability_not_authorized。 - [ ] Op-ID 的第 1 层代码具体传播;grant 侧代码则归并为
capability_not_authorized。 - [ ] 多 grant 采用任一覆盖原则:窄 grant 不能 deny 宽 grant 的 operation。
- [ ] 遗留义务只对同时覆盖并允许的 grant 取并集;被拒绝的 grant 不贡献任何内容。
- [ ]
allow_unresolved绝不是allow;unknown是内部状态,在证据侧绝不是第三种顶层 verdict。
常见误区
- 只测试
verdict == "allow"——遗留义务会作为未经确认的 allow 溜过去(§8.4)。 - 期待证据侧报告
unknown——它报告的是二值UNSATISFIED,并带有稳定的 reason。
← 09-intersection.md · → 11-reason-codes.md · 相关:08-constraints.md、11-reason-codes.md