fix: replace device pod lease with api key
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
- GitHub PR/issue 能力通过 `toolCredentials[].tool=github` 注入,默认 SecretRef 是 `agentrun-v01-tool-github-pr` key `GH_TOKEN`。
|
||||
- UniDesk SSH passthrough 通过 `toolCredentials[].tool=unidesk-ssh` 注入,默认 SecretRef 是 `agentrun-v01-tool-unidesk-ssh` key `UNIDESK_SSH_CLIENT_TOKEN`。
|
||||
- `UNIDESK_SSH_CLIENT_TOKEN` 只授予 UniDesk frontend `/ws/ssh` scoped client 能力;route allowlist 由 UniDesk frontend 配置控制。HWLAB 不持有 provider token、主 server SSH key 或完整 frontend 登录态。
|
||||
- `runnerJob.transientEnv` 只能承接短期或非敏感执行上下文,例如 device-pod session token 和 `UNIDESK_MAIN_SERVER_IP`;不得承载 GitHub token、UniDesk SSH client token、provider key、长期 SSH key 或 registry token。
|
||||
- `runnerJob.transientEnv` 只能承接本次 runner job 需要的短期执行上下文,例如 `HWLAB_DEVICE_POD_API_KEY` 和 `UNIDESK_MAIN_SERVER_IP`;`HWLAB_DEVICE_POD_API_KEY` 必须标记 sensitive,不得承载 GitHub token、UniDesk SSH client token、provider key、长期 SSH key 或 registry token。
|
||||
|
||||
## ResourceBundle
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ Forwarder 不需要人工维护长驻进程。正式固化后,它应由 Kubern
|
||||
|
||||
AgentRun 接入后,`agentrun-v01` 只能表示执行基础设施,不等同于真实 provider/model。Code Agent result `completed` 要被 Web 或 CLI 标记为真实完成,必须同时具备 final assistant response、真实 provider/model、`providerTrace`、traceId、conversationId/sessionId 和可回放 trace;否则应显示“完成证据不足”,不能用 SOURCE、fixture、echo、mock 或 stub 补齐。AgentRun adapter 应把真实执行形态暴露为 `codex-stdio` / Codex app-server stdio 等价长会话,把 `agentrun-v01` 保留在 adapter、runner 或 infrastructure 字段里。
|
||||
|
||||
同一 conversation/session 的后续消息必须在 AgentRun runner lease 有效时进入既有 run/runner 的新 command/turn,避免每次消息都重新 bundle、重新启动 runner、再把历史 thread 当作新 runner 可 resume 的 rollout。每条消息都重新 bundle 或启动新 runner 是功能缺口,不得只靠 trace 说明包装成通过。只有 run 已 terminal、runner lease 过期或 AgentRun manager 明确拒绝复用时才允许新建 runner;trace/result 可以说明原因,但该说明只是诊断证据,不替代复用能力本身。
|
||||
同一 conversation/session 的后续消息必须在 AgentRun runner reuse window 有效时进入既有 run/runner 的新 command/turn,避免每次消息都重新 bundle、重新启动 runner、再把历史 thread 当作新 runner 可 resume 的 rollout。每条消息都重新 bundle 或启动新 runner 是功能缺口,不得只靠 trace 说明包装成通过。只有 run 已 terminal、runner reuse window 过期或 AgentRun manager 明确拒绝复用时才允许新建 runner;trace/result 可以说明原因,但该说明只是诊断证据,不替代复用能力本身。
|
||||
|
||||
Trace 展示问题按“同源 row 转换优先”排查:先用 `hwlab-cli client agent trace <traceId> --render web` 输出 Cloud Web 同一 trace row 摘要;CLI 也乱说明 row 转换逻辑问题,CLI 正常而浏览器乱再查 DOM、CSS、滚动和增量 patch。
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
```text
|
||||
device-pod-cli or cloud-web
|
||||
-> cloud-api auth + device_pod_grants + lease
|
||||
-> cloud-api auth + device_pod_grants + AgentRun Device Pod API key
|
||||
-> hwlab-device-pod internal REST
|
||||
-> gateway transport
|
||||
-> device-host-cli
|
||||
@@ -17,14 +17,14 @@ device-pod-cli or cloud-web
|
||||
|
||||
## 在系统中的职责划分
|
||||
|
||||
`device-pod` 是云端可授权、可租约保护、可审计的逻辑设备能力单元。`hwlab-cloud-api` 是用户身份、grant、lease、profile authority 和用户态 REST API 的入口;`hwlab-device-pod` 是内部执行服务;`hwlab-gateway` 只承载 transport;`device-host-cli` 只在硬件 host 侧执行 Keil、pyOCD、UART 和 workspace 操作。
|
||||
`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 操作。
|
||||
|
||||
普通用户、浏览器和 Code Agent session 不直接持有 gateway route、host workspace route、Kubernetes Service 直连能力或 profile 修改权。
|
||||
|
||||
## 设计目标
|
||||
|
||||
- 用最少组件把 `device-pod-cli` 从“本地 profile + RPC/gateway 调用”迁到“1:1 REST 请求”。
|
||||
- `cloud-api` 是用户身份、device grant、profile authority 和 lease 判断入口。
|
||||
- `cloud-api` 是用户身份、device grant、AgentRun Device Pod API key 和 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。
|
||||
@@ -84,7 +84,7 @@ code agent 本地文件只能作为非权威 hint/cache,最多包含:
|
||||
|
||||
## 内部架构
|
||||
|
||||
正式 device-pod 由 profile registry、job lifecycle、freshness/blocker、bounded output、gateway/device-host adapter 和 lease integration 组成。第一阶段只有一个 `hwlab-device-pod` Deployment 管理多个 `devicePodId`;profile authority 和 user grant 在 cloud-api/Postgres 中,device-pod 服务只接受 cloud-api 内部调用。
|
||||
正式 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 内部调用。
|
||||
|
||||
当前 v02 部署中的 `hwlab-device-pod` 微服务实现情况见 [spec-v02-hwlab-device-pod-service.md](spec-v02-hwlab-device-pod-service.md)。
|
||||
|
||||
@@ -163,9 +163,6 @@ POST /v1/device-pods/{devicePodId}/jobs
|
||||
GET /v1/device-pods/{devicePodId}/jobs/{jobId}
|
||||
GET /v1/device-pods/{devicePodId}/jobs/{jobId}/output
|
||||
POST /v1/device-pods/{devicePodId}/jobs/{jobId}/cancel
|
||||
POST /v1/device-pods/{devicePodId}/leases
|
||||
GET /v1/device-pods/{devicePodId}/leases/current
|
||||
DELETE /v1/device-pods/{devicePodId}/leases/current
|
||||
```
|
||||
|
||||
管理员 API 由 `cloud-api` 提供:
|
||||
@@ -217,7 +214,7 @@ DELETE /v1/admin/device-pod-grants/{devicePodId}/{userId}
|
||||
|
||||
| 服务 | 职责 |
|
||||
| --- | --- |
|
||||
| `hwlab-cloud-api` | 用户身份、admin/user、device grant、lease、profile authority、用户态 REST API、转发到内部 device-pod。 |
|
||||
| `hwlab-cloud-api` | 用户身份、admin/user、device grant、AgentRun Device Pod API key、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 文件操作。 |
|
||||
@@ -253,9 +250,9 @@ 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,并在物理互斥需要时获取 `device_leases`。
|
||||
- `POST /v1/device-pods/{devicePodId}/leases` 只对已授权 actor 创建或刷新互斥租约,响应只返回一次性 `leaseToken`;后续强副作用 job 必须通过 `leaseToken` 或 `x-hwlab-device-lease-token` 证明持有租约。
|
||||
- 撤销 device pod grant 必须释放该用户对同一 `devicePodId` 的活动 lease。
|
||||
- 强副作用 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 的可见性与使用权。
|
||||
|
||||
## CLI 实现口径
|
||||
|
||||
@@ -269,7 +266,7 @@ manages: many devicePodId
|
||||
- 源码局部编辑优先使用 `apply-patch`;`put` 只用于明确的整文件写入或新文件创建。
|
||||
- UART 业务覆盖 `read`、`write`、`read-after-launch-flash` 和 `jsonrpc`;JSON-RPC 请求必须由 device-host-cli 校验 response id,除非显式传入允许 id mismatch 的业务参数。
|
||||
- apply-patch 类失败必须返回可定位的 patch hint,例如缺少 `*** End Patch`、hunk 上下文不匹配或 header 错误;调用方应先重新读取目标文件再重试小 hunk,不应默认绕到整文件覆盖。
|
||||
- mutating job 继续由 cloud-api 侧强制 lease/reason;CLI 只转发 `reason` 和 `leaseToken`,不在本地绕过。
|
||||
- mutating job 由 cloud-api 侧强制 `reason`;CLI 只转发 `intent`、`args` 和 `reason`。
|
||||
- `profile create` 这类本地 profile bootstrap 在正式默认路径中返回 `legacy_profile_create_removed`;管理员应使用 cloud-api admin API 管理服务端 profile/grant。
|
||||
- DS/device-pod prompt 和 skill 示例必须优先使用 `hwpod`,避免把长路径 wrapper 复制成常态命令;host job 轮询时 job id 必须作为 `status/output/cancel` 的紧随位置参数传入,不能放到 flags 后面或靠 shell 管道解析 JSON。
|
||||
|
||||
@@ -363,29 +360,22 @@ bun tools/device-pod-cli.ts bootsharp --pod-id D601-F103-V2 \
|
||||
--api-base-url http://74.48.78.17:19667 \
|
||||
--cookie "$COOKIE"
|
||||
|
||||
LEASE=$(bun tools/device-pod-cli.ts lease acquire --pod-id D601-F103-V2 \
|
||||
--api-base-url http://74.48.78.17:19667 \
|
||||
--cookie "$COOKIE" \
|
||||
--reason "D601-F103-V2 build/download validation" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).body.leaseToken))')
|
||||
|
||||
bun tools/device-pod-cli.ts D601-F103-V2:workspace:/ build start \
|
||||
--api-base-url http://74.48.78.17:19667 \
|
||||
--cookie "$COOKIE" \
|
||||
--lease-token "$LEASE" \
|
||||
--reason "D601-F103-V2 Keil build validation" \
|
||||
--timeout-ms 120000
|
||||
|
||||
bun tools/device-pod-cli.ts D601-F103-V2:debug-probe download start \
|
||||
--api-base-url http://74.48.78.17:19667 \
|
||||
--cookie "$COOKIE" \
|
||||
--lease-token "$LEASE" \
|
||||
--reason "D601-F103-V2 Keil download validation" \
|
||||
--capture-uart uart/1 \
|
||||
--capture-duration-ms 8000 \
|
||||
--timeout-ms 120000
|
||||
```
|
||||
|
||||
Code-agent/DS runner 内执行同类验收时,把 `bun tools/device-pod-cli.ts` 换成 `hwpod`;只有 `hwpod` 不在 PATH 时才临时 fallback 到 `/app/skills/device-pod-cli/scripts/device-pod-cli.mjs`。UART 串口若被 Windows 侧工具占用,应把 COM busy/access denied 记录为可选串口证据缺口,Keil build/download 是否通过以 job output 中的 build summary、`Programming Done`、`Verify OK` 和 `Application running` 为准。
|
||||
Code-agent/DS runner 内执行同类验收时,把 `bun tools/device-pod-cli.ts` 换成 `hwpod`;`hwpod` 不在 PATH 时应判定为 runner 镜像或包安装错误并修复该标准入口,不得临时改走长路径 wrapper。UART 串口若被 Windows 侧工具占用,应把 COM busy/access denied 记录为可选串口证据缺口,Keil build/download 是否通过以 job output 中的 build summary、`Programming Done`、`Verify OK` 和 `Application running` 为准。
|
||||
|
||||
DS 或其他 code-agent runner 由 `hwlab-cli client harness submit` 触发时,控制面应保持短连接:提交后用 `client harness result`、`client harness trace --limit <N>` 和 `client harness audit --require-bootsharp` 轮询,不把 UniDesk `ssh/tran` 连接长期挂在一次 `wait` 上。`client harness wait` 只用于短窗口观察,CLI 会把超长等待压到低于 UniDesk 透传硬超时的安全窗口,并在 JSON 中返回后续短轮询命令。
|
||||
|
||||
@@ -421,11 +411,11 @@ hwpod D601-F103-V2:workspace:/ rg \
|
||||
|
||||
## T3
|
||||
|
||||
阅读 docs/reference/spec-device-pod.md,然后用 cli 手动测试以下内容:提交一个强副作用 job,例如 download/reset,缺少 reason 或 lease 时必须被拒绝;获得 lease 后响应必须包含 devicePodId、profileHash、traceId、operationId、freshness、blocker 和 bounded output metadata。
|
||||
阅读 docs/reference/spec-device-pod.md,然后用 cli 手动测试以下内容:提交一个强副作用 job,例如 download/reset,缺少 reason 时必须被拒绝;补充 reason 后必须经同一条 cloud-api job REST 路径进入 executor,并返回 devicePodId、profileHash、traceId、operationId、freshness、blocker 和 bounded output metadata。
|
||||
|
||||
## T4
|
||||
|
||||
阅读 docs/reference/spec-device-pod.md,然后用 cli 手动测试以下内容:对授权 Device Pod 运行 `workspace put`、`workspace rm`、`workspace rmdir`、`workspace keil add-source/remove-source` 和 `io-probe jsonrpc` 的 `--dry-run` 与一次真实小闭环。确认请求只经过 cloud-api job REST,输出 intent、reason、lease、traceId 和 bounded output,不读取本地 profile 或直连 gateway。
|
||||
阅读 docs/reference/spec-device-pod.md,然后用 cli 手动测试以下内容:对授权 Device Pod 运行 `workspace put`、`workspace rm`、`workspace rmdir`、`workspace keil add-source/remove-source` 和 `io-probe jsonrpc` 的 `--dry-run` 与一次真实小闭环。确认请求只经过 cloud-api job REST,输出 intent、reason、traceId 和 bounded output,不读取本地 profile、不直连 gateway。
|
||||
|
||||
## 规格的实现情况
|
||||
|
||||
@@ -433,8 +423,8 @@ hwpod D601-F103-V2:workspace:/ rg \
|
||||
| --- | --- | --- |
|
||||
| 逻辑 device-pod 模型 | 已实现为规格 | 四要素、profile shape 和 Kubernetes 口径已定义。 |
|
||||
| profile server authority | 部分实现 | cloud-api 保存正式 DB profile 并向用户返回脱敏摘要;device-pod executor 不接受用户上传 profile。 |
|
||||
| 用户 grant + lease | 部分实现 | cloud-api 已实现 admin grant、可见性过滤、lease acquire/current/release、强副作用 job lease 校验和撤销授权释放 lease。 |
|
||||
| REST/job API | 部分实现 | cloud-api 已实现 list/status/events/probe/job/output/cancel 和 lease API,并可把已授权 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/lease/profile authority。 |
|
||||
| 用户 grant + AgentRun API key | 部分实现 | cloud-api 已实现 admin grant、可见性过滤、AgentRun Device Pod API key 认证和强副作用 job reason 校验。 |
|
||||
| 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。 |
|
||||
| 禁止 fake 作为 DEV-LIVE | 已实现/持续约束 | 规格和服务 payload 要求显式标记 fake/source。 |
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
## 在系统中的职责划分
|
||||
|
||||
用户和权限管理不是独立微服务,权威实现收敛在 `hwlab-cloud-api`:它负责登录、session、角色、device pod grant、device lease 和 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`:它负责登录、session、角色、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 权限。
|
||||
|
||||
Postgres 是该规格的数据持久化边界。Kubernetes namespace、ServiceAccount、Service 直连和 gateway route 都不能替代用户权限模型;普通用户不获得 kubeconfig、内部 Service 直连能力或长期 Secret。
|
||||
|
||||
@@ -23,7 +23,7 @@ Postgres 是该规格的数据持久化边界。Kubernetes namespace、ServiceAc
|
||||
- `device pod` 由 `admin` 管理;普通用户只有在被 `admin` 授权后才能看到和使用对应 device pod。
|
||||
- device pod 授权不拆分 `read`、`operate` 或 capability;授权关系存在即代表该用户拥有该 device pod 的完整使用权限。
|
||||
- MVP 不新增产品级 `audit_events` 用户审计表,也不把用户权限依赖到 audit。现有硬件 trace/evidence/audit 字段属于硬件闭环证据,不是多用户权限模型的一部分。
|
||||
- `device lease` 可以保留,但它只解决物理设备并发互斥,不表达用户权限。
|
||||
- 强副作用 device-pod job 只额外要求业务 `reason`;设备互斥由 executor、gateway 和硬件 host 串行化或返回 blocker,不进入用户权限模型。
|
||||
- 普通用户不获得 Kubernetes 用户、kubeconfig、namespace 管理权或直接访问 device pod Service 的权限;所有用户权限判断在 cloud-api 应用层完成。
|
||||
- v0.2 权限数据必须与 `hwlab-dev`/`hwlab-prod` 运行数据隔离。优先在 `hwlab-v02` namespace 内使用独立 Postgres StatefulSet/PVC;若未来显式复用共享 Postgres 实例,也必须使用独立 database 或 schema、独立 Secret 和独立 migration ledger,不得直接复用 `hwlab-dev` 的 pgdata。
|
||||
|
||||
@@ -137,26 +137,8 @@ CREATE TABLE IF NOT EXISTS device_pod_grants (
|
||||
```
|
||||
|
||||
- 不包含 `capability`、`scope`、`expires_at`。
|
||||
- 撤销授权就是删除对应行;如果用户仍持有该 device pod 的活动 lease,撤销流程必须先释放或标记失效 lease。
|
||||
|
||||
### `device_leases`
|
||||
|
||||
设备互斥锁;不表达权限。
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS device_leases (
|
||||
device_pod_id TEXT PRIMARY KEY REFERENCES device_pods(id) ON DELETE CASCADE,
|
||||
holder_session_id TEXT NOT NULL REFERENCES agent_sessions(id) ON DELETE CASCADE,
|
||||
holder_user_id TEXT NOT NULL REFERENCES users(id),
|
||||
lease_token_hash TEXT NOT NULL UNIQUE,
|
||||
created_at TEXT NOT NULL,
|
||||
expires_at TEXT NOT NULL,
|
||||
released_at TEXT
|
||||
);
|
||||
```
|
||||
|
||||
- 下载、复位、长时间采样、串口独占等会占用真实物理设备的操作必须先拿 lease。
|
||||
- 读短状态可以不拿 lease,但仍必须通过 device grant 授权。
|
||||
- 撤销授权就是删除对应行;撤销后该用户通过普通 session/cookie 不再看到或使用该 device pod。
|
||||
- AgentRun runner 不依赖用户 grant 行逐个授权;cloud-api 组装 runner 时注入统一的 `HWLAB_DEVICE_POD_API_KEY`,该 key 只用于 runner 内 `hwpod` 短入口访问正式 device-pod。
|
||||
|
||||
## 权限矩阵
|
||||
|
||||
@@ -170,14 +152,14 @@ CREATE TABLE IF NOT EXISTS device_leases (
|
||||
| 给用户授权或撤销 device pod | 可以 | 不可以 |
|
||||
| 查看 device pod | 可以查看全部 | 只能查看被授权的 device pod |
|
||||
| 使用 device pod 的 workspace/debug/io 能力 | 可以使用全部 | 只能使用被授权的 device pod |
|
||||
| 获取 device lease | 可以 | 只能对被授权的 device pod 获取 |
|
||||
| 提交强副作用 device-pod job | 必须填写 reason | 被授权后必须填写 reason |
|
||||
|
||||
## 请求链路
|
||||
|
||||
cloud-api 每个用户态请求都按同一顺序处理:
|
||||
|
||||
```text
|
||||
authenticate -> actor -> authorize(actor, action, resource) -> optional lease check -> execute
|
||||
authenticate -> actor -> authorize(actor, action, resource) -> reason check for mutating device jobs -> execute
|
||||
```
|
||||
|
||||
### 登录和 session 恢复
|
||||
@@ -219,7 +201,7 @@ browser admin UI
|
||||
-> return grant summary
|
||||
```
|
||||
|
||||
撤销授权走 `DELETE /v1/admin/device-pod-grants/{devicePodId}/{userId}`,先释放或失效该用户对该 device pod 的活动 lease。
|
||||
撤销授权走 `DELETE /v1/admin/device-pod-grants/{devicePodId}/{userId}`,删除后该用户通过普通 session/cookie 不再能看到或使用该 device pod。
|
||||
|
||||
### 用户列出 device pod
|
||||
|
||||
@@ -255,8 +237,8 @@ code agent turn
|
||||
-> cloud-api device operation route
|
||||
-> authenticate actor from owning session
|
||||
-> verify agent_sessions.owner_user_id == actor.id
|
||||
-> authorize device_pod_grants or admin
|
||||
-> acquire or validate device_leases when operation is exclusive
|
||||
-> authorize device_pod_grants/admin or assembled AgentRun Device Pod API key
|
||||
-> require reason for mutating operations
|
||||
-> cloud-api -> hwlab-device-pod internal Service
|
||||
-> gateway/device-host-cli/hardware path
|
||||
```
|
||||
@@ -265,9 +247,9 @@ code agent prompt、runner 或 worker 不得直接绕过 cloud-api 调用 device
|
||||
|
||||
## 内部架构
|
||||
|
||||
`hwlab-cloud-api` 内部应按 auth/session、authorization、agent session owner、device-pod grant、device lease 和 admin API 模块分层。所有模块共享同一 Postgres runtime store 和 migration ledger,避免拆出早期 `hwlab-user-api` 造成跨服务一致性成本。
|
||||
`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` 造成跨服务一致性成本。
|
||||
|
||||
`user_sessions` 存浏览器 session token hash;`agent_sessions.owner_user_id` 绑定 Code Agent session;`device_pods` 存 profile authority;`device_pod_grants` 表示用户对 device pod 的完整使用权;`device_leases` 只表达物理设备互斥,不表达权限。
|
||||
`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 的统一短入口授权。
|
||||
|
||||
## API 接口说明
|
||||
|
||||
@@ -282,7 +264,6 @@ code agent prompt、runner 或 worker 不得直接绕过 cloud-api 调用 device
|
||||
| `POST /v1/admin/device-pods`、`PUT /v1/admin/device-pods/{devicePodId}` | admin 管理 device pod profile authority。 |
|
||||
| `POST /v1/admin/device-pod-grants`、`DELETE /v1/admin/device-pod-grants/{devicePodId}/{userId}` | admin 授权或撤销普通用户使用 device pod。 |
|
||||
| `GET /v1/device-pods` 和 device-pod 操作 API | 按 actor role 和 grant 过滤可见/可用 device pod。 |
|
||||
| `POST /v1/device-pods/{devicePodId}/leases`、`GET/DELETE /v1/device-pods/{devicePodId}/leases/current` | 对已授权 device pod 获取、查看和释放互斥 lease;强副作用 job 必须携带有效 lease token。 |
|
||||
| `POST /v1/agent/chat` 及 result/trace/cancel | 必须校验 `agent_sessions.owner_user_id`;admin 可跨用户查看和取消。 |
|
||||
|
||||
`POST /v1/setup/first-admin` 的 device-pod 初始化只用于空库首次进入系统,不能作为长期 profile 管理入口。每个 seed 必须包含 `devicePodId` 和 object `profile`;cloud-api 会写入 `device_pods.profile_json/profile_hash` 并创建 `device_pod_grants(device_pod_id, first_admin_user_id)`。响应只能返回脱敏 profile、profileHash 和 grant summary,不得返回 `gatewaySessionId`、`hostWorkspaceRoot`、password 或 session token 原文。
|
||||
@@ -300,11 +281,11 @@ v0.2 不新增独立用户管理微服务。用户管理、登录、session、de
|
||||
| 服务 | v0.2 职责 |
|
||||
| --- | --- |
|
||||
| `hwlab-cloud-web` | 登录页、普通用户工作台、admin 用户/授权 UI;浏览器 `/auth/*` 可由 cloud-web 代理到 cloud-api。 |
|
||||
| `hwlab-cloud-api` | 用户、session、授权、device grant、lease、code agent owner 校验和对 device pod 的受控转发。 |
|
||||
| `hwlab-cloud-api` | 用户、session、授权、device grant、AgentRun Device Pod API key、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。 |
|
||||
| Postgres | v0.2 用户、session、授权、device pod、lease 和既有 runtime durable state。 |
|
||||
| Postgres | v0.2 用户、session、授权、device pod 和既有 runtime durable state。 |
|
||||
|
||||
## Kubernetes 落点
|
||||
|
||||
@@ -339,7 +320,7 @@ Kubernetes 只做运行时隔离和资源兜底,不承载 HWLAB 用户权限
|
||||
| 规格项 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| admin/user 两角色模型 | 部分实现 | cloud-api 已实现 `/auth/*`、bootstrap admin、admin/user 创建和 admin-only 路由。 |
|
||||
| `users`、`user_sessions`、grant/lease 表 | 部分实现 | 0001 schema 和 access-control bootstrap 覆盖 users、sessions、device_pods、grants、leases 和 jobs;Device Pod 强副作用 job 已接入 lease token 校验,真实硬件执行仍依赖 gateway/device-host-cli 在线。 |
|
||||
| `users`、`user_sessions`、grant 和 job 表 | 部分实现 | 0001 schema 和 access-control bootstrap 覆盖 users、sessions、device_pods、grants 和 jobs;Device Pod 强副作用 job 已接入 reason 校验,真实硬件执行仍依赖 gateway/device-host-cli 在线。 |
|
||||
| Code Agent owner 绑定 | 已实现 | 已在 `agent_sessions` 写入 `owner_user_id`、conversation/thread/trace 和脱敏 session evidence;trace/result cache 也按 owner/admin 限制访问。 |
|
||||
| device pod 授权模型 | 部分实现 | cloud-api 已实现 admin profile/grant、普通用户可见性和 job 持久化;无在线 gateway/device-host-cli 时返回 blocker。 |
|
||||
| 不用 Kubernetes 表达用户权限 | 已实现/持续约束 | 规格明确禁止普通用户持有 kubeconfig 或直连 Service 权限。 |
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
- `client agent send` 默认先恢复账号 workspace,从 selected conversation/session 和 workspace JSON 中读取标准 `conversationId/sessionId/threadId`,再向 `/v1/agent/chat` 发送这些 IDs、`workspaceId` 和 `expectedWorkspaceRevision`;服务端接受后 CLI 保存新的 workspace revision,终态轮询后再 PATCH workspace 清理终态 `activeTraceId`。默认 workspace 恢复只恢复 ID 和 revision,不恢复 messages/facts,不生成 `conversationContext`,也不得把历史文本拼入 prompt。只有显式 `--no-workspace` 才跳过这一默认恢复路径。
|
||||
- `client agent steer <traceId>` 是运行中引导入口,必须调用 Cloud Web 同源 `POST /v1/agent/chat/steer`,把 steer 文本装配成 AgentRun `type=steer` command 作用到目标 trace 的 active turn。CLI 不手动穿内部 URL;验收使用当前 runtime namespace/lane 自动解析的 `19666` Web 入口,并通过原 trace 的 result/trace 观察 steer 是否被 runner 接收和应用。
|
||||
- `client agent trace <traceId> --render web` 必须调用 Cloud Web trace row 的同一纯转换路径,输出 `render="web"`、renderer 标识、source event count、rendered row count、默认压制的 noise event count 和 row 摘要。浏览器 trace 展示错乱时,必须先用该 CLI 入口确认 Web 渲染转换是否已经乱序、重复、缺 final response、吞掉关键 row 或只显示泛化 tool call,再继续修浏览器 DOM/CSS。
|
||||
- AgentRun v0.1 短连接 runner 已要求支持同 run/runner 多轮 command。CLI 仍应把 Web 提交的 `conversationId/sessionId/threadId` 原样送到 Cloud Web API,用于验证 adapter 是否在 runner lease 有效时复用同一个 AgentRun `runId` / `jobName` 并创建新 `commandId`;每轮都新建 runner 或重新 bundle 不是通过状态,trace 中的原因说明只能用于定位。
|
||||
- AgentRun v0.1 短连接 runner 已要求支持同 run/runner 多轮 command。CLI 仍应把 Web 提交的 `conversationId/sessionId/threadId` 原样送到 Cloud Web API,用于验证 adapter 是否在 runner reuse window 有效时复用同一个 AgentRun `runId` / `jobName` 并创建新 `commandId`;每轮都新建 runner 或重新 bundle 不是通过状态,trace 中的原因说明只能用于定位。
|
||||
- `client harness`、`client harness-ops` 和 `client harness-opt` 吸收 G14 harness-ops 的短连接业务能力:health、submit、result、trace、wait 和 audit。
|
||||
- harness 系列命令只调用 Cloud Web/Code Agent 同源 API,不创建镜像、Job、常驻服务,也不执行 hot-sync、kubectl cp 或硬编码 namespace/pod 的运行面写路径。
|
||||
- 旧 `hwlab-cli cicd`、fixture MVP gate 和 CLI 镜像/Job 口径属于废弃路径;开发中遇到这些旧门禁、旧测试或旧预检时直接删除,不再维护兼容。
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
- 承担 runtime health、DB readiness、用户/session 权限、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` 等 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` 和 `hwlab-v02-device-pod-api-key/api-key` 等 v02 独立 SecretRef;文档和日志只允许记录 SecretRef 名称、key、字节数或哈希指纹,不记录值。
|
||||
|
||||
## 内部架构
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
- AgentRun v0.1 接入只使用标准 `threadId` 路径:`POST /v1/agent/chat` 收到的 `conversationId/sessionId/threadId` 必须写入 AgentRun command `payload.threadId` 和 `SessionRef.threadId`;协议字段、trace、result 和 conversation facts 都以该字段为唯一 thread identity。
|
||||
- AgentRun run 级 events 写回 HWLAB trace 时必须按当前 `commandId` 归属过滤;同一 run 的旧 command 尾部事件不能混入后续 command trace。取消、失败或 blocked 轮次如果已有 assistant/tool 可读进展,必须以脱敏、限长的 conversation facts 写入 UI/trace/inspect 证据,供后续 `inspect`/`--from-trace` 可见性使用;这些 facts 不得作为下一轮模型上下文或 prompt 拼接来源。
|
||||
- AgentRun completed 轮次续接必须依赖 Codex stdio 原生 session continuation。Cloud API 只把本轮原始 `message/prompt` 和标准 `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` 终止本轮。
|
||||
- Cloud API 通过 AgentRun v0.1 `runner-jobs.transientEnv` 传递本次 Code Agent turn 的短期上下文,例如 `HWLAB_RUNTIME_*`、`HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME` 和 device-pod session token。`transientEnv` 不设固定 8 项上限,新增短期上下文时必须按 name 去重、只传本次 Job 需要的 value,并继续禁止承载 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` 和 `HWLAB_DEVICE_POD_API_KEY`。`transientEnv` 不设固定 8 项上限,新增短期上下文时必须按 name 去重、只传本次 Job 需要的 value;`HWLAB_DEVICE_POD_API_KEY` 只能作为 assembled runner 内 `hwpod` 访问正式 device-pod 的统一授权,必须标记 sensitive,并继续禁止承载 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 运行资源,不是独立用户入口。
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
- Cloud Web trace 展示与 `hwlab-cli client agent trace --render web` 必须共享同一套 trace row 纯转换路径。Web 发生 row 顺序错乱、final response 缺失、assistant 消息被吞、tool call 只显示泛化占位或噪声事件淹没时,先用 CLI 输出同一渲染 row 摘要和 noise event count 复现;CLI 可复现说明是 trace row 转换问题,CLI 不可复现再进入 DOM/CSS/滚动状态调查。默认展示应压制 AgentRun backend echo、token/rate-limit/status/terminal echo 等低价值事件,但原始 trace JSON 仍必须保留用于 `--full`/下载排障。
|
||||
- Cloud Web Code Agent composer 必须无锁:运行中 turn 不得把输入框或发送按钮 disabled。浏览器提交时必须按共享 composer policy 自动分流,空闲/终态走 `POST /v1/agent/chat` 开新 turn,存在 active running trace 时走 `POST /v1/agent/chat/steer` 引导当前 turn。`hwlab-cli client agent composer status` 必须能用同一 policy 输出 `locked=false`、`disabled=false`、`submitMode=turn|steer`、`route` 和 `targetTraceId`,用于复现 Web 输入框是否被旧逻辑锁住。
|
||||
- Code Agent result `completed` 只有在同时包含真实 provider/model/trace/conversation 元数据、`providerTrace` 和可展示的 final assistant response 时,才能被 Web 标记为真实完成;`provider=agentrun-v01` 只是执行基础设施标识,不得替代上游 provider/model,也不得把 SOURCE、fixture、echo、mock 或 stub 当成 DEV-LIVE 完成。
|
||||
- 同一 conversation/session 的后续用户消息必须在 AgentRun runner lease 有效时复用已存在的 AgentRun run/runner 继续新 command/turn;只有 runner 不可用、已过期或协议明确要求新 runner 时才重新 bundle 和启动 runner。每条消息都重新 bundle/runner 属于 v0.2 AgentRun 接入缺口,不能只靠 trace 显示原因当成已完成。
|
||||
- 同一 conversation/session 的后续用户消息必须在 AgentRun runner reuse window 有效时复用已存在的 AgentRun run/runner 继续新 command/turn;只有 runner 不可用、已过期或协议明确要求新 runner 时才重新 bundle 和启动 runner。每条消息都重新 bundle/runner 属于 v0.2 AgentRun 接入缺口,不能只靠 trace 显示原因当成已完成。
|
||||
- AgentRun 会话连续性只有一个标准路径:Cloud Web/CLI 提交的 `threadId` 必须经 Cloud API adapter 写入 AgentRun command `payload.threadId` 和 `SessionRef.threadId`。前端、CLI、API 和 AgentRun 的协议字段、trace、result 和 conversation facts 都以该字段为唯一 thread identity。
|
||||
- Cloud Web 提交 Code Agent turn 时只发送当前用户消息、共享 workspace 的 `conversationId/sessionId/threadId`、workspace revision 和必要运行元数据;不得发送 `conversationContext/messages`,也不得把浏览器历史拼入 prompt。历史消息只用于本地 UI 展示和 trace/inspect 可见性,不能替代 AgentRun/Codex stdio 原生 `thread/resume`。
|
||||
- 同一 AgentRun run 复用多条 command 时,Web trace 展示只显示当前 command 归属事件和必要 run 级状态;旧 command 的 assistant/tool/terminal 尾部不能堆到新 command 末尾。取消轮次的可读进展必须作为脱敏 conversation facts 进入 UI/trace/inspect 证据,而不是靠旧 trace 尾部串线让后续轮次“碰巧看到”;这些 facts 不得作为下一轮模型上下文或 prompt 拼接来源。
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
## 在系统中的职责划分
|
||||
|
||||
- 承接 `cloud-api -> hwlab-device-pod -> gateway/device-host-cli` 的内部执行服务位置。
|
||||
- 当前阶段只暴露 device-pod executor 边界;用户、profile、grant、lease 和 job authority 都在 `hwlab-cloud-api`,不能由该 Service 伪造或兜底。
|
||||
- 普通用户和 Code Agent 不应直接调用该 Service;正式路径必须经过 `hwlab-cloud-api` 鉴权、grant 和 lease。
|
||||
- 当前阶段只暴露 device-pod executor 边界;用户、profile、grant、AgentRun Device Pod API key 和 job authority 都在 `hwlab-cloud-api`,不能由该 Service 伪造或兜底。
|
||||
- 普通用户和 Code Agent 不应直接调用该 Service;正式路径必须经过 `hwlab-cloud-api` 鉴权、grant/API key 和 mutating job reason 校验。
|
||||
|
||||
## 内部架构
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
| health 和 executor boundary REST | 已实现 | 服务声明内部 executor、cloud-api authority 和非 fake 来源。 |
|
||||
| bounded events/status | 已实现 | 只返回 executor boundary/blocker,不伪造硬件事件。 |
|
||||
| 正式 profile authority | 已在 cloud-api 实现 | `hwlab-device-pod` 不读取或覆盖 `device_pods.profile_json`。 |
|
||||
| job lifecycle | 部分实现 | 用户态 job 由 cloud-api 鉴权、授权、lease 校验和持久化;executor 侧已提供内部 job create/get/output/cancel lifecycle,并能把 job dispatch 结果写回 bounded output。 |
|
||||
| job lifecycle | 部分实现 | 用户态 job 由 cloud-api 鉴权、授权、reason 校验和持久化;executor 侧已提供内部 job create/get/output/cancel lifecycle,并能把 job dispatch 结果写回 bounded output。 |
|
||||
| gateway/device-host-cli adapter | 部分实现 | executor 已通过 cloud-api internal dispatch 接入 gateway poll/result 和 device-host-cli 命令映射;真实执行仍依赖 profile route、在线 gateway 和 host CLI。 |
|
||||
| device-pod-cli REST authority | 已实现 | `tools/device-pod-cli.ts` 默认只走 cloud-api REST,不读取 `.device-pod/*.json` 作为 profile authority;旧 `.mjs` 入口只负责启动 TypeScript CLI。 |
|
||||
|
||||
|
||||
@@ -55,6 +55,6 @@
|
||||
| bounded shell execution | 已实现 | 受 env 开关、timeout 和 output limit 约束。 |
|
||||
| gateway 压测闭环 | 已实现 | `hwlab-cli client gateway pressure` 覆盖大输出、timeout 和并发背压,不依赖 shell pipe 裁剪。 |
|
||||
| v02 environment 标记 | 已实现 | response meta、audit 和 evidence 从请求 meta 或 gateway env 派生,不把 v02 dispatch 证据落回 `dev`。 |
|
||||
| device-pod grant/lease | 不在本服务 | 由 cloud-api/device-pod 负责。 |
|
||||
| device-pod grant/API key | 不在本服务 | 由 cloud-api/device-pod 负责。 |
|
||||
| 生产级 gateway 多租户隔离 | 未完全实现 | 当前是 demo/transport skeleton。 |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user