---
name: unidesk-secret
description: UniDesk 统一管理员密码的 YAML-first 分发与清理技能。用户提到统一管理员密码、unified-admin-password、OA/PikaOA、SelfMedia、HWLAB/lab、Sub2Rank 或 ApiState 的管理员密码轮换、Secret 同步、开发版与生产版密码对齐、清理服务级 admin password 时使用。
---

# UniDesk 统一管理员密码

遵循 `Skill(cli-spec)`，只通过 owning YAML、领域受控 CLI 和 `web-probe` 分发与验收，不读取、打印或从运行面反解密码。

- 通用 Secret 生命周期、工具改进和跨服务治理任务统一用 TaskTree 跟踪；遗留 MDTODO 按 `$unidesk-tasktree` 迁移。

## 唯一事实源

- 统一管理员密码只保存在 `/root/.unidesk/.env/unified-admin-password.txt`。
- 文件必须是 owner-only `0600` raw file，只包含一行密码。
- `config/secrets-distribution.yaml` 声明 raw-file source 和 Kubernetes `targetKey` 映射。
- `config/pikaoa.yaml` 声明 PikaOA development/release 管理员密码来源。
- `config/hwlab-node-lanes.yaml` 声明 HWLAB development/production bootstrap admin hash 来源。
- `config/hwlab-web-probe-sentinel/*.yaml` 的 bootstrap-admin 和 admin account 来源必须指向同一文件。
- 各应用可以保留不同 `targetKey`、Secret 名和 hash transform，但不得保留不同密码来源。

## 明确边界

- 统一以下管理员登录：
  - PikaOA `pikaoa` 与 `pikaoa-dev`；
  - SelfMedia `selfmedia` 与 `selfmedia-production`；
  - HWLAB `v03` 与 `production`；
  - Sub2Rank/ApiState 的 `APISTATE_WEB_PASSWORD`。
- 不统一以下非管理员凭据：
  - PikaOA employee 密码；
  - API key、session secret、admin token；
  - 数据库密码和 FRP token；
  - Sub2Rank 访问 Sub2API 的 `SUB2API_ADMIN_PASSWORD`；
  - HWLAB 第二测试账号和 OpenCode 账号密码。

## 分发流程

1. 先确认 source 文件 presence、字节数、SHA-256 fingerprint 和 `0600`，不得输出内容。
2. 检查 owning YAML 中所有管理员 sourceRef 均指向统一文件。
3. 对每个 Secret scope 先执行 `secrets plan`，再执行 `secrets sync --confirm`，最后按 job ID 查询终态并执行 `secrets status`。
4. HWLAB 先执行 `hwlab nodes secret ensure --node NC01 --lane <lane> --name <bootstrap-secret> --dry-run`，确认后改为 `--confirm` 同步 hash Secret 和 rollout。
5. 用领域 status/validate 确认 Secret key presence、fingerprint、Deployment rollout 和 health；输出必须保持 `valuesPrinted=false`。
6. 用 `web-probe` 从 owning YAML 选择 public origin，分别验证 development 与 production 管理员登录。
7. 只有所有目标分发和登录验收通过后，才清理旧服务级密码文件或 env 键。

运行面判定：

- PikaOA 的 `PIKAOA_BOOTSTRAP_ADMIN_PASSWORD` 只用于创建尚不存在的管理员：
  - `secrets sync` 和 Deployment rollout 不会轮换数据库中已有管理员的密码哈希；
  - sync 完成后先用已投影的 `OA_ADMIN_TOKEN` 执行 `whoami`，再用 `employees update <admin-id> --password-stdin` 从统一 raw file 经 stdin 显式轮换；
  - 密码不得进入命令参数、日志、issue 或报告；
  - `OA_ADMIN_TOKEN` 未投影时：
    - 先修正当前 consumer 的 YAML/source artifact；
    - 禁止从 Kubernetes Secret 反解 token 或启动临时高权限 Pod 绕过。
- Secret apply 成功但 consumer rollout 失败时，先用领域 status 区分运行面未部署和已部署 workload 异常：
  - namespace 存在但 workload 为 `0/0` 时，记录为“Secret 已预置、登录不适用”，不得重复 restart 或宣称密码已在业务入口生效；
  - workload 存在时，rollout 未 ready 属于分发未完成，禁止清理旧来源。
- 只使用已有 repo-owned typed command 验证登录：
  - PikaOA development 使用 `web-probe product-smoke --product pikaoa --target NC01 --profile admin-mvp --runtime development`；
  - PikaOA release 使用 `web-probe product-smoke --product pikaoa --target NC01 --profile admin-mvp --runtime release`；
  - Sub2Rank/ApiState 使用 `web-probe product-smoke --product apistate --target NC01 --profile operations`；
  - HWLAB 已部署 lane 使用 `web-probe run --node <node> --lane <lane> --origin public`。
- WebProbe 报告底层错误为 `Target page, context or browser has been closed` 时：
  - 结论是 `browser=blocked`，不是密码错误；
  - 公网 PikaOA CLI 登录可以独立证明账号密码有效，但不得冒充浏览器验收；
  - 停止重复浏览器尝试，按 `$unidesk-webdev` 处理受控浏览器运行面。
- SelfMedia target 没有启用只读 typed login smoke 时：
  - 不得复制临时浏览器脚本、手写 URL 或使用会保存业务设置的 SelfMedia `voice-algorithm` smoke 代替；
  - 以 Secret status、consumer rollout 和公开 health 分层报告，并把缺失的只读登录入口登记为独立工具改进。

Secret 分发高频入口：

```bash
bun scripts/cli.ts secrets plan --config config/secrets-distribution.yaml --scope <scope> --target <target>
bun scripts/cli.ts secrets sync --config config/secrets-distribution.yaml --scope <scope> --target <target> --confirm
bun scripts/cli.ts secrets status --config config/secrets-distribution.yaml --scope <scope> --target <target>
```

目标矩阵：

- `pikaoa` / `pikaoa-nc01`；
- `pikaoa-dev` / `pikaoa-dev-nc01`；
- `selfmedia` / `selfmedia-nc01`；
- `selfmedia-production` / `selfmedia-production-nc01`；
- `sub2rank` / `sub2rank-nc01`。

清理后的五目标最短复核入口：

```bash
while read -r scope target; do
  bun scripts/cli.ts secrets plan \
    --config config/secrets-distribution.yaml \
    --scope "$scope" \
    --target "$target" |
    jq '{ok: .ok, targetId: .data.config.targetId, localSourcesOk: .data.localSources.ok, missingKeys: [.data.localSources.entries[] | .missingKeys[]?], unifiedPresent: ([.data.localSources.entries[] | select(.sourceRef == "/root/.unidesk/.env/unified-admin-password.txt") | .presence] | any), valuesPrinted: .data.policy.valuesPrinted}'
done <<'TARGETS'
pikaoa pikaoa-nc01
pikaoa-dev pikaoa-dev-nc01
selfmedia selfmedia-nc01
selfmedia-production selfmedia-production-nc01
sub2rank sub2rank-nc01
TARGETS
```

- 五行结果必须同时满足：
  - `ok=true`；
  - `localSourcesOk=true`；
  - `missingKeys=[]`；
  - `unifiedPresent=true`；
  - `valuesPrinted=false`。
- 该入口只做清理后反证，不替代 sync job 终态、运行面 status 或登录 smoke。

## 清理规则

- 删除 `pikaoa-admin-password.txt` 和含不可见字符的旧 unified 文件名。
- 从 `selfmedia-access.env` 删除 `SELFMEDIA_ADMIN_PASSWORD`，保留 username、API key 和 session secret。
- 从 `platform-infra/apistate.env` 删除 `APISTATE_WEB_PASSWORD`，保留 API key 和 session secret。
- 删除只包含 `HWLAB_BOOTSTRAP_ADMIN_PASSWORD` 的旧 bootstrap-admin env 文件。
- `hwlab.auth` 或 `HWLAB_admin.txt` 若同时保存用户名，只删除密码行并保留用户名；owning YAML 不得再引用其密码行。
- 清理后重新执行 plan，确认旧 source 不再是 required source，统一 source 仍为 present。
- 禁止用 Secret decode、Pod env、数据库或日志回填旧来源。

## 验收判定

- 所有声明只引用一个管理员密码 sourceRef。
- Secret sync 成功，consumer rollout 成功，status key presence 完整。
- PikaOA、SelfMedia、HWLAB、Sub2Rank/ApiState 的 development/production 目标按实际存在矩阵通过管理员登录。
- 旧服务级管理员密码来源已删除或移除对应键。
- 全程只披露路径、键、presence、fingerprint、字节数、job/trace/artifact ID 和状态。
