This commit is contained in:
rookit
2026-07-31 16:28:47 +08:00
parent 0a2880f266
commit 24896701bc
10 changed files with 2827 additions and 0 deletions
+118
View File
@@ -0,0 +1,118 @@
# v0.6.0 release scope
Status: Confirmed
## 1. Release objective
v0.6.0 面向单组织私有化部署,目标是让一个小型 SOC 团队完成稳定的告警分诊、案件调查、响应执行和日常运维。该版本以核心功能闭环为优先,不以 SaaS、多租户或大规模集群为目标。
## 2. Supported deployment
- 唯一正式支持的部署拓扑是单主机 Docker Compose。
- 不承诺 Kubernetes、横向扩容、多节点高可用或自动故障切换。
- 每种后台 Worker 正式支持一个实例;重复实例必须按 Worker Health Spec 拒绝启动。
- 数据库降级不受支持。回滚依赖升级前备份恢复。
## 3. Upgrade contract
- 必须支持从 v0.5.2 直接升级到 v0.6.0。
- 升级必须保留所有业务数据、用户、LDAP 配置、集成配置、API Key、附件和自定义脚本。
- 所有数据库变更必须提供 Django migration。
- migration 必须适用于已有数据,不得要求清空数据库。
- 升级流程继续先运行 migration,再启动应用服务和 Worker。
- 不承诺从 v0.5.1 或更早版本直接升级,也不提供 v0.6.0 到 v0.5.2 的数据库 downgrade。
## 4. Capacity baseline
正式验收使用现有 `generate_perf_data --scale medium` 数据规模:
| Resource | Baseline |
| --- | ---: |
| Users | 20 |
| Cases | 10,000 |
| Alerts | 100,000 |
| Artifacts | 50,000 |
| Alert-artifact links | 300,000 |
| Enrichments | 30,000 |
| Playbook runs | 10,000 |
| Knowledge records | 2,000 |
| Audit logs | 100,000 |
`large``extreme` 数据档位可用于开发压测,但不属于 v0.6.0 响应时间承诺。
## 5. Official compatibility matrix
| Area | Officially supported |
| --- | --- |
| SIEM | Splunk, ELK |
| LLM | OpenAI-compatible Chat Completions endpoints |
| Threat intelligence | AlienVault OTX, OpenCTI |
| Authentication | Local account, LDAP |
| Object storage | 当前 Compose 分发所配置的 S3-compatible storage |
| Cache/stream | 当前 Compose 分发所配置的 Redis |
代码枚举或 UI 示例中出现其他厂商名称,不代表官方连接器或兼容承诺。
## 6. Roles
v0.6.0 保持三个固定角色:
| Role | Meaning |
| --- | --- |
| Admin | 系统管理和全部业务写操作 |
| User / Analyst | 分析师业务写操作 |
| Viewer | 只读访问 |
不实现自定义角色、权限编辑器或团队级数据隔离。每个新功能必须在自己的 Spec 中定义三种角色的具体权限。
## 7. Language
- 正式 UI 只支持英文。
- 项目用户文档保持中英文版本,先完成中文再同步英文。
- v0.6.0 不引入前端 i18n 框架。
## 8. API compatibility
- v0.6.0 允许破坏性修改现有前端 API 和 `/api/agent/v1/`
- 不创建 Agent API v2 作为兼容层。
- 不要求旧 CLI 或旧插件拒绝连接,也不维护其兼容性。
- 新 API 仍应有明确的 DRF schema,避免无意的响应漂移。
## 9. Confirmed functional domains
1. Case 批量分诊。
2. 案件合并。
3. Playbook 执行可观测性和控制。
4. Custom Variables。
5. Worker Health。
6. Integration Health。
7. SLA 管理,待详细讨论。
8. AI 质量评估,待详细讨论。
9. 抑制规则,待详细讨论。
10. Operations 页面整合,待详细讨论。
SLA、AI 质量评估和抑制规则都是 v0.6.0 正式发布的阻断项,但必须限制为最小可用闭环。
## 10. Explicit exclusions
- 多租户、组织/Workspace 隔离。
- Kubernetes 和高可用部署。
- OIDC、SAML 或其他 SSO。
- 自定义角色。
- Jira、ServiceNow 等专用连接器。
- 可视化或表单式 Playbook 编排器。
- Playbook 中途人工审批。
- 通用 HTTP/Webhook Connector 或统一厂商动作抽象。
- 全站 UI 国际化。
- 旧 CLI/插件兼容层。
- 自动 Unmerge。
## 11. Cross-domain invariants
- merged source Case 默认不得进入 Dashboard、SLA、案件数量和正常列表统计。
- Case 单条编辑和批量编辑必须调用同一服务端状态机。
- Playbook、Module 和 Worker 错误不得向 API 暴露原始凭据、响应正文或 traceback。
- Admin 管理动作按各 Spec 写 AuditLog;高频健康遥测不写 AuditLog。
- 所有时间使用 timezone-aware UTC 存储,前端按浏览器时区显示。
- 所有列表型 API 必须分页;动态 Stage 数量不设上限,因此 Stage API 尤其不得全量返回。
- 业务写操作不得通过前端限制替代服务端权限和状态校验。
+323
View File
@@ -0,0 +1,323 @@
# Bulk Case Triage
Status: Confirmed
## 1. Purpose
允许分析师在 Case 列表中明确勾选一组 Case,一次修改相同的分诊字段。该功能优化重复人工操作,不替代案件合并、抑制规则、AI 分析或 Playbook。
## 2. Scope
### Included
- 仅 Case 支持批量分诊。
- 一次可组合修改 Assignee、Status、Severity、Verdict。
- 最多 100 个显式 Case ID。
- 支持跨分页选择。
- 同步执行并返回逐 Case 成功或失败结果。
- 允许部分成功。
### Excluded
- Alert 批量分诊。
- Priority 和 Tags 批量修改。
- 对当前筛选结果全部执行。
- 后台批量任务。
- 服务端幂等键。
- updated_at 乐观锁。
- 批次级 AuditLog 实体。
## 3. Permission matrix
| Action | Admin | User | Viewer |
| --- | --- | --- | --- |
| Select cases | Yes | Yes | No |
| Bulk update any case | Yes | Yes | No |
| Bulk assign to any valid user | Yes | Yes | No |
| Bulk close | Yes | Yes | No |
权限必须在服务端检查。User 不受 assignee 所有权限制。
## 4. Shared Case state machine
单条 PATCH 与 bulk triage 必须调用同一个 domain service,不得分别维护状态逻辑。
### Allowed transitions
| Current | Allowed next |
| --- | --- |
| New | In Progress, Closed |
| In Progress | On Hold, Resolved, Closed |
| On Hold | In Progress, Resolved, Closed |
| Resolved | In Progress, Closed |
| Closed | In Progress |
相同状态写入可以作为无变化字段跳过,不应产生状态错误。
### Transition side effects
- Case 第一次离开 `New` 时设置 `acknowledged_time=now()`
- `acknowledged_time` 设置后永久保留,Reopen 不重置。
- 进入 `Closed` 时设置 `closed_time=now()`
- 进入 `Closed` 必须在最终状态上存在非空 Verdict,并要求本次请求提供 disposition note。
- `Closed → In Progress` 是 Reopen
- 清空 `closed_time`
- 清空 `verdict`
- 保留 Summary、acknowledged_time 和历史审计。
- 其他离开 Closed 的路径不存在。
状态机应作为可复用服务,例如 `apps.cases.services.transition_case()`Serializer 和 bulk endpoint 都调用它。
## 5. Editable field semantics
### Assignee
- 字段未包含:保持不变。
- 提供有效用户 ID:设置新 assignee。
- 显式 `null`:取消分配。
- 不允许设置不存在或不可用的用户。
### Status
- 字段未包含:保持不变。
- 必须是 CaseStatus 枚举。
- 必须满足共享状态机。
- Status 不允许清空或设为 null。
### Severity
- 字段未包含:保持不变。
- 必须是 CaseSeverity 枚举。
- 不使用空字符串表达清空;使用 `Unknown`
### Verdict
- 字段未包含:保持不变。
- 必须是 CaseVerdict 枚举。
- 非 Closed Case 可以显式设为 null/空值以清空 Verdict。
- 请求结束后的 Case 若为 ClosedVerdict 必须非空。
- 不允许只清空 Closed Case 的 Verdict。
### Multi-field evaluation
校验应基于本次请求全部字段应用后的最终 Case 状态,而不是按 JSON 字段顺序执行。例如同一次请求可以把 New Case 设为 Closed 并提供 Verdict。
## 6. Bulk close note
进入 Closed 时 `reason` 必填。该文本同时用于审计和 Summary 追加。
Summary 追加格式:
```markdown
### Bulk disposition · 2026-07-28 10:44 UTC · alice
Confirmed as false positive after campaign review.
```
规则:
- 保留现有 Summary。
- 现有 Summary 与新段落之间插入空行。
- 标题时间使用 UTC 的稳定格式。
- actor 使用当前用户名。
- 对每个成功关闭的 Case 追加相同说明。
- 普通分配、Severity、Status 或 Verdict 修改的 reason 可选;如果提供,只写审计,不追加 Summary。
## 7. API
### Endpoint
`POST /api/cases/bulk-triage/`
这是 Case 专用 collection action,不实现通用 bulk PATCH。
### Request
```json
{
"case_ids": [
"6387d62e-4ed6-45b4-b83a-522cd7b5e845",
"b109ce5c-956a-42d5-b53c-bc883d19dbfc"
],
"changes": {
"assignee": "e0602519-1cd0-4750-80af-aac269a98722",
"status": "In Progress",
"severity": "High",
"verdict": "Suspicious"
},
"reason": "Campaign triage"
}
```
Validation:
- `case_ids` 必须是非空数组。
- 去重后最多 100 个。
- ID 必须是合法 UUID;请求结构中的非法 UUID 是请求级 400,而不存在的合法 UUID 是逐项失败。
- `changes` 至少包含一个允许字段。
- 不接受 Priority、Tags 或其他字段。
- `reason` 去除首尾空白后校验。
- 如果请求的最终目标状态是 Closed,reason 必填。
### Success and partial success response
只要请求结构有效,返回 HTTP 200:
```json
{
"operation_id": "a143bc8b-df7b-40d8-b0ee-e5df4e7efdc4",
"requested": 2,
"succeeded_count": 1,
"failed_count": 1,
"succeeded": [
{
"id": "6387d62e-4ed6-45b4-b83a-522cd7b5e845",
"case_id": "case_000123",
"updated_at": "2026-07-28T02:44:00Z"
}
],
"failed": [
{
"id": "b109ce5c-956a-42d5-b53c-bc883d19dbfc",
"case_id": "case_000124",
"code": "invalid_transition",
"detail": "Case cannot transition from New to Resolved."
}
]
}
```
允许的安全失败码至少包括:
- `not_found`
- `permission_denied`
- `invalid_transition`
- `invalid_final_state`
- `invalid_assignee`
- `update_failed`
不得在 `detail` 返回 traceback 或数据库错误。
### Request-level errors
以下返回 400,不处理任何 Case:
- 空 case_ids。
- 超过 100 个 ID。
- 非法 UUID。
- changes 为空。
- 未知字段。
- 非法枚举值。
- 目标 Closed 但 reason 缺失。
401/403 使用现有认证和权限响应。
## 8. Transaction and failure behavior
- 整批不使用一个全局原子事务。
- 每个 Case 在自己的短事务中读取、应用状态机、保存并写 AuditLog。
- 一个 Case 失败不得回滚已成功 Case。
- 使用 last-write-wins,不比较客户端看到的 updated_at。
- 在事务中读取最新 Case;只覆盖请求明确包含的字段。
- 前端请求进行中禁用提交按钮,平台不提供服务端 idempotency key。
## 9. Notifications
只有 assignee 实际变化时产生 assignment notification。
- 按最终 assignee 分组。
- 每位接收人一次批量请求最多收到一条 Inbox 消息。
- 消息包含成功分配给该用户的 Case 数量和可打开的 Case ID 列表。
- 失败 Case 不进入通知。
- 取消分配不发送通知。
- 如果 assignee 未改变,不发送通知。
- 通知在对应 Case 事务成功后统一生成;通知失败不得把已完成业务更新伪装为失败,应按现有通知错误策略显式记录。
## 10. Audit
每个成功 Case 写一条现有 `updated` AuditLog
```json
{
"action": "updated",
"changes": {
"status": {"from": "New", "to": "In Progress"},
"severity": {"from": "Medium", "to": "High"}
},
"metadata": {
"source": "bulk_triage",
"operation_id": "a143bc8b-df7b-40d8-b0ee-e5df4e7efdc4",
"reason": "Campaign triage"
}
}
```
- 后端为每次请求生成一个 UUID operation_id。
- 同一请求的所有成功 Case 共享 operation_id。
- 不创建单独的批次 AuditLog。
- 无实际字段变化的 Case 可以视为成功,但不得写空 changes 审计;响应应包含 `unchanged: true`
- 失败 Case 不写业务更新审计。
## 11. Frontend
### Selection
- 仅 Case 主列表启用批量分诊。
- 翻页保留选择。
- Search、普通 Filter 或 Advanced Filter 发生变化时清空选择。
- 不支持“Select all filtered results”。
- 最多选择 100 条;达到上限后其他 checkbox disabled,并显示上限提示。
- Toolbar 始终显示选中数量和 Clear selection。
### Bulk triage modal
- 用户点击 Bulk Triage 打开 Modal,不立即执行。
- 每个字段有独立“修改此字段”开关;未启用字段不进入 changes。
- Assignee 支持选择用户和 Unassigned。
- Status、Severity、Verdict 使用现有选项与 Tag 表现。
- reason 默认可选;Status 选择 Closed 后立即变为必填并解释会追加到 Summary。
- 显示选中数量、字段变更预览和关闭副作用。
- 提交期间禁用所有操作。
### Result handling
- 成功项从 selection 移除。
- 失败项保持选中。
- 显示成功/失败汇总。
- 失败列表显示 Case ID、失败码对应的用户可读说明。
- 不自动重试。
- 刷新当前列表数据,但不得因刷新清除失败 selection。
## 12. Backend implementation surfaces
预期涉及:
- `backend/apps/cases/services.py`:共享状态机和字段应用。
- `backend/apps/cases/serializers.py`bulk request/response serializer。
- `backend/apps/cases/views.py`collection action。
- `backend/apps/inbox/notifications.py`:汇总 assignment notification。
- `frontend/src/components/DataTable.tsx`:受控跨页 selection 和自定义 bulk action context。
- Case resource 页面:Bulk Triage modal 和结果展示。
不得把 Case 业务状态机写进通用 DataTable。
## 13. Acceptance criteria
1. Admin/User 可对 1100 个 Case 组合修改四个允许字段。
2. Viewer 看不到操作并且 API 返回 403。
3. 跨页选择保留,筛选变化清空。
4. 非法状态转换只失败对应 Case,其他 Case 成功。
5. Closed 必须有最终 Verdict 和 reason。
6. Bulk close 正确追加带时间和 actor 的 Markdown Summary。
7. Reopen 清空 closed_time/verdict,保留 acknowledged_time/Summary。
8. assignment notification 按用户汇总。
9. 每个成功 Case 有 source、operation_id 和 changes 审计。
10. 请求级错误不产生任何 Case 更新。
11. medium 数据集下 100 条同步请求可在正式验收设定的超时内完成。
## 14. Known tradeoffs
- last-write-wins 可能覆盖并发编辑,这是已接受行为。
- 没有服务端 idempotency,客户端网络重试可能重复追加 close note;前端必须避免自动重试 POST。
- 部分成功使一次 operation_id 不代表全量成功;响应和逐 Case 审计是事实来源。
+424
View File
@@ -0,0 +1,424 @@
# Case Merge
Status: Confirmed
## 1. Purpose
允许 Admin 将最多 20 个重复源 Case 原子地合并到一个明确目标 Case。业务对象迁移到目标,源 Case 永久保留为只读历史入口,确保 correlation routing、调查证据和审计可追溯。
## 2. Scope
### Included
- 多源到单目标合并。
- 服务端预检。
- 原子执行和行锁复检。
- operation_id 幂等。
- 关联 Alert、Enrichment、Comment、Playbook 和 AI Job 迁移。
- merged source 只读 API 和 UI。
- 后续 correlation_uid 路由到最终目标。
- 合并关系扁平化。
### Excluded
- 自动重复检测。
- 自动选择目标。
- Unmerge。
- 非 Admin 合并。
- 自动合并字段、Tags、Summary、AI 报告或 Knowledge。
- 活动任务自动取消。
## 3. Permission matrix
| Action | Admin | User | Viewer |
| --- | --- | --- | --- |
| View merged source | Yes | Yes | Yes |
| View Merged Sources tab | Yes | Yes | Yes |
| Run merge preflight | Yes | No | No |
| Execute merge | Yes | No | No |
| Edit merged source | No | No | No |
User 可以普通编辑 Verdict 为 Duplicate,但不能迁移关系。
## 4. Data model
### Case additions
```python
merged_into = models.ForeignKey(
"self",
null=True,
blank=True,
on_delete=models.PROTECT,
related_name="merged_sources",
)
```
约束:
- `merged_into_id != id`
- merged source 的 merged_into 必须直接指向最终目标。
- 最终目标的 merged_into 必须为空。
- 应为 `merged_into` 建索引。
- 使用 PROTECT 防止目标删除;业务 API 本身也不应允许删除有历史关系的 Case。
### CaseMergeOperation
目标模型字段:
| Field | Notes |
| --- | --- |
| id | UUID primary key |
| operation_id | UUID, unique, client supplied |
| target | FK Case, PROTECT |
| actor | nullable FK User, SET_NULL |
| reason | required text |
| source_snapshot | JSON list of explicit and flattened source metadata |
| target_changes | JSON of explicit target edits |
| moved_counts | JSON counters |
| result | JSON stable idempotent response |
| created_at | immutable timestamp |
Operation 创建后不可修改或删除。`source_snapshot` 至少保存源 UUID、readable ID、title、原 status、原 verdict、原 assignee、原 merged_into 和本次是否显式选择。
不单独创建可变 join tableCase.merged_into 是当前关系来源,Operation 是历史事实。
## 5. Eligibility
### Target
- 必须存在。
- 必须是未合并最终 Case,即 `merged_into IS NULL`
- 不能同时出现在 source_ids。
- Status 不能是 Closed;用户必须先显式 Reopen 到 In Progress。
- 可以已经拥有 merged sources。
### Explicit sources
- 120 个唯一 ID。
- 必须存在。
- 可以是任何 Status,包括 Closed。
- 必须 `merged_into IS NULL`,即已经作为 source 的 Case 不能再次显式合并。
- 不能等于 target。
- 可以本身拥有历史 merged sources;执行时这些 inbound source 一并扁平化到新目标。
### Active job blocker
任一显式 source 或其需要迁移的任务存在以下状态时阻止整次合并:
- Playbook Pending 或 Running。
- CaseAnalysisJob Pending 或 Running。
系统不自动取消任务。用户必须等待结束或通过对应合法操作取消后重试。
## 6. Preflight API
### Endpoint
`POST /api/cases/merge/preflight/`
### Request
```json
{
"target_id": "ef235eb5-a0d8-48d2-a568-741909ce2e06",
"source_ids": [
"87cc7cf4-66df-4f4e-bb96-66c1155c0219",
"aa3d9963-8338-4401-b92d-3eeaa9fcbfde"
]
}
```
### Response
预检返回:
- target 摘要及可编辑字段。
- 每个 source 的字段对比。
- source Tags 差异。
- 将迁移的 Alert、Case-level Enrichment、Comment、Playbook、AI Job 数量。
- 保留在 source 的 Knowledge、Summary 和 AI report 标记。
- active job blocker。
- target Closed、source already merged、循环或其他 blocker。
- 需要扁平化重新指向的历史 source 数量。
- 不可撤销提示。
示例:
```json
{
"eligible": true,
"target": {
"id": "ef235eb5-a0d8-48d2-a568-741909ce2e06",
"case_id": "case_000100",
"status": "In Progress"
},
"sources": [],
"move_counts": {
"alerts": 17,
"case_enrichments": 4,
"comments": 8,
"playbooks": 3,
"analysis_jobs": 2
},
"retained_counts": {
"knowledge": 1,
"source_reports": 2
},
"flattened_source_count": 3,
"blockers": [],
"warnings": ["This merge cannot be undone."]
}
```
Preflight 不获取长期锁,不保证执行时仍可合并。执行必须复检。
## 7. Merge API
### Endpoint
`POST /api/cases/merge/`
### Request
```json
{
"operation_id": "a00384a1-bca5-471f-95e2-02fc8f419a3a",
"target_id": "ef235eb5-a0d8-48d2-a568-741909ce2e06",
"source_ids": [
"87cc7cf4-66df-4f4e-bb96-66c1155c0219"
],
"reason": "Duplicate cases generated by the same campaign",
"target_changes": {
"severity": "High",
"tags": ["phishing", "campaign-2026-07"]
}
}
```
规则:
- operation_id 必填 UUID。
- reason trim 后必填。
- target_changes 可选,只允许 Case 正常可编辑业务字段。
- target_changes 必须通过共享 Case serializer/state machine;不能在 merge 中把 target 设为 Closed。
- target 默认字段全部保留,source 永不自动覆盖 target。
- Tags 只有在 target_changes 明确给出时改变,不自动并集。
### Idempotency
- operation_id unique。
- 已存在相同 operation_id 时,不再次执行;返回 Operation 保存的原始 result。
- 如果相同 operation_id 携带不同 target/source/reason,也返回原 result,不重新解释请求;可以附 `replayed: true`
- Operation 与业务迁移在同一数据库事务提交。
### Success response
返回目标摘要、显式 source、扁平化 source、moved_counts、保留项和 operation_id。
### Failure
- 结构错误返回 400。
- 权限错误返回 403。
- target/source 不存在返回 404 或统一 400;实现必须保持 schema 一致。
- 执行时状态变化、active job 或已合并冲突返回 409。
- 任一失败整次事务回滚。
- 不返回原始数据库异常。
## 8. Execution algorithm
在一个 `transaction.atomic()` 中:
1. 按稳定 UUID 顺序 `select_for_update()` 锁定 target 和显式 sources,避免死锁。
2. 查找显式 source 已有的 inbound merged sources,并锁定这些 Case。
3. 重新校验 target、source、merged relation 和活动任务。
4. 应用显式 target_changes。
5. 保存 Operation 初始事实。
6. 迁移业务关系。
7. 把所有显式 source 和其 inbound source 的 `merged_into` 设为 target,形成一层关系。
8. 显式 source 设置 Closed、Duplicate、closed_time;保留 Summary、AI 字段和 acknowledged_time。
9. 写 target 和每个显式 source 的 merge AuditLog。
10. 保存 moved_counts 和稳定 result。
11. transaction commit 后发送汇总通知。
任何步骤失败全部回滚。
## 9. Relationship migration
| Relation | Behavior |
| --- | --- |
| Alert.case | 全部改为 target |
| Alert.artifacts | 不变 |
| Alert-level Enrichment | 不变,随 Alert 可见 |
| Artifact-level Enrichment | 不变 |
| Case-level Enrichment | case_id 改为 target;不去重 |
| Completed/Failed Playbook | case_id 改为 target |
| Completed/Failed CaseAnalysisJob | case_id 改为 target |
| Pending/Running jobs | 阻止合并 |
| Comment on source Case | content object 改为 target |
| Comment reply tree | 保持 parent/mentions/attachments |
| Knowledge.case | 保持 source |
| Existing AuditLog | 保持原 object_id |
| Source Summary/report | 保持 source |
### Comment origin
评论迁移后必须能显示来源。推荐在 Comment 增加 nullable `origin_case`,或创建等价不可变 metadata。不得修改评论正文来注入来源文本。
## 10. Source final state
显式 source
- `status = Closed`
- `verdict = Duplicate`
- `closed_time = merge time`
- `merged_into = target`
- 保留 title、description、summary、tags、AI 字段、acknowledged_time 和 correlation_uid。
- 记录合并前 status/verdict 到 Operation snapshot 和 AuditLog。
历史 inbound source 已经是 merged source,只更新 merged_into 到最终 target,不重写其原 merge 时间或历史。
## 11. Correlation routing
Alert ingestion 按 correlation_uid 找到 Case 后:
1. 如果 Case.merged_into 为空,正常使用。
2. 如果不为空,使用 merged_into 最终 target。
3. 数据约束要求最多一跳;服务仍可防御性解析并检测循环。
4. source 保留 correlation_uid,作为目标的历史 alias。
这项逻辑必须放在统一 Case correlation service,不能只修某个 Module。
## 12. Merged source API behavior
### Read
- GET list 默认排除 `merged_into IS NOT NULL`
- 提供 `include_merged=true` Admin/User/Viewer 筛选。
- 精确 Case ID 搜索必须能找到 merged source。
- GET detail 返回 200,并包含:
- `is_merged: true`
- target UUID/readable ID/title
- merge actor/time/reason
- 原只读字段和历史 Summary/report。
### Write
对 merged source 的所有业务写操作返回 409:
- PATCH/PUT/DELETE Case。
- 添加/删除评论。
- 启动 Playbook 或 AI 分析。
- 新建 Case-level Enrichment/Knowledge。
- 任何其他以 Case 为目标的 mutation。
409 响应包含安全目标摘要:
```json
{
"code": "case_merged",
"detail": "This case was merged and is read-only.",
"merged_into": {
"id": "...",
"case_id": "case_000100"
}
}
```
## 13. Visibility and metrics
默认排除 merged source
- Case 主列表。
- Dashboard Case 数量、状态分布和 SLA。
- 任何“当前案件”统计。
- Assignee 活跃工作量。
保留:
- Audit 搜索。
- 精确 ID 搜索。
- `include_merged` 筛选。
- target 的 Merged Sources tab。
## 14. Audit
现有历史 AuditLog 永不迁移或改写。
本次合并:
- target 一条 `merged` AuditLog。
- 每个显式 source 一条 `merged` AuditLog。
- 共享 operation_id。
- metadata 包含 target、显式 sources、actor、reason、moved_counts、flattened count。
- source changes 包含 status/verdict/merged_into 的 before/after。
- 不为每个 Alert 外键变化生成独立业务审计,避免日志爆炸;迁移数量由 merge event 覆盖。
## 15. Notifications
通知目标:
- target 当前 assignee。
- 每个显式 source 合并前 assignee。
- 去重用户。
- null assignee 忽略。
每个用户只收到一条 Inbox 消息,包含 target、source 数量、source IDs 和 reason。通知在 commit 后发送,通知失败不回滚合并。
## 16. Frontend
### Entry
- Case 列表 Admin 批量操作增加 Merge。
- Detail 页面 Admin 可发起“Merge into another case”。
- 非 Admin 不显示入口。
### Modal
1. 选择或确认最多 20 个 source。
2. 通过 Case ID/title 搜索明确选择任意有效 target。
3. 调用 preflight。
4. 展示 target/source 字段对比、Tags 差异、迁移数量、保留数据和 blocker。
5. 允许手动编辑 target 字段。
6. reason 必填。
7. 显示不可撤销警告。
8. 生成 operation_id 后提交;网络重试复用同一 operation_id。
### Merged source
- Detail 顶部显示明显 Warning banner。
- 提供 Open target case。
- 所有编辑控件、评论、Playbook 等 mutation 隐藏或 disabled。
### Target
新增 `Merged Sources` tab
- source Case ID、title。
- 合并前 status/verdict。
- merge time、actor、reason。
- 打开只读 source。
- 使用分页。
## 17. Acceptance criteria
1. Admin 可把 120 个 source 原子合并到 target。
2. User/Viewer 无法 preflight 或 merge。
3. Closed target 被拒绝,Closed source 可合并。
4. active Playbook/AI Job 阻止整次操作。
5. 所有规定关系迁移或保留正确。
6. 任一迁移异常整次回滚。
7. 重复 operation_id 不产生重复迁移、审计或通知。
8. 现有审计 object identity 不变。
9. merged source GET 可读、所有 mutation 409。
10. 后续 correlation_uid Alert 路由到最终 target。
11. 二次合并扁平化,不形成多跳。
12. 默认列表/Dashboard/SLA 排除 merged source。
13. Merged Sources tab 可追溯原 Summary 和 AI report。
## 18. Known tradeoffs
- Merge 不可撤销;误操作只能人工修复或恢复备份。
- Knowledge 不迁移,target 与 source 可能分别保留知识。
- target 字段默认胜出,不自动选择“更严重”的值。
- 合并后的评论失去 source 详情页独立讨论入口,但通过 origin metadata 可追溯。
+388
View File
@@ -0,0 +1,388 @@
# Playbook Execution
Status: Confirmed
## 1. Purpose
保留低心智成本的 Python `run()` 编程模型,同时增加可持久化的结构化执行阶段、明确时间、取消、完整重试、崩溃恢复和只读运行历史。
该设计不是工作流引擎。Stage 是观测事件,不是独立调度、恢复或重试的 Step。
## 2. Authoring model
Playbook 继续由 Python 代码定义:
```python
class Playbook(BasePlaybook):
NAME = "Contain Endpoint"
DESC = "Contain the endpoint associated with the case."
TAGS = ["EDR", "Response"]
RISK_LEVEL = "High"
def run(self):
with self.stage("collect", "Collect endpoint context") as stage:
endpoints = collect_endpoints(self.case)
stage.summary = f"Collected {len(endpoints)} endpoint(s)."
for endpoint in endpoints:
with self.stage("contain", f"Contain {endpoint.hostname}") as stage:
contain(endpoint)
stage.summary = "Containment request accepted."
return f"Contained {len(endpoints)} endpoint(s)."
```
规则:
- `run()` 仍是唯一执行入口。
- Stage 完全可选;现有 v0.5.2 Playbook 无需修改即可运行。
- Stage 不保存 Python 返回值或跨阶段输入。
- Stage 不独立调度、不暂停、不恢复、不单步重试。
- `run()` 未捕获异常导致整个 Run Failed。
- 开发者可以在 Stage 内捕获可容忍错误,并显式写安全 summary。
- Playbook 可直接使用 `httpx` 或厂商 SDK;平台不提供通用 Connector。
## 3. Explicit exclusions
- 可视化/表单式编排器。
- DAG、分支、并行 Step。
- 中途人工审批;点击 Run 即授权整个 Playbook。
- Running hard cancel 或 cooperative cancel。
- 单步 retry/resume。
- 源码、hash 或定义版本锁定。
- 结构化 input schema。
- HTTP/Webhook Connection profile。
- 自动轮询或 WebSocket 进度。
## 4. Definition metadata
定义扫描继续读取:
- `NAME`
- `DESC`
- `TAGS`
- 新增 `RISK_LEVEL`
风险枚举:
- Low
- Medium
- High
- Critical
默认 Low。风险只用于 UI 展示,不改变权限、确认或执行流程。
Run 不保存 DESC/TAGS/RISK_LEVEL 快照。历史页面按 name 解析当前定义:
- 定义仍存在:展示当前 metadata。
- 定义已删除或改名:只展示 Run 保存的 name,并标记 definition unavailable。
Pending/Retry 执行时始终加载当前最新 Python 代码。
## 5. Run model
现有 `Playbook` 记录继续作为 Run,可考虑重命名 Python 类但不要求修改 db_table。
新增/调整字段:
| Field | Type | Semantics |
| --- | --- | --- |
| job_status | enum | Pending/Running/Success/Failed/Cancelled |
| job_id | string/UUID | 当前执行标识 |
| retry_of | nullable self FK | Failed Run 的重试来源 |
| started_at | nullable datetime | claim 成功时间 |
| finished_at | nullable datetime | terminal 时间 |
| cancelled_by | nullable FK User | Pending cancel actor |
| remark | text | 终态安全摘要 |
保留:
- case
- name
- user
- user_input
- created_at/updated_at
### Status transitions
| Current | Allowed next |
| --- | --- |
| Pending | Running, Cancelled |
| Running | Success, Failed |
| Success | none |
| Failed | none; Retry creates new Run |
| Cancelled | none |
不允许直接修改 job_status。所有状态变化通过 domain service。
### Timing
- Pending 创建时 started_at/finished_at 为空。
- Pending→Running 设置 started_at。
- Running→Success/Failed 设置 finished_at。
- Pending→Cancelled 设置 finished_at,不设置 started_at。
- duration_seconds 由 started_at 和 finished_at 计算;Running 使用 now-started_at。
## 6. Stage model
建议模型 `PlaybookStage`
| Field | Type | Notes |
| --- | --- | --- |
| id | UUID | primary key |
| playbook_run | FK | CASCADE at DB level, though Run API cannot delete |
| sequence | positive bigint | per Run append order |
| key | string | developer supplied, may repeat |
| label | string | human-readable |
| status | enum | Running/Success/Failed |
| summary | text | explicit safe summary |
| error_type | string | sanitized exception class |
| error_message | text | sanitized length-limited message |
| started_at | datetime | context enter |
| finished_at | nullable datetime | context exit |
| duration_ms | nullable bigint | derived/persisted |
Constraints/indexes:
- unique `(playbook_run, sequence)`.
- index `(playbook_run, sequence)`.
- index `(playbook_run, status)`.
- key/label 长度必须有限,但 Stage 数量不限。
### Stage context behavior
进入 `with self.stage(key, label)`
1. 原子分配下一个 sequence。
2. 创建 Running Stage。
3. 返回可设置 `summary` 的 context object。
正常退出:
1. 保存显式 summary。
2. 设置 Success、finished_at、duration。
异常退出:
1. 设置 Failed。
2. 保存异常类型。
3. 保存经过敏感字段过滤和长度限制的安全错误。
4. 完整 traceback 只进入 Worker log。
5. 原异常继续抛出,使 Run Failed。
Stage key/label 可以重复,支持循环动态生成。Stage 是扁平 sequence,不支持 parent。
### Output safety
- 不自动 `str()` 或 JSON serialize 任意函数输出。
- 不自动保存 HTTP response、LLM output、SIEM records 或变量值。
- summary 由自定义代码显式提供。
- error_message 使用统一 sanitizer,至少屏蔽 password/token/api_key/secret/authorization 等值。
- API 不返回 traceback。
## 7. Queue and Worker behavior
### Supported topology
- 正式支持一个 Playbook Worker。
- 全局 FIFO,按 created_at/id claim。
- 不按 Case Severity 或用户优先级排序。
### Per-Case concurrency
同一 Case 最多一个 Running Run
- claim 时跳过已经存在 Running Run 的 Case。
- 同 Case 的其他 Pending 保持队列。
- 不同 Case 在未来多 Worker 实现中可并行,但 v0.6.0 不支持多 Worker。
### Duplicate launch
Run endpoint 不提供 idempotency。重复请求可以创建多条 Pending Run,这是已接受行为。
### Worker loss
Playbook Worker 使用 Worker Health 心跳。检测到前一实例丢失后:
- 遗留 Running Run 标记 Failed。
- 遗留 Running Stage 标记 Failed。
- remark 使用固定安全文本,说明 Worker stopped before completion。
- 不自动重置 Pending 或重跑。
- 用户检查后手动 Retry。
实现可在 Worker 成功获取 singleton lease 后执行 orphan recovery。不得仅按运行时长把合法长任务判失败。
## 8. Cancellation
只有 Pending 可取消。
`POST /api/playbooks/{id}/cancel/`
- Admin/User 可取消任意 Pending Run。
- Viewer 403。
- 非 Pending 返回 409。
- 设置 Cancelled、finished_at、cancelled_by 和安全 remark。
- 写 AuditLog。
- 不发送 completion notification。
Running 无取消入口。Playbook 中每个外部调用必须自行设置超时。
## 9. Retry
`POST /api/playbooks/{id}/retry/`
- 仅 Failed Run。
- Admin/User 可重试任意 Failed Run。
- Viewer 403。
- 创建新的 Pending Run。
- `retry_of` 指向原 Run。
- 复制 case、name、user_input。
- 新 Run 的 user 是执行 Retry 的当前用户。
- 使用当前 Case 数据和最新 Playbook 代码。
- 原 Run/Stage 不修改。
- 写 retry AuditLog,关联新旧 Run。
- Retry 不受幂等保护;重复点击可能创建多个 Run。
## 10. Launch
`POST /api/playbooks/run/`
- Admin/User 可运行,Viewer 403。
- 任何未合并 Case 均可运行,包括 Closed。
- merged source 返回 409 和 target 摘要。
- name 必须能在当前定义扫描中找到。
- user_input 是可选自由文本。
- 点击 Run 直接创建 Pending,不增加确认。
- risk level 只展示。
## 11. API shape
Playbook Run 资源改为 read-only
- GET list。
- GET retrieve。
- GET definitions。
- POST run。
- POST cancel。
- POST retry。
- GET stagesdetail action 或独立 nested endpoint)。
禁止:
- 普通 POST create。
- PUT/PATCH。
- DELETE。
Stage API
- 只读。
- 必须按 sequence 分页。
- 支持 status 筛选可选,但不得一次返回无限 Stage。
### Run response additions
```json
{
"id": "...",
"playbook_id": "playbook_000123",
"job_status": "Running",
"retry_of": null,
"started_at": "2026-07-30T08:00:00Z",
"finished_at": null,
"duration_seconds": 42,
"current_stage": {
"sequence": 8,
"key": "contain",
"label": "Contain endpoint-7",
"status": "Running"
},
"stage_count": 8,
"definition": {
"available": true,
"risk_level": "High",
"tags": ["EDR", "Response"]
}
}
```
## 12. Remark semantics
| Terminal state | Remark |
| --- | --- |
| Success | `str(run() return value)`,经长度限制和安全处理 |
| Failed | 固定安全摘要,可引用失败 Stage label/sequence |
| Cancelled | 固定文本并记录取消 actor |
过程日志不得拼接到 remark。原始异常只进服务器日志。
## 13. Notifications
遵循发起用户现有 `notify_on_playbook_completion` 偏好:
- Success 通知。
- Failed 通知。
- Cancelled 不通知。
- Stage 状态变化不通知。
- Retry 新 Run 按新发起用户偏好处理。
## 14. Audit
只记录用户动作:
- launch
- cancel
- retry
Worker 自动状态变化不写全局 AuditLog,因为 Run/Stage 已是状态事实。
Audit metadata 不包含 user_input 全文、Stage summary 或任何 Secret。
## 15. Frontend
### Definition selection
- 显示 name、description、tags、risk level。
- 点击 Run 直接排队。
- 保留自由文本 user_input。
### Run list/detail
- 状态、Case、发起人、时间、duration、retry relation。
- Pending 显示 Cancel。
- Failed 显示 Retry。
- Run/Stage 无 Delete/Edit。
- Stage 使用分页的扁平时间线或表格。
- 页面不自动轮询、不使用 WebSocket;提供 Refresh。
- definition 删除后显示 unavailable,而不是报页面错误。
## 16. Migration
- 现有四状态数据直接保留。
- 新 Cancelled 只用于 v0.6.0 后记录。
- 已有 Success/Failed Run 的 started_at 可为空,不伪造历史时间。
- 旧 Running Run 在升级后由首次 Worker recovery 处理。
- retry_of、timing、cancel actor 均 nullable。
## 17. Acceptance criteria
1. v0.5.2 旧 Playbook 不修改即可运行。
2. 可选 Stage 正确保存动态重复 key 和 sequence。
3. Stage 异常导致 Stage/Run FailedAPI 不泄露 traceback。
4. Pending 可取消,Running 不可取消。
5. Failed Retry 创建新 Run并保留原历史。
6. Run/Stage 所有普通 mutation/delete 被拒绝。
7. 同一 Case 不同时 Running 两个 Run。
8. FIFO claim 可预测。
9. Worker 崩溃后遗留 Running 标记 Failed且不自动重跑。
10. Closed Case 可运行,merged source 409。
11. Success/Failed 通知符合用户偏好。
12. Stage 数量大时 API 正确分页。
## 18. Known tradeoffs
- 最新代码执行使 Pending Run 语义可能在排队期间变化。
- 不保存 metadata 快照,历史 risk/tags 会随定义变化。
- 重复 launch/retry 可产生重复外部副作用。
- Running 不可取消。
- 动态无限 Stage 可能产生大量数据,开发者需自律;平台只通过分页保护读取。
- 直接 httpx 调用的重试、幂等和 Secret 安全由自定义代码负责。
+316
View File
@@ -0,0 +1,316 @@
# Custom Variables
Status: Confirmed
## 1. Purpose
提供一个由 Admin 通过 UI 管理、由自定义 Playbook 和 Agentic Module 在后端运行时读取的字符串变量仓库。它类似受控的数据库版环境变量,但不会修改真实 `os.environ`,也不影响 Django 全局配置。
典型用途:
- 外部系统 base URL。
- API token、username/password。
- tenant/project ID。
- 自定义 JSON 字符串。
- Module 或 Playbook 的运行参数。
## 2. Scope
### Consumers
- `BasePlaybook.get_variable(key)`
- `BaseModule.get_variable(key)`
### Not consumers
- Agent API。
- CLI 或插件。
- 前端运行时。
- Django template。
- 其他任意后端模块。
- 系统 Runtime Settings。
### Excluded
- 写入真实进程环境变量。
- 全局配置覆盖。
- per-Playbook/per-Module scope。
- 变量继承或 override。
- value 类型系统。
- `.env` 导入导出。
- REQUIRED_VARIABLES 声明。
- Secret 加密、版本历史或自动泄露防护。
## 3. Data model
建议模型 `CustomVariable`
| Field | Type | Rules |
| --- | --- | --- |
| id | UUID | primary key |
| key | CharField(128) | unique, immutable |
| value | TextField | non-empty, max 65,536 UTF-8 bytes |
| is_secret | Boolean | controls API masking only |
| description | TextField | optional |
| enabled | Boolean | default true |
| created_at | DateTime | auto |
| updated_at | DateTime | auto |
### Key validation
Regex
```text
[A-Z][A-Z0-9_]{0,127}
```
- 全局唯一。
- 大小写敏感,但合法输入只有大写。
- 创建后不可改名。
- 修改 key 的 PATCH/PUT 返回 validation error。
### Value validation
- 必须至少一个字符。
- 以 UTF-8 bytes 计算,最多 65,536 bytes。
- 可包含换行。
- 不支持 binary。
- 不做 trim;空格可能是有意值,但零长度禁止。
- 更新 Secret 时省略 value 表示保留旧值。
- 显式 `""` 始终拒绝。
## 4. Storage security
已确认:
- Secret 和非 Secret 均以 PostgreSQL 明文保存。
- 数据库管理员、数据库泄露和未加密备份可以读取 Secret。
- `is_secret` 只控制 API/UI 显示与审计,不提供 cryptographic protection。
- 用户文档必须明确该限制。
不得在 AuditLog、普通 API response、异常文本或日志中复制 value。
## 5. Runtime API
Base class helper
```python
def get_variable(self, key):
...
```
返回:
- Enabled 且存在:原始 `str`
- 不存在:`None`
- Disabled`None`
- 已删除:`None`
行为:
- 每次调用都查询 PostgreSQL。
- 不做 per-run、per-message 或 Worker 全局缓存。
- Admin 在 Playbook/Module 运行中修改、Disabled 或删除变量,下一次读取立即看到变化。
- 不抛 missing variable 异常。
- 不支持 default 参数作为平台约定;自定义代码自行使用 `or` 或显式 None 处理。
- 不返回 is_secret/description 等 metadata。
- 不记录 read audit 或 usage relation。
建议共享 service 位于 `apps.settings.custom_variables` 或等价窄模块,BasePlaybook/BaseModule 只做代理,避免重复 ORM 代码。
## 6. Permissions
| Action | Admin | User | Viewer | Playbook/Module Worker |
| --- | --- | --- | --- | --- |
| List metadata | Yes | No | No | No |
| Read non-secret value via Admin API | Yes | No | No | N/A |
| Reveal secret | Yes | No | No | N/A |
| Create/update/delete | Yes | No | No | No |
| get_variable runtime | No direct API | No direct API | No direct API | Yes |
Worker 读取不根据发起 Playbook 的用户角色过滤。User 发起的 Playbook 仍可读取所有 Custom Variables,因此 Admin 必须只安装可信自定义代码。
## 7. Admin API
建议资源:
`/api/settings/custom-variables/`
### List/retrieve default representation
非 Secret
```json
{
"id": "...",
"key": "EDR_BASE_URL",
"value": "https://edr.internal.example",
"is_secret": false,
"description": "Production EDR API",
"enabled": true
}
```
Secret
```json
{
"id": "...",
"key": "EDR_API_TOKEN",
"value": "",
"value_configured": true,
"is_secret": true,
"description": "Production EDR token",
"enabled": true
}
```
### Reveal
`POST /api/settings/custom-variables/{id}/reveal/`
- 仅 active Admin session。
- 不要求重新输入本地或 LDAP 密码。
- 返回一次明文 value。
- 每次请求写 AuditLog。
- 不应支持 bulk reveal。
- response 应使用 no-store cache headers。
### Update
- key 不可改。
- Secret update 未包含 value:保留旧值。
- Secret→non-secretAPI 需要显式确认字段,例如 `confirm_secret_exposure=true`
- 没有确认返回 400。
- non-secret→secret 正常允许。
- 所有 changes 审计不包含 value。
### Delete
- 允许硬删除。
- UI 必须二次确认。
- API 不负责扫描 Python 代码引用。
- 删除后运行时返回 None。
- 删除 AuditLog 保存 key、description、is_secret、enabled,不保存 value。
## 8. Audit
写 AuditLog
- create
- update
- enable/disable(作为 update
- reveal
- delete
不写:
- get_variable runtime read。
- Admin 普通 list/retrieve。
Secret 和非 Secret value 均不得进入 changes。可使用:
```json
{
"changes": {
"value": {"from": "***", "to": "***"},
"enabled": {"from": true, "to": false}
},
"metadata": {
"key": "EDR_API_TOKEN",
"value_changed": true
}
}
```
不保留旧 value,不支持 rollback。
## 9. Frontend
位置:System Settings 中新增 `Custom Variables`
### List
- Key。
- Description。
- Secret 标记。
- Enabled。
- Value configured。
- Updated time。
- Edit/Delete actions。
- Secret 默认不可见。
### Create/edit modal
- Key 创建时可编辑,编辑时只读。
- Value 使用 multiline inputSecret 使用 password input。
- is_secret switch。
- enabled switch。
- description。
- value byte limit 提示。
- 编辑 Secret 时 value 留空表示不修改,UI 必须明确说明。
### Reveal
- Secret 行显示 Reveal。
- active Admin session 直接调用。
- 明文只显示在临时 Modal。
- Modal 关闭后从前端 state 清除。
- 不复制到列表 state、URL、localStorage 或 console。
### Secret downgrade
从 Secret 改为普通变量时显示额外确认:
> This value will become visible in normal Admin API responses and UI.
## 10. Interaction with custom code
示例:
```python
class Playbook(BasePlaybook):
def run(self):
base_url = self.get_variable("EDR_BASE_URL")
token = self.get_variable("EDR_API_TOKEN")
if not base_url or not token:
raise ValueError("EDR custom variables are not configured.")
```
自定义代码责任:
- 检查 None。
- 解析 JSON/boolean/number。
- 不把 Secret 写入 log、Stage summary、remark、Enrichment 或异常。
- 为 HTTP 调用设置 timeout、TLS、proxy、重试和幂等。
平台不静态分析 key,也不展示“变量被哪些脚本使用”。
## 11. Migration and backup
- 新表 migration,无旧数据迁移。
- v0.5.2 现有 LLM/SIEM/LDAP/TI Secret 不自动复制到 Custom Variables。
- 备份/恢复自然包含明文 value。
- Compose 文档需提醒保护数据库备份。
## 12. Acceptance criteria
1. 只有 Admin 能访问资源和 Reveal。
2. key regex、唯一和不可改名规则生效。
3. 空 value 和超过 65,536 bytes 被拒绝。
4. Secret 默认 response 不含明文。
5. Admin Reveal 返回明文并写不含 value 的审计。
6. Secret→普通无确认被拒绝。
7. Playbook 和 Module 每次读取当前数据库值。
8. Disabled/missing/deleted 返回 None。
9. Agent API、CLI 和普通用户没有读取端点。
10. CRUD AuditLog 永不包含 old/new value。
11. 删除无需引用检查且立即影响运行时读取。
## 13. Known tradeoffs
- PostgreSQL 和备份保存明文 Secret。
- active Admin session 无需重新认证即可 Reveal。
- User 发起的可信 Playbook 可以间接使用全部 Secret。
- 平台无法阻止恶意或错误自定义代码泄露 Secret。
- 每次 ORM 查询增加少量开销,这是为即时一致性接受的成本。
+362
View File
@@ -0,0 +1,362 @@
# Worker Health
Status: Confirmed
## 1. Purpose
让 Admin 不依赖 Docker CLI 或日志文件,就能判断后台 Worker 是否存活、正在做什么、是否失败以及业务积压情况。
v0.6.0 最终监控六个逻辑 Worker
1. Agentic Module。
2. Case Analysis。
3. Playbook。
4. ELK Action。
5. Dashboard Cache。
6. Integration Health。
监控粒度是逻辑进程类型,不是每个 Module/Playbook definition,也不是 Docker container ID。
## 2. Architecture
Worker Health 基础设施集成进 `apps.common.worker_runner.run_worker()`
每个 Worker
- 启动时获取 Redis singleton lease。
- 启动 daemon heartbeat thread。
- 主线程在 iteration 边界更新执行状态与计数。
- 优雅退出时释放 lease并留下安全退出原因。
Admin API 从 Redis 读取当前状态,并按 Worker 类型附加 backlog diagnostics。
## 3. Redis keys
建议:
```text
worker-health:v1:{worker_type}:lease
worker-health:v1:{worker_type}:state
worker-health:v1:{worker_type}:last-exit
```
### Lease
- value 至少包含随机 instance_id。
- TTL 30 秒。
- heartbeat 每 10 秒 compare-and-refresh,只有 owner instance_id 可续租。
- 第二个同类型 Worker 发现有效 lease 后拒绝启动。
- lease 过期后新实例可获取。
- 不允许 last-writer-wins 覆盖。
### State
state 可与 lease 同一个 JSON key,也可独立;必须保证 owner 才能更新。
建议字段:
| Field | Meaning |
| --- | --- |
| worker_type | stable logical identifier |
| instance_id | random UUID per process |
| hostname | safe host/container hostname |
| state | Starting/Idle/Running/Degraded |
| started_at | process start |
| heartbeat_at | last heartbeat |
| iteration_started_at | current/last iteration start |
| last_iteration_success_at | any successful iteration, including idle |
| last_processed_at | last iteration that processed work |
| last_failure_at | last failed/partial-failed iteration |
| last_duration_ms | last iteration duration |
| consecutive_failures | reset on successful iteration |
| iteration_count | process-lifetime count |
| processed_iteration_count | iterations with processed=true |
| success_count | successful iterations |
| failure_count | failed or partial-failed iterations |
| last_message | safe WorkerIterationResult message |
| last_error | normalized safe error |
| log_role | log file role |
PID、完整 command、环境变量和 Secret 不通过 API 暴露。
### Last exit
优雅退出时记录短 TTL 或非租约型安全信息:
- instance_id
- exited_at
- reason=`graceful`
意外退出没有 last-exit updateAPI 通过 lease expired 判定。
## 4. Heartbeat
- daemon thread 每 10 秒刷新 lease。
- 主线程运行长任务或 sleep 时仍持续刷新。
- heartbeat Redis 写失败应记录安全日志;如果长期失败 lease 会过期。
- heartbeat thread 不改变业务 iteration 状态。
- Running 不设最大时长,也没有 Stalled。
- 只要 heartbeat 存活,任意长任务保持 Running。
线程退出规则:
- Worker 正常 SIGTERM/KeyboardInterrupt 时停止 heartbeat。
- 释放仅属于自身 instance_id 的 lease。
- 不能删除新实例已取得的 lease。
## 5. Singleton startup
Worker 启动:
1. 生成 instance_id。
2. 原子 SET NX 获取 lease。
3. 失败则抛 CommandError 并退出,Compose 可记录重启失败。
4. 成功写 Starting state。
5. 启动 heartbeat thread。
6. 进入主循环。
这适用于所有六个正式 Worker。`--once` 是运维命令,不应长期占用 singleton lease;如果它会与正式 Worker 并行影响同一数据,需要显式决定是否短暂获取 lease,默认建议获取以避免并发。
## 6. States
API 状态:
| State | Definition |
| --- | --- |
| Starting | live lease exists, first iteration not completed |
| Idle | live lease, last iteration successful, currently no work |
| Running | live lease, iteration currently executing |
| Degraded | live lease, latest iteration has any failure |
| Down | expected Worker has no live lease |
### Never reported
系统知道六种 expected worker type。没有 lease 且没有 state/last-exit 时:
- state=Down
- reason=`never_reported`
- UI 显示 Never reported
### Graceful and expired
- 正常退出:Down / graceful。
- 意外崩溃或进程被杀:30 秒后 Down / heartbeat_expired。
- Redis 本身不可用不是 Unknown/Down;整个 Worker Health API 返回 503。
### Degraded recovery
- 一次完整失败立即 Degraded。
- `WorkerIterationResult.failure_count > 0` 的部分失败也立即 Degraded。
- consecutive_failures 增加。
- 下一次无失败的 iteration 清零并恢复 Idle 或完成后的健康状态。
## 7. WorkerIterationResult contract
扩展当前 dataclass
```python
@dataclass(frozen=True)
class WorkerIterationResult:
processed: bool = False
message: str = ""
failure_count: int = 0
```
语义:
- `processed` 表示至少完成一个业务工作项。
- `failure_count` 表示 iteration 内被捕获的业务失败数。
- 抛异常是完整 iteration failure。
- `message` 必须是安全摘要。
### Time semantics
- 正常 idle polling 更新 `last_iteration_success_at`
- 只有 `processed=True` 更新 `last_processed_at`
- partial failure 不更新 success timestamp;是否同时有 processed 由结果如实记录。
## 8. Backlog diagnostics
不得强制统一为 queue_depth。
### Playbook
- Pending Run count。
- oldest Pending age。
- Running count。
### Case Analysis
- Pending job count。
- oldest eligible scheduled job age。
- Running count。
### Module
复用 Redis Stream health
- stream length。
- consumer group pending。
- consumer count。
- last-delivered-id。
- 可计算的 lag。
- 每个 Module definition 仍在现有 Custom 页面展示;Worker Health 可给汇总和跳转。
### ELK Action
外部索引完整积压不可可靠得知,只显示:
- last poll time。
- last poll actions/sent/skipped。
- last successful processed time。
- current configured interval。
### Dashboard Cache
- 24h/7d/30d 各缓存 age。
- generated/refreshed time。
- configured interval。
- cache missing 标记。
### Integration Health
- enabled target count。
- Healthy/Unhealthy/Disabled counts。
- current serial check progress(如果可安全获得)。
Backlog 查询失败不应使 heartbeat 消失。API 行级 diagnostics 可返回 safe warning。
## 9. Error safety
`last_error` 只包含:
- exception type。
- 标准 reason code 或固定安全摘要。
- failure time。
- log role。
不包含:
- 原始 exception message。
- traceback。
- HTTP response。
- SIEM query/event。
- username、password、token、API key。
完整排查信息留在 Worker 日志。
## 10. API
建议:
`GET /api/settings/operations/workers/`
仅 Admin。
正常返回六行:
```json
{
"results": [
{
"worker_type": "playbook",
"display_name": "Playbook Worker",
"state": "Idle",
"reason": "",
"instance_id": "...",
"hostname": "asp-worker-playbook",
"started_at": "...",
"heartbeat_at": "...",
"last_iteration_success_at": "...",
"last_processed_at": "...",
"last_failure_at": null,
"last_duration_ms": 8,
"consecutive_failures": 0,
"counters": {},
"last_message": "",
"last_error": null,
"log_role": "agentic-playbook-worker",
"backlog": {
"pending_count": 0,
"oldest_pending_age_seconds": null,
"running_count": 0
}
}
]
}
```
Redis health storage 无法访问:
- HTTP 503。
- 固定信息:`Worker health monitoring is unavailable.`
- 不返回六个伪造 Down 状态。
API 不提供:
- Restart。
- Run Now。
- Stop。
- Tail/download logs。
- 历史趋势。
## 11. Permissions and audit
- 仅 Admin 可访问 API/UI。
- User/Viewer 403。
- Health read 不写 AuditLog。
- heartbeat/state change 不写 AuditLog。
- 没有 Worker health notification。
## 12. Frontend
最终位置:`System Settings → Operations → Worker Health`
行为:
- 每 10 秒自动刷新。
- 提供手动 Refresh。
- 503 显示页面级 monitoring unavailable,不显示全红 Down。
- 状态 TagStarting、Idle、Running、Degraded、Down。
- 每行显示心跳、最后处理、最后失败、错误摘要、积压和 log reference。
- Worker-specific backlog 使用不同 detail 展示,不强行同列 JSON。
- 不提供任何 mutation 按钮。
- 可展示运维命令文本,但 Operations Center TODO 尚未确认具体命令 UX。
## 13. History and retention
- Redis 只保存当前状态。
- 计数从进程启动开始。
- Worker 重启后计数重置。
- 不提供 uptime 百分比、趋势图或历史事件。
- 日志是历史排查来源。
## 14. Compose changes
- 新增 Integration Health Worker 服务。
- 六个 Worker 使用明确 command 和 log role。
- 不挂载 Docker socket。
- 不通过 Web app 重启容器。
- Worker singleton 冲突应在日志中明确显示。
## 15. Acceptance criteria
1. 六类 Worker 正常显示 Starting→Idle/Running。
2. 第二个同类型实例拒绝启动。
3. heartbeat 10 秒、30 秒过期行为正确。
4. 长 Running 任务保持 heartbeat,不被判 Stalled/Down。
5. 进程被强杀后约 30 秒显示 Down/heartbeat expired。
6. 优雅退出显示 Down/graceful。
7. 第一次 iteration/partial failure 立即 Degraded,后续成功恢复。
8. idle success 与 actual processed 时间分离。
9. Redis 不可用 API 503。
10. 错误 API 不泄露原始异常或 Secret。
11. 每类 backlog 数据符合专属 schema。
12. User/Viewer 403Admin 页面每 10 秒刷新。
## 16. Known tradeoffs
- Redis 故障时无法独立判断 Worker 健康。
- 当前状态和计数不会跨进程重启保留。
- daemon thread 增加少量线程复杂度,但解决了长任务 liveness。
- Running 永不按时长 Stalled,业务死循环只要 heartbeat thread 活着就仍显示 Running。
+355
View File
@@ -0,0 +1,355 @@
# Integration Health
Status: Confirmed
## 1. Purpose
通过独立定时 Worker 主动验证正式支持的外部集成和关键依赖,并在 Admin Operations 页面展示每个配置实例的当前状态。
该功能表达“最近一次轻量检查是否成功”,不保证所有业务查询、数据权限或具体动作都可用。
## 2. Targets
定时检查:
- Splunk singleton config。
- ELK singleton config。
- 每个 enabled OpenAI-compatible LLM Provider。
- AlienVault OTX。
- OpenCTI。
- LDAP。
- Redis。
- S3-compatible object storage。
不检查 PostgreSQLWeb/API 本身已依赖 PostgreSQL。
大量 EnrichmentProvider 枚举值不等于可检查的官方集成。
## 3. Dedicated Worker
新增 `run_integration_health_worker`
- 使用公共 `run_worker()`
- 作为第六类 singleton Worker 出现在 Worker Health。
- 固定每 5 分钟检查一次。
- 串行检查目标。
- 单目标超时 10 秒。
- 单项失败后继续其他目标。
- iteration 中任一失败使 Integration Health Worker 本轮 `failure_count > 0`,因此 Worker 状态 Degraded。
页面加载不直接 fan-out 外部请求。
## 4. States
持久状态只有:
- Healthy
- Unhealthy
- Disabled
附加 reason 表达细节:
| Situation | State | Reason |
| --- | --- | --- |
| enabled, never checked | Unhealthy | never_checked |
| check running | 保持原状态 | transient `checking=true` |
| last check succeeded | Healthy | ok |
| last check failed | Unhealthy | normalized failure code |
| config disabled | Disabled | disabled |
| config incomplete/not configured | Disabled | not_configured |
不使用 Unknown/Degraded/Checking 作为持久 state。
未配置和 Disabled 是中性状态,不算健康也不算故障。页面不计算整体 platform/integration status。
## 5. Data model
建议模型 `IntegrationHealth`
| Field | Type | Notes |
| --- | --- | --- |
| id | UUID | primary key |
| integration_type | string enum | splunk/elk/llm/otx/opencti/ldap/redis/storage |
| config_object_id | nullable string | LLM Provider UUIDsingleton/dependency 使用稳定 sentinel |
| display_name | string | safe display label |
| state | enum | Healthy/Unhealthy/Disabled |
| reason_code | string | normalized |
| message | string | fixed safe message |
| checking_started_at | nullable datetime | transient check marker |
| last_checked_at | nullable datetime | any completed check |
| last_success_at | nullable datetime | successful check |
| last_failure_at | nullable datetime | failed check |
| duration_ms | nullable integer | latest check |
| consecutive_failures | nonnegative integer | reset on success |
| updated_at | datetime | auto |
Constraints:
- unique `(integration_type, config_object_id)`null/sentinel 处理必须稳定。
- index `(state, integration_type)`
- 不保存完整 config、URL、username、Secret、response body。
只保存当前状态,不保存历史行或趋势。
## 6. Configuration synchronization
### Create
- 新 enabled config:创建 Unhealthy/never_checked。
- 新 disabled config:创建 Disabled/disabled。
### Update
相关配置字段改变:
- Enabled:立即 Unhealthy/configuration_changed。
- DisabledDisabled/disabled。
- 不保留旧 Healthy 到下一个检查。
现有 Settings 保存逻辑应在同一 transaction commit 后同步 health 状态。
### Delete
- 多实例配置(例如 LLM Provider)删除时同步硬删除 health row。
- singleton config 不删除;Disabled 时保留 Disabled row。
- 配置 CRUD 自身继续由现有 AuditLog 追溯。
## 7. Check depth by target
### LLM
- 对每个 enabled Provider 发最小 Chat Completions 请求。
- 验证 base URL、认证、model 和实际推理路径。
- 限制最大 token,接受每 5 分钟极低但非零费用。
- 不保存 prompt/response content。
### Splunk
- 使用轻量认证管理/信息接口。
- 不执行 SPL。
- 不依赖 index、time field 或数据存在。
### ELK
- 使用集群 info/health 或等价轻量认证接口。
- 不搜索用户 index。
- 不将 yellow 等集群业务状态自动扩展为复杂 Degraded;检查器应按能否满足现有连接需求返回 Healthy/Unhealthy,并在 reason code 中规范化。
### LDAP
- 连接服务器。
- 使用配置的 bind DN/password 进行 service bind。
- 验证 search base 可访问。
- 不保存或使用专用普通用户测试密码。
- 没有 bind DN 时执行当前支持模式下可行的基础连接/search check。
### OTX/OpenCTI
- 调用轻量身份/账户 endpoint。
- 验证 Token。
- 不执行 IOC 搜索。
### Redis
- PING。
- 读取安全的基础 INFO:版本、内存、连接状态。
- 不写测试 key。
- 不重复 Module stream backlog diagnostics。
### Object storage
- 验证 endpoint、凭据和目标 bucket metadata/list 权限。
- 不写入或删除 probe object。
## 8. Check service contract
统一内部结果:
```python
@dataclass(frozen=True)
class IntegrationCheckResult:
success: bool
reason_code: str
message: str
duration_ms: int
```
规范 reason_code 至少包括:
- ok
- never_checked
- configuration_changed
- not_configured
- disabled
- authentication_failed
- timeout
- tls_error
- connection_refused
- dns_error
- invalid_response
- permission_denied
- service_unavailable
- unknown_error
message 必须来自固定映射,不直接使用 exception message。
## 9. State update rules
检查开始:
- 设置 checking_started_at。
- 不改变当前 state。
成功:
- state=Healthy。
- reason_code=ok。
- last_checked_at/last_success_at=now。
- consecutive_failures=0。
- 清空 checking_started_at。
失败:
- 第一次失败立即 state=Unhealthy。
- last_checked_at/last_failure_at=now。
- consecutive_failures += 1。
- 保存 normalized reason/message。
- 清空 checking_started_at。
Worker 崩溃遗留 checking_started_at 时,下次 Worker 可覆盖;持久 state 仍是上一次结果。
## 10. Manual Settings tests
保留现有各配置页 Test
- 用于测试未保存或已保存配置。
- 已保存配置的 Test 结果更新对应 IntegrationHealth。
- 未保存临时配置的 Test 不更新 health。
- Manual Test 继续写现有 AuditLog。
- Unified Integration Health 页面不提供 Check Now。
普通业务调用的成功/失败永不更新 IntegrationHealth,避免查询输入、限流或业务权限错误污染集成状态。
## 11. API
建议:
`GET /api/settings/operations/integrations/`
仅 Admin。
返回每个目标/配置实例的独立状态:
```json
{
"results": [
{
"integration_type": "llm",
"config_object_id": "...",
"display_name": "OpenAI Production",
"state": "Healthy",
"reason_code": "ok",
"message": "The provider responded successfully.",
"checking": false,
"checking_started_at": null,
"last_checked_at": "...",
"last_success_at": "...",
"last_failure_at": null,
"duration_ms": 821,
"consecutive_failures": 0,
"settings_route": "/system/llm-providers/..."
}
]
}
```
- 不返回 overall status。
- 不返回 Secret、完整 endpoint、username 或 response preview。
- API 只读取 PostgreSQL,不执行检查。
- Redis target 的健康状态也是定时检查结果;与 Worker Health Redis 503 是不同语义。
## 12. Error safety
UI/API 只显示:
- normalized reason code。
- 固定安全 message。
- check time/duration。
禁止:
- 原始 exception。
- traceback。
- response body。
- URL query。
- username。
- API key/token/password。
完整异常进入 Integration Health Worker log,仍需遵循现有日志 Secret 规范。
## 13. Permissions and audit
- 仅 Admin 可看 API/UI。
- User/Viewer 403。
- Scheduled check 不写 AuditLog。
- 定时状态变化不写 AuditLog。
- Manual saved-config Test 写现有 AuditLog。
- 不发送 Inbox/Webhook 健康通知。
## 14. Frontend
位置:`System Settings → Operations → Integration Health`
- 与 Worker Health 独立表格/API。
- 每 30 秒读取 PostgreSQL 当前状态。
- 提供页面手动 Refresh,但不触发外部检查。
- 展示 integration type/name/state/reason/last check/duration/consecutive failures。
- Disabled/Not configured 可见且使用中性样式。
- enabled never checked 显示 Unhealthy + Never checked。
- checking 时保留原 state Tag并显示 Checking 辅助标记。
- 行可跳转对应 Settings 页面。
- 不显示 overall status。
- 不提供 Check Now。
## 15. Worker Health interaction
Integration Health Worker 自身:
- 使用第六个 Worker type。
- heartbeat/lease 遵循 Worker Health Spec。
- 本轮任一集成失败时 WorkerIterationResult.failure_count > 0Worker Health 显示 Degraded。
- Integration 表显示具体失败目标。
- Redis health target 失败可能同时导致 Worker 心跳不可用;此时 Worker Health API 可能 503,但 PostgreSQL 中最后 Integration Health 结果仍可显示。
## 16. Migration
- 创建 IntegrationHealth 表。
- 为现有配置生成初始行:
- enabled/configured → Unhealthy/never_checked。
- disabled/incomplete → Disabled。
- 不在 migration 中访问外部服务。
- 添加 Integration Health Worker Compose service。
- 更新 log role mapping。
## 17. Acceptance criteria
1. Worker 每 5 分钟串行检查所有 eligible targets。
2. 每项超时 10 秒,失败不阻止后续目标。
3. 各目标使用已确认的轻量检查深度。
4. enabled 首次检查前 Unhealthy/never_checked。
5. 一次失败立即 Unhealthy,一次成功立即恢复。
6. config 修改立即 configuration_changed。
7. saved-config Test 更新状态,unsaved Test 不更新。
8. 业务请求不更新状态。
9. 删除 LLM Provider 同步删除 health row。
10. API 不执行外部请求、不返回敏感信息。
11. Admin-only 和 30 秒 UI 刷新正确。
12. Worker 自身出现在 Worker Health。
## 18. Known tradeoffs
- 没有历史趋势和整体状态。
- 没有统一 Check Now。
- LLM 检查产生持续小额调用成本。
- 一次瞬时失败立即 Unhealthy,可能产生短暂抖动,但当前不发送通知。
- 轻量管理接口 Healthy 不等于所有索引、模型能力或业务查询均正常。
+391
View File
@@ -0,0 +1,391 @@
# SLA Management
Status: Confirmed
## 1. Purpose
为升级后新建的 Case 建立按 Severity 配置的 TTD、TTA、TTR 时限,向负责人提示即将超时和已经超时的工作,并在 Case 和 Dashboard 中提供与现有平均时间指标完全一致的达标统计。
## 2. Terminology and formulas
单个 Case 使用不带 Mean 前缀的名称:
| Per-Case | Formula | Dashboard aggregate |
| --- | --- | --- |
| TTD, Time to Detect | earliest valid Alert.first_seen_time → Case.created_at | MTTD |
| TTA, Time to Acknowledge | Case.created_at → Case.acknowledged_time | MTTA |
| TTR, Time to Resolve | Case.acknowledged_time → Case.closed_time | MTTR |
规则:
- `M` 仅表示多个样本的 Mean。
- Dashboard 现有 MTTD/MTTA/MTTR 公式必须与上表一致。
- created_at→closed_time 可以作为总耗时展示,但没有独立 SLA target。
- 全部使用 24×7 elapsed seconds,不使用工作时间、节假日或暂停时钟。
## 3. Policy
每个 CaseSeverity 一行全局策略:
| Severity | TTD | TTA | TTR |
| --- | ---: | ---: | ---: |
| Critical | 300s | 900s | 14,400s |
| High | 900s | 1,800s | 28,800s |
| Medium | 1,800s | 7,200s | 86,400s |
| Low | 7,200s | 28,800s | 259,200s |
| Informational | 28,800s | 86,400s | 604,800s |
| Unknown | 3,600s | 14,400s | 172,800s |
- v0.6.0 中 SLA 始终启用。
- 六行和三项目标都必填。
- 每个目标为整数 seconds,范围 60 秒到 365 天。
- 不要求 TTD ≤ TTA ≤ TTR,因为三者覆盖不同阶段。
- 不按 Category、Tag、Assignee 或业务组配置。
### Policy model
建议 `SlaPolicy`
- severityunique。
- ttd_target_seconds。
- tta_target_seconds。
- ttr_target_seconds。
- created_at/updated_at。
Settings API 一次提交全部六行,并在一个事务中全部保存。任一值非法则全部拒绝。
## 4. Snapshot semantics
每个阶段开始时快照当时 Severity 和 target
- TTDCase 创建时。
- TTACase 创建时。
- TTR:首次 acknowledged_time 设置时。
之后修改 Case Severity 不改变已经开始或完成的阶段。
策略修改只影响未来创建的阶段快照:
- 新 Case 的 TTD/TTA 使用新策略。
- 旧但尚未 acknowledge 的 Case,其 TTR 在未来开始时使用新策略。
- 不批量重算已有快照。
## 5. CaseSla model
每个参与 SLA 的 Case 一条 OneToOne `CaseSla`,不用 JSON 或通用 metric child table。
每项指标明确保存:
- severity_snapshot。
- target_seconds。
- started_at。
- ended_at。
- deadline_at。
- elapsed_seconds。
补充字段:
- case OneToOne。
- created_at/updated_at。
建议索引:
- tta_deadline_at,配合 acknowledged_time/null 或等价 active marker。
- ttr_deadline_at,配合 closed_time/null。
- CaseSla.case unique。
状态不周期写入数据库,按快照、当前时间和完成时间动态计算。
## 6. Metric states
通用状态:
- Pending。
- Warning。
- Met。
- Breached。
- Not applicable。
未完成指标:
- elapsed < 80% targetPending。
- 80% ≤ elapsed < 100%Warning。
- elapsed ≥ targetBreached。
已完成指标:
- elapsed ≤ targetMet。
- elapsed > targetBreached。
- 完成后超时仍保持 Breached,不增加 Completed late。
### TTD subset
TTD 在被观察时已经完成,因此只可能:
- Met。
- Breached。
- Not applicable。
TTD 不进入 Pending 或 Warning。
### TTR before acknowledgement
尚未 acknowledge
- UI state 显示 Pending。
- started/deadline/elapsed 为空。
- 标注 `Starts after acknowledgement`
- SLA Worker 不扫描 Warning/Breach。
不计算 Case overall SLA 状态。TTD、TTA、TTR 始终独立展示和筛选。
## 7. TTD behavior
### Valid source
使用当前 Case 下最早的有效 Alert.first_seen_time,要求:
- 非空。
- `first_seen_time <= Case.created_at`
没有有效时间时:
- TTD=Not applicable。
- 不进入达标率分母。
- 不使用 Alert.created_at、Case.created_at 或 0 秒兜底。
### Recalculation
以下情况重算 TTD start、elapsed 和 result
- Alert 创建并关联 Case。
- Alert.first_seen_time 修改。
- Alert 移动到其他 Case。
- Case merge 迁移 Alert。
TTD target 和 Severity snapshot 不变。更早 Alert 可能使 Met 变为 Breached。
## 8. TTA behavior
- Case 创建时立即启动。
- deadline=created_at + snapshotted target。
- Case 第一次离开 New 时设置 acknowledged_time 并结束。
- acknowledged_time 永久保留,Reopen 不重置。
- On Hold 不暂停。
## 9. TTR behavior
- 首次 acknowledged_time 设置时启动并快照当时 Severity/target。
- deadline=acknowledged_time + target。
- closed_time 设置时结束。
- On Hold 不暂停。
- Closed→In Progress Reopen 清空 closed_time 后,从原 acknowledged_time 恢复同一时钟。
- 再次 Closed 后使用新的 closed_time 作为当前最终结果。
- 原关闭历史只通过 AuditLog 保留。
### Direct New→Closed
状态机同时设置 acknowledged_time 和 closed_time
- TTA=created_at→transition timestamp。
- TTR=0 秒,Met。
## 10. Upgrade boundary
- 只有 SLA migration/feature 启用后新建的 Case 创建 CaseSla。
- v0.5.2 已存在 Case 不回填,不展示 SLA 状态、不筛选、不通知、不进入达标率。
- 旧 Case 继续进入现有 MTTD/MTTA/MTTR mean,只要满足原查询条件。
- Dashboard 必须显示 mean 和 compliance 各自 sample count,因为样本集合不同。
## 11. Case merge
- merged source 排除 SLA、达标率、active count 和通知。
- target 保留自己的 TTA/TTR snapshot 和时钟。
- Alert 迁入后 target 重算 TTD。
- target 不继承 source target、Severity snapshot、状态或通知记录。
## 12. Notifications
### Recipient
- 只通知当前 Assignee。
- 未分配 Case 不通知。
- Admin 不作为 fallback recipient。
- 用户不能关闭 SLA 通知。
### Events
- TTA Warning。
- TTA Breached。
- TTR Warning。
- TTR Breached。
- TTD Breached。
- 不发送 TTD Warning。
- 不发送 Met、恢复或完成通知。
Warning 和 Breached 分别通知。同一 recipient 最多各一次。Worker 首次看到已 Breached 时只发 Breached,不补发 Warning。
### Reassignment
按 CaseSla + metric + state + recipient 去重。当前状态已经 Warning/Breached 后重新分配,新 Assignee 在下一次扫描收到一次当前状态通知;原 Assignee不收到撤销消息。
### Notification storage
`CaseSlaNotification`
- case_sla FK。
- metric enum TTD/TTA/TTR。
- state enum Warning/Breached。
- recipient nullable FK User,删除用户后 SET_NULL。
- sent_at。
- unique(case_sla, metric, state, recipient)nullable recipient 的历史处理需保证不会影响实际去重。
通知记录不保存消息 Secret 或完整 Case 内容。
## 13. SLA Worker
新增单实例 `run_sla_worker`
- 每 60 秒扫描。
- 接入 Worker Health,成为第 7 个 Worker。
- 只负责发现需通知状态并去重发送。
- API 状态仍动态计算,不依赖 Worker 更新状态。
- 对适用且未完成的 TTA/TTR 使用 deadline 索引扫描。
- 对 TTD Breached 和 reassignment 使用未通知查询。
- 一个通知失败不得吞掉;按 WorkerIterationResult.failure_count 进入 Degraded。
- 不发送外部 Webhook 或邮件。
## 14. API
Case list/detail 增加嵌套 SLA
```json
{
"sla": {
"applicable": true,
"ttd": {
"state": "Met",
"severity": "High",
"target_seconds": 900,
"elapsed_seconds": 420,
"started_at": "...",
"ended_at": "...",
"deadline_at": "..."
},
"tta": {},
"ttr": {
"state": "Pending",
"started": false
}
}
}
```
旧 Case
```json
{"sla": {"applicable": false}}
```
Case list 支持每项 state filter 和 deadline ordering。不得用 Python 全量计算后分页;查询必须可在数据库层筛选。
Settings SLA API
- Admin GET。
- Admin 原子 PUT/PATCH 全部六行。
- User/Viewer 403。
- seconds 为唯一 API 单位。
## 15. Frontend
### Case list
- TTA state 默认显示。
- TTR state 默认显示。
- TTD state 默认隐藏但可选。
- 三项分别筛选。
- TTA/TTR 支持 deadline 排序。
- 不显示 overall Tag。
### Case detail
SLA 区块分别显示:
- TTD/TTA/TTR。
- state。
- target。
- elapsed。
- start/end/deadline。
- Severity snapshot。
- TTR 未开始提示。
### Settings
`System Settings → SLA`
- 六个 Severity 行。
- 三个目标列。
- UI 使用分钟/小时可读输入,提交转换为精确 seconds。
- 一次 Save 全部原子提交。
- 仅 Admin。
## 16. Dashboard
保留现有:
- MTTD mean/sample。
- MTTA mean/sample。
- MTTR mean/sample。
新增:
- TTD compliance rate/sample。
- TTA compliance rate/sample。
- TTR compliance rate/sample。
- 当前 TTA Warning count。
- 当前 TTA Breached count。
- 当前 TTR Warning count。
- 当前 TTR Breached count。
取样:
- TTD complianceCase.created_at 在窗口。
- TTA complianceacknowledged_time 在窗口。
- TTR complianceclosed_time 在窗口。
- 当前 Warning/Breached:所有活动、未合并且有 CaseSla 的 Case,不受创建时间窗口限制。
TTD 没有当前 Warning/Breach count。
## 17. Audit
- SLA policy 修改写 AuditLog,记录六行三项目标的 before/after seconds。
- 时间推移导致的 Pending/Warning/Breached/Met 不写 Case AuditLog。
- SLA Worker 扫描不写 AuditLog。
- CaseSlaNotification 提供发送历史。
## 18. Acceptance criteria
1. 单案 TTD/TTA/TTR 与 Dashboard MTTD/MTTA/MTTR公式一致。
2. 六个 Severity 默认值与范围正确,Admin 原子保存。
3. 每阶段按当时 Severity 快照,后续修改不追溯。
4. TTD 缺失时间为 NA,Alert 变化可重算。
5. TTA first-exit-New 结束,TTR acknowledge 开始。
6. On Hold 不暂停,Reopen 从原 acknowledge 继续。
7. Direct close 的 TTR=0 Met。
8. 80% Warning、100% Breached,完成后 late 仍 Breached。
9. 旧 Case 无 SLA,新 Case有 SLA。
10. merged source 排除,target 仅重算 TTD。
11. SLA Worker 每分钟运行并进入 Worker Health。
12. 仅当前 Assignee 强制接收去重 Warning/Breach。
13. 新 Assignee 可收到当前状态,未分配不通知。
14. Case list/detail、Dashboard 和 Settings 行为符合 Spec。
15. medium 数据规模下 active deadline 扫描使用索引,不全表 Python 计算。
## 19. Known tradeoffs
- 旧 Case 不进入达标率,升级初期样本较少。
- On Hold 持续计时,不反映净工作时间。
- 重开 Case 会持续拉长同一 TTR。
- Severity 变化不追溯,单 Case 不同阶段可能使用不同策略版本。
- TTD 可因迟到或合并 Alert 从 Met 变为 Breached。
- 未分配 Case 不产生 SLA 通知。
+36
View File
@@ -0,0 +1,36 @@
# ASP v0.6.0 specification index
本目录是 v0.6.0 的跨会话实施依据。已完成讨论的功能使用实施级 Spec 固化;尚未完成讨论的功能只记录 TODO 和待决策问题,不得把 TODO 中的推荐项当作已经确认的需求。
## 已确认 Spec
| 文档 | 状态 | 内容 |
| --- | --- | --- |
| [00-release-scope.md](00-release-scope.md) | Confirmed | 版本目标、部署边界、兼容矩阵、容量、权限与排除项 |
| [01-bulk-case-triage.md](01-bulk-case-triage.md) | Confirmed | Case 批量分诊、共享状态机、通知与审计 |
| [02-case-merge.md](02-case-merge.md) | Confirmed | 多源案件合并、数据迁移、只读源案件与幂等 |
| [03-playbook-execution.md](03-playbook-execution.md) | Confirmed | Playbook Run、结构化 Stage、取消、重试与 Worker 语义 |
| [04-custom-variables.md](04-custom-variables.md) | Confirmed | Playbook/Module 可读取的 UI 管理变量 |
| [05-worker-health.md](05-worker-health.md) | Confirmed | Redis 心跳、Worker 状态、积压指标与 Admin API |
| [06-integration-health.md](06-integration-health.md) | Confirmed | 定时集成检查、当前状态持久化与安全错误 |
| [07-sla-management.md](07-sla-management.md) | Confirmed | TTD/TTA/TTR 时限、Severity 策略、通知和 Dashboard 达标率 |
## 待讨论
[TODO-remaining-domains.md](TODO-remaining-domains.md) 记录 AI 质量评估、抑制规则、Operations 页面整合和版本验收。继续讨论时应逐项把决定写回独立 Spec。
## 实施顺序
1. 先完成 Case 状态机,再实现批量分诊和案件合并。
2. 完成 Playbook Run/Stage 后实现 Custom Variables。
3. 完成通用 Worker Health 基础设施,再接入六类 Worker。
4. 完成 Integration Health 数据层和 Worker,再实现 Operations 页面。
5. 待剩余三个业务域定稿后,统一补齐 v0.6.0 验收规范。
## Spec 使用规则
- `Confirmed` 表示产品决策已确认,实施不得自行改变行为。
- Spec 中的模型名和 URL 是目标设计;若代码库已有命名约束冲突,可以做等价调整,但外部行为必须一致。
- 每项功能必须同时覆盖后端、前端、权限、审计、迁移和失败行为。
- v0.6.0 允许破坏性 API 调整,不需要兼容旧 CLI 或插件。
- 不得把本目录复制到 `asp-doc` 作为用户文档;用户文档应在功能实现定型后另行编写。
+114
View File
@@ -0,0 +1,114 @@
# v0.6.0 remaining domain TODO
Status: Not discussed
本文件用于在另一台电脑或新会话中继续产品讨论。以下内容仅是讨论清单,不是已确认需求。
## TODO 1: AI quality evaluation
Release blocking: Yes
Goal: 用人工最终判断评估 AI 严重度、置信度、影响、优先级和 Verdict 的质量,形成可解释的反馈闭环。
需要逐项决定:
- 评估对象是所有 AI 字段,还是先只做 Verdict/Severity。
- 何时生成评价记录:字段修改、Case Close 或定时快照。
- AI 输出与人工输出为空时如何处理。
- 一次 Case 多次 AI 分析如何选择被评估版本。
- 是否必须保存 model、provider、prompt slug/version 和 analysis job。
- 指标使用 agreement rate、confusion matrix、precision/recall 还是更简单统计。
- Verdict 多分类如何归并,Unknown/Insufficient Data 是否排除。
- 分析师是否提供显式 thumbs up/down 和错误原因。
- 是否允许抽样复核和争议标记。
- 时间窗口、Provider、Model、Playbook/Trigger、Case category 等筛选维度。
- 数据保留、历史不可变性和模型配置删除后的展示。
- Dashboard/独立页面的信息架构。
- 权限和匿名化要求。
- 是否将反馈用于自动 prompt 优化;建议 v0.6.0 排除自动学习。
- 审计、迁移和验收案例。
输出目标:`08-ai-quality-evaluation.md`
## TODO 2: suppression rules
Release blocking: Yes
Goal: 在告警进入 Case 流程前降低已知噪声,同时保留可审计的命中记录,避免简单删除安全数据。
需要逐项决定:
- Rule 匹配对象是原始 Webhook、标准化 Alert 字段还是 Module 输出。
- 可匹配字段白名单以及 text/exact/list/CIDR/regex 运算符。
- 多条件 AND/OR 能力和是否允许嵌套。
- Rule 作用域:全局、Module、rule_id、产品或数据源。
- 动作是 drop、mark suppressed、route to existing Case 还是不创建 Case。
- 被抑制事件是否持久化;存储多少原始数据。
- Rule 优先级、first-match 或 all-match。
- Enabled、有效期、自动过期和命中计数。
- 模拟/预览如何在历史样本上运行,是否必须先模拟再启用。
- 如何防止一条宽泛 Rule 隐藏大量真实告警。
- Admin/User/Viewer 权限;建议至少创建/修改仅 Admin。
- 命中 AuditLog、Rule 变更审计和 Secret/PII 脱敏。
- Module correlation 与 merged source routing 的执行顺序。
- 列表、详情、命中历史和筛选 UX。
- 数据库索引、性能目标和验收案例。
输出目标:`09-suppression-rules.md`
## TODO 3: Operations Center
Release blocking: Depends on final scope
已确认的固定边界:
- 位于 `System Settings → Operations`
- 包含 Worker Health 和 Integration Health 两个独立区块。
- 仅 Admin 可访问。
- Worker 每 10 秒刷新,Integration 每 30 秒刷新。
- 不提供 Worker Restart、Run Now、日志读取或健康通知。
- Integration 不提供统一 Check Now;保留各 Settings 页的 Test。
- 不计算整体 Integration Health。
仍需决定:
- 页面布局、过滤、排序、状态颜色和移动端是否考虑。
- Worker backlog 的不同数据结构如何展示。
- 如何从 Integration 行跳转到对应 Settings。
- Redis 监控不可用时页面局部还是整体错误。
- Operations 导航徽标是否显示异常数量。
- 是否显示 Compose 修复命令,以及具体安全文本。
- 空状态、加载状态和权限拒绝 UX。
- API 聚合还是前端调用两个独立 API。
- 前端组件复用和验收案例。
输出目标:`10-operations-center.md`
## TODO 4: v0.6.0 acceptance
Release blocking: Yes
需要在所有功能 Spec 完成后定义:
- 从 v0.5.2 生产备份副本升级的完整演练。
- 全新 Docker Compose 安装。
- medium 数据规模下的关键 API/页面性能阈值。
- Admin/User/Viewer 权限矩阵回归。
- Case 单条和批量状态机一致性。
- 部分成功批量分诊、原子合并、幂等重试和 merged source 路由。
- Playbook Pending/Running/终态、Cancel、Retry、Stage 和 Worker 崩溃恢复。
- Custom Variables 的 Secret masking、Reveal audit 和 Module/Playbook 读取。
- Worker Redis 故障、重复实例、优雅退出和心跳过期。
- 所有正式集成的 Healthy/Unhealthy/Disabled 行为。
- SLA、AI 质量评估和抑制规则端到端场景。
- 备份、恢复和回滚演练。
- 文档、release notes、已知限制和功能冻结条件。
- P0/P1 缺陷门槛和 RC 观察周期。
输出目标:`11-release-acceptance.md`
## Suggested continuation prompt
在新电脑上可从下面的提示继续:
> 阅读 `docs/specs/v0.6.0/README.md` 和 `TODO-remaining-domains.md`。已确认 Spec 不要重新讨论。从 AI quality evaluation 开始,一次只问一个决策问题,每个问题给出推荐答案;确认完成后依次处理 suppression rules、Operations Center 和 release acceptance。