8.7 KiB
ADR-0175:私有认证 Local Model Price Catalog CLI
- 状态:Accepted
- 日期:2026-07-27
- 关联:RFC D-49、D-73、D-84、D-85、D-156、D-162、D-163、D-164、D-165;ADR-0085、ADR-0143、ADR-0167、ADR-0173、ADR-0174
背景
ADR-0174 已完成授权型 Model Price Catalog facade、双方言 9006 原子授权事实与
Profile 决策模式,但本机用户仍没有受审产品入口。若直接把 repository 暴露给脚本,
调用方就可以伪造 actor、Policy、assurance 或授权结果;若让常驻 edge runtime 或
local-admin 根入口静态导入 AI,则禁用 AI 的路由设备仍要支付模块加载和制品成本。
本机入口还存在两个真实竞态:
- local-console 在事务外验证 credential 后,credential、pepper、User 或 Owner binding 可能在 catalog transaction 开始前被撤销;
- 同一私有命令文件在进程退出或响应丢失后重试,会建立新的认证时间窗。若把该时间 漂移当作 durable authorization 漂移,已经提交的命令无法安全收敛。
AI migration 是显式 feature stream。产品 CLI 不能为了“方便”在运行时自动执行 9001–9006 DDL,否则只读检查、低资源设备和生产变更控制都会失去边界。
决策
1. 复用现有短生命周期 CLI package
在现有 @qinglong/local-owner-cli 增加:
- 显式子路径
@qinglong/local-owner-cli/model-price-command; - 二进制
ql3-model-price; model-price.publish|activate|deactivate|revoke|inspect五种 operation。
不新增 workspace package、第三方依赖、daemon、listener、timer、watcher、缓存或数据库
连接。只增加 local-owner-cli → @qinglong/ai workspace 依赖;通用
local-admin、cluster-admin、默认 edge/standalone runtime 和基础制品不得反向导入
AI。命令执行完成后关闭单一 SQLite authority。
CLI 只接受:
ql3-model-price run --command-file /absolute/private-command.json
命令文件必须是私有、规范化、有界绝对路径上的 exact-shape JSON。body 只能包含公开 intent、CAS fence、幂等 ID 和失败审计 event ID,不得包含 principal、subject、 authentication ID、assurance、Policy、decision mode、catalog/result digest 或任意 authority seam。输出只含 publication/head 与低敏授权摘要,不返回 credential、 principal 或认证 ID。
2. 显式 feature activation,运行时不执行 DDL
入口打开已经通过主 SQLite readiness 的数据库后,只读核对:
- 9001–9006 六条 AI migration history、stream identity 与 checksum;
- 11 张 Model Invocation/Price Catalog 业务表;
- 独立
QingLong3AiSchemaMigrationshistory 表。
任一缺失或漂移均以 LOCAL_MODEL_INVOCATION_FEATURE_NOT_READY 失败,并且在认证前停止。
CLI 不创建、修补或迁移 schema。部署者必须通过受审 feature activation ceremony 先行
执行 AI migration。
3. 本机强认证与平台 Owner 资格
所有 operation 复用 local-console POSIX/private-file proof、API credential、
credential-version pepper provenance 和 local_console assurance。请求不得指定 User。
edge/standalone 当前以 default Project 的最新 active owner binding 证明该本机 User
是产品平台 Owner。这个 binding 只作为本机 operator 资格证据,不把价格数据变成
Project-scoped 资源:catalog、Policy、authorization 和 resolver 中仍不存在 Project ID。
inspect 也要求当前 Owner,避免该管理入口成为普通本机 User 的旁路。
本机平台 Policy 固定为:
- revision
local_console_platform_owner_v1; - allow reason
local_console_confirmed; - decision mode
human_confirmation。
Policy、assurance、principal 和 result digest 均由受信 composition 派生。
4. SQLite transaction 内二次围栏
publishAuthorized/transitionAuthorized 在取得 BEGIN IMMEDIATE 后、读取 replay 或
写入任何 catalog/authorization 行前调用同步 transaction hook。hook 在同一 connection
和 transaction 内精确复验:
- credential ID/version、active state、secret digest 与有效期;
- active User identity;
- credential-to-pepper binding、active/retired pepper state 与 material digest;
defaultProject active 状态和该 User 最新 active Owner binding。
任一撤销、版本、摘要、时间或角色漂移都回滚 publication/head/authorization 全部写入。
进程时钟和事务外 confirm() 只用于早拒绝,不能代替数据库 fence。
5. 成功事实、失败审计与重放
成功 mutation 继续只由 9006 authorization 与 publication/head 在同一事务证明。 transport 不先写一条“成功 security audit”,避免双事务裂缝。
下列失败写入现有低敏 QingLong3SecurityAuditEvents:
- credential authentication rejection;
- credential/User/pepper transaction fence rejection;
- 当前平台 Owner 资格 rejection;
- Policy deny 或 quota deny。
审计只保存 caller 提供的独立 event ID、request/operation、nullable authenticated subject/authentication ID、固定 outcome/reason 和本地时间;不保存 token、secret、 价格 body、stack 或 raw error。相同失败 event ID 的精确重放忽略观察时间差并收敛为 一条事实。
对于已提交 mutation,同一 authorization/request/catalog command、同一 User、同一 credential proof authentication ID、assurance、Policy 和 decision mode,可以在当前 transaction fence 再次通过后使用新的认证时间窗重放。repository 返回首次提交的不可变 authorization,不重写其时间或摘要;不同 User、authentication proof、Policy、ID 或 catalog command 仍然 conflict。
拒绝方案
- 新增
ql3-model-price-clipackage:没有独立部署或权限边界,只会继续制造单文件 package,拒绝。 - 把 CLI 放进常驻 edge runtime:会扩大默认导入闭包和攻击面,拒绝。
- 由 CLI 自动运行 AI migration:把产品调用升级为 DDL authority,拒绝。
- 只做事务外 local-console confirm:无法关闭撤权竞态,拒绝。
- 把调用方 body 当作 Policy 或 User 来源:可伪造授权,拒绝。
- 把价格目录挂到
defaultProject:全局 catalog 会形成虚假租户边界,拒绝; Owner binding 只证明本机 operator 资格。 - 因新认证时间窗拒绝已提交重放:会让响应丢失无法收敛,拒绝。
- 用新认证覆盖首次授权事实:会改写历史,拒绝。
- 现在开放 Cluster CLI/HTTP:尚无 TLS identity assertion、平台 Policy repository、耐久 quota 与双人 ceremony,拒绝。
当前证据
@qinglong/ai92 项:90 pass,2 条真实 PostgreSQL 条件 skip;新增 AI readiness、 transaction hook 与 fresh-reauth replay 测试;@qinglong/local-owner-cli16/16,覆盖 publish replay、activate、inspect、真实 product binary、无敏感输出、未激活 schema、widened body、认证失败审计精确重放、 过期强认证、precheck 后 credential revoke 和非 Owner rollback;- 受影响 AI/local-sqlite/local-owner-console/local-owner-cli 均通过 TypeScript build;
- 22 个 QL3 package 已完成干净全量 build/test,0 fail;22-importer dependency audit
覆盖 AI 20 个、Owner CLI 8 个源码文件且
findings=[],edge 121-module import gate 无 AI/cluster 越界; - 默认 edge/standalone 仍为 3,910,465/3,910,525 bytes、478 files;显式 edge-ai/standalone-ai 为 4,555,506/4,555,578 bytes、520 files。禁用态三个 Profile 的 storage/provider/management loader 全为 0,模块加载 RSS 增量 475,136 bytes;
- PostgreSQL 18.4 arm64 physical HA 总门通过:9001–9006、11 张 AI 表和最小 ACL
在 timeline 1→2 后一致,physical streaming、
remote_apply、partition guard、 fencing、promotion、pg_rewindrejoin 与全部 domain gate 为 true;临时 Docker 资源已清理; - workspace 仍为 22 个 QL3 package;没有新增第三方生产依赖或长期资源。
后续门禁
- 独立、显式的 AI feature activation/deactivation 产品 ceremony(ADR-0176 已完成);
- 私有命令模板、operator 文档、备份/恢复和真实低配 Linux 设备证据;
- Model Price Catalog mutation 专属 SQLite crash/COMMIT-response-loss 矩阵;
- Cluster TLS/identity assertion、平台 Policy repository、耐久 quota、双人发布/激活 ceremony 与 deny/unavailable audit;
- Cluster 产品入口完成后重新运行 PostgreSQL 三角色 integration 与 physical HA 门。
后续状态
第 1 项已由 ADR-0176 完成:本机 9007 append-only active/inactive head、
ql3-ai-feature、migration plan/data-safety fence、Owner transaction fence 和
invocation/price 写事务内 active fence 已实现。其余门禁保持不变。