@modus-ai/modus 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -4
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +9 -8
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/global.js +1 -1
- package/dist/commands/global.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +0 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/status.js +2 -2
- package/dist/generators/claude.d.ts.map +1 -1
- package/dist/generators/claude.js +0 -36
- package/dist/generators/claude.js.map +1 -1
- package/dist/generators/copilot.d.ts.map +1 -1
- package/dist/generators/copilot.js +0 -1
- package/dist/generators/copilot.js.map +1 -1
- package/dist/utils/config.d.ts +32 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +10 -2
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/file-system.d.ts.map +1 -1
- package/dist/utils/file-system.js +2 -1
- package/dist/utils/file-system.js.map +1 -1
- package/package.json +1 -1
- package/schemas/knowledge-schema.yaml +111 -1
- package/templates/behavior-guard.md +165 -0
- package/templates/commands/auto.md +3 -1
- package/templates/commands/commit.md +63 -0
- package/templates/commands/harness.md +15 -8
- package/templates/commands/vibe.md +1 -1
- package/templates/knowledge-catalog.md +61 -32
- package/templates/skills/modus-agents/analyst/SKILL.md +16 -0
- package/templates/skills/modus-agents/deployer/SKILL.md +114 -62
- package/templates/skills/modus-agents/designer/SKILL.md +104 -92
- package/templates/skills/modus-agents/developer/SKILL.md +106 -67
- package/templates/skills/modus-agents/perf-auditor/SKILL.md +98 -61
- package/templates/skills/modus-agents/reviewer/SKILL.md +25 -2
- package/templates/skills/modus-agents/security-auditor/SKILL.md +111 -67
- package/templates/skills/modus-agents/skill-creator/SKILL.md +30 -12
- package/templates/skills/modus-agents/tester/SKILL.md +100 -54
- package/templates/skills/modus-auto/SKILL.md +16 -1
- package/templates/skills/modus-design-brief/SKILL.md +31 -13
- package/templates/skills/modus-harness/SKILL.md +78 -12
- package/templates/skills/modus-init/SKILL.md +783 -172
- package/templates/skills/modus-plan/SKILL.md +109 -43
- package/templates/skills/modus-spec/SKILL.md +175 -331
- package/templates/skills/modus-vibe/SKILL.md +147 -44
|
@@ -1,123 +1,167 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: modus-security-auditor
|
|
3
|
-
description: Use this skill when the Harness orchestrator needs to perform security audit on code
|
|
4
|
-
allowed-tools: Read,
|
|
3
|
+
description: Use this skill when the Harness orchestrator needs to perform static security audit on changed code. Detects multi-tenant data isolation leaks (tenantId from request vs UserContext), missing permission annotations, SQL injection risks, sensitive data logging, and improper bypass interfaces. Grades as critical/high/low and generates 05-security-report.md with HANDOFF block. Triggered by modus-harness in parallel with tester and perf-auditor after Gate A passes.
|
|
4
|
+
allowed-tools: Read, Glob
|
|
5
5
|
disable: false
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# modus-security-auditor(安全审计 SubAgent)
|
|
9
9
|
|
|
10
|
-
**调用方:** Harness Orchestrator
|
|
11
|
-
**输入:** `02-sprint-contract.md
|
|
10
|
+
**调用方:** Harness Orchestrator(Gate A 通过后,与 03/04 并行触发)
|
|
11
|
+
**输入:** `02-sprint-contract.md`(变更文件列表)+ 代码变更 + 业务 Skill(≤ 2 个)
|
|
12
12
|
**产出物:** `modus/plans/active/{story-id}/05-security-report.md`
|
|
13
13
|
|
|
14
14
|
## 职责
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
对本次代码变更进行静态安全审计,重点检测多租户隔离漏洞、权限校验缺失、SQL 注入、敏感信息泄露等高频安全问题。不执行代码,不修改文件。
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## 检测规则
|
|
21
21
|
|
|
22
|
-
### 1
|
|
22
|
+
### Rule 1:多租户数据隔离漏洞(严重)
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
- DB 查询/更新缺少 `tenantId` 条件
|
|
26
|
-
- `tenantId` 来自 request 参数(可被篡改),而不是从用户会话/上下文中获取
|
|
27
|
-
- 数据归属校验:操作前是否验证当前用户有权操作该条记录
|
|
24
|
+
**触发条件:** Service / Mapper 中的 WHERE 条件使用了来自 request 参数而非 UserContext 的 `tenantId`
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
```java
|
|
27
|
+
// ❌ 严重漏洞:tenantId 来自用户输入,可查看任意租户数据
|
|
28
|
+
public List<Order> listOrders(OrderQueryRequest request) {
|
|
29
|
+
return orderMapper.selectByTenantId(request.getTenantId()); // 危险
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ✅ 正确:tenantId 必须来自 UserContext(登录上下文)
|
|
33
|
+
public List<Order> listOrders(OrderQueryRequest request) {
|
|
34
|
+
Long tenantId = UserContext.getCurrentTenantId(); // 安全
|
|
35
|
+
return orderMapper.selectByTenantId(tenantId);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**危害:** 横向越权,A 租户可读取 B 租户数据
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
### Rule 2:Facade/Controller 权限校验缺失(高风险)
|
|
44
|
+
|
|
45
|
+
**触发条件:** 新增的 Facade / Controller 方法缺少权限注解(如 `@UserAuthorization`、`@PreAuthorize`、`@RolesAllowed`)
|
|
46
|
+
|
|
47
|
+
**危害:** 未授权用户可直接调用接口
|
|
48
|
+
**修复建议:** 所有对外接口必须有权限注解,最小权限原则
|
|
33
49
|
|
|
34
50
|
---
|
|
35
51
|
|
|
36
|
-
###
|
|
52
|
+
### Rule 3:敏感信息日志泄露(高风险)
|
|
37
53
|
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
54
|
+
**触发条件:** `log.info` / `log.debug` / `log.error` 中直接打印以下敏感字段:
|
|
55
|
+
- 身份证号(idCard / idNo)
|
|
56
|
+
- 银行卡号(bankCard / cardNo)
|
|
57
|
+
- 手机号(phone / mobile)
|
|
58
|
+
- 密码(password / pwd)
|
|
59
|
+
- 完整 Token / sessionId
|
|
42
60
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
- 结合项目的权限框架(RBAC/自定义注解)进行检查
|
|
61
|
+
**危害:** 日志系统通常访问范围较广,敏感信息泄露风险高
|
|
62
|
+
**修复建议:** 使用脱敏工具类处理后再打印,如 `MaskUtils.maskPhone(phone)`
|
|
46
63
|
|
|
47
64
|
---
|
|
48
65
|
|
|
49
|
-
###
|
|
66
|
+
### Rule 4:SQL 注入风险(严重)
|
|
67
|
+
|
|
68
|
+
**触发条件:** MyBatis XML / 注解 SQL 中使用 `${}` 拼接用户输入(应使用 `#{}`)
|
|
50
69
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
- 异常信息中暴露内部实现细节(SQL 语句、堆栈等)
|
|
70
|
+
```xml
|
|
71
|
+
<!-- ❌ SQL 注入 -->
|
|
72
|
+
SELECT * FROM orders WHERE status = ${status}
|
|
55
73
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
74
|
+
<!-- ✅ 安全 -->
|
|
75
|
+
SELECT * FROM orders WHERE status = #{status}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**危害:** 用户可构造恶意 SQL 执行任意查询或修改数据
|
|
60
79
|
|
|
61
80
|
---
|
|
62
81
|
|
|
63
|
-
###
|
|
82
|
+
### Rule 5:Bypass 接口缺少多租户保护(高风险)
|
|
64
83
|
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
84
|
+
**触发条件:** 以下类型的"内部接口"没有 tenantId 过滤:
|
|
85
|
+
- 定时任务(`@Scheduled` / `@XxlJob`)中的全量查询
|
|
86
|
+
- 管理后台接口中可跨租户的查询
|
|
87
|
+
- MQ 消费者处理消息时未验证消息的 tenantId
|
|
69
88
|
|
|
70
|
-
|
|
71
|
-
- 用户输入一律使用 `#{}` 参数化
|
|
72
|
-
- 动态排序字段做枚举白名单校验
|
|
89
|
+
**危害:** 批量操作可能意外处理其他租户的数据
|
|
73
90
|
|
|
74
91
|
---
|
|
75
92
|
|
|
76
|
-
###
|
|
93
|
+
### Rule 6:不安全的反序列化(中风险)
|
|
94
|
+
|
|
95
|
+
**触发条件:** 使用 `ObjectInputStream` 直接反序列化用户可控的数据,或使用不安全的 JSON 反序列化(如 `JSONObject.parseObject(str, Object.class)`)
|
|
77
96
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
97
|
+
**危害:** 远程代码执行(RCE)风险
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 执行流程
|
|
102
|
+
|
|
103
|
+
### Step 1:确定审计范围
|
|
104
|
+
|
|
105
|
+
读取 `02-sprint-contract.md` 的 `changed_files`,筛选需要审计的文件:
|
|
106
|
+
- Controller / Facade(Rule 1/2/3)
|
|
107
|
+
- Service / Manager(Rule 1/3/5)
|
|
108
|
+
- XML Mapper(Rule 4)
|
|
109
|
+
- MQ Consumer(Rule 5)
|
|
110
|
+
- 定时任务类(Rule 5)
|
|
111
|
+
|
|
112
|
+
### Step 2:逐规则扫描
|
|
113
|
+
|
|
114
|
+
对每个目标文件,逐一应用上述 6 条规则,记录发现的安全漏洞。
|
|
115
|
+
|
|
116
|
+
### Step 3:风险分级
|
|
117
|
+
|
|
118
|
+
| 风险等级 | 定义 | 处理要求 |
|
|
119
|
+
|---------|------|---------|
|
|
120
|
+
| 严重(需 P1 重入)| 可直接导致数据泄露或越权的漏洞 | modus-reviewer 标记为 P1,触发 Loop 2 |
|
|
121
|
+
| 高(需 P2 重入)| 安全隐患,在特定条件下可被利用 | modus-reviewer 标记为 P2,触发 Loop 2 |
|
|
122
|
+
| 中(建议修复)| 潜在风险,当前影响有限 | cr-report 中作为 P3 建议 |
|
|
81
123
|
|
|
82
124
|
---
|
|
83
125
|
|
|
84
126
|
## 产出物格式(05-security-report.md)
|
|
85
127
|
|
|
86
128
|
```markdown
|
|
87
|
-
|
|
129
|
+
<!--HANDOFF
|
|
130
|
+
agent: "05-security-auditor"
|
|
131
|
+
story_id: "{story-id}"
|
|
132
|
+
gate_status: "passed"
|
|
133
|
+
critical_risks: {N}
|
|
134
|
+
high_risks: {N}
|
|
135
|
+
-->
|
|
136
|
+
|
|
137
|
+
# 安全审计报告 — {Story 标题}
|
|
88
138
|
|
|
89
139
|
## 审计摘要
|
|
90
|
-
-
|
|
140
|
+
- 审计文件数: {N}
|
|
141
|
+
- 严重: {N} 个 | 高风险: {N} 个 | 中风险: {N} 个
|
|
91
142
|
|
|
92
|
-
##
|
|
143
|
+
## 严重漏洞(必须修复)
|
|
93
144
|
|
|
94
|
-
### [SEC-CRITICAL-01]
|
|
145
|
+
### [SEC-CRITICAL-01] 多租户隔离漏洞 — {ClassName}.{method}()
|
|
95
146
|
- **位置:** `{文件名}.java:{行号}`
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// 正确
|
|
102
|
-
Long tenantId = UserContext.getCurrentTenantId();
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## 高风险问题
|
|
147
|
+
- **漏洞描述:** tenantId 来自 request.getTenantId(),而非 UserContext
|
|
148
|
+
- **危害:** 横向越权,A 租户可读取 B 租户数据
|
|
149
|
+
- **修复方案:** 将 `request.getTenantId()` 替换为 `UserContext.getCurrentTenantId()`
|
|
150
|
+
|
|
151
|
+
## 高风险(必须修复)
|
|
106
152
|
...
|
|
107
153
|
|
|
108
|
-
##
|
|
154
|
+
## 中风险(建议修复)
|
|
109
155
|
...
|
|
110
156
|
|
|
111
|
-
##
|
|
112
|
-
{
|
|
157
|
+
## 无风险确认
|
|
158
|
+
{若某类规则未发现风险,明确写出「Rule N:未发现 XXX 风险」}
|
|
113
159
|
```
|
|
114
160
|
|
|
115
161
|
---
|
|
116
162
|
|
|
117
|
-
##
|
|
163
|
+
## 质量标准
|
|
118
164
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
| 高风险 | 有潜在安全风险,影响范围较大 | 必须在合入前修复,触发 Loop 2 重入 |
|
|
123
|
-
| 低风险 | 安全最佳实践问题,影响范围有限 | 建议修复,不阻塞合入 |
|
|
165
|
+
- 每个漏洞必须有文件路径 + 行号定位
|
|
166
|
+
- 严重/高风险必须提供具体修复代码示例
|
|
167
|
+
- **HANDOFF 块必须位于文件最顶部**,`critical_risks` + `high_risks` 供 modus-reviewer 决定 P1/P2 级别
|
|
@@ -13,7 +13,7 @@ disable: false
|
|
|
13
13
|
|
|
14
14
|
## 职责
|
|
15
15
|
|
|
16
|
-
从项目代码和工作流产物中提炼业务知识,生成或更新标准格式的 Skill 文件(
|
|
16
|
+
从项目代码和工作流产物中提炼业务知识,生成或更新标准格式的 Skill 文件(v3/17节,当前默认),并维护知识全景目录(`knowledge-catalog.md`)。支持五种调用模式,覆盖从初始化到持续积累的完整知识生命周期。
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
@@ -21,7 +21,7 @@ disable: false
|
|
|
21
21
|
|
|
22
22
|
### 模式 A:全量初始化(来自 /modus:init)
|
|
23
23
|
|
|
24
|
-
为每个确认的业务域从零生成 `modus-biz-{domain}/SKILL.md`,初始 `status: draft`,`format_version:
|
|
24
|
+
为每个确认的业务域从零生成 `modus-biz-{domain}/SKILL.md`,初始 `status: draft`,`format_version: v3`(17节标准格式,详见 modus-init SKILL 区块 C)。
|
|
25
25
|
|
|
26
26
|
### 模式 B:增量更新(来自 /plan 或 /spec 前置,含 hash 快速检查)
|
|
27
27
|
|
|
@@ -46,8 +46,12 @@ disable: false
|
|
|
46
46
|
**hash 检查(防腐校验通过后执行):**
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
#
|
|
50
|
-
|
|
49
|
+
# 标准全局 hash 计算命令(必须与 modus-init 区块 B、modus-plan Step 4-2 使用完全相同的算法)
|
|
50
|
+
# 算法:按文件路径排序 → 输出 "SHA-1:文件路径" 字符串 → 整体再 hash
|
|
51
|
+
# 禁止使用「仅 hash 值排序 hash」或「内容拼接整体 hash」的替代算法
|
|
52
|
+
for f in $(echo "{key_files}" | tr ' ' '\n' | sort); do
|
|
53
|
+
echo "$(shasum -a 1 "$f" | awk '{print $1}'):$f"
|
|
54
|
+
done | shasum -a 1 | awk '{print $1}'
|
|
51
55
|
```
|
|
52
56
|
|
|
53
57
|
**对比结果分级处理:**
|
|
@@ -84,16 +88,16 @@ Step B-10-6:触发跨域联动提示(检查引用了本域的其他 Skill,
|
|
|
84
88
|
### 模式 C:后置回写(来自 /plan、/spec 归档后)
|
|
85
89
|
|
|
86
90
|
将本次工作中新确立的决策、规则、接口契约追加或更新到对应 Skill 文件。
|
|
87
|
-
从产出物(design.md、specs/*/spec.md)提取带类型标签的知识:
|
|
91
|
+
从产出物(design-brief.md、specs/*/spec.md)提取带类型标签的知识:
|
|
88
92
|
- delta spec 的 ADDED Requirements → `[process]` / `[model]` 追加到业务 Skill
|
|
89
93
|
- delta spec 的 MODIFIED Requirements → 更新对应 `[guideline]`
|
|
90
|
-
- design.md 的架构决策章节 → `[decision]` 追加到对应业务 Skill 或 modus-tech-wiki
|
|
94
|
+
- design-brief.md 的架构决策章节 → `[decision]` 追加到对应业务 Skill 或 modus-tech-wiki
|
|
91
95
|
|
|
92
96
|
### 模式 D:知识提取(来自 Harness ARCHIVE 阶段)
|
|
93
97
|
|
|
94
98
|
从 Harness 全流程产物中系统性提取知识条目,判断提升路径,写回 Skill 并更新 catalog。
|
|
95
99
|
|
|
96
|
-
**输入产物:** `01-analysis.md`、`02-sprint-contract.md`、`cr-report.md`、`07-deploy-status.md`
|
|
100
|
+
**输入产物:** `01-analysis.md`、`02-sprint-contract.md`、`03-test-report.md`、`04-perf-report.md`、`05-security-report.md`、`cr-report.md`、`07-deploy-status.md`
|
|
97
101
|
|
|
98
102
|
**提取规则:**
|
|
99
103
|
|
|
@@ -101,9 +105,17 @@ Step B-10-6:触发跨域联动提示(检查引用了本域的其他 Skill,
|
|
|
101
105
|
|---------|---------|---------|---------|
|
|
102
106
|
| 01-analysis.md 的风险点 | 业务边界条件、并发风险 | `[pitfall]` | modus-biz-{domain} |
|
|
103
107
|
| 02-sprint-contract.md 的架构决策 | 技术选型原因 | `[decision]` | modus-tech-wiki |
|
|
108
|
+
| 03-test-report.md 的失败用例与边界条件 | 未覆盖的测试场景、发现的 bug 规律 | `[pitfall]` | modus-biz-{domain} |
|
|
109
|
+
| 04-perf-report.md 的高/中风险项 | N+1 查询、大数据量无分页、慢查询模式 | `[pitfall]` | modus-tech-wiki |
|
|
110
|
+
| 05-security-report.md 的严重/高风险项 | 多租户隔离漏洞、权限缺失、敏感信息泄露 | `[pitfall]` `[invariant]` | modus-team-conventions |
|
|
104
111
|
| cr-report.md 的 P1/P2 问题 | 规范违反模式 | `[pitfall]` `[guideline]` | modus-team-conventions |
|
|
105
112
|
| 07-deploy-status.md 的部署注意事项 | 环境特殊配置 | `[guideline]` | modus-tech-wiki |
|
|
106
113
|
|
|
114
|
+
**03/04/05 报告提取优先级:**
|
|
115
|
+
- `05-security-report.md` 的严重/高危问题必须提取,不可跳过(涉及安全不变量)
|
|
116
|
+
- `04-perf-report.md` 的高风险项(N+1、无分页大查询)必须提取,中风险项选择性提取
|
|
117
|
+
- `03-test-report.md` 仅提取因测试失败而发现的新 pitfall,已通过的用例不提取
|
|
118
|
+
|
|
107
119
|
**成熟度提升判定(统一使用 status 字段):**
|
|
108
120
|
- 本次工作流成功验证了某条知识 → `draft` 升为 `verified`,更新 `last_referenced` 和 `usage_count +1`
|
|
109
121
|
- 若该知识已是 `verified` 且跨不同工作流被引用 ≥2 次 → 升为 `proven`
|
|
@@ -111,7 +123,10 @@ Step B-10-6:触发跨域联动提示(检查引用了本域的其他 Skill,
|
|
|
111
123
|
**hash 更新(ARCHIVE 阶段必做):**
|
|
112
124
|
|
|
113
125
|
```bash
|
|
114
|
-
|
|
126
|
+
# 标准全局 hash 计算命令(与 modus-init 区块 B 规定的算法完全一致)
|
|
127
|
+
for f in $(echo "{key_files}" | tr ' ' '\n' | sort); do
|
|
128
|
+
echo "$(shasum -a 1 "$f" | awk '{print $1}'):$f"
|
|
129
|
+
done | shasum -a 1 | awk '{print $1}'
|
|
115
130
|
```
|
|
116
131
|
|
|
117
132
|
将新 hash 写入 SKILL.md frontmatter 的 `last_hash` 字段。
|
|
@@ -679,7 +694,7 @@ Step 4 扩展:upstream/downstream 双向同步(append-only,Git 无冲突
|
|
|
679
694
|
|
|
680
695
|
### Step 6:质量自检(生成后执行)
|
|
681
696
|
|
|
682
|
-
|
|
697
|
+
`modus-skill-creator`(SubAgent 00)在完成 Skill 生成后,执行自动质量自检:
|
|
683
698
|
|
|
684
699
|
```
|
|
685
700
|
质量自检清单(v3 版本,含新节检查):
|
|
@@ -1042,7 +1057,7 @@ layer: "1"
|
|
|
1042
1057
|
- 更新时必须更新 `updated` 日期和 `last_referenced`
|
|
1043
1058
|
- 模式 D 每次执行后必须同步更新 `modus/knowledge-catalog.md`
|
|
1044
1059
|
- 统一使用 `status` 字段(不使用 `maturity`),枚举值:`draft | verified | proven | stale | archived`
|
|
1045
|
-
- 新生成的 Skill 默认写入 `format_version: v2`;存量 7 节 Skill 迁移前标记 `format_version: v1`
|
|
1060
|
+
- 新生成的 Skill 默认写入 `format_version: v3`(17节标准格式);存量 14 节 Skill 保留 `format_version: v2`;存量 7 节 Skill 迁移前标记 `format_version: v1`
|
|
1046
1061
|
|
|
1047
1062
|
---
|
|
1048
1063
|
|
|
@@ -1050,8 +1065,11 @@ layer: "1"
|
|
|
1050
1065
|
|
|
1051
1066
|
```
|
|
1052
1067
|
verified 达标条件(全部满足方可从 draft 升为 verified):
|
|
1053
|
-
✅ 条件 1
|
|
1054
|
-
|
|
1068
|
+
✅ 条件 1:分两类检查
|
|
1069
|
+
【必须有实质内容的节】Section 2(枚举)、Section 3(业务规则)、Section 5(API)
|
|
1070
|
+
→ 不得为空或仅含「暂无发现」占位符(这些节在项目中必然有真实内容可填)
|
|
1071
|
+
【允许占位符的节】Section 9/10/13/15/16/17(积累型知识)
|
|
1072
|
+
→ 「暂无发现,随工作流积累」是合法初始内容,不阻碍 verified 升级
|
|
1055
1073
|
✅ 条件 2:质量自检清单(见 Step 6)零 ⚠️ 警告
|
|
1056
1074
|
新增检查项:Section 17 开发场景速查 ≥ 3 行
|
|
1057
1075
|
✅ 条件 3:key_files hash 与当前代码库一致(无 stale 状态)
|
|
@@ -1,91 +1,137 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: modus-tester
|
|
3
|
-
description: Use this skill when the Harness orchestrator needs to generate unit tests for code
|
|
3
|
+
description: Use this skill when the Harness orchestrator needs to generate unit tests for changed code after Gate A. Covers three test paths (Happy Path / boundary / exception), uses MockBean isolation, inherits project base test class, and generates 03-test-report.md with HANDOFF block. Triggered by modus-harness in parallel with perf-auditor and security-auditor after Gate A passes.
|
|
4
4
|
allowed-tools: Read, Write, Glob, Bash
|
|
5
5
|
disable: false
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# modus-tester(代码测试 SubAgent)
|
|
9
9
|
|
|
10
|
-
**调用方:** Harness Orchestrator
|
|
11
|
-
**输入:** `02-sprint-contract.md
|
|
12
|
-
**产出物:** `modus/plans/active/{story-id}/03-test-report.md` +
|
|
10
|
+
**调用方:** Harness Orchestrator(Gate A 通过后,与 04/05 并行触发)
|
|
11
|
+
**输入:** `02-sprint-contract.md`(变更文件列表)+ 代码变更 + 业务 Skill(≤ 2 个)
|
|
12
|
+
**产出物:** `modus/plans/active/{story-id}/03-test-report.md` + 测试代码
|
|
13
13
|
|
|
14
14
|
## 职责
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
为本次代码变更生成单元测试,覆盖核心业务逻辑的三条测试路径(Happy Path / 边界条件 / 异常路径),使用 Mock 隔离外部依赖,确保测试独立可重复运行。
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
20
|
## 执行流程
|
|
21
21
|
|
|
22
|
-
### Step 1
|
|
22
|
+
### Step 1:确定测试目标
|
|
23
23
|
|
|
24
|
-
读取 `02-sprint-contract.md
|
|
25
|
-
- Service/Manager 层的核心业务方法
|
|
26
|
-
- 有复杂条件分支的逻辑
|
|
27
|
-
- `01-analysis.md` 中标注的验收标准对应的逻辑
|
|
24
|
+
读取 `02-sprint-contract.md` 的 `changed_files`,识别需要测试的类:
|
|
28
25
|
|
|
29
|
-
|
|
26
|
+
**优先级(高 → 低):**
|
|
27
|
+
1. Service / Manager 类(核心业务逻辑,必须测试)
|
|
28
|
+
2. 含复杂条件分支的 Util / Helper 类
|
|
29
|
+
3. Controller / Facade(仅测试参数校验和权限逻辑)
|
|
30
|
+
4. Mapper 接口(通常跳过,属于集成测试范围)
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
### Step 2:三路径测试生成
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
- 主流程成功执行
|
|
35
|
-
- 返回值正确
|
|
34
|
+
对每个测试目标,生成以下三类测试用例:
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
**Path 1 — Happy Path(正常流程)**
|
|
37
|
+
```java
|
|
38
|
+
@Test
|
|
39
|
+
void {method}_success() {
|
|
40
|
+
// Given: 构造合法的输入数据
|
|
41
|
+
// When: 调用被测方法
|
|
42
|
+
// Then: 验证返回结果符合预期
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Path 2 — 边界条件(Boundary)**
|
|
47
|
+
```java
|
|
48
|
+
@Test
|
|
49
|
+
void {method}_withNullInput_throws() { ... }
|
|
50
|
+
|
|
51
|
+
@Test
|
|
52
|
+
void {method}_withEmptyList_returnsEmpty() { ... }
|
|
53
|
+
|
|
54
|
+
@Test
|
|
55
|
+
void {method}_withMaxValue_succeeds() { ... }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Path 3 — 异常路径(Exception)**
|
|
59
|
+
```java
|
|
60
|
+
@Test
|
|
61
|
+
void {method}_whenDistributedLockFails_throws() { ... }
|
|
62
|
+
|
|
63
|
+
@Test
|
|
64
|
+
void {method}_whenDownstreamRpcTimeout_throwsServiceException() { ... }
|
|
65
|
+
|
|
66
|
+
@Test
|
|
67
|
+
void {method}_whenDatabaseError_rollsBack() { ... }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Step 3:测试代码规范
|
|
41
71
|
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
- 并发场景(如分布式锁被占用)
|
|
72
|
+
**Mock 隔离原则:**
|
|
73
|
+
- 使用 `@MockBean`(Spring)或 `@Mock`(Mockito)隔离所有外部依赖
|
|
74
|
+
- 不使用 `@SpringBootTest`(启动全量容器,速度慢),优先使用 `@ExtendWith(MockitoExtension.class)` 或项目已有的轻量基类
|
|
75
|
+
- 数据库操作全部 Mock,不依赖真实数据库
|
|
47
76
|
|
|
48
|
-
|
|
77
|
+
**继承项目基类:**
|
|
78
|
+
- 读取项目已有的测试基类(如 `AbstractBaseTest`、`BaseServiceTest`),继承或参照其 Mock 配置
|
|
79
|
+
- 若无基类,使用 `@ExtendWith(MockitoExtension.class)`
|
|
49
80
|
|
|
50
|
-
|
|
51
|
-
- 使用
|
|
52
|
-
-
|
|
53
|
-
- 测试方法命名清晰表达场景:`test_{methodName}_{scenario}_{expectedResult}`
|
|
54
|
-
- 断言明确,不只断言 "no exception"
|
|
81
|
+
**断言规范:**
|
|
82
|
+
- 使用 AssertJ 或 JUnit 5 标准断言(`assertThat`/`assertEquals`)
|
|
83
|
+
- 异常测试用 `assertThrows`,验证异常类型和消息
|
|
55
84
|
|
|
56
|
-
### Step 4
|
|
85
|
+
### Step 4:执行测试验证
|
|
57
86
|
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
|
|
87
|
+
```bash
|
|
88
|
+
{constitution.test_command} # 如 mvn test -pl {module} -Dtest={TestClass}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
测试失败 → 修复测试代码(不修改业务代码)后重试。
|
|
61
92
|
|
|
62
93
|
---
|
|
63
94
|
|
|
64
95
|
## 产出物格式(03-test-report.md)
|
|
65
96
|
|
|
66
97
|
```markdown
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
98
|
+
<!--HANDOFF
|
|
99
|
+
agent: "03-tester"
|
|
100
|
+
story_id: "{story-id}"
|
|
101
|
+
gate_status: "passed"
|
|
102
|
+
tests_generated: {N}
|
|
103
|
+
tests_passed: {N}
|
|
104
|
+
coverage_targets:
|
|
105
|
+
- "{ClassName}.{method}(): {覆盖的路径描述}"
|
|
106
|
+
-->
|
|
107
|
+
|
|
108
|
+
# 测试报告 — {Story 标题}
|
|
109
|
+
|
|
110
|
+
## 测试摘要
|
|
111
|
+
- 生成测试用例: {N} 个
|
|
112
|
+
- 通过: {N} 个 | 失败: {N} 个
|
|
113
|
+
- 覆盖的核心逻辑: {列表}
|
|
73
114
|
|
|
74
115
|
## 测试用例列表
|
|
75
116
|
|
|
76
117
|
### {ClassName}Test
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
## 验收标准覆盖
|
|
88
|
-
| 验收场景 | 对应测试 | 状态 |
|
|
89
|
-
|----------|----------|------|
|
|
90
|
-
| {从 01-analysis.md 提取} | {测试方法名} | ✅/❌ |
|
|
118
|
+
|
|
119
|
+
| 测试用例 | 路径类型 | 测试场景 | 结果 |
|
|
120
|
+
|---------|---------|---------|------|
|
|
121
|
+
| {method}_success | Happy Path | {场景} | ✅ |
|
|
122
|
+
| {method}_withNull_throws | Boundary | null 输入 | ✅ |
|
|
123
|
+
| {method}_whenLockFail | Exception | 分布式锁获取失败 | ✅ |
|
|
124
|
+
|
|
125
|
+
## 未覆盖说明
|
|
126
|
+
|
|
127
|
+
{若有意跳过某些场景,说明原因(如:Mapper 接口属于集成测试范畴,本次跳过)}
|
|
91
128
|
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 质量标准
|
|
133
|
+
|
|
134
|
+
- Service / Manager 类的核心业务方法必须有 Happy Path 覆盖
|
|
135
|
+
- 01-analysis.md 中标注的并发/事务风险点必须有对应的异常路径测试
|
|
136
|
+
- 所有测试必须在 Mock 隔离下独立通过,不依赖外部环境
|
|
137
|
+
- **HANDOFF 块必须位于文件最顶部**,`gate_status` 仅在所有测试通过时为 `passed`
|
|
@@ -63,6 +63,8 @@ story = tapd_mcp.get_story(story_id)
|
|
|
63
63
|
|
|
64
64
|
#### 维度三:需求明确度 (Clarity)
|
|
65
65
|
|
|
66
|
+
> ⚠️ **刻度方向与复杂度/风险相反**:分值越高 = 需求越清晰(好)。判定树中「明确度=低」触发 harness,「明确度=高」支持 plan,方向勿与其他维度混淆。
|
|
67
|
+
|
|
66
68
|
| 分值 | 判定条件 |
|
|
67
69
|
|------|----------|
|
|
68
70
|
| 高 (3) | 验收标准完整(有具体输入输出)、边界条件明确 |
|
|
@@ -98,6 +100,12 @@ story = tapd_mcp.get_story(story_id)
|
|
|
98
100
|
- 复杂度=高 且 风险=高
|
|
99
101
|
- 用户希望全自动从需求到部署
|
|
100
102
|
→ 推荐 harness(双 Loop 全自动流程)
|
|
103
|
+
|
|
104
|
+
**优先级规则(多条件同时满足时):**
|
|
105
|
+
harness > spec > plan > vibe
|
|
106
|
+
即:若 harness 条件与 spec 条件同时满足,推荐 harness;
|
|
107
|
+
若 spec 条件与 plan 条件同时满足,推荐 spec;以此类推。
|
|
108
|
+
向用户展示次优选项以供参考。
|
|
101
109
|
```
|
|
102
110
|
|
|
103
111
|
### Step 5:展示推荐与对比
|
|
@@ -179,7 +187,14 @@ D. /modus:harness — 全自动 Harness
|
|
|
179
187
|
用户确认后,根据选择自动触发对应模式:
|
|
180
188
|
|
|
181
189
|
- **vibe**:以已整理的任务描述调用 `/modus:vibe`,上下文包含 Story 摘要
|
|
182
|
-
- **plan**:以整理好的 prompt 调用 `/modus:plan
|
|
190
|
+
- **plan**:以整理好的 prompt 调用 `/modus:plan`,在 prompt 末尾附加标记 `[AUTO_MODE: questions_confirmed]` 和答案摘要(格式见下),modus-plan Step 3 识别到此标记后跳过交互式澄清阶段:
|
|
191
|
+
```
|
|
192
|
+
[AUTO_MODE: questions_confirmed]
|
|
193
|
+
已确认的关键信息:
|
|
194
|
+
- 业务域: {domain}
|
|
195
|
+
- 核心目标: {一句话目标}
|
|
196
|
+
- 技术约束: {列表,若用户在 Step 6 中补充了约束}
|
|
197
|
+
```
|
|
183
198
|
- **spec**:以整理好的 prompt 调用 `/modus:spec`,携带 Story 验收标准作为 Scenario 参考输入
|
|
184
199
|
- **harness**:直接调用 `/modus:harness {tapd_url}`
|
|
185
200
|
|