Files
pikasTech-HWLAB/docs/reference/spec-user-access.md
T

9.6 KiB
Raw Blame History

v0.2 用户和权限管理规格

本文定义 HWLAB v0.2 用户、session、API key、Code Agent owner 和工具能力的最小权限口径。当前 HWPOD 快速闭环阶段只设计核心业务功能;不为旧设备路由、旧授权表或旧 REST/job 保留兼容路径。

登录入口、Keycloak OIDC、Web session、CLI API key 和 AuthPrincipal 归一见 spec-v02-auth.md。OpenFGA、Admin Access WebUI 和同路径 CLI 细节见 spec-v02-openfga-authorization.md。HWPOD 概念、hwpod-spechwpod-clihwpod-ctlhwpod-compiler-clihwpod-node-opshwpod-nodespec-hwpod-harness.mdv0.3 的注册、登录、API key、用户状态和计费 authority 已收敛到 spec-v03-user-billing.md,不继承 v0.2 Keycloak 作为注册依赖的目标状态。

在系统中的职责划分

用户和权限管理不拆独立微服务,权威实现收敛在 hwlab-cloud-api:它消费认证模块产出的 AuthPrincipal,负责角色、OpenFGA check/write、用户 API key、tool capability 和 Code Agent session owner 校验。hwlab-cloud-web 只提供浏览器 UI 和同源代理;AgentRun v0.1 只消费 cloud-api 按用户权限注入的 actor/session/tool 上下文,不成为 HWLAB 用户权限 authority。

Postgres 是用户、session、业务对象和迁移 ledger 的持久化边界;OpenFGA 是细粒度授权关系与授权判定边界。Kubernetes namespace、ServiceAccount、Service 直连和 host route 都不能替代用户权限模型;普通用户不获得 kubeconfig、内部 Service 直连能力、OpenFGA token 或长期 Secret。

规格目标

  • 只保留两类基础角色:adminuser
  • Code Agent session 直接归属于创建它的用户;普通用户只能查看、继续和取消自己的 session。
  • 工具能力独立授权,例如 hwpodunidesk_sshtrans_cmd 和 GitHub 写工具;拥有 Code Agent session 不等于拥有这些工具。
  • 当前 HWPOD 快速阶段不引入用户级 hwpod 授权矩阵;hwpod-spec 位于 Code Agent workspace,执行链路按 owner session 和工具能力约束。
  • 普通用户不获得 Kubernetes 用户、kubeconfig、namespace 管理权或直接访问内部 Service 的权限;所有用户权限判断在 cloud-api 应用层完成。
  • MVP 不新增产品级 audit_events 用户审计表,也不把用户权限依赖到 audit。
  • v0.2 权限数据必须与 hwlab-dev/hwlab-prod 运行数据隔离。

表结构

users

用户身份和角色 source of truth。

CREATE TABLE IF NOT EXISTS users (
  id TEXT PRIMARY KEY,
  username TEXT NOT NULL UNIQUE,
  display_name TEXT NOT NULL DEFAULT '',
  role TEXT NOT NULL CHECK (role IN ('admin', 'user')),
  status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled')),
  password_hash TEXT,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL
);

user_sessions

浏览器 server session/cookie 的持久状态。cookie 中只保存不可逆 session token;数据库保存 token hash。

CREATE TABLE IF NOT EXISTS user_sessions (
  id TEXT PRIMARY KEY,
  user_id TEXT NOT NULL REFERENCES users(id),
  session_token_hash TEXT NOT NULL UNIQUE,
  created_at TEXT NOT NULL,
  last_seen_at TEXT NOT NULL,
  expires_at TEXT NOT NULL,
  revoked_at TEXT
);

api_keys

CLI 和 runner 的用户 API key 必须映射到 users.id。API key 只能收窄用户权限,不能授予超过用户和 OpenFGA tuple 的能力。

agent_sessions

复用现有 agent_sessions 作为 Code Agent session 归属记录,不新增同义表。

ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS owner_user_id TEXT REFERENCES users(id);
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS conversation_id TEXT;
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS thread_id TEXT;
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS last_trace_id TEXT;
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS session_json TEXT NOT NULL DEFAULT '{}';
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS updated_at TEXT;
CREATE INDEX IF NOT EXISTS idx_agent_sessions_owner ON agent_sessions(owner_user_id);
CREATE INDEX IF NOT EXISTS idx_agent_sessions_conversation ON agent_sessions(conversation_id);

新建 Code Agent session 必须写入 owner_user_id。历史 ownerless session 在迁移时可以一次性归属 bootstrap admin 或标记为 expired;迁移完成后不再允许 ownerless 活跃 session。

权限矩阵

操作 admin user
管理用户和权限 可以;应镜像为 system:hwlab#adminaccess_manager 只有被授予 access_manager 才可以
创建自己的 Code Agent session 可以 可以
查看、继续、取消自己的 Code Agent session 可以 拥有该 session 的 viewer/operator 时可以
查看、取消别人的 Code Agent session 可以 需要该 session 的显式 relation
调用 hwpod-cli / hwpod-ctl 可以,但仍受 session owner 和工具边界约束 需要 tool:hwpod#can_use
调用 UniDesk SSH / trans cmd / GitHub 写工具 可以,但仍受工具边界约束 需要对应 tool:*#can_use

请求链路

cloud-api 每个用户态请求都按同一顺序处理:

authenticate -> actor -> authorize(actor, action, resource) -> execute

登录、API key 和 session 恢复

browser
-> Keycloak OIDC login/callback
-> cloud-api auth controller
-> users issuer+sub/status/role mapping
-> user_sessions insert token hash
-> Set-Cookie httpOnly sameSite
-> browser

cli
-> Authorization: Bearer hwl_live_...
-> cloud-api api_keys lookup
-> users status/role check
-> AuthPrincipal(authMethod='api-key')

用户创建或继续 Code Agent session

browser
-> cloud-api POST /v1/agent/chat
-> authenticate actor
-> find or create agent_sessions(owner_user_id=actor.id, conversation_id)
-> run Code Agent turn
-> persist last_trace_id/thread_id/session_json
-> return 202 trace/result polling pointer

GET /v1/agent/chat/result/{traceId}GET /v1/agent/chat/trace/{traceId}POST /v1/agent/chat/cancel 必须通过 agent_sessions.owner_user_id 校验 owneradmin 可跨用户查看和取消。

Code Agent 使用 HWPOD

code agent turn
-> hwpod-cli in workspace
-> hwpod-compiler-cli reads .hwlab/hwpod-spec.yaml
-> hwpod-node-ops plan
-> cloud-api /v1/hwpod-node-ops
-> hwpod-node

Cloud API 给 AgentRun runner 注入 hwpod、UniDesk SSH、trans_cmd 或 GitHub 写工具前,必须先按 spec-v02-openfga-authorization.md 检查对应 tool:*#can_use

API 接口说明

接口 说明
GET /auth/oidc/loginGET /auth/oidc/callback Web 登录入口;按 spec-v02-auth.md 接入 Keycloak 并写入 24 小时 user_sessions token hash。
GET /auth/session 从 cookie 恢复 actor、role 和 session 状态;API key actor 摘要见 /v1/users/me
GET /v1/auth/sessionGET /v1/users/meGET /v1/access/statusGET /v1/setup/status REST 状态入口;不得读取或返回 password hash、session token 原文或 Secret 值。
GET/POST /v1/api-keys... 用户 API key 管理入口;CLI HWLAB_API_KEY 规则见 spec-v02-auth.md
POST /v1/setup/first-admin 仅当 users 表为空时创建第一个 admin 并建立 session;一旦已有用户必须返回 409 setup_already_completed
POST /auth/logout 设置 revoked_at,撤销当前 browser session。
POST /v1/admin/users admin 创建用户,响应不得返回 password_hash 或 token。
GET/PATCH/PUT/DELETE /v1/admin/access... admin Access API,读写 OpenFGA 授权、tool capability、role/status 和 effective matrix。
POST /v1/hwpod-node-ops HWPOD node-ops 转发入口;业务翻译必须已由 workspace-local compiler 完成。
POST /v1/agent/chat 及 result/trace/cancel 必须校验 agent_sessions.owner_user_idadmin 可跨用户查看和取消。

测试规格

T1

阅读 docs/reference/spec-user-access.md,然后用 CLI 手动测试以下内容:创建普通用户,确认 role=userstatus=active,响应不包含 password hash、session token 或 Secret 值。

T2

阅读 docs/reference/spec-user-access.md,然后用普通用户创建 Code Agent session,确认 agent_sessions.owner_user_id 写入当前用户;另一个普通用户不能读取或取消该 session。

T3

阅读 docs/reference/spec-user-access.md,然后撤销普通用户的 tool:hwpod 能力,创建新的 Code Agent session 并调用 HWPOD,确认 cloud-api 或 runner 装配返回结构化 authorization blocker。

T4

阅读 docs/reference/spec-user-access.md,然后检查 source schema、migration 和 live Postgres,确认不存在旧设备授权表或旧 profile authority 表作为授权来源。

规格的实现情况

规格项 状态 说明
admin/user 两角色模型 已实现/持续约束 cloud-api 已实现 /auth/*、bootstrap admin、admin/user 创建和 admin-only route。
usersuser_sessionsapi_keys、OpenFGA relation 已实现/持续约束 当前授权只表达用户、session 和 tool capability;不保留旧设备授权 source。
Code Agent owner 绑定 已实现/持续约束 session owner、trace/result/cancel 必须按 owner 校验。
HWPOD 工具能力授权 目标状态 tool:hwpod 控制 runner 是否注入 HWPOD 能力;具体 HWPOD 执行链路见 spec-hwpod-harness.md