mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 00:38:14 +08:00
6.2 KiB
6.2 KiB
ADR-0367:单进程、受认证的 Local Run HTTP API
- 状态:Proposed(实现完成,固定物理设备证据待补)
- 日期:2026-08-11
- 关联:QL-RFC-0001 D-45、D-46、D-49、D-52、D-175、D-257、D-269、D-278、D-279,ADR-0347、ADR-0366
背景
Local 3.0 已有完整 Run、API Credential、Project Policy、安全审计、Owner Pepper 和 MCP 只读纵向链路,但部署用户仍没有稳定的 /api/v3 HTTP 产品入口。直接复用 Legacy Express 会延续 Controller/Model/service-locator 架构;把 HTTP 放进 MCP package 会把 MCP SDK/Zod 带入普通 API 制品;另起 sidecar 又会让低内存路由器承担第二个 Node 进程和第二个 SQLite authority。
该能力满足 D-278 对新 package 的严格例外:它是默认关闭、独立交付的网络 listener 与安全入口,不是为了整理目录而拆出的 projection/codec 微包。它必须形成完整单进程 Profile,而不是只有一条 route 的壳。
决策
- 新增
@qinglong/local-api组合根,发布ql3-local-api。它在同一 Node 进程中启动现有 Local Application 和 HTTP listener,复用 Application 已打开的唯一 SQLite operation authority;不得启动 sidecar、第二个数据库连接、scheduler 或 watcher。 @qinglong/local-application增加可选、依赖反转的 product-surface port。默认未注入时构建、导入、启动、资源和制品闭包不变;注入时只能取得runs/apiCredentials/ownerPepper/projectPolicy/securityAudit五个窄 authority。Application 恢复完成并启动 scheduler/execution lifecycle 后才开放 surface;停机先撤 listener admission 并 drain,再停 scheduler/execution,最后关闭 SQLite。- 首个且唯一 route 为
GET /api/v3/projects/{projectId}/runs/{runId},operation/permission 固定为run.get/run.read,与 Cluster API 同构。原始 path 必须是无 query、无%编码、无尾斜杠的 canonical ASCII;Project/Run ID 各最多 128 字符。任何 body、Transfer-Encoding 或非零 Content-Length 都在读取 body 前拒绝。 - v1 listener 只允许
127.0.0.1或::1。远端访问必须由同机受管 TLS reverse proxy 终止;进程不信任 Forwarded/X-Forwarded-*,也不允许配置非 loopback 地址。LAN TLS、Unix socket 与代理身份绑定需要后续独立 ADR。 - 每个请求必须执行 route resolution → exact Bearer credential → Project Policy → durable security audit → credential/pepper fence confirm → bounded Run read。认证不得缓存;撤销、版本、subject、有效期、secret digest、pepper key state/material digest 任一变化都在读取前失败关闭。
- HTTP Run 响应复用 Runtime Core 的
qinglong.run.get低敏投影并映射为 Cluster 同构{run};不存在和跨 Project 均为 404。request/ref/trigger/attempt、executor handle、错误摘要、Artifact/日志位置、Secret 和数据库 row 不出网。 - transport 固定 header、URL、并发、请求时限、keep-alive、响应和 drain 上限。Edge 默认并发 4,Standalone 默认 32;超载在认证前拒绝,避免攻击者制造无界 credential/Policy/SQLite 队列。
- workspace hard cap 由 17 提升到 18,仅授权这个完整 deployable/authority package。新增 route、projection、认证 helper 或 client 必须进入该 package 的领域目录,不能继续增加 importer。
不采用方案
- Legacy
backExpress route:继续绑定 2.x Sequelize/Controller 与共享服务定位器。 - MCP package 内增加 HTTP:普通 API 制品会安装无关 MCP SDK,协议和攻击面混合。
- 独立 Local API sidecar:低配设备承担第二个 Node RSS 和 SQLite connection;与单进程目标冲突。
- 把 listener 放进 Owner Console/CLI:把短生命周期高权限 ceremony 变成长驻网络 authority。
- 默认把 HTTP 编进 headless Application artifact:所有路由器即使不用 API 也支付 flash/审计面成本。
完成门
- canonical route、认证拒绝/不可用、Policy deny/approval/allow、audit failure、credential fence、cross-Project 404、损坏 Run、过载、body-before-auth 和 graceful drain 均有定向测试;
- 真实 loopback HTTP + SQLite + API Credential + Pepper + Policy + durable Audit E2E;
- headless Edge/Standalone 十二档现有 artifact 数字不回归;新增 API Profile 有独立 bytes/files/RSS 预算;
- 18-package build/test、dependency/source boundary、Local image与完整 backend 通过;
- GitNexus compare/detect-changes 通过(已跟踪 diff 为 risk
low、affected processes0;本分支尚未纳入 index 的新增文件另由重建后的代码图与 package/source/import gates 覆盖); - 固定物理路由设备 RSS/flash/并发报告完成前保持 Proposed,不宣称默认开放远程 API。
实现与验证证据(2026-08-11)
- workspace 为 18 package、1,015 个 TypeScript source;997 个位于领域子目录,18 个是受审 public/binary root entry。
local-api自身为 8 个 source,其中 7 个分布在六个内部领域目录,根只保留cli.ts;当前没有 single-source 或 1–2 source 未登记薄包。 local-api定向门 15/15,包括真实 SQLite authority、API Credential、Owner Pepper、Project Policy、durable audit 与 loopback HTTP E2E,以及 Edge 并发 4 的过载拒绝和 accepted-work drain。- Edge API artifact 为 5,073,844 bytes / 515 files / 54 loaded modules,启动 RSS 增量 12,517,376 bytes;Standalone API artifact 为 5,073,988 bytes / 515 files / 54 loaded modules,RSS 增量 12,582,912 bytes,均低于 6 MiB / 640 files / 24 MiB 门。
- Runtime Core 的 bounded Run read projection 已成为纯叶子 subpath;API 导入闭包不再加载 Tool Registry/SemVer,投影模块门为不超过 4 个 loaded modules。
- 十二档既有 Local artifact 全部 compatible;默认 Local Application image 静态闭包不含
@qinglong/local-api。package boundary、source/dependency firewall 均无 finding;完整 backend 为 1,156 pass / 2 条条件 skip / 0 fail。 - 尚欠的是固定物理路由器的 flash、冷启动/稳态 RSS 与并发 1/4 报告。该缺口只阻止 ADR 转为 Accepted,不回退已经验证的 loopback-only、默认关闭实现。