# ADR-0191:私有 Cluster Plugin Package 管理客户端 - 状态:Accepted - 日期:2026-07-29 - 关联:RFC D-140、D-144、D-145、D-175、D-178、D-180、D-181; ADR-0144、ADR-0145、ADR-0185、ADR-0188、ADR-0190 ## 背景 Cluster 已有独立、默认关闭的 Plugin Package management HTTPS process,服务端具备 TLS 1.3、强 User assertion、Project Policy、durable quota、Approval 与低敏响应。 `ql3-plugin-package-manage` 只是该服务端进程入口;现有调用端仅是 release live-evidence 脚本,不是可交付的日常 operator CLI。 因此 D-180 虽已完成数据库与 transport 能力,部署者仍需要自行拼 HTTP header、JSON 和 TLS 参数。直接建议 `curl` 会让 assertion 进入 shell history/process argv,并容易关闭 证书验证或把完整错误响应写入日志。 ## 决策 ### 1. 新增 client binary,不复用 server binary 在既有 `@qinglong/cluster-admin` 内新增: - `./plugin-package-management-client` library subpath; - `ql3-plugin-package-client` executable。 不新增 workspace package、第三方生产依赖、数据库角色、Service、listener、timer、 watcher 或 controller。server 的 `ql3-plugin-package-manage` 名称和启动语义保持不变, 避免一个 binary 同时承担入站 authority 与出站 client。 ### 2. 私有文件是唯一 credential/command 输入 CLI 只接受三个非秘密路径参数: - `--config=/absolute/client.json` - `--command=/absolute/command.json` - `--assertion=/absolute/assertion.jwt` 禁止从 argv、环境变量、stdin 或 command JSON 接收 assertion、Bearer token、私钥、 数据库 DSN 或 CA 内容。 config、command、assertion 必须是当前 POSIX UID 拥有、规范绝对路径、非 symlink、 `0600` regular file,并通过 `lstat → O_NOFOLLOW open → fstat` 在同一 descriptor 读取。config/assertion 最大 16 KiB,command 最大 256 KiB。CA 是公开验证材料,但仍须 是规范、非 symlink、owner 为当前 UID 或 root、group/world 不可写的 regular file, 最大 256 KiB。 config schema v1 精确包含: - `endpoint`:固定 `/api/v3/plugin-packages/management` 的 HTTPS URL; - `servername`:显式 DNS 名,必须等于 URL hostname; - `caFile`:绝对 CA bundle 路径; - `requestTimeoutMs`:1–30 秒。 不读取 `HTTP_PROXY`、`HTTPS_PROXY`、`NO_PROXY` 或系统代理。 ### 3. 一次进程只执行一个 exact command command 必须是 management transport 已公开的 schema v1 command,operation 只能是: - Package install `propose|decide|inspect`; - publisher emergency revocation `propose|decide|inspect`; - publisher trust transition `propose|decide|inspect`。 客户端不补 ID、不改 expected version、不派生 digest、不上传 PEM/snapshot,也不自动 重试。网络结果不确定时,operator 必须用原 command 文件显式重放;服务端 exact replay 负责收敛。 ### 4. TLS 与 HTTP 严格失败关闭 client 固定: - TLS 1.3 min/max; - `rejectUnauthorized=true`; - endpoint hostname 与显式 `servername` 一致; - CA bundle 显式注入; - 无 redirect、无 connection pooling、无压缩、单一 POST; - request/response 各 256/128 KiB 硬上限; - exact `application/json` request 与 `application/json; charset=utf-8` response; - bounded timeout,超时销毁 socket。 成功响应必须是 exact schema v1 envelope、带有 bounded request ID,且 result operation 与 command operation 完全一致。非 200 响应只保留 status、bounded error code、 request ID 和可选 Retry-After;不回显 response body、header、assertion、路径或 TLS diagnostic。 ### 5. 输出保持低敏 stdout 只输出服务端已经审查过的低敏 result envelope。stderr 失败事实只包含稳定 component/event/error code、可选 HTTP status/request ID/retry-after;不输出 Error message、stack、文件路径、endpoint、assertion、command 原文或证书内容。 客户端在请求结束后清零可变 assertion/CA/command Buffer。Node.js/HTTP 内部可能产生 不可控复制,因此本能力不声称 secure enclave 或零内存残留;短生命周期进程和不落盘/ 不回显是当前边界。 ## 不采用方案 ### 用 curl 文档代替产品 client Bearer 参数容易进入 shell history/process argv,TLS/redirect/response 上限也无法被 仓库门禁稳定约束。 ### client 自行持有 IdP 私钥并签 assertion 会把身份签发 authority 混入 Package 管理客户端;本 CLI 只消费外部 ceremony 产生的 短期 assertion。 ### 把 client 合入 cluster-control 常驻 runtime 不应获得管理 assertion 或出站管理 authority。 ### 新增独立 workspace package 客户端与现有 management protocol 同发布、无新依赖或独立制品矩阵;新增第 23 个包不满足 ADR-0185。 ### 自动重试 网络断开不能证明服务端未提交。自动重试会隐藏 outcome unknown;显式 exact replay 才是 可审计恢复。 ## 验收证据 - `@qinglong/cluster-admin/plugin-package-management-client` 与 `ql3-plugin-package-client` 已发布在既有 cluster-admin 包,workspace 仍为 22 包, 未新增第三方生产依赖、listener、timer、watcher 或 controller。 - client 专项 5/5 通过:真实 TLS 1.3 + CA + DNS hostname、one request、九种 operation、 unknown operation、private/canonical/no-follow 文件、redirect、content-type、128 KiB response、timeout 与 CLI 输出脱敏均有正负向证据。 - cluster-admin 全量回归为 121 pass、0 fail、1 条真实 Kubernetes 条件 skip;构建闭包 同时编译 runtime-core、cluster-postgres 与 cluster-admin。 - cluster deployment audit 18/18,dependency boundary 37/37;22 个 package importer、 31 个 cluster-admin source、CloudNativePG 与 edge-import 审计均无 finding。 - operator 使用契约见 `docs/operations/ql3-plugin-package-management-client.md`。