From b23ba1cb826a5a2a6e0e6113b4fc2663384dd63a Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 4 Jun 2026 01:06:36 +0800 Subject: [PATCH] docs: unify v0.2 user api key auth --- docs/reference/spec-device-pod.md | 24 +++++++------- docs/reference/spec-user-access.md | 14 ++++----- docs/reference/spec-v02-auth.md | 31 ++++++++++--------- docs/reference/spec-v02-hwlab-cli.md | 2 +- docs/reference/spec-v02-hwlab-cloud-api.md | 6 ++-- docs/reference/spec-v02-hwlab-cloud-web.md | 2 +- .../spec-v02-hwlab-device-pod-service.md | 2 +- 7 files changed, 42 insertions(+), 39 deletions(-) diff --git a/docs/reference/spec-device-pod.md b/docs/reference/spec-device-pod.md index 06962acc..d8610ce0 100644 --- a/docs/reference/spec-device-pod.md +++ b/docs/reference/spec-device-pod.md @@ -8,25 +8,25 @@ ```text browser Cloud Web UI or hwpod/device-pod-cli --> cloud-api auth + device_pod_grants + AgentRun Device Pod API key +-> cloud-api AuthPrincipal + device_pod_grants -> hwlab-device-pod internal REST -> gateway transport -> device-host-cli -> Keil / pyOCD / UART / target ``` -AgentRun runner 和 `hwpod` 的标准设备 API 入口是 `HWLAB_RUNTIME_API_URL=http://hwlab-cloud-api..svc.cluster.local:6667`,不是 `hwlab-cloud-web`。Cloud Web 只服务浏览器同源 UI 代理;它不得承载 AgentRun Device Pod API key,也不得作为 `hwpod` 的设备 API 替代入口。内部 `:6667` 属于 WHATWG bad port 时,`hwpod` 必须使用 Node `http/https` 原生请求层访问 cloud-api,不能为了规避 bad-port 把设备 API 改走 Cloud Web。 +AgentRun runner 和 `hwpod` 的标准设备 API 入口是 `HWLAB_RUNTIME_API_URL=http://hwlab-cloud-api..svc.cluster.local:6667`,不是 `hwlab-cloud-web`。Cloud Web 只服务浏览器同源 UI 代理;`hwpod` 必须携带映射到发起用户的 `HWLAB_API_KEY` 直连 cloud-api,由 cloud-api 按该用户 grant 授权。内部 `:6667` 属于 WHATWG bad port 时,`hwpod` 必须使用 Node `http/https` 原生请求层访问 cloud-api,不能为了规避 bad-port 把设备 API 改走 Cloud Web。 ## 在系统中的职责划分 -`device-pod` 是云端可授权、可审计的逻辑设备能力单元。`hwlab-cloud-api` 是用户身份、grant、AgentRun Device Pod API key、profile authority 和用户态 REST API 的入口;`hwlab-device-pod` 是内部执行服务;`hwlab-gateway` 只承载 transport;`device-host-cli` 只在硬件 host 侧执行 Keil、pyOCD、UART 和 workspace 操作。 +`device-pod` 是云端可授权、可审计的逻辑设备能力单元。`hwlab-cloud-api` 是用户身份、用户 API key、grant、profile authority 和用户态 REST API 的入口;`hwlab-device-pod` 是内部执行服务;`hwlab-gateway` 只承载 transport;`device-host-cli` 只在硬件 host 侧执行 Keil、pyOCD、UART 和 workspace 操作。 普通用户、浏览器和 Code Agent session 不直接持有 gateway route、host workspace route、Kubernetes Service 直连能力或 profile 修改权。 ## 设计目标 - 用最少组件把 `device-pod-cli` 从“本地 profile + RPC/gateway 调用”迁到“1:1 REST 请求”。 -- `cloud-api` 是用户身份、device grant、AgentRun Device Pod API key 和 profile authority 判断入口。 +- `cloud-api` 是用户身份、用户 API key、device grant 和 profile authority 判断入口。 - `hwlab-device-pod` 承接设备业务:profile 校验后的运行、job 生命周期、freshness、blocker、bounded output 和 gateway 调用。 - `device-pod-cli` 只做 selector 解析、cloud-api REST 请求和 JSON 输出;默认正式模式不读取 `.device-pod/*.json`,不保存、不上传、不修改权威 profile。 - 第一阶段只部署一个 `hwlab-device-pod` Deployment/Service,管理多个逻辑 `devicePodId`,避免为每台设备创建独立 k8s Service/Deployment。 @@ -86,7 +86,7 @@ code agent 本地文件只能作为非权威 hint/cache,最多包含: ## 内部架构 -正式 device-pod 由 profile registry、job lifecycle、freshness/blocker、bounded output、gateway/device-host adapter 和 AgentRun Device Pod API key integration 组成。第一阶段只有一个 `hwlab-device-pod` Deployment 管理多个 `devicePodId`;profile authority、user grant 和 AgentRun API key 在 cloud-api/Postgres/Secret 中,device-pod 服务只接受 cloud-api 内部调用。 +正式 device-pod 由 profile registry、job lifecycle、freshness/blocker、bounded output、gateway/device-host adapter 和用户 API key integration 组成。第一阶段只有一个 `hwlab-device-pod` Deployment 管理多个 `devicePodId`;profile authority、user grant 和 `api_keys` 在 cloud-api/Postgres 中,device-pod 服务只接受 cloud-api 内部调用。 当前 v02 部署中的 `hwlab-device-pod` 微服务实现情况见 [spec-v02-hwlab-device-pod-service.md](spec-v02-hwlab-device-pod-service.md)。 @@ -216,7 +216,7 @@ DELETE /v1/admin/device-pod-grants/{devicePodId}/{userId} | 服务 | 职责 | | --- | --- | -| `hwlab-cloud-api` | 用户身份、admin/user、device grant、AgentRun Device Pod API key、profile authority、用户态 REST API、转发到内部 device-pod。 | +| `hwlab-cloud-api` | 用户身份、admin/user、用户 API key、device grant、profile authority、用户态 REST API、转发到内部 device-pod。 | | `hwlab-device-pod` | 多 `devicePodId` 运行 registry、profile runtime validation、job store、freshness、bounded output、gateway/device-host-cli adapter。 | | `device-pod-cli` | 把 `devicePodId:surface:path operation args` 1:1 转成 cloud-api REST;不保存权威 profile、不读取本地 profile 作为默认 authority、不直连 gateway。 | | `device-host-cli` | Windows host 侧自包含业务工具,负责 Keil、pyOCD、UART、workspace 文件操作。 | @@ -252,16 +252,16 @@ manages: many devicePodId - `hwlab-device-pod` 不接受无内部服务凭据的 profile snapshot 或 job 请求。 - `hwlab-device-pod` 一个实例可以列出并执行多个 `devicePodId` 的状态/job。 - cloud-api legacy compatibility entry 只能返回 blocked authority payload,不得合成 fake device pod 数据或作为正式 device-pod DEV-LIVE 证据。 -- 强副作用 job 必须有 `reason`;正式路径只使用普通用户 session/cookie 或 AgentRun `HWLAB_DEVICE_POD_API_KEY` 做身份授权。 -- AgentRun runner 访问 device-pod 必须使用 cloud-api 组装的 `HWLAB_DEVICE_POD_API_KEY`,该 API key 对所有正式 device-pod 授权;用户本地调试只使用普通 Web session/cookie 和 grant。 -- 撤销 device pod grant 只影响该用户通过普通 session/cookie 的可见性与使用权。 +- 强副作用 job 必须有 `reason`;正式路径只使用 Web session/cookie 或映射到具体用户的 `HWLAB_API_KEY` 做身份授权。 +- AgentRun runner 访问 device-pod 必须使用 cloud-api 组装的用户 `HWLAB_API_KEY`,该 key 恢复为发起 Code Agent session 的 owner 用户;不得使用跨用户共享、对所有正式 device-pod 授权的 system key。 +- 撤销 device pod grant 必须同时影响该用户通过 Web session、CLI API key 和 AgentRun `hwpod` 的可见性与使用权;revoke API key 后 CLI 和 runner 内旧 key 都必须失效。 ## CLI 实现口径 `tools/device-pod-cli.ts` 是 v0.2 正式 CLI 实现;HWLAB code-agent runner 内的唯一稳定短入口是 `hwpod`。runner 镜像必须把 `hwpod` 放入 PATH;缺少 `hwpod` 时应判定为 runner image/package 错误并修复镜像或封装,不得改走 `/app/skills/device-pod-cli/scripts/device-pod-cli.mjs` 长路径。正式 CLI 的默认行为是: - `profile list/show` 调用 cloud-api `/v1/device-pods` 和 `/status`,只显示服务端脱敏 profile 摘要和 `profileHash`。 -- AgentRun runner 中只使用装配好的 `HWLAB_RUNTIME_API_URL` 和 `HWLAB_DEVICE_POD_API_KEY`,直接访问 `hwlab-cloud-api`;不得手动传 `--api-base-url`,也不得改走 Cloud Web 同源代理。 +- AgentRun runner 中只使用装配好的 `HWLAB_RUNTIME_API_URL` 和映射到当前用户的 `HWLAB_API_KEY`,直接访问 `hwlab-cloud-api`;不得手动传 `--api-base-url`,也不得改走 Cloud Web 同源代理。 - `setup first-admin` 和 `admin device-pod upsert/grant` 只作为 cloud-api REST wrapper,用于首次空库 seed 或 admin profile/grant 管理;它们接受显式 `--profile-json` 或 `--device-pod-json`,不得读取本地 `.device-pod/*.json` 作为权威 profile。 - `devicePodId:workspace|debug-probe|io-probe...` selector 转换为 `POST /v1/device-pods/{devicePodId}/jobs` 或 job status/output/cancel REST,不直接调用 `/v1/rpc/hardware.invoke.shell`。 - `bootsharp --pod-id ` 和 `:workspace:/ bootsharp` 都转换为 `workspace.bootsharp` job,用于返回 workspace tree、AGENTS.md 摘要和当前路径提示;该入口是上下文恢复和 DS 派单的首个探测动作,不读取本地 profile。 @@ -426,8 +426,8 @@ hwpod D601-F103-V2:workspace:/ rg \ | --- | --- | --- | | 逻辑 device-pod 模型 | 已实现为规格 | 四要素、profile shape 和 Kubernetes 口径已定义。 | | profile server authority | 部分实现 | cloud-api 保存正式 DB profile 并向用户返回脱敏摘要;device-pod executor 不接受用户上传 profile。 | -| 用户 grant + AgentRun API key | 部分实现 | cloud-api 已实现 admin grant、可见性过滤、AgentRun Device Pod API key 认证和强副作用 job reason 校验。 | +| 用户 grant + 用户 API key | 部分实现 | cloud-api 已实现 admin grant、可见性过滤和强副作用 job reason 校验;AgentRun/hwpod 仍需从旧 shared device-pod key 收敛到映射用户的 `HWLAB_API_KEY`。 | | REST/job API | 部分实现 | cloud-api 已实现 list/status/events/probe/job/output/cancel,并可把已授权 job 转发给内部 `hwlab-device-pod` executor;executor 已实现内部 job create/get/output/cancel lifecycle 和 gateway/device-host-cli dispatch adapter,无在线 gateway/device-host-cli 时返回 blocker。 | -| G14 device-host 功能吸收 | 部分实现 | v0.2 job intent 已覆盖 workspace put/rm/rmdir、Keil 工程维护和 UART JSON-RPC,保持 cloud-api grant/profile authority 和 AgentRun API key runtime auth。 | +| G14 device-host 功能吸收 | 部分实现 | v0.2 job intent 已覆盖 workspace put/rm/rmdir、Keil 工程维护和 UART JSON-RPC,保持 cloud-api grant/profile authority 和用户 API key runtime auth。 | | 禁止 fake 作为 DEV-LIVE | 已实现/持续约束 | 规格和服务 payload 要求显式标记 fake/source。 | diff --git a/docs/reference/spec-user-access.md b/docs/reference/spec-user-access.md index 765e690e..8048c4c6 100644 --- a/docs/reference/spec-user-access.md +++ b/docs/reference/spec-user-access.md @@ -10,7 +10,7 @@ ## 在系统中的职责划分 -用户和权限管理不是独立微服务,权威实现收敛在 `hwlab-cloud-api`:它消费 [spec-v02-auth.md](spec-v02-auth.md) 产出的 `AuthPrincipal`,负责角色、device pod grant、AgentRun Device Pod API key 和 code agent session owner 校验。`hwlab-cloud-web` 只提供浏览器 UI 和同源代理;`hwlab-device-pod` 只执行设备语义;`hwlab-agent-mgr`、`hwlab-agent-worker` 和 Code Agent runtime 只能消费已经由 cloud-api 判断过的 actor/session/device 权限。 +用户和权限管理不是独立微服务,权威实现收敛在 `hwlab-cloud-api`:它消费 [spec-v02-auth.md](spec-v02-auth.md) 产出的 `AuthPrincipal`,负责角色、device pod grant、用户 API key 和 code agent session owner 校验。`hwlab-cloud-web` 只提供浏览器 UI 和同源代理;`hwlab-device-pod` 只执行设备语义;`hwlab-agent-mgr`、`hwlab-agent-worker` 和 Code Agent runtime 只能消费已经由 cloud-api 判断过的 actor/session/device 权限。 Postgres 是该规格的数据持久化边界。Kubernetes namespace、ServiceAccount、Service 直连和 gateway route 都不能替代用户权限模型;普通用户不获得 kubeconfig、内部 Service 直连能力或长期 Secret。 @@ -140,7 +140,7 @@ CREATE TABLE IF NOT EXISTS device_pod_grants ( - 不包含 `capability`、`scope`、`expires_at`。 - 撤销授权就是删除对应行;撤销后该用户通过普通 session/cookie 不再看到或使用该 device pod。 -- AgentRun runner 不依赖用户 grant 行逐个授权;cloud-api 组装 runner 时注入统一的 `HWLAB_DEVICE_POD_API_KEY`,该 key 只用于 runner 内 `hwpod` 短入口访问正式 device-pod。 +- AgentRun runner 不使用跨用户共享的 device-pod 系统 key。runner 内 `hwpod` 只能使用映射到 Code Agent session owner 的 `HWLAB_API_KEY`,并按同一用户的 `device_pod_grants` 授权。 ## 权限矩阵 @@ -243,9 +243,9 @@ browser ```text code agent turn -> cloud-api device operation route --> authenticate actor from owning session +-> authenticate actor from owning session or user API key in runner -> verify agent_sessions.owner_user_id == actor.id --> authorize device_pod_grants/admin or assembled AgentRun Device Pod API key +-> authorize device_pod_grants/admin -> require reason for mutating operations -> cloud-api -> hwlab-device-pod internal Service -> gateway/device-host-cli/hardware path @@ -255,9 +255,9 @@ code agent prompt、runner 或 worker 不得直接绕过 cloud-api 调用 device ## 内部架构 -`hwlab-cloud-api` 内部应按 auth/session、authorization、agent session owner、device-pod grant、AgentRun Device Pod API key 和 admin API 模块分层。所有模块共享同一 Postgres runtime store 和 migration ledger,避免拆出早期 `hwlab-user-api` 造成跨服务一致性成本。 +`hwlab-cloud-api` 内部应按 auth/session/API key、authorization、agent session owner、device-pod grant 和 admin API 模块分层。所有模块共享同一 Postgres runtime store 和 migration ledger,避免拆出早期 `hwlab-user-api` 造成跨服务一致性成本。 -`user_sessions` 存浏览器 session token hash;`agent_sessions.owner_user_id` 绑定 Code Agent session;`device_pods` 存 profile authority;`device_pod_grants` 表示普通用户对 device pod 的完整使用权;`HWLAB_DEVICE_POD_API_KEY` 表示 assembled AgentRun runner 对正式 device-pod 的统一短入口授权。 +`user_sessions` 存浏览器 session token hash;`api_keys` 存映射到用户的 CLI/runner API key;`agent_sessions.owner_user_id` 绑定 Code Agent session;`device_pods` 存 profile authority;`device_pod_grants` 表示普通用户对 device pod 的完整使用权。不得再引入对所有正式 device pod 授权的 `HWLAB_DEVICE_POD_API_KEY`。 ## API 接口说明 @@ -291,7 +291,7 @@ v0.2 不新增独立用户管理微服务。Keycloak 是独立身份提供方, | 服务 | v0.2 职责 | | --- | --- | | `hwlab-cloud-web` | Keycloak 登录入口、普通用户工作台、API key 管理入口和 admin 用户/授权 UI;浏览器 `/auth/*` 可由 cloud-web 代理到 cloud-api。 | -| `hwlab-cloud-api` | 用户映射、Web session/API key 消费、授权、device grant、AgentRun Device Pod API key、code agent owner 校验和对 device pod 的受控转发。 | +| `hwlab-cloud-api` | 用户映射、Web session/API key 消费、授权、device grant、code agent owner 校验和对 device pod 的受控转发。 | | `hwlab-agent-mgr` / `hwlab-agent-worker` | 执行 code agent session;接收 owner/session label 或 env 方便观测,但不作为最终权限 authority。 | | `hwlab-device-pod` | 暴露设备语义 API;不保存用户权限,不直接面向浏览器或普通用户 session Pod。 | | `hwlab-edge-proxy` | 公网/FRP 入口和 HTTP 转发;不做业务权限,只转发 cookie/header,不注入伪 actor。 | diff --git a/docs/reference/spec-v02-auth.md b/docs/reference/spec-v02-auth.md index a4d85c2a..1a0133cc 100644 --- a/docs/reference/spec-v02-auth.md +++ b/docs/reference/spec-v02-auth.md @@ -1,6 +1,6 @@ # v0.2 登录与鉴权规格 -本文是 HWLAB `v0.2` 登录、认证和应用层鉴权入口的长期规格。它把 Keycloak OIDC、浏览器 Web session、CLI API key 和 HWLAB 内部 `AuthPrincipal` 归一到同一套口径,避免把本地账号密码、浏览器 cookie、用户 API key 和 AgentRun Device Pod API key 混用。 +本文是 HWLAB `v0.2` 登录、认证和应用层鉴权入口的长期规格。它把 Keycloak OIDC、浏览器 Web session、CLI/API/AgentRun 共用的用户 API key 和 HWLAB 内部 `AuthPrincipal` 归一到同一套口径,避免把本地账号密码、浏览器 cookie 和设备专用系统 key 混用。 基础设施实施跟踪见 [pikasTech/HWLAB#788](https://github.com/pikasTech/HWLAB/issues/788)。用户角色、Code Agent session owner、device pod grant 和资源授权矩阵见 [spec-user-access.md](spec-user-access.md);本文只定义“如何登录、如何恢复 actor、如何把请求归一成 actor”。 @@ -9,10 +9,11 @@ - Web 用户通过 Keycloak OIDC 登录或注册,HWLAB 不再把本地账号密码表单作为目标登录体验。 - Web 使用 `hwlab-cloud-api` 发行的 httpOnly `hwlab_session`,每个 session token 最长 24 小时;第一版不做复杂 refresh token 管理,但必须可撤销、可重新登录轮换。 - CLI 是纯 CLI 体验,不打开浏览器、不跳转 Web、不做 device-code flow;标准凭据是环境变量 `HWLAB_API_KEY`。 +- AgentRun runner 内的 `hwpod` 也必须使用同一类用户 API key 认证,映射到发起 Code Agent session 的 `users.id`;不再引入单独的 `HWLAB_DEVICE_POD_API_KEY`。 - 每个用户在首次登录后自动拥有一个默认 API key;用户也可以在 Web 中创建、查看、失效或重新生成 API key。 - API key 长效有效,除非用户或管理员手动 revoke/regenerate;它不跟 Web session 的 24 小时过期绑定。 - Keycloak 只做身份认证和账号注册;HWLAB 的 `users.role`、`users.status`、device pod grant 和 Code Agent owner 仍是应用层授权 source of truth。 -- `HWLAB_DEVICE_POD_API_KEY` 只用于 assembled AgentRun runner 内 `hwpod` 访问正式 device-pod,不是用户 CLI API key。 +- device-pod 权限只由 `users.role/status`、Code Agent session owner 和 `device_pod_grants` 控制;不存在“对所有正式 device pod 授权”的共享 runner key。 ## 系统边界 @@ -22,7 +23,7 @@ | Keycloak Postgres | Keycloak 专用数据库,短期可与 Keycloak 同在 `keycloak` namespace;不复用 HWLAB v0.2 业务 Postgres。 | | `hwlab-cloud-api` | OIDC callback、session token、API key、用户映射、`AuthPrincipal` 和应用层授权收口。 | | `hwlab-cloud-web` | 浏览器 UI 和同源代理;未登录时引导到 Keycloak,不持有 Keycloak client secret,不直接访问 Postgres。 | -| `hwlab-cli` | 读取 `HWLAB_API_KEY`,向 Cloud Web 同源 API 或 Cloud API 发送 `Authorization: Bearer hwl_live_...`。 | +| `hwlab-cli` / AgentRun `hwpod` | 读取 `HWLAB_API_KEY`,向 Cloud Web 同源 API 或 Cloud API 发送 `Authorization: Bearer hwl_live_...`,恢复到同一个用户 actor。 | | `hwlab-edge-proxy` / FRP | 只转发 cookie/header 和 HTTP 流量,不注入伪 actor,不做业务授权。 | | HWLAB v0.2 Postgres | 保存 HWLAB 用户映射、session、API key、resource grant 和 runtime durable state。 | @@ -91,7 +92,7 @@ type AuthPrincipal = { displayName: string; role: "admin" | "user"; status: "active" | "disabled"; - authMethod: "web-session" | "api-key" | "device-pod-api-key" | "legacy-local-session"; + authMethod: "web-session" | "api-key" | "legacy-local-session"; sessionId?: string; apiKeyId?: string; keycloakIssuer?: string; @@ -100,11 +101,11 @@ type AuthPrincipal = { }; ``` -认证顺序必须显式区分三类凭据: +认证顺序必须显式区分两类正式用户凭据和 legacy fallback: -1. `Authorization: Bearer hwl_live_...` 或 `HWLAB_API_KEY` 映射出的 header 是用户 API key。 -2. `x-hwlab-device-pod-api-key` 是 AgentRun Device Pod API key,只允许 assembled runner/device-pod 短入口使用。 -3. `hwlab_session` cookie 或兼容 session token 是 Web session。 +1. `Authorization: Bearer hwl_live_...` 或 `HWLAB_API_KEY` 映射出的 header 是用户 API key,适用于 CLI 和 AgentRun runner 内 `hwpod`。 +2. `hwlab_session` cookie 是 Web session。 +3. 本地账号密码 session token 只作为 legacy/debug fallback。 现有 `Authorization: Bearer ` 兼容入口只能保留为 legacy/debug,不得阻塞 `hwl_live_` 前缀的用户 API key 识别。 @@ -135,7 +136,7 @@ Session 规则: ## CLI API key 流程 -CLI 标准认证方式: +CLI 和 AgentRun `hwpod` 标准认证方式: ```bash export HWLAB_API_KEY=hwl_live_xxx @@ -146,9 +147,11 @@ bun tools/hwlab-cli/bin/hwlab-cli.ts client auth whoami - CLI 不跳转浏览器,不依赖 Web cookie,不要求 username/password 交互。 - `hwlab-cli` 默认从 `HWLAB_API_KEY` 读取 key,并发送 `Authorization: Bearer `。 +- AgentRun runner 的 transient env 只允许注入映射到当前 Code Agent session owner 的 `HWLAB_API_KEY`;可以使用该用户默认 key,也可以使用同一 `api_keys` 表中为该用户创建的 runner 专用 key,但绝不能使用跨用户共享的 device-pod 系统 key。 - `client auth status` 必须显示 endpoint、是否检测到 `HWLAB_API_KEY`、key prefix 和用户摘要;不得输出完整 API key。 - `client auth whoami` 或 `client request GET /v1/users/me` 必须能用 API key 返回与 Web 同一用户的 `AuthPrincipal` 摘要。 - `client auth login --username ...` 和本地 cookie profile 属于 legacy 兼容入口;目标体验不再把它作为一等 CLI 登录。 +- `hwpod` 在 runner 中必须自动使用 `HWLAB_RUNTIME_API_URL` 和 `HWLAB_API_KEY` 直连 `hwlab-cloud-api`,并让 cloud-api 按该 key 对应用户的 role/grant 做授权。 API key 数据结构: @@ -175,7 +178,7 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_api_keys_prefix ON api_keys(key_prefix); API key 行为: - 首次 OIDC 登录后自动创建默认 key;如果默认 key 被 revoke,用户可在 Web 中重新生成。 -- 默认 key 和手动创建的 key 都继承该用户的 `role/status/grant`,不额外绕过权限矩阵。 +- 默认 key、手动创建的 key 和 AgentRun runner 使用的 key 都继承该用户的 `role/status/grant`,不额外绕过权限矩阵。 - revoke 后同一 key 立刻返回 `401 api_key_invalid`,不能等 Web session 过期。 - 每次 API key 成功认证应更新 `last_used_at`,但不得记录完整 key。 @@ -203,7 +206,7 @@ API key 行为: - `admin` 可以管理用户、device pod profile/grant,并跨用户查看或取消 Code Agent session。 - `user` 只能访问自己的 Code Agent session 和被授权的 device pod。 -- Web session 和 CLI API key 得到同一个 `users.id` 时,应看到相同 device pod grant 和账号 workspace。 +- Web session、CLI API key 和 AgentRun runner 内 `hwpod` API key 得到同一个 `users.id` 时,应看到相同 device pod grant 和账号 workspace。 - Keycloak realm role、group 或 claim 不直接决定 HWLAB device pod 权限;最多作为创建/绑定用户时的输入线索。 ## 测试规格 @@ -230,7 +233,7 @@ API key 行为: ## T6 -阅读 docs/reference/spec-v02-auth.md,然后检查 cloud-api 日志、trace、CLI 默认输出和 issue 复现材料,确认不出现 Keycloak client secret、session token、完整 API key、`HWLAB_DEVICE_POD_API_KEY` 或 Postgres URL 原文。 +阅读 docs/reference/spec-v02-auth.md,然后检查 cloud-api 日志、trace、CLI 默认输出和 issue 复现材料,确认不出现 Keycloak client secret、session token、完整 API key、历史 `HWLAB_DEVICE_POD_API_KEY` 或 Postgres URL 原文;AgentRun runner 中也不得存在跨用户共享的 device-pod 系统 key。 ## 规格的实现情况 @@ -240,7 +243,7 @@ API key 行为: | Keycloak 自助注册且不强制邮箱/手机验证 | 目标状态 | 只适合小范围测试;默认 `user`、无 device pod grant。 | | Web OIDC login/callback | 目标状态 | 当前源码仍以 `/auth/login` 本地账号密码为主。 | | Web session 24 小时轮换 | 目标状态 | 当前 `internal/cloud/access-control.ts` 为 7 天本地 session,后续需改为 24 小时。 | -| CLI `HWLAB_API_KEY` 一等登录 | 目标状态 | 当前 CLI 主要保存 cookie session;目标是 env API key,无浏览器跳转。 | +| CLI/AgentRun `HWLAB_API_KEY` 一等登录 | 目标状态 | 当前 CLI 主要保存 cookie session,AgentRun/device-pod 仍有旧 shared key 口径;目标是统一 env API key 映射到用户,无浏览器跳转,无跨用户 device-pod key。 | | 默认 API key 自动生成和 Web 可查看 | 目标状态 | 小范围测试允许重复查看明文;生产化再改为 hash-only。 | -| `AuthPrincipal` 归一 | 目标状态 | 后续实现必须区分 Web session、用户 API key 和 AgentRun Device Pod API key。 | +| `AuthPrincipal` 归一 | 目标状态 | 后续实现必须把 Web session、CLI API key 和 AgentRun `hwpod` API key 都归一成同一用户 actor。 | | `admin/user` 与 device pod grant 授权 | 部分实现 | 现有 cloud-api 已有本地用户、session、grant 和 Code Agent owner 绑定;资源授权继续按 spec-user-access 收敛。 | diff --git a/docs/reference/spec-v02-hwlab-cli.md b/docs/reference/spec-v02-hwlab-cli.md index 5cc6ce35..bf67658e 100644 --- a/docs/reference/spec-v02-hwlab-cli.md +++ b/docs/reference/spec-v02-hwlab-cli.md @@ -38,7 +38,7 @@ Code Agent session 是显式资源,不再由普通 `client agent send`、Workb - 专用子命令覆盖高频用户工作台;`client request METHOD /path` 覆盖 WEB 同源代理允许的其他非视觉 API。`client request` 只接受以 `/` 开头的 Cloud Web 相对路径,禁止绝对 URL,避免绕过 Cloud Web 直接打内部服务。 - `client gateway pressure` 是 device-pod/gateway 高频故障的真实业务传输压测入口;必须覆盖 small stdout、大 stdout、长单行 stdout、stderr flood、结构化 timeout 和超出 gateway inflight 上限的并发请求。所有场景必须返回 JSON、HTTP/route/traceId/requestId、字节数、truncated 标记、sha256 和 bounded preview;失败必须明确是 `http_*`、`stdout_not_truncated`、`stderr_not_truncated`、`timeout_not_observed`、`structured_gateway_busy` 等可定位原因,禁止无输出、长时间黑洞或只靠 shell pipe 截断。 - 输出默认是 JSON;任何失败都要有 `ok:false`、`action`、`status`、HTTP 状态、route 和可定位错误,不允许无 stdout 成功。可能返回大对象的 `client` 子命令默认返回紧凑摘要,避免高频排障输出爆炸;需要完整响应体时显式加 `--full`。 -- `device-pod-cli`/`hwpod` 在 AgentRun runner 中是设备 API 标准短入口,必须自动使用装配的 `HWLAB_RUNTIME_API_URL` 直达 `hwlab-cloud-api` 和 `HWLAB_DEVICE_POD_API_KEY`,不能把 Cloud Web 同源代理当作设备 API 通道,也不能手动传 URL 或 session token。`job output` 默认也必须返回紧凑 JSON:保留 job/status/blocker/freshness/text/evidence 摘要,省略嵌套 gateway dispatch 和长命令;需要完整 payload 时显式加 `--full`。Code Agent 和人工不得用 `| head`、`grep` 或 shell 管道作为默认输出压缩方式,避免 stdout pipe、子进程信号转发或长输出造成 commandExecution 黑洞。 +- `device-pod-cli`/`hwpod` 在 AgentRun runner 中是设备 API 标准短入口,必须自动使用装配的 `HWLAB_RUNTIME_API_URL` 直达 `hwlab-cloud-api`,并使用映射到当前 Code Agent session owner 的 `HWLAB_API_KEY`;不能把 Cloud Web 同源代理当作设备 API 通道,也不能手动传 URL、session token 或历史 `HWLAB_DEVICE_POD_API_KEY`。`job output` 默认也必须返回紧凑 JSON:保留 job/status/blocker/freshness/text/evidence 摘要,省略嵌套 gateway dispatch 和长命令;需要完整 payload 时显式加 `--full`。Code Agent 和人工不得用 `| head`、`grep` 或 shell 管道作为默认输出压缩方式,避免 stdout pipe、子进程信号转发或长输出造成 commandExecution 黑洞。 - Code Agent 交互必须默认暴露 `traceId`、`resultUrl`、终态和 assistant 回复文本摘要;不能要求用户先拉全量 trace 再手工查找回复。 - CLI 本地登录态必须支持 `--profile NAME` 隔离,同一 base URL 下不同 profile 写入 `.state/hwlab-cli/profiles//.json`。切换到其他账号再切回原账号时,`client workbench restore/status` 必须从服务端账号 workspace 恢复之前的 `workspaceId`、`conversationId`、`sessionId`、`threadId`、`activeTraceId` 和 revision,而不是只依赖本地文件。 - `client workbench restore/status/watch/reset` 是账号 workspace 的非视觉入口:`restore/status` 对应 `GET /v1/workbench/workspace`,`watch` 对应 `/events?afterRevision=`,`reset --confirm` 对应服务端 reset。输出必须显示 workspace revision、selected conversation/session、active trace 和本地 state file,且不得保存 password、session token 原文以外的 Secret 值。 diff --git a/docs/reference/spec-v02-hwlab-cloud-api.md b/docs/reference/spec-v02-hwlab-cloud-api.md index c815d717..fbb936af 100644 --- a/docs/reference/spec-v02-hwlab-cloud-api.md +++ b/docs/reference/spec-v02-hwlab-cloud-api.md @@ -6,7 +6,7 @@ - 承担 runtime health、DB readiness、登录鉴权、`AuthPrincipal`、用户/session/API key 权限、Code Agent 对话、trace/result 轮询、gateway outbound registry、M3 IO 控制、device-pod authority/job 和 live build inventory。 - 是 `hwlab-cloud-web`、Code Agent session、device-pod 用户态操作和 gateway outbound poll 的唯一应用层收口点;普通用户不直接访问内部 `hwlab-device-pod` Service。 -- 读取 `hwlab-cloud-api-v02-db/database-url`、`hwlab-v02-code-agent-provider/openai-api-key`、`hwlab-v02-code-agent-codex-auth/auth.json` 和 `hwlab-v02-device-pod-api-key/api-key` 等 v02 独立 SecretRef;文档和日志只允许记录 SecretRef 名称、key、字节数或哈希指纹,不记录值。 +- 读取 `hwlab-cloud-api-v02-db/database-url`、`hwlab-v02-code-agent-provider/openai-api-key` 和 `hwlab-v02-code-agent-codex-auth/auth.json` 等 v02 独立 SecretRef;用户 API key 存在 Postgres `api_keys`,不得再以 `hwlab-v02-device-pod-api-key/api-key` 这类跨用户 SecretRef 授权 device-pod。文档和日志只允许记录 SecretRef 名称、key、字节数或哈希指纹,不记录值。 ## 内部架构 @@ -24,7 +24,7 @@ - AgentRun completed 轮次续接必须依赖 Codex stdio 原生 session continuation。Cloud API 只把本轮原始 `message/prompt` 和显式 session 的标准 `conversationId/sessionId/threadId` 写入 AgentRun command payload 与 `SessionRef`;不得从请求、account workspace 或 account conversation 生成 `conversationContext`,不得把历史消息拼入 prompt,也不得把请求体里的 `conversationContext/messages` 当作模型上下文。历史 conversation facts 只用于 UI、inspect、trace 和 `--from-trace` 的可见性证据;收到 synthetic context 字段时只能记录 ignored trace 并剥离。`thread/resume` 失败时按 AgentRun `thread-resume-failed` 终止本轮并标记当前 session failed/stale,不自动创建新 session。 - Code Agent 不允许存在 turn/session/conversation 总时长 timeout;只允许无新 app-server 响应、无 notification、无 assistant/tool/event activity 的 idle timeout。AgentRun command 失败、provider 失败或 idle timeout 只终结当前 command,并按 session policy 标记当前 session 状态;系统不得自动滚动到新 session。后续消息要么继续同一个 usable session/thread,要么由用户显式创建或选择另一个 session。 - runner pod 被删、runner Job 被重建或旧 lease 失效后,同一 HWLAB session 的恢复判定必须基于同一个 `sessionId`、`threadId`、`providerProfile/backendProfile`、AgentRun `SessionRef` 和 PVC。replacement run/job 只能作为恢复执行壳;Cloud API 仍要把它映射为同一业务 session 的后续 turn,并在 trace/result 中分离业务 session identity 与执行 run/job identity。长期目标仍是在 runner reuse window 内复用同一 AgentRun run/runner。 -- Cloud API 通过 AgentRun v0.1 `runner-jobs.transientEnv` 传递本次 Code Agent turn 的短期上下文,例如 `HWLAB_RUNTIME_*`、`HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME` 和 `HWLAB_DEVICE_POD_API_KEY`。`transientEnv` 不设固定 8 项上限,新增短期上下文时必须按 name 去重、只传本次 Job 需要的 value;`HWLAB_RUNTIME_API_URL` 必须指向当前 namespace 内的 `hwlab-cloud-api` Service,`HWLAB_RUNTIME_WEB_URL` 才指向 `hwlab-cloud-web`;`HWLAB_DEVICE_POD_API_KEY` 只能作为 assembled runner 内 `hwpod` 访问正式 device-pod 的统一授权,必须标记 sensitive,并继续禁止承载 GitHub token、provider key、长期 SSH key 或其他可复用 credential;文档、日志和 trace 只允许保留脱敏后的 name、来源或摘要,不打印 Secret 值。 +- Cloud API 通过 AgentRun v0.1 `runner-jobs.transientEnv` 传递本次 Code Agent turn 的短期上下文,例如 `HWLAB_RUNTIME_*`、`HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME` 和映射到当前 session owner 的 `HWLAB_API_KEY`。`transientEnv` 不设固定 8 项上限,新增短期上下文时必须按 name 去重、只传本次 Job 需要的 value;`HWLAB_RUNTIME_API_URL` 必须指向当前 namespace 内的 `hwlab-cloud-api` Service,`HWLAB_RUNTIME_WEB_URL` 才指向 `hwlab-cloud-web`;`HWLAB_API_KEY` 必须对应当前 `agent_sessions.owner_user_id`,并继续禁止承载 GitHub token、provider key、长期 SSH key 或其他无关 credential;文档、日志和 trace 只允许保留脱敏后的 name、来源或摘要,不打印 Secret 值。 - 同 Pod sidecar `hwlab-codex-api-forwarder` 监听 `127.0.0.1:49280/responses`,用于 `codex-api` profile 直连 hyueapi,并保持 hyueapi 在 `NO_PROXY` 中。 - `hwlab-code-agent-workspace` PVC 挂载到 `/workspace/hwlab`,用于长会话 workspace;它是 cloud-api 运行资源,不是独立用户入口。 @@ -41,7 +41,7 @@ | `GET /auth/oidc/login`、`GET /auth/oidc/callback`、`GET /auth/session`、`POST /auth/logout` | Keycloak OIDC、Web session 24 小时轮换和 logout 入口,最终规格见 [spec-v02-auth.md](spec-v02-auth.md)。 | | `POST /auth/login` | 本地账号密码 bootstrap/legacy fallback;目标 Web/CLI 登录不依赖该入口。 | | `GET /v1/auth/session`、`GET /v1/users/me`、`GET /v1/access/status`、`GET /v1/setup/status` | v0.2 用户/session/setup 的 REST 状态和兼容入口;响应不得暴露 password hash、session token 原文或 Secret 值。 | -| `GET/POST /v1/api-keys...` | 用户 API key 管理入口;CLI 使用 `HWLAB_API_KEY`,与 AgentRun `HWLAB_DEVICE_POD_API_KEY` 分离。 | +| `GET/POST /v1/api-keys...` | 用户 API key 管理入口;CLI 和 AgentRun runner 内 `hwpod` 都使用 `HWLAB_API_KEY`,映射到用户后再按权限表授权。 | | `POST /v1/admin/users`、`POST/PUT /v1/admin/device-pods`、`POST/DELETE /v1/admin/device-pod-grants...` | `admin` 管理用户、device pod profile 和 grant 的入口。 | | `GET/PATCH /v1/workbench/workspace`、`POST /v1/workbench/workspace/{id}/reset`、`GET /events` | 账号级共享 workspace authority;所有读写按 ownerUserId 隔离,写入使用 revision 观测冲突,active trace 只表示最近活动/当前选中 trace,不作为同账号 Code Agent 并发互斥锁。 | | `POST /v1/agent/sessions`、`GET/PATCH /v1/agent/sessions...` | 显式 Code Agent session 生命周期入口;创建/选择/状态标记 session,并与账号 workspace selection 同步。 | diff --git a/docs/reference/spec-v02-hwlab-cloud-web.md b/docs/reference/spec-v02-hwlab-cloud-web.md index 961c1820..0f07ea65 100644 --- a/docs/reference/spec-v02-hwlab-cloud-web.md +++ b/docs/reference/spec-v02-hwlab-cloud-web.md @@ -10,7 +10,7 @@ - Web 登录按 [spec-v02-auth.md](spec-v02-auth.md) 走 Keycloak OIDC;未登录用户进入 Keycloak 登录/注册,callback 后由 cloud-api 发行 24 小时 `hwlab_session`。本地账号密码表单和自动 admin 登录只允许作为 legacy/bootstrap fallback,不是目标体验。 - Cloud Web 提供 API key 管理入口,让用户查看默认 API key、创建新 key、revoke 或 regenerate;浏览器日常请求仍使用 Web session,不要求用户手动输入 API key。 - Cloud Web 与 `hwlab-cli client` 必须共享同一组非视觉业务 API。浏览器遇到的 Code Agent continuation、trace/result、device-pod list/status 和 device-pod job 问题,必须能通过 `hwlab-cli client` 走同一 `19666` Cloud Web path 复现;不能让 CLI 长期绕到 `19667` Cloud API 后把 Web 路径缺口误判为业务已通过。 -- Cloud Web 只承担浏览器 UI 和 `hwlab-cli client` 的同源代理。AgentRun runner 内的 `hwpod` 不走 Cloud Web;Cloud Web 不转发 AgentRun Device Pod API key,也不保留 device-pod lease 路由。 +- Cloud Web 只承担浏览器 UI 和 `hwlab-cli client` 的同源代理。AgentRun runner 内的 `hwpod` 不走 Cloud Web;runner 使用映射到发起用户的 `HWLAB_API_KEY` 直连 Cloud API,Cloud Web 不保留 device-pod lease 路由。 - 浏览器启动后必须从 `GET /v1/workbench/workspace` hydrate 账号 workspace;同一个账号在多个浏览器标签页、多个浏览器或 CLI profile 中应看到同一个 `workspaceId`、selected conversation/session/thread、provider profile 和 active trace。浏览器 localStorage 只能作为短期缓存,并必须绑定 actor,不能作为 workspace authority。 - Code Agent session 管理必须全部手动化。Workbench 可以从账号 workspace 恢复“已显式选中”的 session,但不能在普通发送、页面刷新、trace replay、失败恢复或 provider resume 失败时自动创建、滚动或替换 session。没有已选 session 时,composer 必须展示“新建 session/选择 session”的显式动作;session failed/stale/canceled 后必须保留失败证据,继续前由用户显式新建或选择另一个 session。 - 显式 session 的 `providerProfile` 优先于账号 workspace provider profile。Workbench 可以展示 workspace 默认 provider,但对已选 session 发送 turn 时必须使用该 session 的 provider profile;用户想切换 provider 时,应显式创建或选择对应 provider 的 session,不能把旧 workspace provider 静默套到当前 session 上。 diff --git a/docs/reference/spec-v02-hwlab-device-pod-service.md b/docs/reference/spec-v02-hwlab-device-pod-service.md index 11e5ede0..6e415267 100644 --- a/docs/reference/spec-v02-hwlab-device-pod-service.md +++ b/docs/reference/spec-v02-hwlab-device-pod-service.md @@ -5,7 +5,7 @@ ## 在系统中的职责划分 - 承接 `cloud-api -> hwlab-device-pod -> gateway/device-host-cli` 的内部执行服务位置。 -- 当前阶段只暴露 device-pod executor 边界;用户、profile、grant、AgentRun Device Pod API key 和 job authority 都在 `hwlab-cloud-api`,不能由该 Service 伪造或兜底。 +- 当前阶段只暴露 device-pod executor 边界;用户、profile、grant、用户 API key 和 job authority 都在 `hwlab-cloud-api`,不能由该 Service 伪造或兜底。 - 普通用户和 Code Agent 不应直接调用该 Service;正式路径必须经过 `hwlab-cloud-api` 鉴权、grant/API key 和 mutating job reason 校验。 ## 内部架构