diff --git a/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.4_Task_Report.md b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.4_Task_Report.md new file mode 100644 index 00000000..3ddc1a67 --- /dev/null +++ b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.4_Task_Report.md @@ -0,0 +1,126 @@ +# R2.7.4 任务报告 + +## 调查范围 + +- 官方仓库:`Wei-Shaw/sub2api`。 +- 最新主分支:`b1a6b8026764dedf6a5f76d02bdc292468d22753`。 +- 当前部署相关版本:`v0.1.159`,对应提交 `2a75d7d2387587d86ca3c5e5cd8ca96cf3d104c6`。 +- 调查只读取官方源码与 Codex 官方手册,没有修改 Sub2API、UniDesk CLI、配置、版本或运行面。 + +## 结论 + +- 现有 Sub2API 不能按下游 API Key 配置或自动加载 Codex skill。 +- 真正的 Codex skill 是客户端文件能力: + - Codex 从 repo `.agents/skills`、用户 `$HOME/.agents/skills`、管理员 `/etc/codex/skills` 等位置发现 skill; + - 首先加载名称、描述和路径,命中后再读取完整 `SKILL.md`、references 与 scripts; + - API 请求中的 `instructions` 只能附加文本,不能把 skill 文件、脚本、参考资料或插件安装到员工机器。 +- 因此“请求时由 API Key 自动加载真正 skill”不符合 Codex 当前发现模型。真正 skill 必须在 Codex 启动或会话开始前已经安装或随仓库存在。 +- 如果“skill”实际只指强制公司提示词,则可以设计按 Key 的 instruction profile,但最新版仍缺该能力,严格按 Key 配置至少需要外部网关或 Sub2API 源码扩展。 + +## 官方源码证据 + +- API Key 鉴权已经具备请求级身份: + - 中间件按 Bearer Key 查询完整 API Key; + - 成功后把 `*service.APIKey` 放入 Gin context; + - Responses handler 可读取 `apiKey.ID`、名称、用户和分组。 +- API Key 数据模型当前没有 skill、instruction profile 或 metadata 字段: + - 只有名称、分组、状态、IP 规则、配额、有效期和限速; + - 用户与管理员 API Key CRUD 也没有对应字段。 +- API Key 鉴权使用 L1/L2 快照缓存: + - 当前快照版本为 15; + - 若新增按 Key profile,必须进入最小查询、快照、版本升级和更新后的跨实例缓存失效链。 +- `v0.1.159` 和最新 main 已有全局 + `gateway.forced_codex_instructions_template_file`: + - 模板启动时读盘并缓存; + - 模板上下文只有已有 instructions 和四个模型字段; + - 没有 API Key ID、名称、用户、分组或 profile; + - 代码只在 `/v1/messages` 转 OpenAI OAuth Responses 的兼容路径调用; + - 原生 `/v1/responses` 只在 instructions 为空时补默认 Codex instructions,没有调用该强制模板。 +- 所以该原生配置可以做全局、文本型、特定兼容路径注入,但不能满足每 Key 配置,也不能代表真正加载 skill。 + +## 候选方案 + +### 方案 A:零 Sub2API 源码改动,客户端分发真正 skill,推荐 + +- 公司级通用 skill: + - 打包为 Codex plugin; + - 发放 API Key 时同时给出一次安装或受控 bootstrap; + - 安装到用户或管理员 skill 目录,后续由 Codex 隐式匹配。 +- 项目级 skill: + - 直接随公司代码仓库提交到 `.agents/skills//SKILL.md`; + - 员工 clone 仓库后自动进入 Codex skill 发现范围。 +- 永久、每次都必须执行的规则使用 `AGENTS.md`,不要包装成按请求触发的 skill。 +- 每 Key 差异由发 Key 的管理流程选择不同 plugin/profile 包,而不是让模型请求携带或解析 Key。 +- 优点: + - 无 Sub2API 修改; + - 是真正的 progressive-disclosure skill; + - scripts、references、MCP 依赖都能工作; + - 不增加每次请求 Token、TTFT 或网关改写风险。 +- 限制: + - API Key 本身不会远程改变已经启动的 Codex 会话; + - skill 更新需要客户端自动同步、插件更新或重新启动/刷新 Codex。 + +### 方案 B:零 Sub2API 源码改动,外部网关按 Key 注入 instructions,不推荐作为 skill + +- 在 Sub2API 前增加薄反向代理: + - 按 Bearer Key 的哈希映射 instruction profile; + - 修改 Responses JSON 的 `instructions`; + - 保留客户端原 instructions。 +- 优点: + - 不改 Sub2API; + - 可以真正按 Key 选择文本。 +- 缺点: + - 只是提示词注入,不是 skill; + - 必须覆盖 `/v1/responses`、compact、WebSocket、`/v1/messages` 和错误/流式语义; + - 新增敏感 Key 处理面、请求体改写面和运维故障点; + - 不能提供本地 scripts、references 或 MCP; + - 不应作为首选。 + +### 方案 C:最小 Sub2API 源码扩展,按 Key instruction profile + +- 适用于只需要按 Key 强制公司文本规则,不需要真正 skill 资产。 +- 推荐数据模型: + - API Key 只保存 nullable `codex_instruction_profile` 标识; + - profile 到模板文件的映射由服务配置管理; + - 不把大段提示词复制进每条 API Key 或鉴权缓存。 +- 最小改动面: + - migration 与 Ent APIKey schema; + - service/repository/DTO; + - 管理员 API Key CRUD,默认不允许员工自行切换 profile; + - auth 最小查询与快照字段,提升快照版本并复用缓存失效; + - 在安全审计前对原生 Responses、compact 和 messages bridge 统一组合 instructions; + - 保留客户端 `ExistingInstructions`,输出只记录 profile ID 和内容 hash,不记录正文。 +- 该方案可复用现有 Go template 渲染器,但必须扩展到原生 Responses,并传入 API Key profile。 +- 这仍应命名为 instruction profile,而不是 skill auto-load。 + +### 方案 D:真正按 Key 管理 skill,完整方案 + +- Sub2API 保存每 Key 的 `skill_profile_id`。 +- 增加经 API Key 鉴权的只读 manifest: + - profile ID、版本、兼容范围、bundle URL、SHA-256、签名和 ETag; + - 不直接返回或记录完整 API Key。 +- 配套 Codex bootstrap/plugin 在启动时: + - 用 Key 获取 manifest; + - 验证签名与 hash; + - 原子同步到用户或管理员 skill 目录; + - 完成后启动/刷新 Codex。 +- 这能满足每 Key 管理和真正 skill,但同时涉及 Sub2API、分发服务、签名制品和客户端工具,不属于最小修改。 + +## 推荐顺序 + +1. 首选方案 A: + - 公司通用工作流做 plugin; + - 项目工作流放 repo `.agents/skills`; + - 必须始终生效的规则放 `AGENTS.md`; + - API Key 发放流程同时选择并安装相应公司 plugin。 +2. 若确实需要管理员在服务端立即控制每 Key 的文本规则,再做方案 C,并明确叫 instruction profile。 +3. 只有需要按 Key 远程版本管理 scripts/references/MCP 时才做方案 D。 +4. 不建议用 API Key 名称承载 profile、把完整 skill 塞入每次 instructions、让模板按原始 Key 分支,或把 skill bundle 暴露为持 Key 即可下载的无签名资源。 + +## 安全与行为边界 + +- API Key 是计费与访问凭据,不应成为可日志化的 skill selector 或下载 URL 参数。 +- 提示词注入不是策略强制;机械约束仍应放 hooks、CI、权限和审批。 +- skill scripts 在员工机器执行,必须固定来源、签名和 digest,更新需要可回退。 +- 每次请求动态拉 skill 会增加 TTFT、可用性依赖和 Token 成本,也与 Codex 会话启动时的 skill 发现模型冲突。 +- 任何网关注入必须保留客户端 instructions,并确保安全审计看到最终请求内容。 diff --git a/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.5_Task_Report.md b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.5_Task_Report.md new file mode 100644 index 00000000..922414b5 --- /dev/null +++ b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.5_Task_Report.md @@ -0,0 +1,71 @@ +# R2.7.5 调查报告 + +## 结论 + +用户澄清后,目标可收敛为按下游 API Key 注入一组虚拟 skill 的 `name + description`。description 负责说明触发条件,并引导 Agent 从公司内网读取最新版说明、文件或脚本;Sub2API 不需要保存或分发完整 `SKILL.md`、references、scripts 或 bundle。 + +这会显著缩小实现面,但 Sub2API 当前仍没有同时满足“按 API Key 配置”和“覆盖原生 `/v1/responses`”的官方配置,因此严格服务端按 Key 控制无法只靠现有配置完成。 + +## 源码事实 + +- `backend/internal/server/middleware/api_key_auth.go` 已将完整 API Key 实体放入请求上下文,具备按 Key 选择配置的基础。 +- `backend/ent/schema/api_key.go` 当前没有 skill、catalog 或 instructions 字段。 +- `backend/internal/service/api_key_auth_cache.go` 与 `api_key_auth_cache_impl.go` 使用 API Key 鉴权快照;新增按 Key catalog 时必须进入快照并提升版本。 +- `gateway.forced_codex_instructions_template_file` 是全局配置,模板数据也不含 API Key 信息。 +- 该全局模板当前只用于 `/v1/messages` 到 OpenAI OAuth Responses 的桥接路径。 +- 原生 `/v1/responses` 路径只在 instructions 为空时补默认 Codex instructions,不会应用上述模板。 + +## 候选方案 + +### 现有全局模板 + +适合所有 Key 共用同一 description,且流量只走 `/v1/messages` 桥接的情况。它不能按 Key 区分,也不覆盖员工 Codex 常用的原生 `/v1/responses`,因此不满足完整目标。 + +### 外部反向代理 + +代理可按 Bearer Key 的指纹映射 catalog,并改写请求 `instructions`。这能做到不修改 Sub2API,但会新增一层敏感 Key 处理面,还要正确处理 Responses、compact、messages、流式和请求体兼容,运维复杂度高,不推荐作为默认方案。 + +### Sub2API 最小扩展 + +推荐在 API Key 上增加结构化字段,例如: + +```json +[ + { + "name": "company-dev", + "description": "当任务涉及公司项目时使用。先从公司内网固定地址读取最新说明。" + } +] +``` + +最小改动范围: + +- API Key migration、Ent schema、repository/service 和管理员 CRUD。 +- 鉴权快照加入 catalog 并提升 snapshot version。 +- 鉴权完成后,将 catalog 追加到最终 Responses instructions,覆盖 `/v1/responses`、`/v1/responses/compact` 和 `/v1/messages` bridge。 +- 保留客户端已有 instructions,只追加企业 catalog,不覆盖用户内容。 +- 日志只记录 API Key 标识、catalog 名称或内容 hash,不记录完整 description。 +- 不增加文件、脚本、manifest 或 bundle 存储与分发能力。 + +建议注入文本保持短小稳定: + +```md +## Company Skills + +- `company-dev`: 当任务涉及公司项目时使用。使用前从公司内网固定地址读取最新说明。 +``` + +## 能力边界 + +- 这是请求上下文里的虚拟 skill catalog,不是 Codex 客户端本地发现的 skill,不会自动出现在 `/skills` 或本地 skill selector。 +- description 应明确写出触发条件、内网入口和读取动作,自动命中仍依赖模型判断。 +- Agent 必须具备访问公司内网及其认证的权限;sandbox 或网络策略可能阻止拉取。 +- description 不应要求 Agent 把 Sub2API API Key 转发给内网服务。 +- 内网资源宜提供版本或内容 hash,避免同一个 description 指向的内容静默漂移。 +- 提示词注入不是安全强制机制;必须强制执行的企业策略仍需独立权限和服务端控制。 + +## 建议 + +若要求每个 API Key 独立配置,并确保 Codex 原生 Responses 请求生效,采用上述最小 Sub2API 扩展。若所有 Key 完全共用一条 description,可暂时使用现有全局模板验证交互文案,但它不是完整交付方案。 + +本轮仅完成只读源码调查和方案收敛,未修改 Sub2API 源码、版本、配置或运行面。 diff --git a/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.6_Task_Report.md b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.6_Task_Report.md new file mode 100644 index 00000000..979232d2 --- /dev/null +++ b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.6_Task_Report.md @@ -0,0 +1,123 @@ +# R2.7.6 任务报告 + +## 结果 + +已在 `/root/superapi` 实现并启动独立的 description-only 企业虚拟 skill 上游加载器。当前链路为: + +```text +Codex -> https://superapi.hwpod.com/v1/responses + -> SuperAPI 按 Bearer API Key 匹配 profile + -> 追加 Company Skills name + description + -> https://api.pikapython.com/v1/responses +``` + +Sub2API 源码、版本、账号池和 runtime 配置均未修改。 + +## 规格与归属 + +- 按 Key catalog 主责归入 `PJ2026-010502 APIKey`。 +- Codex-compatible 透传关联 `PJ2026-010204 后端Profile`。 +- 域名、TLS 和 Caddy 关联 `PJ2026-010604 公开入口`。 +- 新增 `PJ2026-01050205 APIKey Skill Catalog` 规格。 +- UniDesk PR:。 +- merge commit:`8eb62cfbd4ec24f7d42423d6a53646bc3dcfbd46`。 + +## 实现 + +本地仓库:`/root/superapi`。 + +本地 commit:`29db775 feat: add per-key skill upstream loader`。 + +主要能力: + +- `config/superapi.yaml` 是唯一配置真相: + - native bind、port 和 probe; + - 上游 base URL 与允许路径; + - public URL、DNS、Caddy config 与 upstream; + - API Key `sourceRef/sourceKey`; + - 每个 Key profile 的 skill `name + description`。 +- API Key 从 `/root/.codex/auth.json.pika#OPENAI_API_KEY` 读取: + - 仓库、CLI、状态和日志均不保存或输出完整 Key; + - 正确 Key 使用恒定时间比较命中 profile; + - 未配置 Key 在进入上游前返回 401。 +- `/v1/responses` 和 `/v1/responses/compact`: + - 保留原字符串 instructions; + - 追加稳定的 `Company Skills` catalog; + - 请求与上游流式响应透明透传。 +- health 和日志只披露 profile、skill 数量、request id、状态和脱敏指标。 +- 项目 CLI 提供: + - `config validate`; + - `l0 probe`; + - `native start|status|logs|stop`; + - `public plan|apply|status`。 + +## L0 验证 + +执行: + +```bash +bun scripts/superapi-cli.ts l0 probe +``` + +结果: + +- `RESULT=PASS`; +- `KEY_MATCH=true`; +- `INVALID_REJECT=true`; +- `PRESERVED_EXISTING=true`; +- profile 为 `pika`; +- skill 数量为 1; +- `VALUES_PRINTED=false`。 + +`bun run check` 使用只编译不执行的 Bun build 入口并通过。首次使用 `bun --check` 时发现该版本会实际执行入口,已改为构建到被忽略的 `.state/check`,没有保留误启动进程。 + +## L1 与公网验证 + +native 服务由项目 CLI 启动: + +- 状态:`ready`; +- bind:`127.0.0.1:18159`; +- health:HTTP 200。 + +公网入口由 owning YAML 渲染的独占 Caddy managed block提供: + +- URL:; +- DNS:`152.53.229.148`,与 YAML `expectedA` 一致; +- Caddy 完整配置 validate 通过; +- public health:HTTP 200; +- public status:`ready`。 + +错误 Key 的公网 `/v1/responses` 请求返回 401,没有进入上游。 + +## 真实 Codex 验证 + +Codex 使用隔离的 `CODEX_HOME`: + +- `auth.json` 软链接到现有 `/root/.codex/auth.json.pika`; +- 不含密钥的 smoke config 指向 `https://superapi.hwpod.com/v1`; +- model 为 `gpt-5.5`,wire API 为 Responses。 + +首次请求使用域名根作为 base URL,Codex 实际请求 `/responses`,被 allowlist 正确拒绝为 404。将 smoke base URL 修正为 `https://superapi.hwpod.com/v1` 后成功。 + +最终真实流式请求证据: + +- path:`/v1/responses`; +- status:200; +- profile:`pika`; +- skillCount:1; +- upstreamErrors:0; +- 模型最终只返回 `SUPERAPI_SKILL_LOADED`。 + +这证明 Codex 实际收到注入的 `pika-company-dev` catalog,而不只是代理本地函数返回成功。 + +## 边界 + +- 这是虚拟 skill catalog,不会注册到 Codex 客户端 `/skills`。 +- 当前只保存并注入 `name + description`,不保存完整 skill 文件或脚本。 +- description 引导 Agent 从公司内网 skill registry 获取后续资料,但网络权限、内网认证和资源版本仍由公司内网负责。 +- 当前是用户要求的 L1 native 服务: + - 进程由项目 CLI 管理; + - 未配置 systemd 或容器级重启自恢复; + - host 重启后需执行 `native start` 和 `public status`。 +- `/root/superapi` 当前是本地 Git 仓库,没有远端,因此只有本地 commit,没有 push 或 PR。 +- 公网开放后观察到常规扫描请求,全部被 allowedPaths 拒绝;业务 Key、description 和上游响应内容未进入日志。 diff --git a/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.7_Task_Report.md b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.7_Task_Report.md new file mode 100644 index 00000000..8f35a0f7 --- /dev/null +++ b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.7_Task_Report.md @@ -0,0 +1,77 @@ +# R2.7.7 任务报告 + +## 结果 + +已对公开入口 `https://superapi.hwpod.com/v1/responses` 完成一次真实同步 Responses 测试。测试使用 `/root/.codex/auth.json.pika` 中的 API Key,但命令输出、日志和报告均未披露 Key 值。 + +- request id:`superapi-request-diff-20260718-01` +- profile:`pika` +- skillCount:1 +- 上游状态:HTTP 200 +- 模型:`gpt-5.5` +- Responses 状态:`completed` +- 模型输出:`SUPERAPI_REQUEST_DIFF_OK` +- 当前累计 upstreamErrors:0 + +## 注入前请求 + +```json +{ + "method": "POST", + "url": "https://superapi.hwpod.com/v1/responses", + "headers": { + "host": "superapi.hwpod.com", + "authorization": "Bearer ", + "accept": "application/json", + "content-type": "application/json", + "content-length": 168, + "user-agent": "superapi-redacted-probe/1.0", + "x-request-id": "superapi-request-diff-20260718-01" + }, + "body": { + "model": "gpt-5.5", + "instructions": "仅执行本次请求差异测试;不要调用工具。", + "input": "只回复 SUPERAPI_REQUEST_DIFF_OK", + "stream": false, + "store": false + } +} +``` + +## 注入后上游请求 + +```json +{ + "method": "POST", + "url": "https://api.pikapython.com/v1/responses", + "headers": { + "host": "api.pikapython.com", + "authorization": "Bearer ", + "accept": "application/json", + "content-type": "application/json", + "content-length": 472, + "user-agent": "superapi-redacted-probe/1.0", + "x-request-id": "superapi-request-diff-20260718-01", + "x-superapi-request-id": "superapi-request-diff-20260718-01" + }, + "body": { + "model": "gpt-5.5", + "instructions": "仅执行本次请求差异测试;不要调用工具。\n\n## Company Skills\n\n- `pika-company-dev`: 当任务涉及公司协作开发时使用;先从公司内网 skill registry 拉取最新说明、文件和脚本,且不得向下载地址发送 API Key;当用户只要求 SUPERAPI_SKILL_PROBE 时,不访问网络并仅回复 SUPERAPI_SKILL_LOADED。", + "input": "只回复 SUPERAPI_REQUEST_DIFF_OK", + "stream": false, + "store": false + } +} +``` + +## 判定 + +除以下内容外,请求业务字段保持不变: + +- URL 从 SuperAPI 公开入口切换为配置声明的上游 `api.pikapython.com`。 +- `host` 随上游变化。 +- `instructions` 保留原文并追加 `Company Skills` catalog。 +- 增加 `x-superapi-request-id` 供上游关联。 +- JSON body 增长后 `content-length` 从 168 变为 472。 + +Authorization 在两侧保持同一个 Bearer Key,但仅以 `` 展示。没有新增完整 skill 文件、脚本或其他请求字段。 diff --git a/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.8_Task_Report.md b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.8_Task_Report.md new file mode 100644 index 00000000..016f1b01 --- /dev/null +++ b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.8_Task_Report.md @@ -0,0 +1,89 @@ +# R2.7.8 任务报告 + +## 结果 + +已使用真实 `codex exec` 生成 Codex Responses 请求,并在 SuperAPI L1 注入点抓取完整的注入前后请求。该请求不是 curl fixture。 + +真实 Codex 结果: + +- Codex CLI:`0.144.5` +- provider:`SuperAPI` +- model:`gpt-5.5` +- wire API:Responses +- stream:`true` +- 模型输出:`SUPERAPI_REAL_CODEX_SKILL_LOADED` +- SuperAPI 日志:HTTP 200、profile `pika`、skillCount `1` +- 上游错误:0 + +## 完整脱敏请求 + +- 注入前: + - `/root/superapi/.state/captures/codex-real-20260718-01.before.sanitized.json` + - 53,216 bytes + - mode `0600` +- 注入后: + - `/root/superapi/.state/captures/codex-real-20260718-01.after.sanitized.json` + - 53,562 bytes + - mode `0600` + +真实请求具有 13 个顶层 body 字段: + +- `client_metadata` +- `include` +- `input` +- `instructions` +- `model` +- `parallel_tool_calls` +- `prompt_cache_key` +- `reasoning` +- `store` +- `stream` +- `text` +- `tool_choice` +- `tools` + +请求包含 3 个 input item 和 8 个工具定义。注入前 instructions 为 21,335 字符,注入后为 21,508 字符。 + +## 差异判定 + +除 instructions 外的完整 body SHA-256 一致。原始 instructions 被完整保留,末尾追加: + +```md +## Company Skills + +- `pika-company-dev`: 当任务涉及公司协作开发时使用;先从公司内网 skill registry 拉取最新说明、文件和脚本,且不得向下载地址发送 API Key;当用户只要求 SUPERAPI_SKILL_PROBE 时,不访问网络并仅回复 SUPERAPI_SKILL_LOADED。 +``` + +Codex 客户端使用 `https://superapi.hwpod.com/v1`。Caddy 终止 TLS 后,loader 捕获的入口 URL 为内部 `http://superapi.hwpod.com/v1/responses`,并保留 `x-forwarded-proto=https`;注入后上游 URL 为 `https://api.pikapython.com/v1/responses`。 + +## 脱敏验证 + +完整 sanitized artifacts 已验证: + +- 真实 API Key:不存在 +- 未脱敏 Authorization:不存在 +- `/root` 绝对路径:不存在 +- IPv4:不存在 +- UUID:不存在 +- session/thread/turn/installation/request ID:值为 `` +- artifacts 权限:`0600` +- JSON 结构:有效 + +## Workspace 与运行面 + +用户要求保留 workspace,已保留: + +`/root/superapi/.worktree/codex-real-capture` + +workspace 保留未提交的: + +- Codex provider 一次性 `http_headers` capture ID +- SuperAPI 请求对捕获补丁 +- 通用递归脱敏脚本 + +实验进程已停止。正式公网服务已重新从 `/root/superapi` master commit `29db775` 启动: + +- native health:200 +- public health:200 +- public URL:`https://superapi.hwpod.com` +- 正式 master 未包含捕获补丁 diff --git a/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.9_Task_Report.md b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.9_Task_Report.md new file mode 100644 index 00000000..734f0b86 --- /dev/null +++ b/docs/MDTODO/details/sub2api-upstream-reliability/R2.7.9_Task_Report.md @@ -0,0 +1,51 @@ +# R2.7.9 任务报告 + +## 结果 + +已将 `/root/superapi/.worktree/codex-real-capture` 中可复用的真实 Codex 请求捕获能力整理并快进合并到 SuperAPI `master`,提交为 `13f4070 feat: add YAML-controlled skill diagnostics`。一次性 Codex capture header 未进入 master,实验 workspace 按用户要求保留。 + +## YAML 开关 + +owning YAML `config/superapi.yaml` 新增: + +- `gateway.skillInjection.enabled`:控制 Responses instructions 注入;关闭时不解析、不修改 body。 +- `gateway.requestCapture.enabled`:控制诊断捕获;关闭时即使请求携带捕获 header 也不落盘。 +- `gateway.requestCapture.headerName`:声明内部 capture header,代理转发前删除。 +- `gateway.requestCapture.outputDir`:声明捕获产物目录。 + +正式状态为 skill 注入开启、诊断捕获关闭。健康接口披露两个布尔开关,不披露 Secret。 + +## 实现 + +- `src/capture.ts`:受控 before/after 原始捕获、capture id 校验和递归脱敏。 +- `src/diagnostics.ts`:L0 探针与配置驱动的脱敏函数。 +- `scripts/superapi-cli.ts capture sanitize --id `:通过 owning YAML 和 profile SecretRef 生成 sanitized artifacts。 +- `src/proxy.ts`:仅在 YAML 开启且请求携带合法 capture id 时捕获;内部 header 不转发上游。 +- CLI 已按职责拆分到 293 行,未超过 300 行规范。 + +## 验证 + +- L0 注入开启:PASS,保留原 instructions,追加 1 个 skill。 +- L0 注入关闭:PASS,skillCount 为 0,原 instructions 完全不变。 +- L1 native:固定端口 `18159`,health 200。 +- 公网入口:`https://superapi.hwpod.com`,DNS、Caddy block、health 均 ready。 +- 捕获关闭真实 Codex:返回 `SUPERAPI_REAL_CODEX_SKILL_LOADED`,未生成 `.raw.json`。 +- 捕获开启真实 Codex:Codex CLI `0.144.5`,provider `SuperAPI`,model `gpt-5.5`,HTTP 200,skillCount 1,上游错误 0。 + +最终 master 捕获 ID 为 `codex-real-20260718-03`: + +- before:`/root/superapi/.state/captures/codex-real-20260718-03.before.sanitized.json` +- after:`/root/superapi/.state/captures/codex-real-20260718-03.after.sanitized.json` +- 两份文件权限均为 `0600`。 +- body 顶层字段均为 13,input item 为 3,tools 为 11。 +- instructions 长度从 21,335 增加到 21,508。 +- 除 instructions 外的 body SHA-256 一致。 +- sanitized artifacts 不含真实 Key、`/root` 路径、IPv4 或 UUID。 +- capture header 未转发到上游。 + +## 最终状态 + +- `/root/superapi`:`master` commit `13f4070`,worktree 干净。 +- 正式 native:ready,诊断捕获已关闭。 +- 正式 public:ready,health 200。 +- 实验 workspace:保留,仅 `config/codex-smoke.toml` 保有一次性 capture id 修改。 diff --git a/docs/MDTODO/sub2api-upstream-reliability.md b/docs/MDTODO/sub2api-upstream-reliability.md index c533f135..557dd472 100644 --- a/docs/MDTODO/sub2api-upstream-reliability.md +++ b/docs/MDTODO/sub2api-upstream-reliability.md @@ -200,6 +200,24 @@ #### R2.7.3 [completed] 结合管理端 `https://sub.yjxm1221.top grok` API Key 账号连接测试成功的新证据,复核 Codex Grok profile 经 Sub2API `/v1/responses` 的网关链路,区分账号直连测试与分组调度路径,完成任务后将详细报告写入[任务报告](./details/sub2api-upstream-reliability/R2.7.3_Task_Report.md)。 +#### R2.7.4 [completed] + +只读调研 Sub2API 官方最新源码如何以最小改动或零改动支持按每个下游 API Key 配置并自动加载企业 Codex skill:核对 API Key 请求上下文、Responses instructions 转换、客户端 skill 发现机制、现有配置/API 扩展点与安全边界,比较客户端分发、网关注入和源码扩展方案并给出推荐;不修改 Sub2API、UniDesk CLI、运行面或版本,完成任务后将详细报告写入[任务报告](./details/sub2api-upstream-reliability/R2.7.4_Task_Report.md)。 +#### R2.7.5 [completed] + +基于用户澄清收敛 R2.7.4:目标仅为按每个下游 API Key 注入企业虚拟 skill 的 name 与 description,由 description 引导 Agent 从公司内网拉取后续文件或脚本;评估现有全局模板、外部代理零源码方案和 Sub2API 最小按 Key 字段及 Responses 注入改动,不实现代码或运行面变更,完成任务后将详细报告写入[任务报告](./details/sub2api-upstream-reliability/R2.7.5_Task_Report.md)。 +#### R2.7.6 [completed] + +在独立 `../superapi` 实现并验证 description-only 企业虚拟 skill 上游加载器:以 YAML 声明 API Key sourceRef、skill name/description、native 端口、上游 `api.pikapython.com` 和 `superapi.hwpod.com` 公网入口;完成 L0 函数注入测试、L1 native 生命周期与 Codex `.pika` Key 真实 Responses 透传测试,不修改 Sub2API 源码或版本,完成任务后将详细报告写入[任务报告](./details/sub2api-upstream-reliability/R2.7.6_Task_Report.md)。 +#### R2.7.7 [completed] + +对已部署 SuperAPI 做一次真实 Responses 注入测试,完整展示脱敏后的入口请求与追加虚拟 skill catalog 后的上游请求,核对 request id、profile、skillCount、上游状态和模型 marker,不披露 Authorization 或 API Key,完成任务后将详细报告写入[任务报告](./details/sub2api-upstream-reliability/R2.7.7_Task_Report.md)。 +#### R2.7.8 [completed] + +使用真实 `codex exec` 产生 Responses 请求,在 SuperAPI L1 注入点做一次可撤销的脱敏 before/after 捕获,验证真实 Codex 请求中的完整字段、skill catalog 追加位置、上游透传结果和 marker;完成后撤销捕获补丁并恢复服务,完成任务后将详细报告写入[任务报告](./details/sub2api-upstream-reliability/R2.7.8_Task_Report.md)。 +#### R2.7.9 [completed] + +将 SuperAPI 真实 Codex 捕获 workspace 的可复用能力语义合并进 master:由 owning YAML 显式控制 skill 注入与诊断捕获,关闭时透明透传且不落盘;保留一次性 smoke header 和原始捕获产物于实验 workspace,不纳入生产配置;完成 L0、L1、真实 codex exec before/after 脱敏复测并记录证据,完成任务后将详细报告写入[任务报告](./details/sub2api-upstream-reliability/R2.7.9_Task_Report.md)。 ### R2.8 [completed] 整理本 MDTODO FILE 的职责层级和编号,并把同一 SUBITEM 下的直接 SUBSUBITEM 一般不超过 20 固化到 mdtodo-edit skill,完成任务后将详细报告写入[任务报告](./details/sub2api-upstream-reliability/R2.8_Task_Report.md)。 diff --git a/project-management/PJ2026-01/specs/PJ2026-01050205-api-key-skill-catalog.md b/project-management/PJ2026-01/specs/PJ2026-01050205-api-key-skill-catalog.md index 9a0707f9..071b032a 100644 --- a/project-management/PJ2026-01/specs/PJ2026-01050205-api-key-skill-catalog.md +++ b/project-management/PJ2026-01/specs/PJ2026-01050205-api-key-skill-catalog.md @@ -90,3 +90,17 @@ Responses 请求验证公开入口到上游的完整链路。 健康和 CLI 状态应披露配置摘要、skill 数量、匹配 profile、请求计数、注入计数、 上游状态和最近错误摘要,但不得披露完整 API Key、Authorization 或 description 全文。每个代理请求应保留或生成可关联的 request id。 + +### 4.6 USER-KEY-SKILL-REQ-006 YAML 功能开关 + +owning YAML 应分别声明 skill 注入和诊断请求捕获是否启用。skill 注入关闭时, +加载器不得解析或修改 Responses body,并应保持透明透传;诊断捕获关闭时, +请求携带捕获 header 也不得生成捕获文件。健康状态和 CLI 配置摘要应披露两个 +开关的布尔状态,但不得披露 Secret 值。 + +### 4.7 USER-KEY-SKILL-REQ-007 受控请求捕获 + +诊断请求捕获只能在 owning YAML 显式启用且请求携带合法 capture id 时生效。 +捕获 header 名称和输出目录必须来自 owning YAML,不得转发给上游。原始捕获 +文件必须使用仅 owner 可读写权限,脱敏应通过项目 CLI 读取已声明的 Key +SecretRef 执行,并生成独立 sanitized artifact;原始捕获不得作为可公开报告。