init: ops-assistant codebase
This commit is contained in:
36
docs/API_RESPONSE_CONVENTION.md
Normal file
36
docs/API_RESPONSE_CONVENTION.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# API Response Convention
|
||||
|
||||
统一响应格式(JSON 接口):
|
||||
|
||||
- 成功:
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "ok|success|...",
|
||||
"data": { }
|
||||
}
|
||||
```
|
||||
|
||||
- 失败:
|
||||
```json
|
||||
{
|
||||
"code": "ERR_...",
|
||||
"message": "..."
|
||||
}
|
||||
```
|
||||
|
||||
## 约定
|
||||
|
||||
1. 所有 `/api/v1/*` JSON 接口使用统一结构。
|
||||
2. 文件流接口(如 CSV 导出)成功时返回文件内容;失败时返回统一错误 JSON。
|
||||
3. 权限失败统一 `ERR_PERMISSION_DENIED`。
|
||||
4. 执行失败统一至少返回一个业务错误码(例如 `ERR_STEP_FAILED`)。
|
||||
5. `message` 用于人类可读,`code` 用于前端逻辑分支。
|
||||
|
||||
## 已接入范围(2026-03-10)
|
||||
|
||||
- Ops: jobs/list/detail/cancel/retry
|
||||
- Flags: list/patch
|
||||
- Channels: list/patch/publish/reload/enable/disable/disable-all/test/apply
|
||||
- Records: list/delete
|
||||
- Audit: list
|
||||
150
docs/ai_command_guide.md
Normal file
150
docs/ai_command_guide.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# AI 命令解释知识库(用于自然语言→标准命令翻译)
|
||||
|
||||
## 总原则
|
||||
- 目标:把用户的自然语言翻译成**唯一**的标准命令。
|
||||
- 只输出一行命令,不要解释。
|
||||
- 不能确定时输出 `FAIL`。
|
||||
- 标准命令必须以 `/` 开头。
|
||||
|
||||
---
|
||||
|
||||
## OPS 模块
|
||||
### /help
|
||||
**用途**:显示 OPS 可用命令清单(同 /start /ops help)。
|
||||
**常见自然语**:
|
||||
- 你能做什么 / 你会什么
|
||||
- 功能 / 菜单 / 帮助 / help
|
||||
- 查看命令 / 看下命令
|
||||
**输出命令**:
|
||||
- `/help`
|
||||
|
||||
### /ops modules
|
||||
**用途**:查看模块启用状态。
|
||||
**常见自然语**:
|
||||
- 模块状态 / 查看模块
|
||||
- ops 模块 / ops modules
|
||||
**输出命令**:
|
||||
- `/ops modules`
|
||||
|
||||
---
|
||||
|
||||
## CPA 模块
|
||||
### /cpa help
|
||||
**用途**:显示 CPA 模块可用命令。
|
||||
**常见自然语**:
|
||||
- cpa 帮助 / cpa help
|
||||
**输出命令**:
|
||||
- `/cpa help`
|
||||
|
||||
**用途**:查询 CPA 服务状态与 usage 快照。
|
||||
**常见自然语**:
|
||||
- cpa状态 / CPA状态 / cpa status / cpastatus
|
||||
- cpa 服务状态 / cpa 运行状态 / cpa 正常吗
|
||||
- 查下 cpa / 看下 cpa 状态
|
||||
**输出命令**:
|
||||
- `/cpa status`
|
||||
|
||||
### /cpa usage backup
|
||||
**用途**:导出实时 usage 并打包备份。
|
||||
**常见自然语**:
|
||||
- cpa 备份 / 备份 cpa
|
||||
- 备份 usage / cpa usage 备份
|
||||
- 导出 cpa 使用情况
|
||||
**输出命令**:
|
||||
- `/cpa usage backup`
|
||||
|
||||
### /cpa usage restore <backup_id>
|
||||
**用途**:从备份恢复 usage。
|
||||
**常见自然语**:
|
||||
- 恢复 cpa / 回滚 cpa
|
||||
- 用备份 <id> 恢复
|
||||
- 恢复 usage <id>
|
||||
**输出命令**:
|
||||
- `/cpa usage restore <backup_id>`
|
||||
|
||||
---
|
||||
|
||||
## Cloudflare 模块
|
||||
### /cf status
|
||||
**用途**:查看 Cloudflare 配置状态。
|
||||
**常见自然语**:
|
||||
- cf 状态 / cloudflare 状态
|
||||
- cf 配置怎么样
|
||||
**输出命令**:
|
||||
- `/cf status`
|
||||
|
||||
### /cf zones
|
||||
**用途**:列出 zone 列表。
|
||||
**常见自然语**:
|
||||
- cf zones / cf 区域列表 / 站点列表
|
||||
**输出命令**:
|
||||
- `/cf zones`
|
||||
|
||||
### /cf dns list <zone_id>
|
||||
**用途**:列出指定 zone 的 DNS 记录。
|
||||
**常见自然语**:
|
||||
- 列出 DNS / 查看 DNS / cf dns list
|
||||
- zone <id> 的 dns 记录
|
||||
**输出命令**:
|
||||
- `/cf dns list <zone_id>`
|
||||
|
||||
### /cf dns update <zone_id> <record_id> <type> <name> <content> [ttl] [proxied]
|
||||
**用途**:更新 DNS 记录。
|
||||
**常见自然语**:
|
||||
- 更新 dns / 修改解析
|
||||
- 把 <name> 改成 <ip>
|
||||
**输出命令**:
|
||||
- `/cf dns update <zone_id> <record_id> <type> <name> <content> [ttl] [proxied]`
|
||||
|
||||
### /cf dnsadd <name> <content> [true] [type]
|
||||
**用途**:新增 DNS 记录(name 自动匹配 zone)。
|
||||
**常见自然语**:
|
||||
- 新增解析 / 添加 DNS
|
||||
- 增加 <name> -> <ip>
|
||||
**输出命令**:
|
||||
- `/cf dnsadd <name> <content> [true] [type]`
|
||||
|
||||
### /cf dnsset <record_id> <content> [true]
|
||||
**用途**:按 record_id 修改内容(可选开启代理)。
|
||||
**常见自然语**:
|
||||
- 更新记录内容 / 改 IP
|
||||
**输出命令**:
|
||||
- `/cf dnsset <record_id> <content> [true]`
|
||||
|
||||
### /cf dnsdel <record_id> YES
|
||||
**用途**:删除 DNS 记录(需 YES 确认)。
|
||||
**常见自然语**:
|
||||
- 删除 DNS 记录 / 删解析
|
||||
**输出命令**:
|
||||
- `/cf dnsdel <record_id> YES`
|
||||
|
||||
### /cf dnsproxy <record_id> on|off
|
||||
**用途**:切换代理开关(不改 content)。
|
||||
**常见自然语**:
|
||||
- 开启/关闭代理
|
||||
**输出命令**:
|
||||
- `/cf dnsproxy <record_id> on|off`
|
||||
|
||||
### /cf workers list
|
||||
**用途**:列出 Workers。
|
||||
**常见自然语**:
|
||||
- 列出 workers / cf workers
|
||||
**输出命令**:
|
||||
- `/cf workers list`
|
||||
|
||||
---
|
||||
|
||||
## Mail 模块
|
||||
### /mail status
|
||||
**用途**:查看邮件服务/配置状态。
|
||||
**常见自然语**:
|
||||
- 邮件状态 / mail 状态
|
||||
- 邮箱配置是否正常
|
||||
**输出命令**:
|
||||
- `/mail status`
|
||||
|
||||
---
|
||||
|
||||
## 兜底规则
|
||||
- 无法确定命令或缺少关键参数时输出 `FAIL`。
|
||||
- 不要猜测 zone_id/record_id/backup_id 等关键参数。
|
||||
104
docs/architecture-core.md
Normal file
104
docs/architecture-core.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Ops-Assistant Core Architecture (v0.0.1)
|
||||
|
||||
> 目标:程序可独立运行,AI 可选接入但无执行权;新通道/新功能模块可低成本适配接入。
|
||||
|
||||
## 1. 设计红线(强约束)
|
||||
|
||||
1. **执行权唯一入口**:所有变更类动作只能经 `Command -> Policy -> Runbook Engine`。
|
||||
2. **AI 不可执行**:AI 仅能做建议/解释,不可直接调用执行器。
|
||||
3. **通道与业务解耦**:TG/QQ/Feishu 仅适配输入输出,不承载业务规则。
|
||||
4. **模块与核心解耦**:CPA/CF/Mail 仅注册命令和构建 runbook 请求。
|
||||
5. **全链路可审计**:job/step、operator、request_id、risk_level、input_json 必须可追溯。
|
||||
|
||||
---
|
||||
|
||||
## 2. 分层结构
|
||||
|
||||
1) **Channel Adapter 层**
|
||||
- 责任:收消息、身份映射、回消息。
|
||||
- 输入:平台消息。
|
||||
- 输出:统一消息结构(text/operator/channel)。
|
||||
|
||||
2) **Command Runtime 层**
|
||||
- 责任:命令解析、路由、参数校验。
|
||||
- 输出:模块请求(Module Request)。
|
||||
|
||||
3) **Policy Gate 层**
|
||||
- 责任:权限、feature flag、confirm token、dry-run。
|
||||
- 输出:允许/拒绝(含原因)。
|
||||
|
||||
4) **Runbook Engine 层**
|
||||
- 责任:确定性执行 step(白名单动作)、锁、超时、断言、取消。
|
||||
|
||||
5) **Audit/State 层**
|
||||
- 责任:记录 job/step 状态和执行证据。
|
||||
|
||||
6) **AI Advisor(可选)**
|
||||
- 责任:建议命令、参数补全、解释结果。
|
||||
- 限制:**无执行器句柄、无 DB 写权限、无外部动作权限**。
|
||||
|
||||
---
|
||||
|
||||
## 3. 接入标准
|
||||
|
||||
### 3.1 新通道接入(最小接口)
|
||||
- 实现统一消息输入
|
||||
- 实现统一回复输出
|
||||
- 提供身份映射(operator_id)
|
||||
|
||||
> 新通道不允许直接操作 runbook / db。
|
||||
|
||||
### 3.2 新功能模块接入(最小接口)
|
||||
- 注册命令前缀(如 `/cpa` `/cf` `/mail`)
|
||||
- 输入校验
|
||||
- 构建 runbook 请求(name + inputs + meta + policy)
|
||||
|
||||
> 新模块不允许直接执行 shell/ssh,只能请求 runbook 引擎。
|
||||
|
||||
### 3.3 当前注册机制
|
||||
- Parser 按 `/xxx` 自动识别 `module=xxx`
|
||||
- Registry 支持两种注册:
|
||||
- 精确命令注册(`Register("/health", ...)`)
|
||||
- 模块前缀注册(`RegisterModule("cpa", ...)`)
|
||||
- 推荐新模块使用 `RegisterModule`,降低接入成本。
|
||||
|
||||
---
|
||||
|
||||
## 4. AI 介入模式
|
||||
|
||||
- `off`:完全关闭 AI(默认可用)
|
||||
- `suggest`:允许 AI 给出命令建议,不自动执行
|
||||
- `explain`:允许 AI 解释结果,不自动执行
|
||||
|
||||
### 安全边界
|
||||
- AI 输出必须是文本建议,不是可执行指令。
|
||||
- 任何执行动作都需要用户命令触发并通过 Policy Gate。
|
||||
|
||||
---
|
||||
|
||||
## 5. 统一执行链
|
||||
|
||||
`Channel -> Command -> Module.BuildRequest -> Policy.Check -> Runbook.Execute -> Audit -> Reply`
|
||||
|
||||
这条链是扩展 CF/Mail 时的唯一合法路径。
|
||||
|
||||
---
|
||||
|
||||
## 6. 当前状态与后续
|
||||
|
||||
### 已具备
|
||||
- Runbook 引擎(执行/锁/超时/取消)
|
||||
- CPA 模块(status/backup/restore)
|
||||
- 任务审计(jobs/steps)
|
||||
- CF/Mail 模块骨架(`/cf status`、`/mail status` 占位)
|
||||
|
||||
### 下一步(框架整理)
|
||||
1. 将模块内零散 gate 逻辑统一沉淀到 `core/policy`
|
||||
2. 形成通道适配模板和模块适配模板
|
||||
3. 引入 `core/ai` 的 Noop Advisor(默认 off)
|
||||
4. 在 CF/Mail 骨架上补齐真实 runbook(不改核心)
|
||||
|
||||
### 模块管理可观测性
|
||||
- 聊天命令:`/ops modules` 查看注册模块与启用状态
|
||||
- Web 首页:模块状态卡片(读取 `enable_module_*`)
|
||||
- 模块启停:统一通过 feature flag 管理,不改代码路径
|
||||
89
docs/backend-independence-status.md
Normal file
89
docs/backend-independence-status.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Ops-Assistant 后端独立化完成清单(Phase 1~6)
|
||||
|
||||
更新日期:2026-03-10
|
||||
|
||||
---
|
||||
|
||||
## 总览
|
||||
|
||||
目标:`ops-assistant` 后端从旧 `xiaji-go` 记账心智中独立,形成 Ops 场景可扩展架构。
|
||||
|
||||
当前结论:
|
||||
- ✅ 核心链路已成型:`Command -> Module -> Policy -> Runbook -> Audit -> Reply`
|
||||
- ✅ 三模块(CPA/CF/Mail)已纳入统一执行骨架(CF/Mail 为安全占位 runbook)
|
||||
- ✅ Ops Web 数据面已具备(dashboard/modules/jobs/channels/audit/flags)
|
||||
- ✅ Legacy 兼容层已进入可观测可下线阶段(usage/trend/readiness)
|
||||
|
||||
---
|
||||
|
||||
## Phase 状态
|
||||
|
||||
## Phase 1:API 基础收口
|
||||
- ✅ 新增/改造接口统一 `{code,message,data}`
|
||||
- ✅ 导出类接口保留文件流(`/api/v1/export`)
|
||||
- ✅ 失败路径统一 JSON 错误
|
||||
|
||||
## Phase 2:模块管理后端
|
||||
- ✅ `GET /api/v1/modules`
|
||||
- ✅ `POST /api/v1/modules/:module/toggle`
|
||||
- ✅ toggle reason 必填
|
||||
- ✅ toggle 幂等 noop 返回
|
||||
- ✅ 关键模块保护:禁止禁用 `cpa`
|
||||
|
||||
## Phase 3:Dashboard 聚合后端
|
||||
- ✅ `GET /api/v1/dashboard/overview`
|
||||
- ✅ `GET /api/v1/dashboard/summary`
|
||||
- ✅ jobs 列表多维筛选(见 Phase 4)
|
||||
|
||||
## Phase 4:Ops Jobs 能力增强
|
||||
- ✅ `GET /api/v1/ops/jobs` 支持筛选:
|
||||
- `limit/status/target/runbook/request_id/operator/risk_level/q/from/to`
|
||||
- ✅ `GET /api/v1/ops/jobs/request/:requestID`(含 `total`)
|
||||
- ✅ `GET /api/v1/ops/jobs/:id`(`step_stats/step_total/duration`)
|
||||
- ✅ `POST /api/v1/ops/jobs/:id/cancel`(reason 必填,状态校验)
|
||||
- ✅ `POST /api/v1/ops/jobs/:id/retry`(reason 必填,仅 failed)
|
||||
|
||||
## Phase 5:策略与风控中心化(阶段性)
|
||||
- ✅ `policy.CheckGate` 作为 gate 核心校验
|
||||
- ✅ 新增 `policy.ParseCommonFlags`,统一 `--dry-run/--confirm`
|
||||
- ✅ CPA 移除重复 guard(不再分散解析)
|
||||
- ✅ CF/Mail 切到 Runner + Gate + Runbook 模式
|
||||
- ⏳ 待补:更细粒度 permission/gate 模板化(跨模块统一声明)
|
||||
|
||||
## Phase 6:兼容层收缩与下线准备
|
||||
- ✅ legacy 路由包装审计:
|
||||
- `/api/records`
|
||||
- `/delete/:id`
|
||||
- `/export`
|
||||
- ✅ 访问 legacy 自动写审计:`legacy.route.access`
|
||||
- ✅ legacy deprecated 响应头:
|
||||
- `X-API-Deprecated: true`
|
||||
- `X-API-Replacement`
|
||||
- `Warning: 299 ...`
|
||||
- ✅ 迁移观测接口:
|
||||
- `GET /api/v1/admin/legacy/usage`
|
||||
- `GET /api/v1/admin/legacy/trend?days=...`
|
||||
- `GET /api/v1/admin/legacy/readiness?days=...&zero_days=...`
|
||||
|
||||
---
|
||||
|
||||
## 仍在进行 / 建议下一步
|
||||
|
||||
1) Policy 进一步模板化
|
||||
- 将 `NeedFlag/RequireConfirm/AllowDryRun` 配置抽成模块命令描述,减少模块内手写。
|
||||
|
||||
2) Channel Adapter 统一化
|
||||
- TG/QQ/Feishu 进一步收敛到 `core/ports/channel.go` 统一适配层。
|
||||
|
||||
3) Legacy 软下线流程
|
||||
- 当 `readiness.ready=true` 连续多日后,先灰度关闭 legacy,再完全移除路由映射。
|
||||
|
||||
4) 发布前整理
|
||||
- 清理工作区改动并提交;执行 `make release-check`。
|
||||
|
||||
---
|
||||
|
||||
## 关键验证
|
||||
|
||||
- 最近多轮 `go build ./cmd/main.go` 均通过(仅 gojieba C++ deprecation warning,非阻塞)。
|
||||
- 双服务并存策略维持不变:`xiaji-go` 与 `ops-assistant` 并行。
|
||||
123
docs/cf-commands-design.md
Normal file
123
docs/cf-commands-design.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# CF 命令设计(ops-assistant v1)
|
||||
|
||||
## 目标
|
||||
为 ops-assistant 提供 Cloudflare DNS 管理能力,保证幂等、安全、可审计。
|
||||
|
||||
---
|
||||
|
||||
## 1. 命令清单
|
||||
|
||||
- `/cf zones`
|
||||
- 列出可用 Zone(name/id)
|
||||
|
||||
- `/cf dnslist <zone> [name] [type]`
|
||||
- 示例:`/cf dnslist example.com`
|
||||
- 示例:`/cf dnslist example.com www A`
|
||||
|
||||
- `/cf dnsadd <fqdn> <ip> [--type A/AAAA/CNAME] [--ttl 120] [--proxied on/off]`
|
||||
- 示例:`/cf dnsadd test.fnos.xx.kg 1.2.3.4`
|
||||
|
||||
- `/cf dnsset <fqdn> <ip> [--type A/AAAA/CNAME] [--ttl 120] [--proxied on/off]`
|
||||
- 存在则更新,不存在则创建
|
||||
|
||||
- `/cf dnsdel <fqdn> --type <A/AAAA/CNAME>`
|
||||
- **必须带 `--type`**
|
||||
- **需二次确认 `YES`**
|
||||
|
||||
- `/cf dnsproxy <fqdn> on|off`
|
||||
- 仅更新 proxied
|
||||
|
||||
- `/cf health`
|
||||
- Token/权限可用性检查
|
||||
|
||||
---
|
||||
|
||||
## 2. 权限与安全
|
||||
|
||||
- `read` 角色:仅允许 `zones / dnslist / health`
|
||||
- `admin` 角色:允许所有命令
|
||||
- `dnsdel` 必须二次确认 `YES`
|
||||
|
||||
---
|
||||
|
||||
## 3. 参数校验
|
||||
|
||||
- `fqdn` 必须属于某个 Zone(`<sub>.<zone>`)
|
||||
- `ip` 校验:
|
||||
- `A` → IPv4
|
||||
- `AAAA` → IPv6
|
||||
- `type` 默认 `A`
|
||||
- `ttl` 默认 `120`
|
||||
- `proxied` 默认保持原值(仅 dnsproxy/dnsset 明确修改)
|
||||
|
||||
---
|
||||
|
||||
## 4. 幂等与更新规则
|
||||
|
||||
### `/cf dnsadd`
|
||||
1) 查询同名同类型记录
|
||||
2) 存在 → 返回“已存在”
|
||||
3) 不存在 → 创建
|
||||
|
||||
### `/cf dnsset`
|
||||
- 若任一字段不同则更新:
|
||||
- `content`
|
||||
- `ttl`
|
||||
- `proxied`
|
||||
- content 相同但 ttl/proxied 不同 → 仍执行更新
|
||||
|
||||
### `/cf dnsdel`
|
||||
- 必须带 `--type`
|
||||
- 仅删除指定 type 记录
|
||||
|
||||
---
|
||||
|
||||
## 5. 输出规范
|
||||
|
||||
### 成功
|
||||
```
|
||||
✅ DNS操作成功
|
||||
- name: <fqdn>
|
||||
- type: <type>
|
||||
- content: <ip>
|
||||
- ttl: <ttl>
|
||||
- proxied: <true/false>
|
||||
- id: <record_id>
|
||||
```
|
||||
|
||||
### 已存在
|
||||
```
|
||||
ℹ️ DNS记录已存在(未变更)
|
||||
- name: <fqdn>
|
||||
- type: <type>
|
||||
- content: <ip>
|
||||
- id: <record_id>
|
||||
```
|
||||
|
||||
### 失败
|
||||
```
|
||||
❌ DNS操作失败
|
||||
- reason: <鉴权/参数/CF错误>
|
||||
- detail: <error_message>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 审计日志(必写)
|
||||
|
||||
字段:
|
||||
- `ts / actor / cmd / zone / fqdn / action / record_id / result / detail`
|
||||
|
||||
示例:
|
||||
```json
|
||||
{
|
||||
"ts": "2026-03-14T15:02:10+08:00",
|
||||
"actor": "kory",
|
||||
"cmd": "/cf dnsadd test.fnos.xx.kg 1.2.3.4",
|
||||
"zone": "fnos.xx.kg",
|
||||
"record_id": "xxxxx",
|
||||
"action": "create",
|
||||
"result": "ok",
|
||||
"detail": {"type":"A","ttl":120,"proxied":false}
|
||||
}
|
||||
```
|
||||
39
docs/cf-dns-runbook-incident-20260313.md
Normal file
39
docs/cf-dns-runbook-incident-20260313.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# CF DNS Runbook 事故复盘(2026-03-13)
|
||||
|
||||
## 背景
|
||||
在 ops-assistant 中新增 CF 模块命令(/cf dnsadd/dnsset/dnsdel/dnsproxy)并进行自测时,出现多次失败与反复修复,导致进度延误。
|
||||
|
||||
## 现象
|
||||
- `/cf dnsadd test.fnos.xx.kg 127.0.0.1` 连续失败多次。
|
||||
- Cloudflare API 返回 `Invalid request headers`。
|
||||
- runbook 步骤日志只回显脚本文本,未见真实 API 返回。
|
||||
|
||||
## 根因
|
||||
1) **认证方式误判**
|
||||
- 将 API Token 误当作 API Key,使用了 `X-Auth-Email/X-Auth-Key` 方式,导致 CF 返回 `Invalid request headers`。
|
||||
- 修复后改回 Bearer 才验证 token 可用。
|
||||
|
||||
2) **runbook 执行方式不稳定(ssh heredoc/转义)**
|
||||
- runbook 使用 `ssh.exec` 远端执行,命令通过 `bash -lc` + `ssh "..."` 传递。
|
||||
- heredoc 在多层转义/引用中被破坏,脚本未执行或被 shell 解释掉,stderr 只回显脚本内容。
|
||||
- `python3 -c` 内联也因换行/转义导致 `SyntaxError`。
|
||||
|
||||
## 卡点分析
|
||||
- **卡点本质不是 Token**,而是 **远端执行链路中的脚本传递/转义失效**。
|
||||
- 缺少一条稳定的“文本脚本传递”方式,导致同一命令多次失败、定位耗时。
|
||||
|
||||
## 最终解决
|
||||
- 改为 **base64 + python3 -c exec(...)** 的方式传递脚本,避免多层引用与换行问题。
|
||||
- `/cf dnsadd test.fnos.xx.kg 127.0.0.1` 成功创建记录。
|
||||
- record id: `acd49e048bc74c1b16d935b69f5aac54`
|
||||
- job: `27`
|
||||
|
||||
## 经验与改进
|
||||
1) **认证方式先验确认**:明确 Token vs Key 的调用差异。
|
||||
2) **避免 heredoc 跨 ssh**:优先 `base64|python3` 或 `python3 -c` 单行命令。
|
||||
3) **失败输出必须可见**:stderr/stdout 要确保能返回实际 API 响应,禁止“只回显脚本文本”。
|
||||
4) **阶段性汇报必须带证据**:无日志/产物不使用“完成/已执行”。
|
||||
|
||||
## 待办
|
||||
- 将 dnsset/dnsdel/dnsproxy 全部切换为稳定执行方式(base64 + python3 -c)。
|
||||
- 评估是否引入 `local.exec`,避免本地项目走 ssh 远端执行。
|
||||
28
docs/channel-adapter-template.md
Normal file
28
docs/channel-adapter-template.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Channel Adapter Template
|
||||
|
||||
目标:新通道只做 I/O 适配,不耦合业务执行。
|
||||
|
||||
## 责任边界
|
||||
|
||||
- 接收平台消息并标准化为统一结构
|
||||
- 调用 `ops.Service.Handle(...)` 处理命令
|
||||
- 将文本回复回传到平台
|
||||
|
||||
## 禁止事项
|
||||
|
||||
- 不在通道内直接执行 shell/ssh/http 运维动作
|
||||
- 不在通道内做模块业务判断(应交给 command/module)
|
||||
|
||||
## 最小流程
|
||||
|
||||
1. `Normalize(raw)` -> `UnifiedMessage`
|
||||
2. `handled, out := opsSvc.Handle(msg.OperatorID, msg.Text)`
|
||||
3. `if handled { Reply(out) }`
|
||||
4. 未处理消息再回退到历史业务逻辑(如记账)
|
||||
|
||||
## 接入检查
|
||||
|
||||
- [ ] 仅实现消息适配与回复
|
||||
- [ ] 已接入 opsSvc.Handle
|
||||
- [ ] 未绕过 policy/runbook
|
||||
- [ ] 错误信息对用户可读
|
||||
79
docs/debug/cf-dnsproxy-dnsadd-20260319.md
Normal file
79
docs/debug/cf-dnsproxy-dnsadd-20260319.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# CF DNS 命令修复与扩展记录(2026-03-19)
|
||||
|
||||
## 背景
|
||||
用户要求:
|
||||
- `/cf dnsproxy` 支持直接用域名,例如:`/cf dnsproxy ima.good.xx.kg on`
|
||||
- `/cf dnsadd` 最后参数用 `on/off` 表示是否开启代理
|
||||
|
||||
线上报错:
|
||||
- `yaml: line 8: did not find expected key`
|
||||
- `/cf dnsproxy` 解析失败(bash: bad substitution)
|
||||
|
||||
## 改动概览
|
||||
1) **命令解析**
|
||||
- `internal/module/cf/commands.go`
|
||||
- `/cf dnsproxy` 支持 `record_id|name`
|
||||
- `/cf dnsadd` 支持 `on/off`(兼容 true/false;当未提供 on/off 时把第4参数视为类型)
|
||||
|
||||
2) **帮助文案**
|
||||
- `internal/module/cf/module.go`
|
||||
- `internal/core/ops/service.go`
|
||||
- 更新 `/cf dnsadd` 与 `/cf dnsproxy` 的参数示例
|
||||
|
||||
3) **runbook 修复**
|
||||
- `runbooks/cf_dns_proxy.yaml`
|
||||
- 解决 YAML 行内命令渲染与变量替换问题
|
||||
- 修复 `${env.INPUT_RECORD_ID}` 未替换导致 bash 报错
|
||||
- 加入占位值 `__empty__`,避免空变量导致替换缺失
|
||||
- `update_dns` 中 JSON 通过单引号包裹,避免 shell 分词/换行破坏
|
||||
|
||||
4) **ops-runner 支持**
|
||||
- `cmd/ops-runner/main.go`
|
||||
- 增加 `/cf dnsproxy` 支持
|
||||
- `/cf dnsadd` 参数改为 on/off
|
||||
|
||||
## 问题与修复记录
|
||||
### 1. YAML 解析错误
|
||||
- 现象:`yaml: line 8: did not find expected key`
|
||||
- 原因:runbook 中 command 复杂引号/换行组合导致 YAML 解析失败
|
||||
- 修复:重写 `cf_dns_proxy.yaml` command 区块
|
||||
|
||||
### 2. dnsproxy 变量替换失败
|
||||
- 现象:`bash: ${env.INPUT_RECORD_ID}: bad substitution`
|
||||
- 原因:输入为空时,没有替换占位,shell 直接解析 `${env.INPUT_RECORD_ID}`
|
||||
- 修复:InputsFn 总是注入 `record_id/name` 占位值,runbook 将 `__empty__` 转为空
|
||||
|
||||
### 3. dnsproxy update 失败(JSON 被 shell 吞掉)
|
||||
- 现象:`bash: line 1: true,: command not found`
|
||||
- 原因:`${steps.resolve_dns.output}` 未加引号,JSON 被 shell 拆分
|
||||
- 修复:`INPUT_JSON='${steps.resolve_dns.output}'`
|
||||
|
||||
### 4. dnsadd on/off 支持
|
||||
- 现象:`DNS record type "on" is invalid`
|
||||
- 原因:解析逻辑未识别 on/off,误当作类型
|
||||
- 修复:InputsFn 与 ops-runner 同步支持 `on/off`
|
||||
|
||||
### 5. 测试记录创建失败(127.0.0.1)
|
||||
- 现象:`Target 127.0.0.1 is not allowed for a proxied record`
|
||||
- 处理:改用公网 IP 199.188.198.12
|
||||
|
||||
## 测试结果
|
||||
1) 新增测试记录
|
||||
```
|
||||
/cf dnsadd test001.good.xx.kg 199.188.198.12 on
|
||||
```
|
||||
- 成功创建,proxied=true
|
||||
|
||||
2) 代理切换
|
||||
```
|
||||
/cf dnsproxy ima.good.xx.kg on
|
||||
```
|
||||
- 成功更新,proxied=true
|
||||
|
||||
## 产物
|
||||
- 修复代码与 runbook
|
||||
- 版本化二进制输出(dist/ 目录)
|
||||
|
||||
## 注意事项
|
||||
- proxied=on 不能指向 127.0.0.1 等内网回环地址
|
||||
- runbook command 中 JSON 建议统一使用单引号包裹
|
||||
491
docs/frontend-api-handoff.md
Normal file
491
docs/frontend-api-handoff.md
Normal file
@@ -0,0 +1,491 @@
|
||||
# Ops-Assistant 前端对接文档(给 Gemini)
|
||||
|
||||
> 目的:让前端可独立完成 ops-assistant 新后台页面,不依赖旧 xiaji 记账页面心智。
|
||||
> 基址:同源(已登录后直接请求 `/api/v1/*`)
|
||||
> 鉴权:Cookie Session(`ops_user` + `ops_token`)
|
||||
|
||||
---
|
||||
|
||||
## 0. 统一响应约定(必须)
|
||||
|
||||
### 成功
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "ok",
|
||||
"data": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### 失败
|
||||
```json
|
||||
{
|
||||
"code": "ERR_XXX",
|
||||
"message": "可读错误信息"
|
||||
}
|
||||
```
|
||||
|
||||
### 前端统一处理建议
|
||||
- `if (!res.ok)`: 显示 `message`
|
||||
- `if (res.ok)`: 使用 `data`
|
||||
- 不再使用 `error/status` 老字段
|
||||
|
||||
> 例外:`GET /api/v1/export` 成功是文件流下载,不是 JSON。
|
||||
|
||||
---
|
||||
|
||||
## 1. 权限与用户信息
|
||||
|
||||
### 1.1 获取当前用户
|
||||
**GET** `/api/v1/me`
|
||||
|
||||
### data 字段
|
||||
- `username`
|
||||
- `role`
|
||||
- `user_id`
|
||||
- `permissions[]`
|
||||
- `flags{}`
|
||||
- `effective_capabilities{}`
|
||||
|
||||
### capability 常用键
|
||||
- `can_view_ops`
|
||||
- `can_cancel_ops`
|
||||
- `can_retry_ops`
|
||||
- `can_view_flags`
|
||||
- `can_edit_flags`
|
||||
- `can_view_channels`
|
||||
- `can_edit_channels`
|
||||
- `can_test_channels`
|
||||
- `can_view_audit`
|
||||
|
||||
前端应以 capability 驱动按钮显隐。
|
||||
|
||||
---
|
||||
|
||||
## 2. Dashboard(新后台首页主数据)
|
||||
|
||||
### 2.1 获取总览
|
||||
**GET** `/api/v1/dashboard/overview`
|
||||
|
||||
### 返回 data
|
||||
```json
|
||||
{
|
||||
"jobs": {
|
||||
"recent": [OpsJob...],
|
||||
"status_count": {
|
||||
"pending": 0,
|
||||
"running": 0,
|
||||
"success": 0,
|
||||
"failed": 0,
|
||||
"cancelled": 0
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
{"module":"cpa","enabled":true},
|
||||
{"module":"cf","enabled":false},
|
||||
{"module":"mail","enabled":false}
|
||||
],
|
||||
"channels": [
|
||||
{"platform":"telegram","enabled":true,"status":"ok"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 获取轻量摘要(推荐首页首屏)
|
||||
**GET** `/api/v1/dashboard/summary`
|
||||
|
||||
### 返回 data
|
||||
```json
|
||||
{
|
||||
"jobs": {
|
||||
"total": 120,
|
||||
"running": 2,
|
||||
"failed": 5,
|
||||
"success": 98
|
||||
},
|
||||
"modules": {
|
||||
"cpa": true,
|
||||
"cf": false,
|
||||
"mail": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 模块管理(Module Center)
|
||||
|
||||
### 3.1 模块列表
|
||||
**GET** `/api/v1/modules`
|
||||
|
||||
### 返回 data
|
||||
```json
|
||||
{
|
||||
"modules": [
|
||||
{
|
||||
"module":"cpa",
|
||||
"display_name":"CPA 管理",
|
||||
"flag_key":"enable_module_cpa",
|
||||
"enabled":true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 切换模块开关
|
||||
**POST** `/api/v1/modules/:module/toggle`
|
||||
|
||||
- `:module` 仅支持:`cpa|cf|mail`
|
||||
|
||||
### body
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"reason": "前端联调启用"
|
||||
}
|
||||
```
|
||||
|
||||
### 成功 data
|
||||
```json
|
||||
{
|
||||
"module": "cf",
|
||||
"flag_key": "enable_module_cf",
|
||||
"old": false,
|
||||
"new": true
|
||||
}
|
||||
```
|
||||
|
||||
### 交互建议
|
||||
- 操作前确认弹窗
|
||||
- 必填 reason
|
||||
- 成功后刷新 `/api/v1/modules` 与 `/api/v1/dashboard/overview`
|
||||
|
||||
---
|
||||
|
||||
## 4. Ops 任务中心
|
||||
|
||||
### 4.1 任务列表
|
||||
**GET** `/api/v1/ops/jobs?limit=50`
|
||||
|
||||
支持筛选 query:
|
||||
- `status`(pending|running|success|failed|cancelled)
|
||||
- `target`(如 hwsg)
|
||||
- `runbook`(如 cpa_usage_backup)
|
||||
- `request_id`
|
||||
- `operator`(操作者 user_id,int64)
|
||||
- `risk_level`(low|medium|high 等)
|
||||
- `q`(模糊检索,命中 command/runbook/target/request_id)
|
||||
- `from`(RFC3339,按 created_at 下界过滤)
|
||||
- `to`(RFC3339,按 created_at 上界过滤)
|
||||
|
||||
### data
|
||||
```json
|
||||
{
|
||||
"jobs": [OpsJob...],
|
||||
"filters": {
|
||||
"limit": 50,
|
||||
"status": "failed",
|
||||
"target": "hwsg",
|
||||
"runbook": "cpa_usage_restore",
|
||||
"request_id": "ops-u1-1741563000",
|
||||
"operator": "1",
|
||||
"risk_level": "high",
|
||||
"q": "restore",
|
||||
"from": "2026-03-10T07:00:00+08:00",
|
||||
"to": "2026-03-10T08:00:00+08:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 按 request_id 反查任务
|
||||
**GET** `/api/v1/ops/jobs/request/:requestID?limit=50`
|
||||
|
||||
### data
|
||||
```json
|
||||
{
|
||||
"request_id":"req-20260310-abc",
|
||||
"total": 3,
|
||||
"jobs":[OpsJob...]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 任务详情(含步骤 + 聚合统计)
|
||||
**GET** `/api/v1/ops/jobs/:id`
|
||||
|
||||
### data
|
||||
```json
|
||||
{
|
||||
"job": { ... },
|
||||
"steps": [
|
||||
{
|
||||
"step_id":"...",
|
||||
"action":"ssh.exec",
|
||||
"status":"success|failed|running",
|
||||
"stdout_tail":"...",
|
||||
"stderr_tail":"..."
|
||||
}
|
||||
],
|
||||
"step_stats": {
|
||||
"running": 0,
|
||||
"success": 3,
|
||||
"failed": 1,
|
||||
"skipped": 0
|
||||
},
|
||||
"step_total": 4,
|
||||
"duration": {
|
||||
"job_ms": 5321,
|
||||
"steps_ms_sum": 4870
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 取消任务
|
||||
**POST** `/api/v1/ops/jobs/:id/cancel`
|
||||
|
||||
body:
|
||||
```json
|
||||
{"reason":"人工终止,参数配置错误"}
|
||||
```
|
||||
|
||||
### data
|
||||
```json
|
||||
{"id":123,"reason":"人工终止,参数配置错误"}
|
||||
```
|
||||
|
||||
### 4.5 重试任务
|
||||
**POST** `/api/v1/ops/jobs/:id/retry`
|
||||
|
||||
body:
|
||||
```json
|
||||
{"reason":"修复配置后重试"}
|
||||
```
|
||||
|
||||
### data
|
||||
```json
|
||||
{"old_job_id":123,"new_job_id":456,"reason":"修复配置后重试"}
|
||||
```
|
||||
|
||||
### 前端权限
|
||||
- cancel 按钮:`can_cancel_ops`
|
||||
- retry 按钮:`can_retry_ops`
|
||||
|
||||
### 交互约束
|
||||
- cancel/retry 必须填写 reason(后端强校验)
|
||||
- retry 仅允许 failed 状态任务
|
||||
- cancel 仅允许 pending/running 状态任务
|
||||
- `from/to` 参数必须是 RFC3339(如 `2026-03-10T07:00:00+08:00`)
|
||||
|
||||
---
|
||||
|
||||
## 5. 通道管理(Channels)
|
||||
|
||||
### 5.1 通道列表
|
||||
**GET** `/api/v1/admin/channels`
|
||||
|
||||
### data
|
||||
```json
|
||||
{
|
||||
"channels": [
|
||||
{
|
||||
"platform":"telegram",
|
||||
"name":"Telegram Bot",
|
||||
"enabled": true,
|
||||
"status":"ok",
|
||||
"config_json":"{}",
|
||||
"draft_config_json":"{}",
|
||||
"secrets":"{\"token\":\"***\"}",
|
||||
"draft_secrets":"{}",
|
||||
"has_draft": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 更新草稿
|
||||
**PATCH** `/api/v1/admin/channels/:platform`
|
||||
|
||||
body 可包含:
|
||||
- `name`
|
||||
- `enabled`
|
||||
- `config`
|
||||
- `secrets`
|
||||
|
||||
### 5.3 发布草稿
|
||||
**POST** `/api/v1/admin/channels/:platform/publish`
|
||||
|
||||
### 5.4 热加载
|
||||
**POST** `/api/v1/admin/channels/reload`
|
||||
|
||||
### 5.5 一键全禁用
|
||||
**POST** `/api/v1/admin/channels/disable-all`
|
||||
|
||||
### 5.6 启用/禁用单通道
|
||||
- **POST** `/api/v1/admin/channels/:platform/enable`
|
||||
- **POST** `/api/v1/admin/channels/:platform/disable`
|
||||
|
||||
### 5.7 连通性测试
|
||||
**POST** `/api/v1/admin/channels/:platform/test`
|
||||
|
||||
### 5.8 原子应用(patch + publish + reload)
|
||||
**POST** `/api/v1/admin/channels/:platform/apply`
|
||||
|
||||
> apply 失败 message 中可能包含 stage 信息(patch/publish/reload)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 审计日志
|
||||
|
||||
### 6.1 查询审计
|
||||
**GET** `/api/v1/admin/audit`
|
||||
|
||||
支持 query:
|
||||
- `action`
|
||||
- `target_type`
|
||||
- `result`
|
||||
- `actor_id`
|
||||
- `from` (RFC3339)
|
||||
- `to` (RFC3339)
|
||||
- `limit` (默认100,最大500)
|
||||
- `offset`
|
||||
|
||||
### data
|
||||
```json
|
||||
{ "logs": [AuditLog...] }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 风险开关(Flags)
|
||||
|
||||
### 7.1 列表
|
||||
**GET** `/api/v1/admin/settings/flags`
|
||||
|
||||
### data
|
||||
```json
|
||||
{ "flags": [FeatureFlag...] }
|
||||
```
|
||||
|
||||
### 7.2 修改
|
||||
**PATCH** `/api/v1/admin/settings/flags/:key`
|
||||
|
||||
body:
|
||||
```json
|
||||
{ "enabled": true, "reason": "..." }
|
||||
```
|
||||
|
||||
> 部分 flag `RequireReason=true`,reason 为空会失败。
|
||||
|
||||
---
|
||||
|
||||
## 8. 兼容层(前端新代码不要用)
|
||||
|
||||
以下仅兼容旧页面:
|
||||
- `GET /api/records`
|
||||
- `POST /delete/:id`
|
||||
- `GET /export`
|
||||
|
||||
新前端一律使用 `/api/v1/*`。
|
||||
|
||||
### 8.1 Legacy 使用统计(用于迁移观察)
|
||||
**GET** `/api/v1/admin/legacy/usage`
|
||||
|
||||
### data
|
||||
```json
|
||||
{
|
||||
"summary": [
|
||||
{"route":"/api/records","count":12},
|
||||
{"route":"/delete/:id","count":3},
|
||||
{"route":"/export","count":1}
|
||||
],
|
||||
"recent": [AuditLog...]
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 Legacy 调用趋势(按天)
|
||||
**GET** `/api/v1/admin/legacy/trend?days=7`
|
||||
|
||||
- `days` 范围:`1~90`,默认 `7`
|
||||
|
||||
### data
|
||||
```json
|
||||
{
|
||||
"days": 7,
|
||||
"from": "2026-03-04T00:00:00+08:00",
|
||||
"trends": [
|
||||
{
|
||||
"route": "/api/records",
|
||||
"points": [
|
||||
{"day":"2026-03-04","count":2},
|
||||
{"day":"2026-03-05","count":1}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 Legacy 响应头(便于前端观察迁移)
|
||||
访问旧路由时,响应头会包含:
|
||||
- `X-API-Deprecated: true`
|
||||
- `X-API-Replacement: <对应新路由>`
|
||||
- `Warning: 299 - "legacy API deprecated, use ..."`
|
||||
|
||||
### 8.4 Legacy 下线就绪评估
|
||||
**GET** `/api/v1/admin/legacy/readiness?days=7&zero_days=3`
|
||||
|
||||
- `days`:观察窗口(1~90,默认 7)
|
||||
- `zero_days`:要求连续 0 调用天数(1~30,默认 3)
|
||||
|
||||
### data
|
||||
```json
|
||||
{
|
||||
"days": 7,
|
||||
"zero_days": 3,
|
||||
"window_total": 0,
|
||||
"route_totals": {
|
||||
"/api/records": 0,
|
||||
"/delete/:id": 0,
|
||||
"/export": 0
|
||||
},
|
||||
"consecutive_zero_days": {
|
||||
"/api/records": 7,
|
||||
"/delete/:id": 7,
|
||||
"/export": 7
|
||||
},
|
||||
"ready": true,
|
||||
"recommendation": "可考虑下线 legacy 路由(已满足连续0调用阈值)"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 前端落地建议(给 Gemini)
|
||||
|
||||
1. 建立统一 `apiClient`:
|
||||
- `request(url, options)`
|
||||
- 自动解析 `{code,message,data}`
|
||||
- 非 2xx 抛 message
|
||||
|
||||
2. 页面优先级:
|
||||
- P1:Dashboard(overview + summary)
|
||||
- P1:Ops Jobs
|
||||
- P1:Modules
|
||||
- P2:Channels
|
||||
- P2:Audit
|
||||
|
||||
3. 权限驱动 UI:
|
||||
- 所有按钮显隐由 `effective_capabilities` 控制
|
||||
|
||||
4. 状态刷新策略:
|
||||
- dashboard 每 10~20s 轮询
|
||||
- ops jobs running 状态 5~10s 轮询
|
||||
|
||||
5. 错误展示:
|
||||
- toast + message 文本
|
||||
- 不展示后端堆栈
|
||||
|
||||
---
|
||||
|
||||
## 10. 已知限制
|
||||
|
||||
- export 成功仍为文件流(设计如此)。
|
||||
- gojieba 编译 warning 可忽略(非功能错误)。
|
||||
98
docs/frontend-joint-checklist.md
Normal file
98
docs/frontend-joint-checklist.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Ops-Assistant 前后端联调检查清单(给前端/Gemini)
|
||||
|
||||
更新日期:2026-03-10
|
||||
|
||||
---
|
||||
|
||||
## A. 统一基础
|
||||
|
||||
- [ ] 所有请求走 `/api/v1/*`(禁用新代码调用 legacy 路由)
|
||||
- [ ] `apiClient` 统一解析 `{code,message,data}`
|
||||
- [ ] 全局错误 toast 仅展示 `message`
|
||||
- [ ] 鉴权失败统一跳转登录
|
||||
|
||||
---
|
||||
|
||||
## B. 登录后初始化
|
||||
|
||||
- [ ] 调 `GET /api/v1/me`
|
||||
- [ ] 用 `effective_capabilities` 控制页面和按钮显隐
|
||||
- [ ] 没有权限时不渲染可操作按钮
|
||||
|
||||
---
|
||||
|
||||
## C. Dashboard
|
||||
|
||||
- [ ] 首屏并行请求:
|
||||
- `GET /api/v1/dashboard/summary`
|
||||
- `GET /api/v1/dashboard/overview`
|
||||
- [ ] 状态卡片展示 jobs 统计、模块状态、通道状态
|
||||
- [ ] 10~20 秒轮询刷新
|
||||
|
||||
---
|
||||
|
||||
## D. Modules 页面
|
||||
|
||||
- [ ] 列表:`GET /api/v1/modules`
|
||||
- [ ] 开关:`POST /api/v1/modules/:module/toggle`
|
||||
- [ ] reason 必填
|
||||
- [ ] 处理 `message=noop`
|
||||
- [ ] cpa 禁用失败提示
|
||||
- [ ] 成功后刷新 modules + overview
|
||||
|
||||
---
|
||||
|
||||
## E. Ops Jobs 页面
|
||||
|
||||
- [ ] 列表:`GET /api/v1/ops/jobs`
|
||||
- [ ] 支持筛选字段:
|
||||
- [ ] status
|
||||
- [ ] target
|
||||
- [ ] runbook
|
||||
- [ ] request_id
|
||||
- [ ] operator
|
||||
- [ ] risk_level
|
||||
- [ ] q
|
||||
- [ ] from/to(RFC3339)
|
||||
- [ ] 展示后端回显的 `filters`
|
||||
- [ ] 详情:`GET /api/v1/ops/jobs/:id`
|
||||
- [ ] step_stats
|
||||
- [ ] step_total
|
||||
- [ ] duration.job_ms / duration.steps_ms_sum
|
||||
- [ ] request_id 反查:`GET /api/v1/ops/jobs/request/:requestID`
|
||||
- [ ] cancel/retry:
|
||||
- [ ] reason 必填
|
||||
- [ ] 按权限按钮显隐(can_cancel_ops / can_retry_ops)
|
||||
|
||||
---
|
||||
|
||||
## F. Channels 页面
|
||||
|
||||
- [ ] `GET /api/v1/admin/channels`
|
||||
- [ ] patch/publish/reload/apply 流程联通
|
||||
- [ ] secrets 脱敏显示并正确提交
|
||||
|
||||
---
|
||||
|
||||
## G. Audit 页面
|
||||
|
||||
- [ ] `GET /api/v1/admin/audit`
|
||||
- [ ] 支持 from/to、action、target_type、result、actor_id
|
||||
|
||||
---
|
||||
|
||||
## H. Legacy 迁移看板(管理页)
|
||||
|
||||
- [ ] `GET /api/v1/admin/legacy/usage`
|
||||
- [ ] `GET /api/v1/admin/legacy/trend?days=7`
|
||||
- [ ] `GET /api/v1/admin/legacy/readiness?days=7&zero_days=3`
|
||||
- [ ] 显示 `ready` + `recommendation`
|
||||
|
||||
---
|
||||
|
||||
## I. 验收标准
|
||||
|
||||
- [ ] 前端无新代码依赖 legacy 路由
|
||||
- [ ] 所有核心页面可在 ops-assistant 独立运行
|
||||
- [ ] 权限控制、错误处理、轮询刷新行为正常
|
||||
- [ ] readiness 达标后可计划 legacy 下线窗口
|
||||
37
docs/module-adapter-template.md
Normal file
37
docs/module-adapter-template.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Module Adapter Template
|
||||
|
||||
目标:新功能模块以最小改动接入 `ops-assistant`。
|
||||
|
||||
## 必备文件
|
||||
|
||||
- `internal/module/<name>/module.go`
|
||||
- `runbooks/<name>_*.yaml`
|
||||
|
||||
## 推荐实现
|
||||
|
||||
1. 在 `module.go` 内解析命令前缀(如 `/cf`)
|
||||
2. 构建 `core/module.Request`
|
||||
3. 统一调用 `core/module.Runner.Run(...)`
|
||||
4. 所有 gate(flag/confirm/dry-run)通过 `Request.Gate` 声明
|
||||
|
||||
## 最小示例(伪代码)
|
||||
|
||||
```go
|
||||
req := coremodule.Request{
|
||||
RunbookName: "cf_dns_upsert",
|
||||
Inputs: map[string]string{"zone": zone, "name": name},
|
||||
Meta: runbook.RunMeta{Target:"cf", RiskLevel:"medium"},
|
||||
Gate: coremodule.Gate{NeedFlag:"allow_cf_write", RequireConfirm:true, ExpectedToken:"YES_CF", AllowDryRun:true},
|
||||
DryRun: dryRun,
|
||||
ConfirmToken: confirm,
|
||||
}
|
||||
jobID, out, err := runner.Run(cmd.Raw, userID, req)
|
||||
```
|
||||
|
||||
## 接入检查
|
||||
|
||||
- [ ] 命令不直接执行 shell/ssh
|
||||
- [ ] 使用统一 Runner
|
||||
- [ ] 风险操作有 Gate
|
||||
- [ ] 返回 job_id 可追踪
|
||||
- [ ] runbook step 可审计
|
||||
72
docs/multi-platform-channel-deploy.md
Normal file
72
docs/multi-platform-channel-deploy.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Ops-Assistant 多平台渠道配置与回调部署说明
|
||||
|
||||
## 已支持平台
|
||||
- 官方 QQ Bot(qqbot_official)
|
||||
- Telegram Bot(telegram)
|
||||
- 飞书 Bot(feishu)
|
||||
|
||||
## 配置优先级
|
||||
- 启动时:`数据库 channel_configs` > `config.yaml`
|
||||
- 建议使用后台页面维护渠道配置:`/channels`
|
||||
|
||||
## 后台入口
|
||||
- 渠道配置页:`/channels`
|
||||
- 渠道 API:
|
||||
- `GET /api/v1/admin/channels`
|
||||
- `PATCH /api/v1/admin/channels/:platform`
|
||||
- `POST /api/v1/admin/channels/:platform/test`
|
||||
- 审计查询:`GET /api/v1/admin/audit`
|
||||
|
||||
## 回调地址
|
||||
- 飞书 webhook: `POST /webhook/feishu`
|
||||
|
||||
### 飞书事件订阅配置
|
||||
1. 在飞书开发者后台启用事件订阅
|
||||
2. 请求网址填:`https://<你的域名>/webhook/feishu`
|
||||
3. 订阅事件:`im.message.receive_v1`
|
||||
4. 将 `verification_token`、`app_id`、`app_secret` 写入渠道 secrets JSON
|
||||
|
||||
## 渠道 secrets JSON 示例
|
||||
|
||||
### telegram
|
||||
```json
|
||||
{
|
||||
"token": "123456:ABCDEF"
|
||||
}
|
||||
```
|
||||
|
||||
### qqbot_official
|
||||
```json
|
||||
{
|
||||
"appid": "102857798",
|
||||
"secret": "xxxxxx"
|
||||
}
|
||||
```
|
||||
|
||||
### feishu
|
||||
```json
|
||||
{
|
||||
"app_id": "cli_xxx",
|
||||
"app_secret": "xxx",
|
||||
"verification_token": "xxx",
|
||||
"encrypt_key": "optional"
|
||||
}
|
||||
```
|
||||
|
||||
## 连接测试说明
|
||||
- Telegram:调用 `getMe`
|
||||
- QQ:调用 `getAppAccessToken`
|
||||
- 飞书:调用 `tenant_access_token/internal`
|
||||
|
||||
测试成功会把渠道状态写成 `ok`,失败写成 `error`。
|
||||
|
||||
## 幂等去重
|
||||
- 三平台入站统一落 `message_dedup`,避免重复处理:
|
||||
- telegram: `tg:<update_id>`
|
||||
- qqbot_official: `qq:<type>:<message_id>`
|
||||
- feishu: `event_id`(回退 message_id)
|
||||
|
||||
## 运行建议
|
||||
- 对公网暴露前请加 HTTPS(飞书回调必需)
|
||||
- 建议将管理后台放在内网或反代鉴权后访问
|
||||
- 定期审计 `audit_logs` 里渠道配置修改记录
|
||||
200
docs/ops-assistant-v1.md
Normal file
200
docs/ops-assistant-v1.md
Normal file
@@ -0,0 +1,200 @@
|
||||
# Ops Assistant 独立项目 v1 方案
|
||||
|
||||
## 目标
|
||||
把高频运维动作做成**固定命令 + 固定流水线**,AI 只负责解释,不参与关键执行决策。
|
||||
|
||||
---
|
||||
|
||||
## v1 范围(先做)
|
||||
|
||||
优先只落地 **CPA 管理中枢**:
|
||||
|
||||
1. 固定命令入口(Telegram/QQ/飞书统一)
|
||||
2. Runbook(YAML)确定性执行器
|
||||
3. 审计日志(步骤级)
|
||||
4. 高风险能力默认关闭(Feature Flag)
|
||||
|
||||
后续再扩展:Cloudflare DNS、邮箱转发。
|
||||
|
||||
---
|
||||
|
||||
## 目录结构(新增)
|
||||
|
||||
```text
|
||||
ops-assistant/
|
||||
├── internal/
|
||||
│ ├── core/
|
||||
│ │ ├── command/ # 命令解析
|
||||
│ │ ├── registry/ # 命令注册与路由
|
||||
│ │ ├── runbook/ # runbook 结构、执行器、锁、target 解析
|
||||
│ │ └── ops/ # ops 服务编排、重试
|
||||
│ └── module/
|
||||
│ └── cpa/ # CPA 模块命令与高风险闸门
|
||||
├── runbooks/
|
||||
│ ├── cpa_status.yaml
|
||||
│ ├── cpa_usage_backup.yaml
|
||||
│ └── cpa_usage_restore.yaml
|
||||
└── docs/
|
||||
└── ops-assistant-v1.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 命令清单(v1)
|
||||
|
||||
- `/cpa status`
|
||||
- `/cpa usage backup`
|
||||
- `/cpa usage restore <backup_id>`
|
||||
- `/cpa codex clean`
|
||||
- `/cpa codex test`
|
||||
- `/cpa codex isolate`
|
||||
|
||||
### 约束
|
||||
- 仅允许上述命令(严格白名单)
|
||||
- 每个命令映射到唯一 runbook
|
||||
- 不支持自由 shell 指令输入
|
||||
|
||||
---
|
||||
|
||||
## Runbook DSL(v1)
|
||||
|
||||
仅支持这些动作:
|
||||
|
||||
- `ssh.exec`:远程执行固定命令
|
||||
- `http.get` / `http.post`:调用固定接口
|
||||
- `file.upload`:上传压缩包到 staging
|
||||
- `file.extract`:解压到 staging
|
||||
- `assert.json`:断言字段值
|
||||
- `sleep`:延迟
|
||||
|
||||
每个步骤必须有:
|
||||
|
||||
- `id`
|
||||
- `action`
|
||||
- `on_fail`(`stop` | `continue`)
|
||||
|
||||
所有变量只能来自:
|
||||
|
||||
- `inputs.*`(命令参数)
|
||||
- `env.*`(服务端配置)
|
||||
- `steps.<id>.output.*`(前置步骤输出)
|
||||
|
||||
---
|
||||
|
||||
## 审计与可追溯
|
||||
|
||||
建议新增两张表:
|
||||
|
||||
### 1) `ops_jobs`
|
||||
- `id`
|
||||
- `command`
|
||||
- `runbook`
|
||||
- `operator_id`
|
||||
- `status`(pending/running/success/failed)
|
||||
- `started_at`
|
||||
- `ended_at`
|
||||
|
||||
### 2) `ops_job_steps`
|
||||
- `id`
|
||||
- `job_id`
|
||||
- `step_id`
|
||||
- `action`
|
||||
- `status`
|
||||
- `rc`
|
||||
- `stdout_tail`
|
||||
- `stderr_tail`
|
||||
- `started_at`
|
||||
- `ended_at`
|
||||
|
||||
> 所有 Bot 命令回执都返回 `job_id`,便于追踪。
|
||||
|
||||
---
|
||||
|
||||
## 风险控制
|
||||
|
||||
- 默认 `dry-run=true`(先演练)
|
||||
- 高风险步骤(restore/import)必须:
|
||||
- 双确认(命令 + confirm token)
|
||||
- feature flag 开启才允许执行
|
||||
- 审计日志不写明文 secrets
|
||||
- 全部 secrets 走现有 `channel` 加密机制存储
|
||||
|
||||
---
|
||||
|
||||
## 与现有系统的集成点(独立项目并存)
|
||||
|
||||
1. **Bot 层**:在 Telegram/QQ/飞书消息处理中增加 `/cpa` 命令分流
|
||||
2. **Web 层**:新增 `/ops` 页面查看任务状态与步骤日志
|
||||
3. **模型层**:新增 `ops_jobs` / `ops_job_steps`
|
||||
4. **配置层**:增加 `ops.targets`(如 hwsg/wjynl)
|
||||
|
||||
---
|
||||
|
||||
## 阶段性进度汇报原则(必须遵守)
|
||||
|
||||
**模板(四要素)**
|
||||
1) 阶段名(设计/实现/自测/上线等)
|
||||
2) 已执行动作(具体到做了什么)
|
||||
3) 可验证证据(日志、产物路径、返回码、截图等)
|
||||
4) 下一步与前置条件(还差什么、需谁确认)
|
||||
|
||||
**硬规则**
|
||||
- 无证据不使用“完成/已执行/进行中”等措辞
|
||||
- 遇到卡点必须立即说明:卡点 + 原因 + 需要的唯一输入
|
||||
- 先清单后执行的任务,未确认不得执行
|
||||
|
||||
---
|
||||
|
||||
## 事故复盘(2026-03-13,CF DNS Runbook)
|
||||
|
||||
详见:`docs/cf-dns-runbook-incident-20260313.md`
|
||||
|
||||
要点摘要:
|
||||
- 认证方式误判(API Token 被当作 API Key)。
|
||||
- heredoc/转义在 ssh.exec 中导致脚本未执行。
|
||||
- 最终采用 base64 + python3 -c exec 稳定执行。
|
||||
- 强化“阶段性汇报必须带证据”的纪律。
|
||||
|
||||
---
|
||||
|
||||
## 验收标准(v1)
|
||||
|
||||
1. `/cpa status` 能返回结构化结果(非自由文本)
|
||||
2. `/cpa usage backup` 能输出:备份路径 + sha256 + usage 快照
|
||||
3. `/cpa usage restore <id>` 支持双校验(立即 + 延迟)
|
||||
4. 任一步骤失败时可追溯到具体 step 日志
|
||||
5. 未授权命令必须被拒绝并记录审计
|
||||
|
||||
---
|
||||
|
||||
## 当前已落地(2026-03-10)
|
||||
|
||||
1. 已打通命令入口:Telegram / QQ / 飞书
|
||||
2. 已支持命令:
|
||||
- `/cpa status`
|
||||
- `/cpa usage backup`
|
||||
- `/cpa usage restore <backup_id>`
|
||||
3. 已提供查询接口:
|
||||
- `GET /api/v1/ops/jobs`
|
||||
- `GET /api/v1/ops/jobs/:id`(含 steps)
|
||||
4. `assert.json` 已支持真实 JSON 路径断言
|
||||
5. 已增加安全闸门:
|
||||
- `allow_ops_restore` feature flag(默认 false)
|
||||
- restore 需要 `--confirm YES_RESTORE`
|
||||
- 支持 `--dry-run`
|
||||
6. 已支持 `ops_targets` 目标主机表(优先解析 target 名称)
|
||||
|
||||
## 当前 Core 强化(2026-03-10 第二阶段)
|
||||
|
||||
1. 同 target 串行锁(避免并发覆盖)
|
||||
2. 作业元信息增强:`target/risk_level/request_id/confirm_hash`
|
||||
3. 统一错误码前缀(如 `ERR_FEATURE_DISABLED` / `ERR_CONFIRM_REQUIRED` / `ERR_STEP_FAILED`)
|
||||
4. step 超时控制(默认 45s)
|
||||
5. 任务取消接口:`POST /api/v1/ops/jobs/:id/cancel`
|
||||
|
||||
## 下一步落地建议
|
||||
|
||||
1. 为取消操作增加权限细分(`ops.cancel`)
|
||||
2. 增加 job 重试接口(仅失败任务可重试)
|
||||
3. 增加步骤级超时配置(runbook 可覆盖)
|
||||
4. 增加 Cloudflare / Mail 模块(在 Core 验收完成后)
|
||||
Reference in New Issue
Block a user