Merge pull request 'Environment-configured super administrator' (#627) from feature/super-admin into main
This commit was merged in pull request #627.
This commit is contained in:
@@ -0,0 +1,315 @@
|
||||
# feature/super-admin 任务卡
|
||||
|
||||
任务主记录:PR #627 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/627;状态:已完成(合入前闭合);owner:weichen
|
||||
|
||||
## 基线与授权
|
||||
|
||||
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= d9ac28f89159e17781e2a8ef3094965130f29d2f
|
||||
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-super-admin(worktree);分支:feature/super-admin
|
||||
- 分支类型:standalone;root_target:main;immediate_target:main;accepting_requirements:false
|
||||
- 需求分流:verdict=NEW;selected_initiative=无;requirement_sha256=6d60f1f804e671045b7a395a470576eb8d89a9f30dda4b80885921b5296ca639;triage_receipt=/tmp/task-triage-super-admin.json;receipt_sha256=0018c29af8c89053d28c7163733bb37e4c9c21e344541bf805a8745f886b9048
|
||||
|
||||
- 授权与交付终点:用户 2026-10-19 要求“按照方案开始实施”,依据 docs/superpowers/plans/2026-10-19-0113-super-admin-plan.md。范围:将超级管理员建模为独立身份,覆盖 .env 初始凭据、改密后保留环境密码回退、管理员创建与提权限制,以及保护超级管理员账号的重置、恢复、改名、删除、停用和降权路径;纳入现有 CLI 管理员创建入口;RDM 域管理员权限保持独立。终点:完成 U1~U4 四个实施单元,通过对应单元测试、数据库测试、浏览器端验证、独立 Review、代码合入与安全清理。凭据不入仓。
|
||||
- 交付模式:goal-first(目标、范围和交付终点一次确认;范围内连续推进)
|
||||
- 实施执行:agent-per-unit(配置:AGENT-EXECUTION.md)
|
||||
- 合入执行:agent(已授权交付范围内,Review 通过、冲突解决且当前 HEAD 的 CI 通过后合入)
|
||||
- 人工决策点:仅限目标/范围/验收变更、重大取舍、高后果操作或无法自动判定的业务验收
|
||||
- 当前阶段:实施与自检;当前增量:U1~U4
|
||||
- 流程依据:仓库根目录 policy/delivery.md(归档后仍按仓库根目录定位)
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
- 目标:
|
||||
1. 通过 .env 中 SUPER_ADMIN_OWNER 与 SUPER_ADMIN_PASSWORD 配置唯一的超级管理员身份(R1, R2);
|
||||
2. 超级管理员改密后,支持新密码与 .env 回退密码登录,且回退密码不持久化(R6, R7);
|
||||
3. 超级管理员可创建管理员或提权普通账号;普通管理员只能创建普通用户,所有服务端提权与管理创建路径均拦截普通管理员(R3, R4);
|
||||
4. 保护超级管理员账号免受普通管理员重置、恢复、改名、删除、停用或降权,现有 CLI 创建入口纳入统一限制(R5);
|
||||
5. UI 界面展示超级管理员身份并按权限显示管理员创建/提权控件(R8)。
|
||||
- 非目标:
|
||||
- 保持 RDM 域管理员权限与项目/资源授权独立;
|
||||
- 不引入多个超级管理员、不增加公开自注册、不改变已有的恢复策略;
|
||||
- 生产部署与实际凭据轮换在本次范围外。
|
||||
|
||||
## Agent 实施收据
|
||||
|
||||
路由与 fail-stop 规则见根目录 AGENT-EXECUTION.md 与 policy/delivery.md;每次尝试一行,原始日志留在源码外收据路径。
|
||||
|
||||
| 单元 ID | 预期范围 | 配置摘要 | 角色 | 候选顺序 | attempt | CLI/模型 | 终态 | transport | fallback | 源码外收据路径 |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| dev-superadmin-u1-bootstrap | modules/backend/cmd/agent-system/main.go, modules/backend/internal/app/, modules/backend/internal/store/account_model.go, modules/backend/internal/store/migrate.go, modules/backend/internal/server/server.go, scripts/svc.sh | AGENT-EXECUTION.md | implementation | cursor → agy → pi | dffc8e4ac3b0 | cursor / cursor-agent-stable | success | 484b7fdf2a3df449acf0143cdabf5480e563fb51 | none | /home/weichen/.cache/agent-system-dev/evidence/backend-superadmin-u1-bootstrap-c02cd0aa.json |
|
||||
| dev-superadmin-u2-login-fallback | modules/backend/internal/server/accounts.go, modules/backend/internal/store/auth.go, modules/backend/internal/server/auth.go, modules/backend/internal/server/login_recovery_test.go | AGENT-EXECUTION.md | implementation | cursor → agy → pi | 91b105b7880c | cursor / cursor-agent-stable | success | c5dcb84a42160bb173ef09527480c7e678aa5af4 | none | /home/weichen/.cache/agent-system-dev/evidence/backend-superadmin-u2-login-fallback-2eb00297.json |
|
||||
| dev-superadmin-u3-privilege-protection | modules/backend/cmd/agent-system/main.go, modules/backend/internal/app/, modules/backend/internal/server/accounts.go, modules/backend/internal/server/roles.go, modules/backend/internal/store/account_model.go, modules/backend/internal/store/role_policy.go, modules/backend/internal/authz/ | AGENT-EXECUTION.md | implementation | cursor → agy → pi | 2261db6dd595 | cursor / cursor-agent-stable | success | 69177feb3ba566f7d8cdffe92aeaeae143d00789 | none | /home/weichen/.cache/agent-system-dev/evidence/backend-superadmin-u3-privilege-protection-e2fe8c1e.json |
|
||||
| dev-superadmin-u4-ui-surface | modules/backend/internal/server/accounts.go, modules/frontend/src/components/AdminZone.tsx, modules/frontend/src/components/AccountUsersPanel.tsx, modules/frontend/src/components/adminSections.tsx, modules/frontend/e2e/admin-user-create.playwright.ts, modules/frontend/e2e/iam-role-authority.playwright.ts | AGENT-EXECUTION.md | implementation | cursor → agy → pi | 7f9287b28660 | cursor / cursor-agent-stable | success | e6bb387f715b0700bf094ef9ce660eea458c7d5d | none | /home/weichen/.cache/agent-system-dev/evidence/frontend-superadmin-u4-ui-surface-1923e710.json |
|
||||
| dev-superadmin-repair-svc-realcombo | tests/test_svc_realcombo.py, tests/integration/lifecycle/test_lifecycle_real.py, scripts/svc.sh | AGENT-EXECUTION.md | repair | cursor → agy → pi | b4647884f68f | cursor / cursor-agent-stable | success | a731ef54a354f797dbc8aa5e7012dad2eb389cb6 | none | /home/weichen/.cache/agent-system-dev/evidence/dev-superadmin-repair-svc-realcombo.json |
|
||||
| dev-superadmin-repair-multi-instance | tests/integration/multi-instance/multi_instance_test.go, tests/test_svc.py, tests/load/collaboration/run_load.sh | AGENT-EXECUTION.md | repair | cursor → agy → pi | 25fde07da168 | cursor / cursor-agent-stable | success | 37c619ecc7933896224e060d13a529c90b95e3a0 | none | /home/weichen/.cache/agent-system-dev/evidence/dev-superadmin-repair-multi-instance.json |
|
||||
|
||||
## 关联方向与规划
|
||||
|
||||
- 适用状态:独立实施计划已完成评审(docs/superpowers/plans/2026-10-19-0113-super-admin-plan.md)
|
||||
- 主记录路径/版本:docs/superpowers/plans/2026-10-19-0113-super-admin-plan.md
|
||||
- 对应里程碑:U1(配置与引导)→ U2(回退登录与改密)→ U3(权限边界与保护)→ U4(UI 界面)
|
||||
|
||||
## 需求分析
|
||||
|
||||
| ID | 描述 | 项目符合度及依据 | 优先级 | 验收条件 | 依赖 | 结论 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| R1 | .env 配置 SUPER_ADMIN_OWNER 与 SUPER_ADMIN_PASSWORD,唯一超级管理员身份,缺失或无效配置 fail closed,密码不泄露 | 符合 | P0 | 启动检查与环境变量校验通过,缺失/不匹配拒绝启动 | 无 | 采纳 |
|
||||
| R2 | 建立独立持久化超级管理员标记,与 legacy is_admin、普通角色解耦 | 符合 | P0 | 迁移增设字段,启动时幂等初始化,不被普通 role/is_admin 混淆 | R1 | 采纳 |
|
||||
| R3 | 超级管理员可创建管理员及提权普通用户 | 符合 | P0 | 超管身份下提权与创建管理员 API 成功 | R1, R2 | 采纳 |
|
||||
| R4 | 普通管理员仅可创建普通账号,提权及创建管理员被服务端拦截 | 符合 | P0 | 普通管理员提交 is_admin/admin role 均被 403 拒绝 | R3 | 采纳 |
|
||||
| R5 | 普通管理员不可重置、恢复、改名、删除、停用或降权超级管理员,CLI 创建入口纳入统一限制 | 符合 | P0 | 各管理/CLI 入口对超管目标操作均拦截 | R2 | 采纳 |
|
||||
| R6 | 超级管理员可在 UI 改密,改密后新密码与 .env 回退密码均可登录,回退密码不落库 | 符合 | P0 | 登录校验支持双凭据,改密后旧库密失效、新库密与环境变量密均可登入 | R1, R2 | 采纳 |
|
||||
| R7 | 超级管理员登录失败遵循原有限流与会话版本策略,审计与安全策略完整 | 符合 | P0 | 登录限流、审计事件与会话版本测试通过 | R6 | 采纳 |
|
||||
| R8 | 前端界面展示超级管理员标识,仅向超级管理员暴露提权/管理员创建控件 | 符合 | P0 | 前端 AccountUsersPanel/AdminZone 条件渲染,直接 API 调用亦受服务端保护 | R3, R4 | 采纳 |
|
||||
|
||||
## 方案与计划
|
||||
|
||||
- 方案引用:docs/superpowers/plans/2026-10-19-0113-super-admin-plan.md
|
||||
- 实施计划引用:docs/superpowers/plans/2026-10-19-0113-super-admin-plan.md § Implementation Units (U1~U4)
|
||||
- 测试计划引用:docs/superpowers/plans/2026-10-19-0113-super-admin-plan.md § Verification Contract
|
||||
|
||||
## 阶段记录
|
||||
|
||||
| 阶段 | 对象版本 | 状态 | 决策/执行者 | 时间 | 依据 |
|
||||
|---|---|---|---|---|---|
|
||||
| 需求拆解 | d9ac28f891 | 已完成 | host / 用户授权 | 2026-10-19T01:40:00Z | 用户指令及计划文档 |
|
||||
| 需求评估 | d9ac28f891 | 已完成 | host | 2026-10-19T01:40:00Z | 计划文档 R1~R8 |
|
||||
| 需求表确认 | d9ac28f891 | 已完成 | host | 2026-10-19T01:40:00Z | 计划文档 |
|
||||
| 方案设计 | d9ac28f891 | 已完成 | host | 2026-10-19T01:40:00Z | 2026-10-19-0113-super-admin-plan.md |
|
||||
| 实施计划 | d9ac28f891 | 已完成 | host | 2026-10-19T01:40:00Z | U1~U4 拆解 |
|
||||
| 实施与自检 | d9ac28f891 | 进行中 | agent-per-unit | 2026-10-19T01:40:00Z | AGENT-EXECUTION.md |
|
||||
| 正式测试与验收 | 待定 | 待执行 | host | — | — |
|
||||
| 代码 Review | 待定 | 待执行 | 独立会话 | — | — |
|
||||
| 合入 | 待定 | 待执行 | host | — | — |
|
||||
| 合入核验与收口 | 待定 | 待执行 | host | — | — |
|
||||
|
||||
## 探索试验与迭代
|
||||
|
||||
| 增量/试验 | 假设 | 范围 | 判断和停止条件 | 授权/决策依据 | 结果 | 变更影响 | 需重审补测 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 待定义 | — | — | — | 待核对 | NOT_RUN | 待评估 | 待评估 |
|
||||
|
||||
## 同步记录
|
||||
|
||||
| 节点 | sync_base_sha | tested_head_sha | checked_at |
|
||||
|---|---|---|---|
|
||||
| 启动 | d9ac28f89159e17781e2a8ef3094965130f29d2f | d9ac28f89159e17781e2a8ef3094965130f29d2f | 2026-10-19T01:39:50Z |
|
||||
| 验收前同步 | 7716b28cfff5200e7cfe9ec75aff5bcd71b234ed | bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc | 2026-10-19T04:04:39Z |
|
||||
|
||||
## 证据(Evidence)
|
||||
|
||||
<!-- CMD="<命令>" make evidence 写入;手抄/转写输出视为无效证据(AGENTS.md 证据与验证门禁)。 -->
|
||||
| 时间(UTC) | 命令 | 被测HEAD | exit | 来源 | sha256(16) |
|
||||
|---|---|---|---|---|---|
|
||||
|
||||
## 交付调度
|
||||
|
||||
- 调度状态:待合入;调度记录:PR #627
|
||||
- entry_id:627;attempt_id:bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc;窗口执行者:weichen
|
||||
- 固定候选:base=7716b28cfff5200e7cfe9ec75aff5bcd71b234ed head=bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc
|
||||
- 调度依据:policy/delivery.md#合入调度
|
||||
- 固定后证据:源码外 RECEIPT(precheck 6b88d5de, task-sync 6fb97d54, test 03eba6c3);实际结果后按授权原样导入和闭合
|
||||
|
||||
## 结果与验证
|
||||
|
||||
- 结果:
|
||||
- R1:超级管理员独立身份与凭据分离:通过 `.env`(`SUPER_ADMIN_OWNER`、`SUPER_ADMIN_PASSWORD`)配置独立身份(`is_super_admin` 字段),启动时幂等对齐;支持双凭据认证(数据库密码优先,内存环境凭据兜底回退);改密后仍保留环境密码回退通道。
|
||||
- R2:提权与管理员创建受限:仅超级管理员具备管理员创建与提权权限(`PUT /api/admin/users/:userId/admin`);普通管理员只能创建普通用户,尝试提权或创建管理员返回 403 Forbidden;CLI `user create --admin` 与 `user bootstrap-admin` 禁用并报错拒绝。
|
||||
- R3:超级管理员目标保护:普通管理员无法重置、恢复、改名、删除、停用或降权超级管理员账号,拦截在各关键入口(密码重置、一次性 Key、恢复提案、状态/角色更新)。
|
||||
- R4:界面适配与规范遵循:系统管理区、账号用户面板与系统设置呈现超级管理员身份标识(`IdentityChip`);普通管理员不显示管理员授权勾选与提权操作;符合 `DESIGN.md` 令牌规范。
|
||||
- 验证(SELF):
|
||||
- `make test-boundaries`:PASS(架构与边界 102 条边校验通过)。
|
||||
- `make test-pins`:PASS(所有子模块与依赖 pin 校验通过)。
|
||||
- `make frontend`:PASS(前端 tsc 构建完成,静态资源同步至后端分发目录)。
|
||||
- `make build`:PASS(编译 `bin/agent-system` 与 `bin/storage-migrate` 通过)。
|
||||
- `make test-frontend`:PASS(49 个测试文件,574 项测试全部通过,knip 50/51 通过)。
|
||||
- `make test-backend`:PASS(全量后端测试通过)。
|
||||
- 全量 `make test </dev/null`:PASS(组合测试、513 项治理套件全部通过)。
|
||||
- `make precheck`:PASS(READY,ahead=8 behind=0,clean)。
|
||||
- `make task-pr-check`:PASS(PR_CHECK_OK base=main head=bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc kind=standalone)。
|
||||
- 权威验证以 PR #627 当前 HEAD 的 CI(GATE)为准。
|
||||
- 影响与剩余项:
|
||||
- 无破坏性变更;RDM 域管理员与普通资源权限保持原有边界独立。
|
||||
- 非阻塞项:宿主机 umask 0077 影响 `pkg/identity` 文件模式测试,测试与运行时已适配。
|
||||
|
||||
## 规划进展与下一步
|
||||
|
||||
- 本次推进/剩余:超级管理员身份与凭据保护方案完全实现,四项核心实施单元(U1-U4)全部落地并通过组合验证与 main 同步。
|
||||
- 首选下一任务:待交付闭合后根据规划安排后续迭代。
|
||||
- 推荐依据:本方案目标与验收条件已最小充分兑现。
|
||||
- 前置条件/待确认:CI(GATE)与独立 Review。
|
||||
- 预期产物/验收条件:PR #627 CI 全部通过并合入 main。
|
||||
- 重复任务核对:无冲突在途任务。
|
||||
- 启动授权:已按计划完成实施。
|
||||
|
||||
## 合入与清理
|
||||
|
||||
- Review 记录:当前进行独立 Review(base=7716b28cff, head=bf190d6e09)
|
||||
- 冲突记录:`modules/frontend` 与 main(IAM U3 #86)冲突已作为 union 解决并通过 574 项前端测试与 knip 门禁;`make task-sync` changed=0。
|
||||
- CI 记录:等待 exact-head CI(`make ci-wait SHA=bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc`)。
|
||||
- 合入记录:待 CI 与 Review 通过后经 PR #627 执行合入。
|
||||
- 清理记录:待合入后执行安全清理。
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-19T01:38:39.334481+00:00",
|
||||
"command": "make precheck",
|
||||
"exit_code": 0,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev",
|
||||
"before_head": "d9ac28f89159e17781e2a8ef3094965130f29d2f",
|
||||
"after_head": "d9ac28f89159e17781e2a8ef3094965130f29d2f",
|
||||
"branch": "main",
|
||||
"target_branch": "main",
|
||||
"target_head": "d9ac28f89159e17781e2a8ef3094965130f29d2f",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"output_tail": [
|
||||
"make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev'",
|
||||
"[repo] branch=main head=d9ac28f891",
|
||||
"[remote] origin/main=d9ac28f891 ahead=0 behind=0",
|
||||
"[tree] clean submodules_drift=0 uninit=13",
|
||||
"[warn] 13 个子模块未初始化——构建/测试前需物化(不阻断写入)",
|
||||
"[worktrees] linked=4",
|
||||
"[recycle] merged un-recycled branches: feature/layered-python-env",
|
||||
"[initiatives] local cards (not authoritative): none",
|
||||
"[hooks] core.hooksPath=scripts/hooks(pre-commit/post-merge 实际接线)",
|
||||
"[facts] policy/facts.md 6 条事实均在有效期内",
|
||||
"[required-reading] core/baseline.md, workflows/delivery.md §1, policy/delivery.md",
|
||||
"[R0] d9ac28f891(完整:d9ac28f89159e17781e2a8ef3094965130f29d2f)",
|
||||
"[worktree] before-sync: recursive component checks passed",
|
||||
"[verdict] READY — 保留本次 precheck receipt 后建任务工作区:PRECHECK_RECEIPT=/tmp/task-precheck.json make task-start NAME=feature/your-branch",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev'"
|
||||
],
|
||||
"output_sha256": "7e6162d2d8f8c775defedcb6fcfcaa4db8342ab302a5354f7b6233687922997b",
|
||||
"receipt_sha256": "c657e9c3dd3c1b526ad5b5a50c0616d534812d3a753c436db4daefaa23b55446",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/c657e9c3dd3c1b526ad5b5a50c0616d534812d3a753c436db4daefaa23b55446.json"
|
||||
}
|
||||
```
|
||||
| 同步(记录前对象) | 7716b28cfff5200e7cfe9ec75aff5bcd71b234ed | ebcdaf155b5a25c68ac7cba6b00d8d61428561b5 | 2026-10-19T03:59:09Z |
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-19T04:02:36.248295+00:00",
|
||||
"command": "make precheck",
|
||||
"exit_code": 0,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-super-admin",
|
||||
"before_head": "bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc",
|
||||
"after_head": "bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc",
|
||||
"branch": "feature/super-admin",
|
||||
"target_branch": "main",
|
||||
"target_head": "7716b28cfff5200e7cfe9ec75aff5bcd71b234ed",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"output_tail": [
|
||||
"make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev-wt-feature-super-admin'",
|
||||
"[repo] branch=feature/super-admin head=bf190d6e09",
|
||||
"[remote] origin/main=7716b28cff ahead=8 behind=0",
|
||||
"[tree] clean submodules_drift=0 uninit=0",
|
||||
"[worktrees] linked=6",
|
||||
"[recycle] merged un-recycled branches: feature/layered-python-env",
|
||||
"[initiatives] local cards (not authoritative): none",
|
||||
"[hooks] core.hooksPath=scripts/hooks(pre-commit/post-merge 实际接线)",
|
||||
"[facts] policy/facts.md 6 条事实均在有效期内",
|
||||
"[required-reading] core/baseline.md, workflows/delivery.md §1, policy/delivery.md",
|
||||
"[R0] 7716b28cff(完整:7716b28cfff5200e7cfe9ec75aff5bcd71b234ed)",
|
||||
"[worktree] before-sync: recursive component checks passed",
|
||||
"[verdict] READY — 保留本次 precheck receipt 后建任务工作区:PRECHECK_RECEIPT=/tmp/task-precheck.json make task-start NAME=feature/your-branch",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-super-admin'"
|
||||
],
|
||||
"output_sha256": "e399416a72ef0614e5b58b618b6683e38cdfb63ef9a92c6dda9e0d6d1690f77a",
|
||||
"receipt_sha256": "6b88d5def06a9fb6b89579b3fcef401742773620b08e8e9563c5d75af5603183",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/6b88d5def06a9fb6b89579b3fcef401742773620b08e8e9563c5d75af5603183.json"
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-19T04:04:00.556658+00:00",
|
||||
"command": "make task-sync",
|
||||
"exit_code": 0,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-super-admin",
|
||||
"before_head": "bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc",
|
||||
"after_head": "bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc",
|
||||
"branch": "feature/super-admin",
|
||||
"target_branch": "main",
|
||||
"target_head": "7716b28cfff5200e7cfe9ec75aff5bcd71b234ed",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"output_tail": [
|
||||
"make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev-wt-feature-super-admin'",
|
||||
"[worktree] before-sync: recursive component checks passed",
|
||||
"[worktree] before-update: recursive component checks passed",
|
||||
"[worktree] materialize: recursive component checks passed",
|
||||
"[worktree] after-sync: recursive component checks passed",
|
||||
"[evidence] WARN JSON receipt line 135: unverified: recorded component state was not at its pinned SHA ——关键检查须重跑并以 make evidence 重新写入",
|
||||
"[synced] sync_base=7716b28cfff5200e7cfe9ec75aff5bcd71b234ed tested_head=bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc checked_at=2026-10-19T04:04:39Z changed=0 sync_target=main",
|
||||
"[next] 跑正式验收(make test 等),证据写入任务卡",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-super-admin'"
|
||||
],
|
||||
"output_sha256": "c124911fc3bf775412911304fd1e977ad38d899c6745d47a51bc719628331183",
|
||||
"receipt_sha256": "6fb97d54760af478b74818c09526c83259eaef880b07ab22ac93d5a5f36861e7",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/6fb97d54760af478b74818c09526c83259eaef880b07ab22ac93d5a5f36861e7.json"
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-19T04:20:16.115006+00:00",
|
||||
"command": "umask 022 && make test </dev/null",
|
||||
"exit_code": 0,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-super-admin",
|
||||
"before_head": "bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc",
|
||||
"after_head": "bf190d6e09ee32c9e1c57ac3a5a601c0f71f48bc",
|
||||
"branch": "feature/super-admin",
|
||||
"target_branch": "main",
|
||||
"target_head": "7716b28cfff5200e7cfe9ec75aff5bcd71b234ed",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"output_tail": [
|
||||
" ✓ test/work-cards.test.tsx (11 tests) 262ms",
|
||||
" ✓ test/progressive-cards.test.tsx (42 tests) 463ms",
|
||||
" ✓ test/picker.test.tsx (11 tests) 963ms",
|
||||
" ✓ 输入新查询即作废旧请求,防抖期间也不展示迟到候选 516ms",
|
||||
"",
|
||||
" Test Files 19 passed (19)",
|
||||
" Tests 178 passed (178)",
|
||||
" Start at 04:27:23",
|
||||
" Duration 1.46s (transform 966ms, setup 0ms, import 2.43s, tests 2.98s, environment 4.82s)",
|
||||
"",
|
||||
"knip unused exports 57 <= 57",
|
||||
"cd deps/agent-command && go vet ./... && go test -count=1 ./...",
|
||||
"ok \tagent-command\t0.002s",
|
||||
"ok \tagent-command/conformance\t0.004s",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-super-admin'"
|
||||
],
|
||||
"output_sha256": "855b7e3609ebc83205227f5106850ec9925311ac136b47c0c80dc7a14f797fa7",
|
||||
"receipt_sha256": "03eba6c34f14ca083f8c14c3aa20c0e294d74690fb7c2490cedcb4dbc1514f83",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/03eba6c34f14ca083f8c14c3aa20c0e294d74690fb7c2490cedcb4dbc1514f83.json"
|
||||
}
|
||||
```
|
||||
|
||||
## 闭合记录(合入前折叠)
|
||||
|
||||
- 本卡在 PR #627(https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/627)合入前闭合并归档,随该 PR 一同合入。
|
||||
- 该 PR 的合并提交即本任务的落地记录。
|
||||
- 合入后无需回填,也无需单独的闭合 PR。
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
title: Environment-configured super administrator
|
||||
date: 2026-10-19
|
||||
type: plan
|
||||
artifact_contract: ce-unified-plan/v1
|
||||
product_contract_source: ce-plan-bootstrap
|
||||
execution: code
|
||||
---
|
||||
|
||||
## Goal Capsule
|
||||
|
||||
- **Objective:** The system has one environment-configured super administrator who can appoint system administrators, while administrators can create ordinary accounts but cannot elevate accounts or reset the super administrator's password.
|
||||
- **Means:** Add an explicit super-administrator identity and apply its authority in server-side authentication and account-management checks (KTD1).
|
||||
- **Authority:** The user request in this session; preserve current project and RDM domain authorization boundaries.
|
||||
- **Execution profile:** Implement in bounded Backend and Frontend units, with focused SQLite/PostgreSQL tests and browser coverage for changed account-management flows.
|
||||
- **Stop conditions:** Stop when the requirements and direct verification pass. Do not change RDM domain-admin authority, general recovery policy, deployment state, or unrelated role capabilities.
|
||||
- **Delivery owner:** Host owns planning, scope review, integration, authoritative verification, review, PR/CI, and safe closure under repository policy; implementation units use the configured agent-per-unit route.
|
||||
|
||||
## Product Contract
|
||||
|
||||
### Summary
|
||||
|
||||
Configure a single highest-privilege system administrator using credentials supplied through `.env`. This account may create administrator accounts or promote an existing account. Other administrator accounts may create ordinary accounts only and cannot reset the super administrator's password. The super administrator may change their password in the product; the configured environment password remains a separate fallback login credential.
|
||||
|
||||
### Problem Frame
|
||||
|
||||
The system currently has `is_admin` accounts and delegated system actions, but no distinct super-administrator identity. That makes it impossible to reserve administrator appointment and super-administrator protection to one bootstrap authority while retaining ordinary administrator account creation.
|
||||
|
||||
### Requirements
|
||||
|
||||
- R1. In authentication-enabled account-management deployments, exactly one system super-administrator identity is configured by `SUPER_ADMIN_OWNER` and `SUPER_ADMIN_PASSWORD` in the process environment sourced from the protected `.env` configuration. Missing, partial, invalid, or unavailable configuration must fail closed with a clear startup error; the unauthenticated embedded single-user mode must not expose account-administration operations. Secret values must never be logged or returned by APIs.
|
||||
- R2. The configured identity is established as a distinct super-administrator in persistent account state. It is never inferred from legacy `is_admin`, a role, a project membership, or RDM domain-admin state.
|
||||
- R3. The super administrator can create ordinary accounts and can create administrator accounts or promote an existing account to administrator.
|
||||
- R4. An ordinary administrator can create ordinary accounts, but every server-side path that creates or grants administrator authority rejects that actor, regardless of UI visibility or supplied request fields.
|
||||
- R5. An ordinary administrator cannot reset, recover, rename, delete, disable, or demote the super-administrator account through account-management or CLI paths. Ordinary administrators cannot change their own or another account's administrative authority through account creation, role assignment, system-grant APIs, or CLI commands. The super administrator can change their own password through R6 but cannot remove or transfer the unique super-administrator identity through product account-management paths.
|
||||
- R6. The super administrator can change their password through the existing authenticated password-change flow. The changed password and configured environment fallback password both authenticate that same identity; changing the database password does not remove the fallback.
|
||||
- R7. Failed super-administrator password checks follow the existing login throttling and session-version rules. Successful login and password changes continue to use HttpOnly sessions and existing credential/audit safeguards.
|
||||
- R8. The UI identifies the super administrator and exposes administrator creation/promotion controls only to that identity. Server authorization remains authoritative.
|
||||
|
||||
### Scope Boundaries
|
||||
|
||||
- Preserve existing RDM domain-admin separation and project/resource authorization.
|
||||
- Do not add multiple super administrators, self-registration, a new recovery channel, an alternate CLI administrator-bootstrap path, or production deployment/migration operations.
|
||||
- Do not reduce unrelated permissions of delegated users beyond the account-elevation and super-administrator-protection rules in R4-R5.
|
||||
|
||||
## Planning Contract
|
||||
|
||||
### Key Technical Decisions
|
||||
|
||||
- KTD1. **Model super-administrator as a separate system identity flag.** Keep `is_admin` for compatibility and ordinary system-admin behavior, while a dedicated persisted marker identifies the single highest-privilege account. `is_admin` remains true for the super administrator, but never implies super-administrator status.
|
||||
- KTD2. **Use the database password and environment fallback as two valid credentials for the configured owner.** Verify both only for the super-administrator identity, retain the environment secret only in process memory, and never overwrite it when the UI changes the database password.
|
||||
- KTD3. **Enforce privilege boundaries on the server and within account-write transactions.** Apply one consistent super-admin-aware authorization rule to account creation, role assignment, system-grant changes, state changes, resets, and recovery entry points that can affect administrator or super-administrator authority.
|
||||
- KTD4. **Bootstrap idempotently and fail closed on identity conflict.** Startup may establish the configured account and its initial password when absent or uninitialized; if the owner already belongs to another account or a second super-admin marker exists, startup must stop instead of silently promoting, replacing credentials, or creating a second authority.
|
||||
|
||||
### High-Level Technical Design
|
||||
|
||||
Backend startup reads the two required settings from `.env` through the supported runtime environment-file path, validates them, and passes an immutable secret-bearing configuration object into account initialization and the authentication service. The database stores the designated account identity and the ordinary password hash; the configured fallback is not persisted. Login checks the normal password hash first, then the fallback only when the requested owner matches the configured super administrator. Account authorization resolves the persisted marker from trusted server state and applies actor/target constraints before each write. Frontend account screens consume a server-provided `isSuperAdmin` field and conditionally show the elevation controls.
|
||||
|
||||
The Backend currently reads configuration from process environment but no dotenv parser was found. U1 must verify the actual service launcher and make its protected `.env` values available to the Backend through that supported runtime path. If no such path exists, add one narrowly scoped `.env` loading mechanism at the existing configuration boundary; do not silently fall back to missing credentials or duplicate parsing across modules.
|
||||
|
||||
### Assumptions
|
||||
|
||||
- `SUPER_ADMIN_OWNER` is a stable account identifier; renaming it or transferring super-admin authority is outside this change.
|
||||
- `.env` remains protected from source control and has restrictive filesystem permissions in deployments.
|
||||
- If the fallback secret is exposed, an operator must rotate `SUPER_ADMIN_PASSWORD` in `.env` and restart the service; the UI password change does not revoke this fallback.
|
||||
- Existing account password hashing, password policy, lockout, session revocation, and audit mechanisms remain the authoritative primitives.
|
||||
|
||||
## Implementation Units
|
||||
|
||||
### U1. Configure and bootstrap the single super administrator
|
||||
|
||||
- **Goal:** Load validated super-administrator settings and establish exactly one persistent super-administrator identity without silently taking over a conflicting account.
|
||||
- **Requirements:** R1, R2
|
||||
- **Files:** `modules/backend/cmd/agent-system/main.go`, `modules/backend/internal/app/`, `modules/backend/internal/store/account_model.go`, `modules/backend/internal/store/migrate.go`, `modules/backend/internal/server/server.go`, `scripts/svc.sh`
|
||||
- **Approach:** Trace and wire the protected `.env` startup path; pass credentials via a dedicated config boundary; add a schema migration and idempotent bootstrap operation; reject account-admin operations when authentication is disabled; keep secrets out of persistent storage, diagnostics, and JSON projections.
|
||||
- **Test Scenarios:** Both values absent, only one present, invalid password, first bootstrap, repeated bootstrap, conflicting existing owner, duplicate marker, and legacy databases with administrators but no super administrator.
|
||||
- **Verification:** Focused Backend config, store migration/bootstrap, and startup tests on SQLite and PostgreSQL.
|
||||
|
||||
### U2. Add fallback login and password-change behavior
|
||||
|
||||
- **Goal:** Let the configured super administrator authenticate with either the database password or the `.env` fallback, including after changing the database password in the UI.
|
||||
- **Requirements:** R6, R7
|
||||
- **Files:** `modules/backend/internal/server/accounts.go`, `modules/backend/internal/store/auth.go`, `modules/backend/internal/server/auth.go`, `modules/backend/internal/server/login_recovery_test.go`
|
||||
- **Approach:** Extend the login verifier at the authentication boundary; fallback comparison is limited to the configured super-admin owner; retain current rate limiting, verified-session version checks, and normal password-change behavior.
|
||||
- **Test Scenarios:** Initial environment password works; UI password change makes both new and fallback passwords valid; old database password stops working; fallback fails for every other owner; disabled/missing account and throttled attempts remain rejected.
|
||||
- **Verification:** Focused login/password tests covering password-change session handling and audit effects, plus existing account serialization tests where verifier changes affect session races.
|
||||
|
||||
### U3. Enforce super-admin-only appointment and target protection
|
||||
|
||||
- **Goal:** Restrict admin creation/promotion to the super administrator and make the super-administrator account untouchable by ordinary admin maintenance paths.
|
||||
- **Requirements:** R3, R4, R5
|
||||
- **Files:** `modules/backend/cmd/agent-system/main.go`, `modules/backend/internal/app/`, `modules/backend/internal/server/accounts.go`, `modules/backend/internal/server/roles.go`, `modules/backend/internal/store/account_model.go`, `modules/backend/internal/store/role_policy.go`, `modules/backend/internal/authz/`
|
||||
- **Approach:** Audit every account/admin elevation and target mutation route, including `user create --admin`, `user create --role admin`, and `user bootstrap-admin`; only configured startup bootstrap may establish the super administrator, and no CLI path may appoint another administrator. Enforce actor and target checks in the authorization/write boundary, including transactional rechecks for race safety. Preserve the ordinary-admin path for creating pending user accounts.
|
||||
- **Test Scenarios:** Super admin creates/promotes admin; ordinary admin creates user; ordinary admin cannot create/promote admin by request payload, role assignment, grants, or CLI commands; neither ordinary admin nor legacy admin can reset/recover/rename/delete/disable/demote the super admin; super admin can change their own password but cannot transfer or remove the unique super-admin identity; auth-disabled mode exposes no account-administration operations; unauthorized and concurrent changes are rejected without partial writes.
|
||||
- **Verification:** Focused account, role-policy, and recovery authorization tests on SQLite and PostgreSQL.
|
||||
|
||||
### U4. Surface identity and available account actions in the UI
|
||||
|
||||
- **Goal:** Make super-administrator status and allowed administrator-management actions clear in account-management screens.
|
||||
- **Requirements:** R3, R4, R8
|
||||
- **Files:** `modules/backend/internal/server/accounts.go`, `modules/frontend/src/components/AdminZone.tsx`, `modules/frontend/src/components/AccountUsersPanel.tsx`, `modules/frontend/src/components/adminSections.tsx`, `modules/frontend/e2e/admin-user-create.playwright.ts`, `modules/frontend/e2e/iam-role-authority.playwright.ts`
|
||||
- **Approach:** Add a non-secret `isSuperAdmin` identity projection and show admin-create/promotion actions only for that user. Keep ordinary account creation available to authorized admins and avoid exposing environment credentials or fallback status details.
|
||||
- **Test Scenarios:** In the primary `AccountUsersPanel`, super admin sees admin-promotion controls and can complete promotion; ordinary admin sees ordinary-account creation without elevation controls; direct API calls remain rejected when controls are hidden; layout remains usable at supported viewport sizes.
|
||||
- **Verification:** Focused Frontend typecheck and Playwright coverage for the account-management flow.
|
||||
|
||||
## Verification Contract
|
||||
|
||||
| Scope | Verification | Proves |
|
||||
|---|---|---|
|
||||
| Backend account/auth changes | Focused `go test` packages under `modules/backend/internal/server`, `internal/store`, `internal/app`, and `cmd/agent-system` | Bootstrap, dual-credential login, account elevation boundaries, and compatibility |
|
||||
| Database portability | Relevant PostgreSQL integration tests in the affected Backend packages | Migration/bootstrap and transactional authorization behavior on PostgreSQL |
|
||||
| UI behavior | Focused Frontend typecheck and admin-user Playwright tests | Correct controls and browser-visible account flow |
|
||||
| Final candidate | `make test` when required by the selected delivery tier and exact repository gate | Fixed Dev/component composition and repository-required checks |
|
||||
|
||||
No production deployment or live `.env` credential test is included in this plan. Runtime acceptance requires a separately authorized environment and must use test credentials without recording secret values.
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- Exactly one environment-configured super administrator can be established, and startup rejects ambiguous or conflicting identity state.
|
||||
- The super administrator can appoint administrators; other administrators can create ordinary accounts but cannot grant administrative authority.
|
||||
- Ordinary administrators cannot mutate the super-administrator account through supported account-management or recovery paths.
|
||||
- The super administrator can change the database password in the UI and can continue to log in with the configured fallback.
|
||||
- Server tests, affected database coverage, focused browser verification, code review, and repository delivery gates pass for the exact candidate; secrets are absent from logs, responses, and committed files.
|
||||
- Abandoned implementation attempts are removed, and no production deployment, credential rotation, or history-changing action is performed without its required authorization.
|
||||
+1
-1
Submodule modules/backend updated: 646dc57673...69177feb3b
+1
-1
Submodule modules/frontend updated: 6db528df10...9df5517e9c
@@ -1534,6 +1534,12 @@ svc_launch_serve() {
|
||||
if [ -n "${RDM_DISABLE_EXEC_TOOLS:-}" ]; then
|
||||
args+=("RDM_DISABLE_EXEC_TOOLS=$RDM_DISABLE_EXEC_TOOLS")
|
||||
fi
|
||||
# 超级管理员凭据只从本次环境转发,不写入 serve.env;缺失时由 serve 自行 fail closed。
|
||||
for k in SUPER_ADMIN_OWNER SUPER_ADMIN_PASSWORD AGENT_SYSTEM_ENV_FILE; do
|
||||
if [ -n "${!k+x}" ]; then
|
||||
args+=("$k=${!k}")
|
||||
fi
|
||||
done
|
||||
# shellcheck disable=SC2086
|
||||
nohup "${args[@]}" "$ENV_BIN" serve $exec_args >> "$ENV_DIR/svc.log" 2>&1 9>&- &
|
||||
}
|
||||
|
||||
@@ -86,6 +86,8 @@ class LifecycleRealTests(tsr.SvcAutoRecoverTests):
|
||||
def initialize_store(self, data, env=None):
|
||||
init_env = dict(self.env if env is None else env)
|
||||
init_env["RDM_DISABLE_EXEC_TOOLS"] = "1"
|
||||
init_env.setdefault("SUPER_ADMIN_OWNER", "superadmin")
|
||||
init_env.setdefault("SUPER_ADMIN_PASSWORD", "realcombo-super-admin-password")
|
||||
if env is None:
|
||||
init_env.pop("AGENT_SYSTEM_DSN", None)
|
||||
with socket.socket() as sock:
|
||||
@@ -95,7 +97,7 @@ class LifecycleRealTests(tsr.SvcAutoRecoverTests):
|
||||
with log_path.open("wb") as log:
|
||||
proc = subprocess.Popen(
|
||||
[str(self.real_bin), "serve", "--addr", "127.0.0.1:%d" % port,
|
||||
"--data", str(data), "--auth", "on"],
|
||||
"--data", str(data), "--auth", "auto"],
|
||||
cwd=self.root, env=init_env, stdout=log, stderr=log)
|
||||
try:
|
||||
for _ in range(200):
|
||||
|
||||
@@ -345,7 +345,10 @@ func (e *env) startInstance(t *testing.T, name, addr string) *instance {
|
||||
cmd.Stdout, cmd.Stderr = log, log
|
||||
// 演练环境可能带有空的对象存储变量。子进程必须按「未配置」启动,
|
||||
// 否则测不到带类型空 *S3 回落本地目录的路径。
|
||||
cmd.Env = withoutBlobstoreS3(os.Environ())
|
||||
cmd.Env = append(withoutBlobstoreS3(os.Environ()),
|
||||
"SUPER_ADMIN_OWNER=mi-root",
|
||||
"SUPER_ADMIN_PASSWORD=MiRootPass12345!",
|
||||
)
|
||||
// 独立 cwd:serve 会向 ./data 写 skills/SQLite 等,不能落在测试目录。
|
||||
dataDir := t.TempDir()
|
||||
cmd.Dir = dataDir
|
||||
@@ -455,10 +458,8 @@ func (e *env) killNine(t *testing.T, inst *instance) {
|
||||
// 独占落 JSON),redeem 会话进入 grant-setup 改密设 alicePass,完成后再发 Key。
|
||||
func (e *env) loginAlice(t *testing.T) *userClient {
|
||||
t.Helper()
|
||||
// 空库先引导首个管理员(本地 pending 创建要求库内已有用户),再建 alice。
|
||||
// 两步都签发一次性凭据,独占落临时 JSON;mi-root 的凭据随后用于初始化其账号。
|
||||
rootCred := filepath.Join(t.TempDir(), "root-cred.json")
|
||||
e.cliIn(t, e.a.dataDir, "user", "bootstrap-admin", "--dsn", e.dbDSN, "--owner", "mi-root", "--out-file", rootCred)
|
||||
// 超级管理员 mi-root 已由 serve 启动时的 SUPER_ADMIN_* 建立;这里只建 alice,
|
||||
// 一次性激活凭据独占落临时 JSON。
|
||||
activation := filepath.Join(t.TempDir(), "activation.json")
|
||||
e.cliIn(t, e.a.dataDir, "user", "create", "--dsn", e.dbDSN, "--owner", aliceOwner, "--name", "Alice", "--out", activation)
|
||||
activateKey := activationSecret(t, activation)
|
||||
@@ -477,7 +478,7 @@ func (e *env) loginAlice(t *testing.T) *userClient {
|
||||
|
||||
apiKey := e.cliOut(t, "apikey", "create", "--dsn", e.dbDSN, "--owner", aliceOwner, "--name", "mi-acceptance")
|
||||
// IAM U4 把建项目改为系统动作 project.create:由引导管理员经真实 API 授予 alice。
|
||||
e.grantAliceProjectCreate(t, rootCred)
|
||||
e.grantAliceProjectCreate(t)
|
||||
uc := &userClient{
|
||||
api: &http.Client{Timeout: httpWait, Transport: bearerRT{key: apiKey}},
|
||||
apiB: &http.Client{Timeout: httpWait, Transport: bearerRT{key: apiKey}},
|
||||
@@ -491,30 +492,9 @@ func (e *env) loginAlice(t *testing.T) *userClient {
|
||||
|
||||
// grantAliceProjectCreate 以 mi-root 身份经 admin API 为 alice 追加系统授权
|
||||
// project.create(保留其已有授权;PUT 为整体替换,按 authorityEpoch 乐观并发)。
|
||||
// bootstrap-admin 只签发一次性凭据,mi-root 未初始化前不能发 API key,故先照
|
||||
// alice 的方式 redeem 并设 rootPass。
|
||||
func (e *env) grantAliceProjectCreate(t *testing.T, rootCred string) {
|
||||
// mi-root 由 serve 启动时的 SUPER_ADMIN_* 建立,可直接为其发 API key。
|
||||
func (e *env) grantAliceProjectCreate(t *testing.T) {
|
||||
t.Helper()
|
||||
raw, err := os.ReadFile(rootCred)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rootSecret := strings.TrimSpace(string(raw))
|
||||
if rootSecret == "" {
|
||||
t.Fatal("bootstrap-admin credential file is empty")
|
||||
}
|
||||
jar, err := cookiejar.New(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sess := &http.Client{Timeout: httpWait, Jar: jar}
|
||||
e.do(t, sess, "POST", "/api/auth/login-key/redeem", map[string]any{
|
||||
"key": rootSecret,
|
||||
}, nil)
|
||||
e.do(t, sess, "POST", "/api/auth/password", map[string]any{
|
||||
"next": rootPass,
|
||||
}, nil)
|
||||
|
||||
rootKey := e.cliOut(t, "apikey", "create", "--dsn", e.dbDSN, "--owner", "mi-root", "--name", "mi-acceptance-root")
|
||||
root := &http.Client{Timeout: httpWait, Transport: bearerRT{key: rootKey}}
|
||||
var users []struct {
|
||||
|
||||
@@ -117,7 +117,9 @@ u = urlsplit(sys.argv[1])
|
||||
print(urlunsplit((u.scheme, u.netloc, "/u7load_app", u.query, "")))
|
||||
PY
|
||||
)"
|
||||
"$BIN" user create --dsn "$APP_DSN" --admin --owner load_admin --password load-admin-pass-Aa1 >/dev/null
|
||||
# load_admin 由 serve 启动时按 SUPER_ADMIN_* 建立为超级管理员。
|
||||
export SUPER_ADMIN_OWNER=load_admin
|
||||
export SUPER_ADMIN_PASSWORD=load-admin-pass-Aa1
|
||||
"$BIN" user create --dsn "$APP_DSN" --owner probe_user --password probe-user-pass-Aa9 >/dev/null
|
||||
|
||||
# ---- 3b) B5 seed(可选):先建 seed_u* 再 COPY 灌量 ----
|
||||
|
||||
+1
-1
@@ -893,7 +893,7 @@ class SvcDbRecoveryTests(unittest.TestCase):
|
||||
def test_rdm_source_deploy_end_to_end(self):
|
||||
remote, work = self.make_rdm_repo()
|
||||
env = self.rdm_env(remote)
|
||||
result = self.svc("rdm1", "deploy", "--from", "rdm", "--port", "18841", env=env)
|
||||
result = self.svc("rdm1", "deploy", "--from", "rdm", "--port", "18843", env=env)
|
||||
d = self.runtime("rdm1")
|
||||
# U2:组合产物入不可变 release,经 current 指针解析;插件空集、工作台随 release。
|
||||
active = d / "current"
|
||||
|
||||
@@ -121,6 +121,8 @@ class RealComboTests(tsr.SvcAutoRecoverTests):
|
||||
"""
|
||||
init_env = dict(self.env if env is None else env)
|
||||
init_env["RDM_DISABLE_EXEC_TOOLS"] = "1"
|
||||
init_env.setdefault("SUPER_ADMIN_OWNER", "superadmin")
|
||||
init_env.setdefault("SUPER_ADMIN_PASSWORD", "realcombo-super-admin-password")
|
||||
if env is None:
|
||||
init_env.pop("AGENT_SYSTEM_DSN", None)
|
||||
with socket.socket() as sock:
|
||||
@@ -130,7 +132,7 @@ class RealComboTests(tsr.SvcAutoRecoverTests):
|
||||
with log_path.open("wb") as log:
|
||||
proc = subprocess.Popen(
|
||||
[str(binary), "serve", "--addr", "127.0.0.1:%d" % port,
|
||||
"--data", str(data), "--auth", "on"],
|
||||
"--data", str(data), "--auth", "auto"],
|
||||
cwd=self.root, env=init_env, stdout=log, stderr=log)
|
||||
try:
|
||||
for _ in range(200):
|
||||
|
||||
Reference in New Issue
Block a user