265 lines
9.6 KiB
Markdown
265 lines
9.6 KiB
Markdown
# Windows Node MVP 实施方案(内网版)
|
||
|
||
> **当前有效的第一阶段开发依据。**本文件取代 `windows-node-mvp.md` 中的 MVP 通信与注册方案。
|
||
> 长期演进边界见 `windows-node-design.md`。
|
||
> 首批能力:`origin.plot@v2`。
|
||
|
||
## 1. 适用边界
|
||
|
||
本方案成立的前提:
|
||
|
||
- zcbot 与 Windows Node 位于同一受控内网、云 VPC 或专用 VPN;
|
||
- 两端使用固定私网地址或内网 DNS;
|
||
- zcbot 的 Node 接口只监听私网地址;
|
||
- 安全组仅允许指定 Node IP 访问指定 zcbot 端口;
|
||
- 通信不经过公网、访客网或不可信办公终端所在网络。
|
||
|
||
MVP 使用:
|
||
|
||
```text
|
||
注册、状态和文件:HTTP
|
||
任务控制长连接:WS
|
||
节点认证:每个 Node 独立的长期 Bearer Token
|
||
```
|
||
|
||
HTTP/WS 不加密传输,Node Token、输入数据、截图和产物在链路上均为明文。如果上述网络边界发生变化,必须先升级 HTTPS/WSS。
|
||
|
||
## 2. MVP 架构
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
Z["内网 zcbot"] <-->|"HTTP + WS<br/>独立 Node Token"| N["Windows Node.exe<br/>登录会话自动启动"]
|
||
N --> P["Origin Python Worker"]
|
||
P --> O["Origin / OriginPro"]
|
||
P --> F["独立任务目录"]
|
||
N -->|"状态、截图、产物"| Z
|
||
```
|
||
|
||
第一版只有两个进程:
|
||
|
||
- `Zcbot.WindowsNode.exe`:.NET 10,负责注册、自动连接、任务状态、进程控制、截图和上传;
|
||
- `OriginAdapter.Worker`:固定 Python 环境,使用 `originpro` 生成 OPJU、PNG、SVG 和 PDF。
|
||
|
||
Node 首期运行在持续登录的专用 Windows 用户会话,通过计划任务在登录后自动启动。暂不拆 Windows Service 与 DesktopRunner。
|
||
|
||
## 3. Node 注册
|
||
|
||
### 3.1 操作流程
|
||
|
||
1. 管理员在 zcbot 管理端创建一次性注册码,默认 10 分钟有效。
|
||
2. Windows Node 首次启动时输入 zcbot 内网地址、节点名称和注册码。
|
||
3. Node 调用内网注册接口。
|
||
4. zcbot 原子消费注册码并返回 `node_id + node_token`。
|
||
5. Node 使用 Windows DPAPI 加密保存 Token。
|
||
6. 此后 Node 或 Windows 重启时自动建立 WS 连接,不再要求人工输入。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as 管理员
|
||
participant Z as zcbot
|
||
participant N as Windows Node
|
||
A->>Z: 创建一次性注册码
|
||
A->>N: 输入内网地址和注册码
|
||
N->>Z: HTTP POST /v1/software-nodes/enroll
|
||
Z->>Z: 校验并原子消费注册码
|
||
Z-->>N: node_id + node_token + 配置
|
||
N->>N: DPAPI 加密保存 node_token
|
||
N->>Z: 携带 Bearer Token 建立 WS
|
||
Z-->>N: active
|
||
```
|
||
|
||
注册请求:
|
||
|
||
```http
|
||
POST http://zcbot.internal:8765/v1/software-nodes/enroll
|
||
Content-Type: application/json
|
||
```
|
||
|
||
```json
|
||
{
|
||
"enrollment_code": "ZCN-7H4K-9P2M",
|
||
"node_name": "win-origin-01",
|
||
"install_id": "019...",
|
||
"node_version": "0.1.0",
|
||
"os_version": "Windows 11 Enterprise 24H2",
|
||
"capabilities": ["origin.plot@v2"]
|
||
}
|
||
```
|
||
|
||
注册响应:
|
||
|
||
```json
|
||
{
|
||
"node_id": "019...",
|
||
"node_token": "仅返回一次的高熵随机 Token",
|
||
"heartbeat_seconds": 15,
|
||
"max_concurrency": 1
|
||
}
|
||
```
|
||
|
||
### 3.2 注册与 Token 底线
|
||
|
||
- 注册码一次性、短期有效,云端只保存哈希;
|
||
- 注册码可以绑定预期节点名称和允许能力;
|
||
- 注册成功或达到失败尝试上限后立即失效;
|
||
- 每个 Node 使用不同 Token,禁止共享全局永久 Token;
|
||
- Token 至少包含 32 字节密码学安全随机数;
|
||
- zcbot 数据库只保存 Token 强哈希,明文仅在注册响应返回一次;
|
||
- Node 使用 Windows DPAPI `LocalMachine` 加密 Token,并用文件 ACL 限制为 Node 运行账号可读;
|
||
- Token 只放 `Authorization` Header,不进入 URL、查询参数或日志;
|
||
- Node 不上传 Windows 密码、许可证密钥或完整硬件指纹;
|
||
- 管理员可以禁用 Node 或轮换 Token;禁用后立即拒绝连接、任务和上传;
|
||
- Windows 重装、本地身份丢失或克隆云盘后必须重新注册。
|
||
|
||
## 4. 自动连接与重连
|
||
|
||
### 4.1 WS 连接
|
||
|
||
```http
|
||
GET ws://zcbot.internal:8765/v1/software-nodes/connect
|
||
Authorization: Bearer <node_token>
|
||
X-Node-Id: <node_id>
|
||
Upgrade: websocket
|
||
```
|
||
|
||
HTTP 注册、状态、文件上传下载和 WS 长连接使用相同的 Node Token,不增加短期 connection token、HMAC、nonce、时间戳签名或证书体系。
|
||
|
||
连接后 Node 上报:
|
||
|
||
- Node、OS 和 Origin 版本;
|
||
- capability 和可用 slot;
|
||
- 本机磁盘和桌面会话状态;
|
||
- 本地运行中或尚未确认终态的 job 摘要。
|
||
|
||
同一 `node_id` 只保留一个活动连接。新连接成功后关闭旧连接。MVP 单节点场景下,发现相同身份来自不同 `install_id` 时拒绝新连接并提示重新注册,避免云盘克隆产生双执行者。
|
||
|
||
### 4.2 重连策略
|
||
|
||
- 断线后按 1、2、5、10、30、60 秒并加随机抖动重连;
|
||
- 最大间隔 60 秒;
|
||
- 正在运行的 Origin 任务不因 WS 断开而终止;
|
||
- 重要终态与上传状态写入本地 SQLite,重连后补报;
|
||
- `401/403` 表示 Token 失效,停止高频重试并显示“需要重新注册”;
|
||
- 连接超时和 `5xx` 继续退避重试;
|
||
- Windows 网络恢复时立即触发连接尝试。
|
||
|
||
## 5. 内网安全配置
|
||
|
||
最低网络规则:
|
||
|
||
```text
|
||
zcbot Node API 绑定:zcbot 私网 IP:8765(示例)
|
||
zcbot 入站安全组:只允许 Windows Node 私网 IP → TCP 8765
|
||
Windows Node 出站:只允许 zcbot 私网 IP → TCP 8765
|
||
Windows Node 入站:不开放 Node 业务端口
|
||
RDP:不向公网开放,使用 VPN、堡垒机或云安全登录
|
||
```
|
||
|
||
即使在内网,应用层仍拒绝:
|
||
|
||
- 任意 PowerShell、Python、LabTalk 和命令行;
|
||
- 任意 URL、绝对路径和 UNC 路径;
|
||
- 未声明 capability;
|
||
- 越权 job 和伪造 artifact ID;
|
||
- 超出大小、类型和配额限制的文件。
|
||
|
||
建议在日志中记录 Node、job、用户、动作和结果,但不得记录注册码或 Token。
|
||
|
||
## 6. MVP 状态与数据
|
||
|
||
云端首期只增加:
|
||
|
||
```text
|
||
software_nodes(
|
||
node_id pk, name, install_id, token_hash, status,
|
||
capabilities jsonb, last_seen_at,
|
||
created_at, updated_at
|
||
)
|
||
|
||
software_jobs(
|
||
job_id pk, user_id fk, task_id fk,
|
||
idempotency_key, capability, request jsonb,
|
||
node_id fk, status, progress,
|
||
error jsonb, artifact_manifest jsonb,
|
||
created_at, terminal_at, updated_at
|
||
)
|
||
```
|
||
|
||
MVP 状态:
|
||
|
||
```text
|
||
queued
|
||
running
|
||
succeeded
|
||
failed
|
||
cancelled
|
||
disconnected
|
||
```
|
||
|
||
Node 断线且本地任务可能仍在执行时标记 `disconnected`,不得自动重派。Node 重连后按 `job_id + request_digest` 和本地终态对账。
|
||
|
||
## 7. Origin 任务闭环
|
||
|
||
当前实现进度:云端任务账本、幂等提交、短期 offer、Node 本地原子保存与 accept/reject 已落地。请求以 `inputs[]` 绑定多个 artifact、以 `outputs[]` 声明多个交付物,Node 逐项流式校验大小和 SHA-256 后将输入保存到 `input/<key>/<filename>`。固定 Worker 使用管理员安装的隔离 Python 运行时与随程序发布的 `worker.py` 驱动 Origin,按 `operation.plot.series[]` 从不同输入选择系列,并按输出声明生成 OPJU、PNG、SVG、PDF;plot spec、provenance 和原子 `terminal.json` 是系统强制元数据。运行不绑定单次 WebSocket,断线后继续执行。同一进程按 job 去重,Node 重启后不重复启动已留启动标记但无可信终态的任务。成功产物逐项流式上传到云端隐藏暂存区,云端复核任务身份、固定文件名、大小和 SHA-256 后,一次性发布到 `<working_dir>/origin/<job_id>/` 并登记平台 artifact UUID;Node 以 `upload-complete.json` 恢复中断上传。
|
||
|
||
```text
|
||
用户上传一个或多个 CSV/XLSX/JSON
|
||
→ zcbot 生成受控 plot spec
|
||
→ Node 接收 origin.plot@v2
|
||
→ 先持久化 job,再启动 Origin Worker
|
||
→ originpro 生成 OPJU/PNG/SVG/PDF
|
||
→ terminal.json 原子记录终态
|
||
→ Node 通过 HTTP 上传最终截图和产物
|
||
→ zcbot 导入 working_dir 并发布
|
||
```
|
||
|
||
MVP 保留:
|
||
|
||
- 一次性注册与自动连接;
|
||
- 每 Node 独立 Token、DPAPI、禁用和轮换;
|
||
- 幂等提交;
|
||
- 独立任务目录;
|
||
- 断线不终止计算;
|
||
- SQLite 和 `terminal.json`;
|
||
- SHA-256 校验;
|
||
- 协作取消与精确进程回收;
|
||
- 最终截图和产物上传。
|
||
|
||
MVP 暂缓:
|
||
|
||
- HTTPS/WSS;
|
||
- 短期连接令牌、HMAC、nonce;
|
||
- 客户端证书和 mTLS;
|
||
- 完整任务租约和多节点调度;
|
||
- 独立 DesktopRunner;
|
||
- 分块断点上传;
|
||
- 自动更新;
|
||
- 任意 Computer Use;
|
||
- 视频直播。
|
||
|
||
## 8. 验收标准
|
||
|
||
1. 新 Node 能凭一次性注册码完成注册。
|
||
2. Node 或 Windows 重启后无需人工操作即可自动连接。
|
||
3. zcbot 能显示在线状态、最后心跳、Origin 版本和 slot。
|
||
4. Token 不出现在 URL、日志或 zcbot 数据库明文中。
|
||
5. 禁用 Node 后,现有连接关闭且无法重新连接或上传。
|
||
6. 复制 Node 配置到不同 `install_id` 的机器不能形成两个活动执行者。
|
||
7. 同一幂等键不会创建两个 Origin 任务。
|
||
8. WS 中断时 Origin 继续运行,重连后能补报状态和产物。
|
||
9. Node 重启后能识别已有终态,不重复绘图。
|
||
10. zcbot 能接收并发布 OPJU、PNG、SVG 和 PDF。
|
||
11. 连续运行 50 个任务,无残留 Origin 进程或许可证泄漏。
|
||
12. 从非白名单内网 IP 访问 Node API 被安全组拒绝。
|
||
|
||
## 9. 升级触发条件
|
||
|
||
出现以下任一情况,先将通信升级到 HTTPS/WSS:
|
||
|
||
- Node 与 zcbot 跨 VPC、跨安全域或经过公网;
|
||
- 同一网络出现不受信任终端;
|
||
- 输入、截图或产物属于敏感数据并要求链路加密;
|
||
- 安全审计明确要求传输加密。
|
||
|
||
升级时保持 URL path、Node ID、Bearer Header 和任务协议不变,只把 `http/ws` scheme 改为 `https/wss` 并部署服务端证书。设备身份治理进一步提高时,再升级客户端证书和 mTLS。
|