4 Commits

Author SHA1 Message Date
ThearchyHelios 19329c873e 访问密钥与服务账号的后端(下一轮第 2 波 W2-d,细案 04 A1–A6、总方案 X8)
外部系统(门户、OA、BI)和个人脚本要用一个身份调接口,以前只能拿个人会话 cookie 去模拟。这次加访问密钥:

- 签发(A1):users.kind 区分人和服务账号(svc- 开头、没有口令、不能登录、角色固定使用者,管理员建);access_keys 只存
  sha256 和开头一截,明文 agl_ 加 32 字节随机串只显示一次;到期必填(最长 365 天、缺省 90 天)、可撤销、可轮换(新钥 + 旧钥
  24 小时后到期);个人访问密钥由管理员开关 auth.personal_keys 管,缺省关,关掉时已有的个人密钥一并不认
- 认人与门禁(A2):Principal 加 via / key_id / key_name / scopes / app_ids(全部带默认值);中间件认 Bearer agl_…,不看
  cookie、不查 CSRF、不看 X-Actor,认不出的各回 401 带各自的 code、绝不退回匿名;WebSocket 带密钥一律拒;关登录时 409
  keys_need_login。KEY_ROUTES(方法 + 路由模板 → scope)一张表,FastAPI(dependencies=[Depends(key_gate)]) 挂一次;不在表里的
  403 key_route_forbidden,缺 scope、限定应用、个人应用和试运行各有各的 403;每把密钥每分钟 120 次(429 + Retry-After)
- 封顶(A3):按密钥认出来的一律是使用者(拥有者现在的组),现有的使用者规则和遮罩全部自动生效,管理员的密钥也一样
- 写操作(A4):发起入口、刷新视图必须带 Idempotency-Key,api_receipts 按(拥有者, 键)去重,轮换后照样认得出;状态机从
  process/hooks.py 抽到 process/receipts.py,钩子和密钥共用(钩子现有测试原样通过),另按请求指纹拒掉同一个键办另一件事;
  有文件控件的入口 422;回复待办只给个人密钥、只限审批 / 补充输入 / 编辑稿件;run.origin、task.responded 记 via=key、哪把密钥
- 视图数据(A5):GET /api/apps/{id}/views/{view}/data(agentlab.viewdata/1),印章、清单哈希、口径卡指标原值和渲染文字,
  遮罩的 value 为 null(和页面同一个判断),按需视图只读缓存、不发起运行,只给正式运行
- 留痕(A6):建 / 撤销 / 轮换密钥、建 / 停用服务账号、开关个人密钥写审计;请求记录进程内缓冲、调度循环一拍里批量写、
  保留 90 天;last_used_at 至少隔 1 分钟写一次;钩子收件记录接口(manage),验签失败只在进程内按钩子计数
- 名录与派单:服务账号在名录里标出,岗位绑定、选人候选、提交审核、改派里排除,应用授权照收;服务账号发起的实例里派给发起人
  的待办交给任何人
- 接口说明(A7):GET /api/access-keys/reference 从 KEY_ROUTES 生成(要登录)

测试:签发与各种 401、门禁合约(遍历全站路由)、CSRF 与身份来源、封顶(管理员密钥取工件也是遮过的)、幂等(含轮换后、
半路杀进程)、留痕、待办种类、视图数据(真跑的遮罩会员库)、限流、钩子收件记录。
2026-10-16 13:48:09 +08:00
ThearchyHelios fbb671a96b 使用者选人(前端):选人控件按池边输入边取候选;个人渠道的实例事件改叫「我发起的实例完成 / 失败」
为什么:使用者读不到名录,选人控件只能凭记忆手填用户名,填错了服务端以前也照收(05-已知遗留 (b))。服务端已按用途给候选池、
开登录时按同一个池核对(上上个提交),前端要把候选给到人手上。另外个人渠道勾「实例完成 / 失败」以前永远收不到,服务端修好之后
(驳回那个提交里的 notify_run),名字要照实写成只推自己发起的实例(04-对外集成与触达 B1)。

做了什么:
- PrincipalPicker 加 source(CandidateSource:form 带 app_id+entry 或 task_id 和 field,review)。搭建者及以上照旧用整份名录;
  使用者开了登录、给了 source 时边输入边按开头取候选(250 毫秒防抖),列表里显示显示名、标签悬停给用户名;加的时候按同一个池
  问一次服务端,不在池里的当场说「「x」不在可选的人里」(问不到就先收下,提交时由服务端判);池要先输开头才列、列不全时照实提示。
- SchemaForm 按表单用在哪(入口、待办,同上传文件的上下文)给选人控件 source;个人应用提交审核用 purpose=review。
- typesApp:CandidateSource、Candidates、FormField 的 x-principal、FormError 的 principal 码(和服务端 FORM_ERROR_CODES 同序)。
- api.identity.candidates。termsApp 的 PRINCIPAL_TEXT 加三句。
- 设置 → 通知:范围是「仅自己」的渠道,run.finished / run.failed 写「我发起的实例完成 / 失败」(termsApp.NOTIFY_PERSONAL_EVENT_LABEL)。
- 服务端 x-principal 写法不对时的说法改成不带半角冒号接中文的写法(check-copy)。
2026-10-16 10:54:30 +08:00
ThearchyHelios a59409cc85 使用者选人(后端):按用途给候选池,开登录时入口表单、待办表单的选人控件按同一个池核对
为什么:使用者在选人控件里没有候选(名录只给搭建者),服务端也不核对。填错的名字原样派下去,待办给了一个不存在的人,
没人能处理、也不报错(05-已知遗留 (b))。名录又不能整份放开给使用者(只读与最小可见)。

做了什么:
- auth/directory 新增候选池:form 用途缺省是「能用这个应用的人」——使用及以上的授权(人;组列出组本身并展开成员),
  加上管理它的人(管理员、建应用的人);应用授权给了所有人时池是全部启用的人(open),不带前缀 q 不列(needs_query)。
  字段可以声明 x-principal: {pool: app | group:<组> | slot:<岗位>}(slot 按这次用到的应用版本的 bindings 展开)。
  review 用途是启用的搭建者和管理员(同 personal._review_targets)。停用的人一律不列。
- GET /api/directory/candidates(任何登录的人;main.py 路由清单只加一行):purpose=form 带 app_id+entry 或 task_id、field,
  调用的人不能用这个应用 403;只回 {users:[{username, display_name}], groups, truncated, needs_query?},不给停用、角色、
  邮箱、组成员;q 按用户名或显示名开头筛,limit 最多 50。/api/directory 仍只给搭建者。
- 开了登录时 start_entry 和待办表单提交按同一个池核对,不在池里 422,errors 的 code=principal(FORM_ERROR_CODES 加一项),
  话写成「「x」不在可选的人里,请从候选中选择」(单点登录另说要先登录一次才进名录)。直接生效(遗留-Q4 按推荐)。
  关登录照旧手填、不核对;不属于应用的待办(试运行、画布)没有池,不核对。
- apps/forms:x-principal 进 _FIELD_KEYS,validate_form_schema 查写法(只能写在选人控件上、只能是三种池)。

搭建者没有授权时按 apps/access 只能「查看全部实例」,不算池里的人——池按「能用」算,这一点写进了 app_pool 的说明。

测试:test_directory_candidates(只给名字、停用的不列、前缀筛、没使用权 403、名录仍 403;授权给所有人要前缀、截断;review
只出搭建者和管理员;入口表单不在池 422、停用的 422、组名和池里的人放行;待办表单同一个池;声明 group:<组> 收窄;关登录
任何名字照收;x-principal 写法校验)。
2026-10-16 10:24:22 +08:00
ThearchyHelios e182c2d214 复测收尾:账号密码登录时应用检查和授权接口核对名录(没有的、已停用的报错或拒收,单点登录只提醒),名录口径收成 auth/directory 一处;受管发布版在页头、版本历史、选择器、发布前检查里按发布级别写,草稿和发布版内容相同时照实说;写入能力在工具库写「只演练」;印章的「截至」只写一次;走驳回出口到达的结局不用成功样式;停着等人时说在等哪一步,同页已有会签进度时待办状态不再画一遍,名单写显示名;应用编辑器可以归档(写清后果),已归档的应用拒收草稿修改和发布;受管发布成功的提示写明受管;权限测试按 id 取应用,不撞别的测试留下的同名应用 2026-10-15 08:35:28 +08:00