Files
qinglong/docs/adr/ADR-0142-authenticated-plugin-package-management-facade.md
T

118 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-0142:认证后 Plugin Package 管理 Facade 与 Profile ceremony
- 状态:Acceptedtransport-neutral 管理 facade、SQLite 真实端到端闭环与
local/cluster Profile 组合已实现;本机 CLI 由 ADR-0143 完成,Cluster transport
边界由 ADR-0144 冻结,identity/keyset 与 HTTP process 由 ADR-0145 完成;
durable quota 由 ADR-0146 完成,ADR-0149 已完成原子 resource generation
identity/source;真实双 User/UI 与资源语义 materializer 待完成)
- 日期:2026-07-25
- 关联 RFCQL-RFC-0001 D-05、D-08、D-09、D-85、D-130 至 D-140
## 上下文
ADR-0141 已完成 immutable proposal、durable Approval、execution/start barrier、
Package 原子 admission 和调用方驱动 dispatcher,但这些能力仍是彼此独立的显式
authority。若 HTTP、CLI、UI 或自动化入口自行拼接这些 repository,很容易出现:
1. 在解析完整 Package action 前查询 Policy,或绕过 `package.manage`
2. 由 transport 提交 Project/RoleBinding fence,而不是读取当前 Policy snapshot
3. local 与 cluster ceremony 漂移为“全部允许自批”或“全部强制四眼”;
4. consumption 复用用户输入的 consumer identity
5. proposal、request、decision、consume 和 dispatch 各自生成不稳定幂等身份;
6. 为每种 transport 或 Profile 新建 workspace package。
公开 transport 现在还不能直接开放,但必须先建立唯一的 use-case 组合边界,后续
adapter 才不会再次复制安全协议。
## 决策
### 1. 共享 use-case 留在 runtime-core 显式子路径
新增 `@qinglong/runtime-core/plugin-package-management`,不新增 workspace package、
第三方依赖、timer、watcher、socket 或数据库连接。Facade 只接受已经认证且仍 active
`SecurityPrincipal`,并固定提供:
- `propose`:规范化完整 install action,执行 `package.manage` Policy,使用返回的
fence 创建 immutable proposal,再创建 digest-bound ApprovalRequest
- `decide`:重新读取 request,以当前 principal 对 `approval.decide` 执行 Policy
再提交强认证 decision
- `consume`:只使用构造时注入的 system consumer authority,重新读取 requester 的
`package.manage` Policy fence,再原子生成 dispatch/execution baseline
- `inspect`:只读取 proposal 与 request durable fact
- `dispatch`:调用既有 bounded dispatcher,不安装后台循环。
Facade 不接收调用方提供的 Policy fence、consumer subject、action digest 或 preview
digest;这些事实必须分别来自 Policy engine、固定 composition 和 canonical proposal。
### 2. 幂等身份由请求显式携带
写操作必须携带稳定的 action/request/decision/consumption/dispatch/audit identity
以及对应发生时间。相同 identity 与相同语义可 exact replay;不同内容复用 actionRef
或 approvalRequestId 必须冲突。Facade 不在响应丢失后静默生成新 identity。
默认 Approval lifetime 为 15 分钟,可由受信 composition 缩短或在领域允许的 24 小时
上限内调整。已超出 lifetime 的新 `propose` 调用在任何 mutation 前拒绝。
### 3. Profile 固定 ceremony,不让 transport 选择
- `@qinglong/local-admin/package-management` 固定
`human_confirmation`,复用唯一 `LocalSqliteOperationAuthority`edge/standalone
dispatcher 默认批量仍为 1/4
- `@qinglong/cluster-admin/plugin-package-management` 固定
`separation_of_duty`,使用 admin-only PostgreSQL repositorydispatcher 默认批量
仍为 16
- 两个入口都不从 package root、常驻 runtime、cluster-control 或 worker 导出。
local 新增 `@qinglong/local-sqlite/project-policy` 窄 adaptercluster 只给现有
`PostgresProjectPolicyRepository` 增加显式 `project-policy` export。没有新增表、
migration、连接或 importer。
### 4. 公开 transport 继续失败关闭
本 ADR 的“认证后”表示 facade 不接受匿名/过期 principal,并不表示 bearer token、
本机 credential file、MFA/hardware assertion 或 HTTP session 已在这里完成验证。
真实 transport adapter 必须在调用 facade 前完成:
- bounded request/body/command-file 解析;
- credential 或本机 console proof
- rate limit、取消和 response mapping
- secret 不进入 argv/stdout/audit
- transport response-loss 的 idempotency key 保留。
因此当前不能把内部 subpath 注册为 2.x Controller route,也不能宣称 UI 或
cluster admin transport 已生产开放。本机私有 command-file CLI 由 ADR-0143 完成;
ADR-0145 提供的 cluster HTTP process 和 Kubernetes operation 仍默认关闭,生产
ingress 继续受 keyset anti-rollback、真实双 User 与 live ingress 门约束。
## 影响
- Package 管理 use-case 不再由每种 transport 自行拼 repository
- workspace importer 仍为 21runtime-core 只增加一个纯协调 source
- edge 禁用 Package 时不会加载 facade 或任何 Package storage
- cluster-control/runtime/worker 仍无 proposal、decision、consume 或 admission 写权限;
- ADR-0143 已在同一 facade 上实现短生命周期本机 CLI;独立 cluster admin API
已由 ADR-0144 冻结双 authority 边界,仍无需改变领域和 Package 数据库协议。
## 验证
1. runtime-core 250/250,其中新增四眼审批、operator mutation-before-deny 与
authorization-before-quota 门禁;
2. local-admin 54/54,其中真实 Node 24 SQLite 流程覆盖
`propose → self-confirm → consume → dispatch → queued admission`
3. 弱认证 decision 与过期 propose 在 mutation 前失败,失败 decision 不产生 Audit
4. 完整流程产生 proposal/request/decision/consume/admit 五类 durable Audit
5. cluster-admin 63 pass/1 条件 skip,构造不打开 PostgreSQL且 ceremony 常量固定为
`separation_of_duty`
6. 26 项 source-boundary test 与 cluster dependency audit
`findings: []``compatible: true`
7. importer 仍为 21;新增能力均为既有 package 的显式 subpath。
## 后续门禁
- 为 keyset generation/revocation 增加跨全副本重启的 durable anti-rollback
- response-loss 下相同 transport idempotency key 的完整端到端重放;
- PostgreSQL 真库 separation-of-duty/concurrent decision/consume
- ADR-0149 已完成 generation publisher/source;继续实现
Task/Workflow/Prompt/Tool 语义 materializer
- UI 只消费低敏 preview/status,不持有数据库或 dispatcher authority。