@xulthekl/team-flow 0.67.0 → 0.69.0
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/.claude/always/phase-guard.md +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/marketplace.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/.github/plugin/marketplace.json +2 -2
- package/CHANGELOG.md +50 -0
- package/GEMINI.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +1 -1
- package/agents/architecture-reviewer.md +15 -4
- package/agents/code-reviewer.md +11 -4
- package/agents/prd-completeness-reviewer.md +18 -9
- package/docs/README_en.md +1 -1
- package/docs/team-flow /344/275/277/347/224/250/350/257/264/346/230/216/357/274/210/347/240/224/345/217/221/345/233/242/351/230/237/347/211/210/357/274/211.md" +7 -5
- package/gemini-extension.json +1 -1
- package/hooks/session-start +2 -2
- package/llms.txt +1 -1
- package/package.json +5 -1
- package/plugin.json +1 -1
- package/scripts/guard/checks/security-baseline-light.mjs +9 -0
- package/scripts/guard/checks/security-baseline.mjs +141 -0
- package/scripts/guard/guard.mjs +22 -5
- package/scripts/lib/cmd-security.mjs +61 -0
- package/scripts/lib/cmd-state.mjs +5 -0
- package/scripts/lib/security-scope.mjs +188 -0
- package/scripts/lib/state-loader.mjs +12 -0
- package/scripts/team-flow.mjs +7 -0
- package/scripts/validate-mermaid.mjs +240 -0
- package/skills/ce-brainstorm/references/security-baseline.json +50 -0
- package/skills/ce-brainstorm/references/security-baseline.md +80 -0
- package/skills/ce-compound/references/agents/security-sentinel.md +5 -0
- package/skills/ce-plan/references/agents/security-sentinel.md +5 -0
- package/skills/code-reviewer/SKILL.md +5 -1
- package/skills/code-reviewer/code-reviewer-prompt.md +10 -0
- package/skills/release-archivist/SKILL.md +21 -2
- package/skills/spec-writer/SKILL.md +5 -0
- package/skills/workflow-start/SKILL.md +8 -3
- package/skills/workflow-start/references/routing-rules.md +1 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// scripts/validate-mermaid.mjs — Markdown 内 ```mermaid 围栏语法快速验证
|
|
3
|
+
//
|
|
4
|
+
// 背景(2026-09-30,LT 提出):实际用 team-flow 产 PRD 时 mermaid 语法错误导致无法渲染。
|
|
5
|
+
// 仓库此前无任何 mermaid 校验(lint 6 规则 / validate-artifacts / 模板测试均只查存在性正则)。
|
|
6
|
+
//
|
|
7
|
+
// 用法:
|
|
8
|
+
// node scripts/validate-mermaid.mjs <file.md> [more.md ...]
|
|
9
|
+
// node scripts/validate-mermaid.mjs --dir <dir> # 递归扫描目录下全部 .md
|
|
10
|
+
//
|
|
11
|
+
// 输出约定(与 `tf prd check-clarity` 同构 + 用法错误参照其 exit 2 惯例):
|
|
12
|
+
// 逐 fence 报告 `file:line: <错误>`;末行 `STATUS: PASS | FAIL | SKIP | ERROR`。
|
|
13
|
+
// PASS → exit 0(全部 fence 可 parse,或无 fence);
|
|
14
|
+
// FAIL → exit 1(语法错误,stdout 必带 file:line 命中——调用方按行号记 finding);
|
|
15
|
+
// SKIP → exit 0(**仅限**依赖不可用且安装失败——按 LT 裁定降级不阻断,显眼告警);
|
|
16
|
+
// ERROR → exit 2(**调用方用法错误**:无参数 / 路径不存在 / 传入目录 / 脚本自身异常——
|
|
17
|
+
// 不是依赖问题,调用方应报环境错误,不得记为 SKIP 依赖降级)。
|
|
18
|
+
//
|
|
19
|
+
// 依赖策略(LT 2026-09-30 裁定):
|
|
20
|
+
// 1. mermaid + jsdom 声明在 package.json dependencies(用户装插件即带上);
|
|
21
|
+
// 2. 运行时缺依赖 → 先尝试 `npm install`(限时)→ 成功则继续;
|
|
22
|
+
// 3. 安装仍失败 → WARN 降级:`STATUS: SKIP` + exit 0,不阻断主流程。
|
|
23
|
+
//
|
|
24
|
+
// 实现要点:
|
|
25
|
+
// - **先 createRequire resolve 再 import**:Node 同进程内失败的 dynamic import 会被
|
|
26
|
+
// 缓存为失败(实测 ERR_MODULE_NOT_FOUND 重试无效),所以绝不能"先 import 失败再装再
|
|
27
|
+
// import"——必须用文件系统级 resolve 探测(不进 ESM 缓存),装完后 import 必成功。
|
|
28
|
+
// - jsdom 提供最小 DOM(mermaid.parse 需要 document/window),实测单图 parse <20ms。
|
|
29
|
+
// - parse 错误信息含 mermaid 内部行号(相对 fence),输出时换算为 md 文件绝对行号。
|
|
30
|
+
|
|
31
|
+
import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';
|
|
32
|
+
import { join, resolve, dirname, relative } from 'node:path';
|
|
33
|
+
import { fileURLToPath } from 'node:url';
|
|
34
|
+
import { createRequire } from 'node:module';
|
|
35
|
+
import { spawnSync } from 'node:child_process';
|
|
36
|
+
|
|
37
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
38
|
+
const PKG_ROOT = resolve(__dirname, '..');
|
|
39
|
+
const require = createRequire(import.meta.url);
|
|
40
|
+
const INSTALL_TIMEOUT_MS = 90_000;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 提取 md 文本中全部 ```mermaid 围栏。
|
|
44
|
+
* 返回 [{ startLine (fence 行, 1-based), content, contentStartLine }]。
|
|
45
|
+
* 不支持嵌套 fence(mermaid 内容本身不含 ```),标准围栏配对即可。
|
|
46
|
+
*/
|
|
47
|
+
export function extractMermaidFences(text) {
|
|
48
|
+
const lines = text.split(/\r?\n/);
|
|
49
|
+
const fences = [];
|
|
50
|
+
let cur = null;
|
|
51
|
+
for (let i = 0; i < lines.length; i++) {
|
|
52
|
+
const line = lines[i];
|
|
53
|
+
if (!cur && /^\s*```mermaid\s*$/.test(line)) {
|
|
54
|
+
cur = { startLine: i + 1, buf: [], contentStartLine: i + 2 };
|
|
55
|
+
} else if (cur && /^\s*```\s*$/.test(line)) {
|
|
56
|
+
fences.push({ startLine: cur.startLine, contentStartLine: cur.contentStartLine, content: cur.buf.join('\n') });
|
|
57
|
+
cur = null;
|
|
58
|
+
} else if (cur) {
|
|
59
|
+
cur.buf.push(line);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (cur) {
|
|
63
|
+
// 未闭合 fence:也算一个待校验项(mermaid.parse 会因缺尾部语法报错,或直接标 ERROR)
|
|
64
|
+
fences.push({ startLine: cur.startLine, contentStartLine: cur.contentStartLine, content: cur.buf.join('\n'), unclosed: true });
|
|
65
|
+
}
|
|
66
|
+
return fences;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 依赖探测 + 按需安装。返回 { ok: true } 或 { ok: false, reason }。
|
|
71
|
+
* 用 resolve 而非 import 做探测(见文件头注:失败 import 会污染同进程 ESM 缓存)。
|
|
72
|
+
*/
|
|
73
|
+
export function ensureDeps({ allowInstall = true, timeoutMs = INSTALL_TIMEOUT_MS, installer = defaultInstall, resolvelike = defaultResolve } = {}) {
|
|
74
|
+
if (resolvelike()) return { ok: true };
|
|
75
|
+
if (!allowInstall) return { ok: false, reason: 'mermaid/jsdom 未安装(安装被禁用)' };
|
|
76
|
+
|
|
77
|
+
process.stderr.write('[validate-mermaid] mermaid/jsdom 缺失,尝试安装...\n');
|
|
78
|
+
const r = installer(timeoutMs);
|
|
79
|
+
if (r.error || r.status !== 0) {
|
|
80
|
+
const why = r.error ? r.error.message : `npm exit ${r.status}: ${(r.stderr || '').trim().split('\n').slice(-3).join(' | ')}`;
|
|
81
|
+
return { ok: false, reason: `依赖安装失败:${why}` };
|
|
82
|
+
}
|
|
83
|
+
return resolvelike()
|
|
84
|
+
? { ok: true }
|
|
85
|
+
: { ok: false, reason: 'npm install 完成但依赖仍不可 resolve' };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** 默认依赖探测:文件系统级 resolve(不进 ESM import 缓存——见文件头注)。 */
|
|
89
|
+
function defaultResolve() {
|
|
90
|
+
try {
|
|
91
|
+
require.resolve('mermaid');
|
|
92
|
+
require.resolve('jsdom');
|
|
93
|
+
return true;
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** 默认安装器:在插件包根执行 npm install。 */
|
|
100
|
+
function defaultInstall(timeoutMs) {
|
|
101
|
+
return spawnSync('npm', ['install', '--no-audit', '--no-fund', '--loglevel=error'], {
|
|
102
|
+
cwd: PKG_ROOT,
|
|
103
|
+
timeout: timeoutMs,
|
|
104
|
+
encoding: 'utf8',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** 初始化 mermaid 解析运行时(jsdom DOM + mermaid.initialize)。仅在 ensureDeps ok 后调用。导出供测试复用——进程内 parse 必须先有 DOM,否则恒报错(假绿风险)。 */
|
|
109
|
+
export async function initRuntime() {
|
|
110
|
+
const { JSDOM } = await import('jsdom');
|
|
111
|
+
const dom = new JSDOM('<!DOCTYPE html><body></body>', { pretendToBeVisual: true });
|
|
112
|
+
if (!globalThis.window) globalThis.window = dom.window;
|
|
113
|
+
if (!globalThis.document) globalThis.document = dom.window.document;
|
|
114
|
+
try {
|
|
115
|
+
Object.defineProperty(globalThis, 'navigator', { value: dom.window.navigator, configurable: true });
|
|
116
|
+
} catch { /* Node >=21 navigator 只读,已有值则忽略 */ }
|
|
117
|
+
const mermaid = (await import('mermaid')).default;
|
|
118
|
+
mermaid.initialize({ startOnLoad: false, securityLevel: 'loose' });
|
|
119
|
+
return mermaid;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** 把 mermaid parse 错误信息里的相对行号换算为 md 绝对行号。 */
|
|
123
|
+
function reline(msg, contentStartLine) {
|
|
124
|
+
const m = /on line (\d+)/.exec(msg);
|
|
125
|
+
if (!m) return contentStartLine;
|
|
126
|
+
return contentStartLine + (parseInt(m[1], 10) - 1);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 校验单个 md 文件。返回 { file, fenceCount, errors: [{ line, message }], skipped? }。
|
|
131
|
+
* deps.ok=false 时返回 skipped 态(不读文件不 parse)。
|
|
132
|
+
*/
|
|
133
|
+
export async function validateFile(mdPath, mermaid) {
|
|
134
|
+
const text = readFileSync(mdPath, 'utf8');
|
|
135
|
+
const fences = extractMermaidFences(text);
|
|
136
|
+
const errors = [];
|
|
137
|
+
for (const f of fences) {
|
|
138
|
+
if (!f.content.trim()) {
|
|
139
|
+
if (f.unclosed) errors.push({ line: f.startLine, message: 'mermaid fence 未闭合' });
|
|
140
|
+
else errors.push({ line: f.startLine, message: 'mermaid fence 为空' });
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
await mermaid.parse(f.content);
|
|
145
|
+
} catch (e) {
|
|
146
|
+
const raw = String(e?.message || e).split('\n').filter(Boolean)[0] || 'parse error';
|
|
147
|
+
errors.push({ line: reline(raw, f.contentStartLine), message: raw, mermaidLine: (/on line (\d+)/.exec(raw)?.[1]) });
|
|
148
|
+
}
|
|
149
|
+
if (f.unclosed) errors.push({ line: f.startLine, message: 'mermaid fence 未闭合' });
|
|
150
|
+
}
|
|
151
|
+
return { file: mdPath, fenceCount: fences.length, errors };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function collectMdFiles(dir, out = []) {
|
|
155
|
+
for (const name of readdirSync(dir)) {
|
|
156
|
+
if (name === 'node_modules' || name.startsWith('.')) continue;
|
|
157
|
+
const p = join(dir, name);
|
|
158
|
+
const st = statSync(p);
|
|
159
|
+
if (st.isDirectory()) collectMdFiles(p, out);
|
|
160
|
+
else if (name.endsWith('.md')) out.push(p);
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function main() {
|
|
166
|
+
const args = process.argv.slice(2);
|
|
167
|
+
const files = [];
|
|
168
|
+
// 用法错误统一 STATUS: ERROR + exit 2(区别于 SKIP=依赖降级 exit 0——
|
|
169
|
+
// 混用会让调用方把"路径没传对"误记成"依赖不可用",门检查不到)
|
|
170
|
+
const usageError = (msg) => {
|
|
171
|
+
console.error(msg);
|
|
172
|
+
console.error('Usage: node scripts/validate-mermaid.mjs <file.md> [...] | --dir <dir>');
|
|
173
|
+
console.log('STATUS: ERROR');
|
|
174
|
+
process.exit(2);
|
|
175
|
+
};
|
|
176
|
+
if (args.length === 0) usageError('no arguments');
|
|
177
|
+
if (args[0] === '--dir') {
|
|
178
|
+
if (!args[1]) usageError('--dir requires a path');
|
|
179
|
+
if (!existsSync(args[1])) usageError(`dir not found: ${args[1]}`);
|
|
180
|
+
if (!statSync(args[1]).isDirectory()) usageError(`not a directory: ${args[1]}`);
|
|
181
|
+
files.push(...collectMdFiles(resolve(args[1])));
|
|
182
|
+
} else {
|
|
183
|
+
for (const a of args) {
|
|
184
|
+
if (!existsSync(a)) usageError(`file not found: ${a}`);
|
|
185
|
+
if (statSync(a).isDirectory()) usageError(`is a directory (use --dir): ${a}`);
|
|
186
|
+
files.push(resolve(a));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 1) 依赖:缺则先装,装不上才降级(LT 裁定)
|
|
191
|
+
const deps = ensureDeps();
|
|
192
|
+
if (!deps.ok) {
|
|
193
|
+
process.stderr.write(`⚠️ [validate-mermaid] ${deps.reason} —— mermaid 校验跳过(WARN 降级,不阻断)\n`);
|
|
194
|
+
console.log('STATUS: SKIP');
|
|
195
|
+
process.exit(0);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 2) 运行时(此时尚未 import mermaid/jsdom,ESM 缓存干净)
|
|
199
|
+
let mermaid;
|
|
200
|
+
try {
|
|
201
|
+
mermaid = await initRuntime();
|
|
202
|
+
} catch (e) {
|
|
203
|
+
process.stderr.write(`⚠️ [validate-mermaid] 运行时初始化失败:${String(e?.message || e)} —— mermaid 校验跳过\n`);
|
|
204
|
+
console.log('STATUS: SKIP');
|
|
205
|
+
process.exit(0);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 3) 逐文件校验(0-fence 文件不逐行打印,防目录扫描刷屏;汇总行给出计数)
|
|
209
|
+
let fenceTotal = 0;
|
|
210
|
+
let errorTotal = 0;
|
|
211
|
+
let filesWithFences = 0;
|
|
212
|
+
for (const f of files) {
|
|
213
|
+
const r = await validateFile(f, mermaid);
|
|
214
|
+
fenceTotal += r.fenceCount;
|
|
215
|
+
if (r.fenceCount === 0 && r.errors.length === 0) continue;
|
|
216
|
+
filesWithFences++;
|
|
217
|
+
const rel = relative(process.cwd(), r.file) || r.file;
|
|
218
|
+
if (r.errors.length === 0) {
|
|
219
|
+
console.log(` ✅ ${rel} (${r.fenceCount} fence)`);
|
|
220
|
+
} else {
|
|
221
|
+
errorTotal += r.errors.length;
|
|
222
|
+
for (const err of r.errors) console.log(` ❌ ${rel}:${err.line}: ${err.message}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (filesWithFences === 0) console.log(' (no mermaid fences found)');
|
|
226
|
+
console.log(`fences: ${fenceTotal} | errors: ${errorTotal} | files: ${files.length} (${filesWithFences} with fences)`);
|
|
227
|
+
console.log(`STATUS: ${errorTotal > 0 ? 'FAIL' : 'PASS'}`);
|
|
228
|
+
process.exit(errorTotal > 0 ? 1 : 0);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// 直接执行时跑 main;被 import(测试)时不跑。
|
|
232
|
+
// 顶层兜底:任何未捕获异常也必须输出 STATUS 行——否则调用方(agent)连
|
|
233
|
+
// "出错"都感知不到,只会看到无 STATUS 的裸异常输出(评审 skill-reviewer M3)。
|
|
234
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
235
|
+
main().catch((e) => {
|
|
236
|
+
console.error(`unexpected error: ${String(e?.stack || e)}`);
|
|
237
|
+
console.log('STATUS: ERROR');
|
|
238
|
+
process.exit(2);
|
|
239
|
+
});
|
|
240
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"baseline_version": "2026-11-enterprise-1",
|
|
3
|
+
"source": "企业安全设计自检表(2026-11 版,44 项控制点;来源 xlsx 见 workspace 设计文档)",
|
|
4
|
+
"items": [
|
|
5
|
+
{ "id": 1, "title": "无硬编码密码 / 空密码", "domain": "代码质量", "trigger": "code-quality", "severity": "must", "locus": "code" },
|
|
6
|
+
{ "id": 2, "title": "无路径遍历(相对/绝对)", "domain": "代码质量", "trigger": "code-quality", "severity": "must", "locus": "code" },
|
|
7
|
+
{ "id": 3, "title": "无硬编码加密密钥", "domain": "代码质量", "trigger": "code-quality", "severity": "must", "locus": "code" },
|
|
8
|
+
{ "id": 4, "title": "SQL 参数化查询", "domain": "代码质量", "trigger": "code-quality", "severity": "must", "locus": "code" },
|
|
9
|
+
{ "id": 5, "title": "不执行不可信赖命令", "domain": "代码质量", "trigger": "code-quality", "severity": "must", "locus": "code" },
|
|
10
|
+
{ "id": 6, "title": "不用未加盐/可预测盐哈希", "domain": "代码质量", "trigger": "code-quality", "severity": "must", "locus": "code" },
|
|
11
|
+
{ "id": 7, "title": "HttpOnly=true", "domain": "代码质量", "trigger": "code-quality", "severity": "must", "locus": "code" },
|
|
12
|
+
{ "id": 8, "title": "服务端权限鉴别(非公开内容)", "domain": "身份认证", "trigger": "authn-authz", "severity": "must", "locus": "code" },
|
|
13
|
+
{ "id": 9, "title": "标准认证协议(JWT/OAuth,禁 Basic)", "domain": "身份认证", "trigger": "authn-authz", "severity": "must", "locus": "code" },
|
|
14
|
+
{ "id": 10, "title": "登录失败处理(防暴破)", "domain": "身份认证", "trigger": "authn-authz", "severity": "must", "locus": "code" },
|
|
15
|
+
{ "id": 11, "title": "超时未活动自动结束会话", "domain": "身份认证", "trigger": "authn-authz", "severity": "must", "locus": "code" },
|
|
16
|
+
{ "id": 12, "title": "会话过期设置(退登失效)", "domain": "身份认证", "trigger": "authn-authz", "severity": "must", "locus": "code" },
|
|
17
|
+
{ "id": 13, "title": "个人信息/车辆信息接口用 POST", "domain": "身份认证", "trigger": "authn-authz", "severity": "must", "locus": "code" },
|
|
18
|
+
{ "id": 14, "title": "系统间调用仅接受 POST", "domain": "身份认证", "trigger": "authn-authz", "severity": "should", "locus": "code" },
|
|
19
|
+
{ "id": 15, "title": "JWT 不存放敏感数据", "domain": "身份认证", "trigger": "authn-authz", "severity": "must", "locus": "code" },
|
|
20
|
+
{ "id": 16, "title": "重定向 URL 白名单校验", "domain": "身份认证", "trigger": "redirect", "severity": "must", "locus": "code" },
|
|
21
|
+
{ "id": 17, "title": "重命名/删除默认账户、改默认口令", "domain": "访问控制", "trigger": "authn-authz", "severity": "must", "locus": "config" },
|
|
22
|
+
{ "id": 18, "title": "分配账户和权限(三权分立)", "domain": "访问控制", "trigger": "authn-authz", "severity": "must", "locus": "config" },
|
|
23
|
+
{ "id": 19, "title": "启用安全审计,覆盖每用户", "domain": "安全审计", "trigger": "audit", "severity": "must", "locus": "code+process" },
|
|
24
|
+
{ "id": 20, "title": "审计日志含日期/用户/事件等", "domain": "安全审计", "trigger": "audit", "severity": "must", "locus": "code+process" },
|
|
25
|
+
{ "id": 21, "title": "远程管理防窃听(HTTPS)", "domain": "通信传输", "trigger": "transport", "severity": "must", "locus": "infra" },
|
|
26
|
+
{ "id": 22, "title": "TLS ≥ 1.2", "domain": "通信传输", "trigger": "transport", "severity": "must", "locus": "infra" },
|
|
27
|
+
{ "id": 23, "title": "HSTS 防 SSL Strip", "domain": "通信传输", "trigger": "transport", "severity": "should", "locus": "infra" },
|
|
28
|
+
{ "id": 24, "title": "传输完整性(签名校验)", "domain": "通信传输", "trigger": "transport", "severity": "should", "locus": "code+infra" },
|
|
29
|
+
{ "id": 25, "title": "所有外部/用户输入验证过滤", "domain": "输入", "trigger": "input", "severity": "must", "locus": "code" },
|
|
30
|
+
{ "id": 26, "title": "输出字符实体编码", "domain": "输入", "trigger": "input", "severity": "must", "locus": "code" },
|
|
31
|
+
{ "id": 27, "title": "URL 不含敏感数据", "domain": "输入", "trigger": "input", "severity": "must", "locus": "code" },
|
|
32
|
+
{ "id": 28, "title": "content-type 验证,否则 415", "domain": "处理", "trigger": "processing", "severity": "should", "locus": "code" },
|
|
33
|
+
{ "id": 29, "title": "Accept 协商,禁校验正文", "domain": "处理", "trigger": "processing", "severity": "must", "locus": "code" },
|
|
34
|
+
{ "id": 30, "title": "XML 实体解析关闭(XXE)", "domain": "处理", "trigger": "processing", "severity": "must", "locus": "code" },
|
|
35
|
+
{ "id": 31, "title": "XML 实体扩展关闭(bomb)", "domain": "处理", "trigger": "processing", "severity": "must", "locus": "code" },
|
|
36
|
+
{ "id": 32, "title": "不返回敏感数据", "domain": "输出", "trigger": "output", "severity": "must", "locus": "code" },
|
|
37
|
+
{ "id": 33, "title": "X-Content-Type-Options: nosniff", "domain": "输出", "trigger": "output", "severity": "should", "locus": "code+infra" },
|
|
38
|
+
{ "id": 34, "title": "X-Frame-Options: deny", "domain": "输出", "trigger": "output", "severity": "should", "locus": "code+infra" },
|
|
39
|
+
{ "id": 35, "title": "CSP: default-src 'none'", "domain": "输出", "trigger": "output", "severity": "should", "locus": "infra+code" },
|
|
40
|
+
{ "id": 36, "title": "错误信息不含系统敏感", "domain": "输出", "trigger": "output", "severity": "must", "locus": "code" },
|
|
41
|
+
{ "id": 37, "title": "中间件最新无安全漏洞", "domain": "中间件", "trigger": "deps", "severity": "must", "locus": "config" },
|
|
42
|
+
{ "id": 38, "title": "信息查询字段过滤(特殊字符)", "domain": "功能-信息查询", "trigger": "input", "severity": "must", "locus": "code" },
|
|
43
|
+
{ "id": 39, "title": "文件上传前端限大小", "domain": "功能-文件上传", "trigger": "file-io", "severity": "must", "locus": "code+infra" },
|
|
44
|
+
{ "id": 40, "title": "文件名随机无规律", "domain": "功能-文件上传", "trigger": "file-io", "severity": "must", "locus": "code" },
|
|
45
|
+
{ "id": 41, "title": "上传文件内容验证(文件头)", "domain": "功能-文件上传", "trigger": "file-io", "severity": "must", "locus": "code" },
|
|
46
|
+
{ "id": 42, "title": "后台内容管理请求鉴权", "domain": "功能-后台管理", "trigger": "authn-authz", "severity": "must", "locus": "code" },
|
|
47
|
+
{ "id": 43, "title": "后台字段格式限制/过滤", "domain": "功能-后台管理", "trigger": "input", "severity": "must", "locus": "code" },
|
|
48
|
+
{ "id": 44, "title": "跳转链接白名单过滤", "domain": "功能-链接跳转", "trigger": "redirect", "severity": "should", "locus": "code" }
|
|
49
|
+
]
|
|
50
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# 安全基线参考(企业 44 项安全设计控制点)
|
|
2
|
+
|
|
3
|
+
> **角色**:安全基线的**人类可读权威**(L1)。同目录 `security-baseline.json` 是机器可读载体(推导模块 `scripts/lib/security-scope.mjs` 与 guard 的消费面),两者由测试断言 `baseline_version` + 条目数锁一致。
|
|
4
|
+
> **来源**:企业安全设计自检表(2026-11 版,44 项控制点)。原始 xlsx 与企业上下文见 workspace 设计文档,**本仓库不落企业信息**。
|
|
5
|
+
> **设计出处**:workspace `docs/plan/security-baseline-integration-design.md`(v1.3)。
|
|
6
|
+
> **同步协议**:企业 xlsx 改版 → 更新设计文档附录 A → 同步本文件与 `.json` → 一致性断言过。禁止只改一侧。
|
|
7
|
+
|
|
8
|
+
## 裁剪双维度
|
|
9
|
+
|
|
10
|
+
- **触发类别(trigger)**:决定本次变更要不要触发安全复核。由 `tf security scope` 从 git diff + spec/arch 关键词推导;无适用类别 = 静默 PASS(零开销,推导结果仍落盘留痕)。
|
|
11
|
+
- **locus**:决定该项归谁核验——`code`(仓库内核验)/ `config`(IAM·部署)/ `infra`(ingress·网关)/ `process`(平台留存)及组合(`code+process` 等,双侧并行)。纯 infra/config/process 项不进代码门禁,路由至 closing `security/handoff.md` 交接。
|
|
12
|
+
|
|
13
|
+
10 个触发类别:`code-quality` `authn-authz` `redirect` `audit` `transport` `input` `processing` `output` `deps` `file-io`。
|
|
14
|
+
|
|
15
|
+
## verdict → 门禁映射(L3 产出、L2 消费)
|
|
16
|
+
|
|
17
|
+
| verdict | 必须项(must) | 建议项(should) |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| satisfied | PASS | PASS |
|
|
20
|
+
| not-applicable | 须过 reason 判据(≥10 字符或含控制点序号),否则视同 uncovered | 同左 |
|
|
21
|
+
| uncovered / 在核验集缺席 | **FAIL** | 不阻断,记 WARN |
|
|
22
|
+
|
|
23
|
+
## 44 项清单
|
|
24
|
+
|
|
25
|
+
| # | 控制点 | 域 | trigger | 性质 | locus |
|
|
26
|
+
|---|---|---|---|---|---|
|
|
27
|
+
| 1 | 无硬编码密码 / 空密码 | 代码质量 | code-quality | 必须 | code |
|
|
28
|
+
| 2 | 无路径遍历(相对/绝对) | 代码质量 | code-quality | 必须 | code |
|
|
29
|
+
| 3 | 无硬编码加密密钥 | 代码质量 | code-quality | 必须 | code |
|
|
30
|
+
| 4 | SQL 参数化查询 | 代码质量 | code-quality | 必须 | code |
|
|
31
|
+
| 5 | 不执行不可信赖命令 | 代码质量 | code-quality | 必须 | code |
|
|
32
|
+
| 6 | 不用未加盐 / 可预测盐哈希 | 代码质量 | code-quality | 必须 | code |
|
|
33
|
+
| 7 | HttpOnly=true | 代码质量 | code-quality | 必须 | code |
|
|
34
|
+
| 8 | 服务端权限鉴别(非公开内容) | 身份认证 | authn-authz | 必须 | code |
|
|
35
|
+
| 9 | 标准认证协议(JWT/OAuth,禁 Basic) | 身份认证 | authn-authz | 必须 | code |
|
|
36
|
+
| 10 | 登录失败处理(防暴破) | 身份认证 | authn-authz | 必须 | code |
|
|
37
|
+
| 11 | 超时未活动自动结束会话 | 身份认证 | authn-authz | 必须 | code |
|
|
38
|
+
| 12 | 会话过期设置(退登失效) | 身份认证 | authn-authz | 必须 | code |
|
|
39
|
+
| 13 | 个人信息/车辆信息接口用 POST | 身份认证 | authn-authz | 必须 | code |
|
|
40
|
+
| 14 | 系统间调用仅接受 POST | 身份认证 | authn-authz | 建议 | code |
|
|
41
|
+
| 15 | JWT 不存放敏感数据 | 身份认证 | authn-authz | 必须 | code |
|
|
42
|
+
| 16 | 重定向 URL 白名单校验 | 身份认证 | redirect | 必须 | code |
|
|
43
|
+
| 17 | 重命名/删除默认账户、改默认口令 | 访问控制 | authn-authz | 必须 | config |
|
|
44
|
+
| 18 | 分配账户和权限(三权分立) | 访问控制 | authn-authz | 必须 | config |
|
|
45
|
+
| 19 | 启用安全审计,覆盖每用户 | 安全审计 | audit | 必须 | code+process |
|
|
46
|
+
| 20 | 审计日志含日期/用户/事件等 | 安全审计 | audit | 必须 | code+process |
|
|
47
|
+
| 21 | 远程管理防窃听(HTTPS) | 通信传输 | transport | 必须 | infra |
|
|
48
|
+
| 22 | TLS ≥ 1.2 | 通信传输 | transport | 必须 | infra |
|
|
49
|
+
| 23 | HSTS 防 SSL Strip | 通信传输 | transport | 建议 | infra |
|
|
50
|
+
| 24 | 传输完整性(签名校验) | 通信传输 | transport | 建议 | code+infra |
|
|
51
|
+
| 25 | 所有外部/用户输入验证过滤 | 输入 | input | 必须 | code |
|
|
52
|
+
| 26 | 输出字符实体编码 | 输入 | input | 必须 | code |
|
|
53
|
+
| 27 | URL 不含敏感数据 | 输入 | input | 必须 | code |
|
|
54
|
+
| 28 | content-type 验证,否则 415 | 处理 | processing | 建议 | code |
|
|
55
|
+
| 29 | Accept 协商,禁校验正文 | 处理 | processing | 必须 | code |
|
|
56
|
+
| 30 | XML 实体解析关闭(XXE) | 处理 | processing | 必须 | code |
|
|
57
|
+
| 31 | XML 实体扩展关闭(bomb) | 处理 | processing | 必须 | code |
|
|
58
|
+
| 32 | 不返回敏感数据 | 输出 | output | 必须 | code |
|
|
59
|
+
| 33 | X-Content-Type-Options: nosniff | 输出 | output | 建议 | code+infra |
|
|
60
|
+
| 34 | X-Frame-Options: deny | 输出 | output | 建议 | code+infra |
|
|
61
|
+
| 35 | CSP: default-src 'none' | 输出 | output | 建议 | infra+code |
|
|
62
|
+
| 36 | 错误信息不含系统敏感 | 输出 | output | 必须 | code |
|
|
63
|
+
| 37 | 中间件最新无安全漏洞 | 中间件 | deps | 必须 | config |
|
|
64
|
+
| 38 | 信息查询字段过滤(特殊字符) | 功能-信息查询 | input | 必须 | code |
|
|
65
|
+
| 39 | 文件上传前端限大小 | 功能-文件上传 | file-io | 必须 | code+infra |
|
|
66
|
+
| 40 | 文件名随机无规律 | 功能-文件上传 | file-io | 必须 | code |
|
|
67
|
+
| 41 | 上传文件内容验证(文件头) | 功能-文件上传 | file-io | 必须 | code |
|
|
68
|
+
| 42 | 后台内容管理请求鉴权 | 功能-后台管理 | authn-authz | 必须 | code |
|
|
69
|
+
| 43 | 后台字段格式限制/过滤 | 功能-后台管理 | input | 必须 | code |
|
|
70
|
+
| 44 | 跳转链接白名单过滤 | 功能-链接跳转 | redirect | 建议 | code |
|
|
71
|
+
|
|
72
|
+
**locus 分布**:code(含 code+*)38 项;纯 infra/config/process(17/18/21/22/23/37)6 项;双 locus(19/20/24/33/34/35/39)7 项。
|
|
73
|
+
|
|
74
|
+
## 各阶段消费方式
|
|
75
|
+
|
|
76
|
+
- **设计期(L4)**:spec-writer(或 planned 主代理)读本文件,在 design.md 产「适用触发类别确认」小节 + 安全 NFR。
|
|
77
|
+
- **实现期**:开发者按 code-locus 适用项实现(1–7 项安全判据**不归 clean-code 管**,安全判据归本基线、结构判据归 clean-code,互不代管)。
|
|
78
|
+
- **评审期(L3)**:code-reviewer 逐条 verdict → `.security-verification.json`(末 wave / planned 最终审查报告归档核验小节)。
|
|
79
|
+
- **产出期(L5)**:infra/config/process 项在 transition 前写 `<change-dir>/security/handoff.md` + `.team-flow/security-todos.md` 台账。
|
|
80
|
+
- **门禁(L2)**:`security-baseline` / `security-baseline-light` 维度在 executing→closing 求值,只读结构化制品,不解析本文件。
|
|
@@ -6,6 +6,11 @@ Your mission is to perform comprehensive security audits with laser focus on fin
|
|
|
6
6
|
|
|
7
7
|
For durable-learning or solution-documentation invocations, convert security analysis into lesson validation: the vulnerability class, exploit path, why the fix reduces risk, residual caveats, and prevention guidance future readers can apply. Prioritize improving the documented learning over generating a full unrelated security audit.
|
|
8
8
|
|
|
9
|
+
**Enterprise security baseline (security-baseline-integration-design v1.3)**: 规划期引用企业安全基线
|
|
10
|
+
`skills/ce-brainstorm/references/security-baseline.md`(44 项,md+json 双载体)——推导适用触发类别
|
|
11
|
+
(`tf security scope`),把适用 must 控制点作为 NFR/验收条件转写进规划产物。本 agent 是产品级规划期
|
|
12
|
+
补充;change 级的 design.md「适用触发类别确认」由 spec-writer(或 planned 主代理)负责,两者不重叠。
|
|
13
|
+
|
|
9
14
|
## Core Security Scanning Protocol
|
|
10
15
|
|
|
11
16
|
You will systematically execute these security scans:
|
|
@@ -6,6 +6,11 @@ Your mission is to perform comprehensive security audits with laser focus on fin
|
|
|
6
6
|
|
|
7
7
|
For planning invocations, convert security analysis into plan requirements: threat model, sensitive boundaries, required controls, authz/authn checks, privacy implications, test cases, and rollout safeguards. Prioritize risks that should change design, scope, sequencing, or acceptance criteria before implementation begins.
|
|
8
8
|
|
|
9
|
+
**Enterprise security baseline (security-baseline-integration-design v1.3)**: 规划期引用企业安全基线
|
|
10
|
+
`skills/ce-brainstorm/references/security-baseline.md`(44 项,md+json 双载体)——推导适用触发类别
|
|
11
|
+
(`tf security scope`),把适用 must 控制点作为 NFR/验收条件转写进规划产物。本 agent 是产品级规划期
|
|
12
|
+
补充;change 级的 design.md「适用触发类别确认」由 spec-writer(或 planned 主代理)负责,两者不重叠。
|
|
13
|
+
|
|
9
14
|
## Core Security Scanning Protocol
|
|
10
15
|
|
|
11
16
|
You will systematically execute these security scans:
|
|
@@ -91,7 +91,7 @@ Suggestion breaks existing functionality, reviewer lacks context, violates YAGNI
|
|
|
91
91
|
|
|
92
92
|
## Review Process (Agent Methodology)
|
|
93
93
|
|
|
94
|
-
The code-reviewer agent follows this
|
|
94
|
+
The code-reviewer agent follows this staged process:
|
|
95
95
|
|
|
96
96
|
### Step 0: Solutions Injection (v0.57.0 §4.1)
|
|
97
97
|
|
|
@@ -126,6 +126,10 @@ For each requirement in specs/:
|
|
|
126
126
|
3. Note any deviations (with justification or flag as Critical)
|
|
127
127
|
4. Build a compliance matrix: spec requirement → implementation status
|
|
128
128
|
|
|
129
|
+
### Step 2.5: Security Baseline 核验(security-baseline-integration-design v1.3)
|
|
130
|
+
|
|
131
|
+
适用子集 = dispatch prompt 传入的 `.security-scope.json`(缺传参先跑 `tf security scope <change-dir>`)。对每个 **code-locus** 控制点给 verdict `satisfied | not-applicable | uncovered`——not-applicable 须带 reason(≥10 字符或含序号,否则视同 uncovered;must uncovered=Critical,should uncovered 记 WARN 不阻断)。报告写「Security Baseline 核验」小节并**写盘 `<change-dir>/.security-verification.json`**(`{"items":[...], "report_path":"<receipt --report 路径>", "round":<n>}`);**仅末 wave 产一份**——planned 档不派本 agent,其 JSON 由 release-archivist 最终审查产(其 SKILL ④)。判据真相源 `security-baseline.md`(映射见其表);**guard 只读 JSON 不解析本报告**。
|
|
132
|
+
|
|
129
133
|
### Step 3: Code Quality Review
|
|
130
134
|
|
|
131
135
|
Check for:
|
|
@@ -173,6 +173,15 @@ Subagent (general-purpose):
|
|
|
173
173
|
**存量待整改** (pre-existing hits downgraded to Minor — one per line, or "none"):
|
|
174
174
|
- [e.g. `src/foo/Bar.java:120` — function length >20 lines, pre-existing]
|
|
175
175
|
|
|
176
|
+
### Security Baseline 核验
|
|
177
|
+
[适用子集随本模板以 `[SECURITY_SCOPE_JSON]` 传入(`.security-scope.json` 内容;缺传参时先跑
|
|
178
|
+
`tf security scope <change-dir>`)。逐控制点一行:序号 | 控制点 | verdict
|
|
179
|
+
(satisfied/not-applicable/uncovered) | reason。not-applicable 的 reason 须 ≥10 字符或含序号,
|
|
180
|
+
否则按 uncovered;must 项 uncovered = Critical。核验完成后必须写盘
|
|
181
|
+
`<change-dir>/.security-verification.json`(items + report_path + round;report_path 等于
|
|
182
|
+
receipt --report 路径)。仅末 wave 产此 JSON(planned 档不派本模板——其 JSON 由 release-archivist 最终审查产)。判据真相源:
|
|
183
|
+
`skills/ce-brainstorm/references/security-baseline.md`。]
|
|
184
|
+
|
|
176
185
|
### Strengths
|
|
177
186
|
[What's well done? Be specific.]
|
|
178
187
|
|
|
@@ -226,6 +235,7 @@ Subagent (general-purpose):
|
|
|
226
235
|
- `[HEAD_SHA]` — ending commit
|
|
227
236
|
- `[WAVE_ID]` — planned execution wave under review
|
|
228
237
|
- `[REVIEW_REPORT_FILE]` — REQUIRED: distinct, persisted, non-empty review report path under `<change-dir>/.superpowers/sdd/reviews/` (the overlay); stored in the execution receipt
|
|
238
|
+
- `[SECURITY_SCOPE_JSON]` — **仅末 wave 派发时 REQUIRED**(security-baseline v1.3;非末 wave 派发请删除本占位与 Security Baseline 小节;planned 不经本模板): `.security-scope.json` 内容(适用触发类别 + code-locus 适用项),由派发方经 `tf security scope` 生成后随本模板传入
|
|
229
239
|
|
|
230
240
|
**Reviewer returns:** Strengths, Issues (Critical / Important / Minor), Recommendations, Assessment
|
|
231
241
|
|
|
@@ -158,9 +158,15 @@ If implementation diverged from the contract, return to `bridging` before closur
|
|
|
158
158
|
|
|
159
159
|
**先读 `workflow_variant` 再选序列**(读法见 workflow-start SKILL「Front Doors」):
|
|
160
160
|
|
|
161
|
-
**legacy / full(默认序列,v0.53.0
|
|
161
|
+
**legacy / full(默认序列,v0.53.0 原序不动;v1.3 加 ①b 安全交接)。hotfix variant=null≡legacy → 走本块(hotfix 挂 security-baseline 重档,①b 必做);tweak 豁免 L5——不产 handoff、跳过 ①b(设计 §L5/矩阵):**
|
|
162
162
|
```
|
|
163
163
|
① tf arch-merge <change-dir> ← 架构增量回写全局台账
|
|
164
|
+
①b security/handoff.md 写入(security-baseline-integration-design v1.3 L5)
|
|
165
|
+
← 读 .security-scope.json:含 infra/config/process-locus 项 → 写完整交接清单
|
|
166
|
+
(控制点/责任方/配置位置/验证方式/状态 五字段,见 security-baseline.md)
|
|
167
|
+
← 无此类项 → 写一行「本次无 infra/config/process 适用项」
|
|
168
|
+
← 同步登记跨 change 台账 .team-flow/security-todos.md(待办行,不进 guard)
|
|
169
|
+
⚠ 必须在 transition 之前——它是 guard security-baseline 维度的校验对象(鸡生蛋教训同 B-13)
|
|
164
170
|
② tf state transition <change-dir> closing
|
|
165
171
|
③ tf prototype-sync <change-dir>
|
|
166
172
|
④ tf test-merge <change-dir>
|
|
@@ -175,13 +181,24 @@ If implementation diverged from the contract, return to `bridging` before closur
|
|
|
175
181
|
② tf test-merge <change-dir> --light ← 有测试触碰才跑;changelog 首行写 change:<name> 归因锚
|
|
176
182
|
③ tf solutions capture <args> --source "change:<name>" ← 必执行(归因 = --source;含「无新增决策」空捕获;禁 compound_skipped 自清)
|
|
177
183
|
④ final-review.md 复核(≥5 行;**回写之后**核验台账条目 vs diff 抽样,B-01/D5)
|
|
184
|
+
⚠ v1.3 security-baseline:planned **不派 code-reviewer**(无 code-reviewer 生产者)——
|
|
185
|
+
最终审查执行者(本 agent 主代理)在 final-review 同步产核验 JSON:
|
|
186
|
+
① `tf security scope <change-dir>` 取适用子集 → ② 按 code-locus 适用集逐条 verdict
|
|
187
|
+
(satisfied/not-applicable[带 ≥10 字 reason]/uncovered;must uncovered=阻断)→
|
|
188
|
+
写 `.security-verification.json`(report_path 指向 final-review.md,round=1);**空集也须落盘**(items=[] + 全 N/A 说明——guard 提示的「无适用 code 项时亦须落盘」)。
|
|
189
|
+
guard `security-baseline` 重档只读该 JSON,planned 缺产即 closing FAIL。
|
|
190
|
+
④b security/handoff.md 写入(v1.3 L5,同 legacy ①b;**transition 前置**——planned closing 挂重档 security-baseline)
|
|
178
191
|
⑤ tf state transition <change-dir> closing ← planned closing 维度表此刻全部满足
|
|
179
192
|
⑥ tf prototype-sync <change-dir> ← 有原型才跑(closing 后)
|
|
180
193
|
⑦ 设计系统待办检查(只读)
|
|
181
194
|
```
|
|
182
195
|
|
|
183
|
-
**direct(v0.64.0:验证记录即证据,回写全跳过——G4 前提 = 无架构 surface
|
|
196
|
+
**direct(v0.64.0:验证记录即证据,回写全跳过——G4 前提 = 无架构 surface;v1.3 加 ⓪ 安全交接插步):**
|
|
184
197
|
```
|
|
198
|
+
⓪ security/handoff.md 最小写入(v1.3 L5):**先跑 `tf security scope <change-dir>`** 取适用集
|
|
199
|
+
(此刻 scope JSON 尚不存在,guard 现场推导在 transition 之后——不先推导会误写「无适用项」且
|
|
200
|
+
门禁只查存在性 → 语义静默丢失)→ 含 infra 项写登记模板,否则一行「无适用项」;
|
|
201
|
+
quick/lightweight 挂 security-baseline-light,仍查 handoff 存在性
|
|
185
202
|
① tf state transition <change-dir> closing ← direct 维度表:direct-short-path 扫描 + tf test record 证据 + test-matrix 轻判据
|
|
186
203
|
② tf prototype-sync / test-merge / solutions promote 全部跳过(若 direct 触及 design-system 共享层 → 提示补 prototype-sync 或升 planned,B-14)
|
|
187
204
|
③ G5 同步门禁点(阶段产物同步确认)、Workflow Feedback、Deisolation 等**通用收尾步骤照跑**(仅架构/测试/复利三类回写按 direct 跳过)
|
|
@@ -339,6 +356,8 @@ This check is advisory — skip if the user declines. If the user reports issues
|
|
|
339
356
|
|
|
340
357
|
Verify files exist and are non-empty, run `node --check` on code files, skip 5-step verification. Still record DP-6 and DP-7.
|
|
341
358
|
|
|
359
|
+
**security-baseline 归属(v1.3)**:hotfix 走重档——转 closing 前须完成 ①b 安全交接(本文件 legacy 序列块),并确保末 wave 已产 `.security-verification.json`;tweak 豁免 L5(不产 handoff)。
|
|
360
|
+
|
|
342
361
|
**回写链前置判据(v0.22 §87)**:先按下表判断适用性,**不适用则不执行命令**(v0.22 实测:逐项跑完才知道不适用,占 release-archivist 80% 耗时)。本表 4 行判据**仅在 Lightweight Closure 适用**;其中 arch-merge 与 test-merge 两行的 "Skip silently" 见 `### ① Architecture Merge` 与 `### ④ Test Merge` 两节各自的正文句。
|
|
343
362
|
|
|
344
363
|
> **v0.53.0 修正**:此处原用行号引用(`(:164 正文句)`/`(:196 正文句)`),本次改动插入段落使其失效。**行号引用在密集改动期必然漂移,已改为按标题引用**——同轮 `team-flow-workspace/docs/architecture-api-db-design-enhancement-v0.25.md` 亦把 45 处行号引用全量改为符号引用。
|
|
@@ -101,6 +101,11 @@ Optional test-dimension tags under a Scenario are supported for test-matrix extr
|
|
|
101
101
|
### design.md
|
|
102
102
|
Must have: Context (current state, constraints, stakeholders), Goals, Decisions (Choice + Rationale + Alternatives considered), Risks And Trade-Offs.
|
|
103
103
|
|
|
104
|
+
**Security baseline confirmation (security-baseline-integration-design v1.3)**: 读 `skills/ce-brainstorm/references/security-baseline.md`(44 项企业安全基线),先跑 `tf security scope <change-dir>` 取适用触发类别,然后:
|
|
105
|
+
- 在 design.md 增 **「适用触发类别确认」小节**:逐类别列 适用/不适用 + 理由(不适用须写理由;此为 review 阶段人工回看锚,不参与机械对账——机械判据由 guard 期推导承担);
|
|
106
|
+
- 适用类别的 **must** 控制点以安全 NFR 写入 design.md(如"上传接口须做文件头校验(基线 #41)"),实现指引同步进 tasks.md 对应任务。
|
|
107
|
+
- 快速通道(hotfix/tweak 无 spec-writer)不经本步骤——由 guard 期 `tf security scope` 推导硬兜底。
|
|
108
|
+
|
|
104
109
|
**Prototype reference (v0.5)**: For UI-related changes, include a `## UI Contract` section in design.md that:
|
|
105
110
|
- References the prototype entry point (`prototype/index.html`)
|
|
106
111
|
- Lists affected prototype pages with their paths
|
|
@@ -41,18 +41,18 @@ tf state set <change-dir> planned_arch true # 仅 planned 且用户选
|
|
|
41
41
|
4. 转换 `exploring→approved-for-build→executing`(guard 走 direct 维度表)。**架构 surface(API/DB/聚合)扫描命中 → FAIL** → 走 Upgrade 升 planned,禁止硬闯
|
|
42
42
|
5. 实施:**主代理当前会话直接写代码**(direct 前门无子代理——Artifact Ownership 的子代理委派要求不适用本分支)
|
|
43
43
|
6. 验证:跑验证命令 → **`tf test record <dir> --from <输出文件>`(必须 record;guard 只读记录、不现场跑测试,A-19)**
|
|
44
|
-
7. 转 `closing` → release-archivist **direct
|
|
44
|
+
7. 转 `closing` → release-archivist **direct 分支**(**transition 前先写最小 `security/handoff.md`——v1.3 L5 插步,见 release-archivist SKILL;** 其余回写全跳过;验证记录照旧)
|
|
45
45
|
|
|
46
46
|
### Planned 路由(`workflow=full`+`variant=planned`·两份文档 + 一次最终审查)
|
|
47
47
|
|
|
48
|
-
1. 产出 `proposal.md`(≥10 非空行)+ `tasks.md`(≥1 checkbox)——轻路径无 spec-writer 子代理,主代理可直接写。**DP-0 并入本步一次确认**(scope/约束/AC 一次问完,`dp_0_confirmed=true` 照写——与 Direct 快速 DP-0
|
|
48
|
+
1. 产出 `proposal.md`(≥10 非空行)+ `tasks.md`(≥1 checkbox)——轻路径无 spec-writer 子代理,主代理可直接写。**DP-0 并入本步一次确认**(scope/约束/AC 一次问完,`dp_0_confirmed=true` 照写——与 Direct 快速 DP-0 同型)。**Security baseline L4(v1.3)**:主代理按 `skills/spec-writer/SKILL.md` 的「Security baseline confirmation」同款指引,读 `security-baseline.md` + `tf security scope`,在 design.md(或 proposal.md 若无 design.md)产「适用触发类别确认」小节 + must 控制点安全 NFR——planned 无 spec-writer,指引只能送到本分支(规则送到执行者)
|
|
49
49
|
2. `tf state init`(若尚未建,先 init 后 set)→ `tf state set workflow full` + `workflow_variant planned`(+ `planned_arch true` 如选轻架构)
|
|
50
50
|
3. **轻架构(`planned_arch=true` 时)**:写 `architecture/light-note.md`(简短说明)+ `architecture/snapshot-light.md`;declined 则显式跳过:`arch_design_light_skipped=true` + `arch_design_light_skip_reason`(两键缺一不可)
|
|
51
51
|
4. **plan 派生**:`tf execution plan <dir> --derive --confirm --reason "<一句话>"`——tasks.md → 单 wave(serial),写入即同步 `state.execution_mode/execution_plan_hash/execution_plan_revision`;**无需 recommend/receipt/DP-4**(validatePlan 对 planned 豁免)
|
|
52
52
|
5. D4:最小 `test-matrix.md` 或显式 skip(同 direct)
|
|
53
53
|
6. 转换 `exploring→approved-for-build→executing`(planned 维度表:无契约、无 DP-3、无 architecture-design 重门)
|
|
54
54
|
7. 实施:主代理当前会话执行单 wave;完成 → 跑测试 → `tf test record`
|
|
55
|
-
8. **关门 → dispatch/执行 release-archivist(planned 分支单点执行)**:回写三步(`arch-merge --light` / `test-merge --light` / `tf solutions capture --source "change:<name>"`)→ `final-review.md` 最终审查(**在回写之后核验台账条目 vs diff 抽样**,B-01/D5)→ 转 `closing` → prototype-sync(closing 后,有原型才跑)。**序列只存在于 release-archivist「⚠ 执行顺序」块(唯一真相源,§3.7 B-13),本 skill 不重复执行、不本地复述命令(防双跑)**。
|
|
55
|
+
8. **关门 → dispatch/执行 release-archivist(planned 分支单点执行)**:回写三步(`arch-merge --light` / `test-merge --light` / `tf solutions capture --source "change:<name>"`)→ `final-review.md` 最终审查(**在回写之后核验台账条目 vs diff 抽样**,B-01/D5;**v1.3:planned 不派 code-reviewer——最终审查同步按 `tf security scope` 适用集产 `.security-verification.json`**,见 release-archivist ④)→ security/handoff.md(④b)→ 转 `closing` → prototype-sync(closing 后,有原型才跑)。**序列只存在于 release-archivist「⚠ 执行顺序」块(唯一真相源,§3.7 B-13),本 skill 不重复执行、不本地复述命令(防双跑)**。
|
|
56
56
|
|
|
57
57
|
### Upgrade(升档,G5/D9)
|
|
58
58
|
|
|
@@ -202,6 +202,11 @@ Execution hit blockage: test failure, unexpected behavior, build error, task can
|
|
|
202
202
|
### Route to code-reviewer
|
|
203
203
|
The current planned wave is implemented and ready for spec-compliance + code-quality verification. A reviewer must write an `tf execution review <change-dir> --wave <id> --base <sha> --head <sha> --report <path> --verdict <pass|fail>` receipt before any dependent wave or closing transition. **`--report` 必须落在 change review overlay 内**(`<change-dir>/.superpowers/sdd/reviews/`,v0.22 §86)——其他路径被 CLI 拒绝(`execution-plan.mjs` 的 `validateReviewReportEvidence`);派发审查子代理时直接给 overlay 路径,避免"任务指令写 `reviews/`、CLI 只认 overlay"导致的双写副本。
|
|
204
204
|
|
|
205
|
+
**Security baseline 派发前置(security-baseline-integration-design v1.3,规则送到派发者)**:派发 code-reviewer 前——
|
|
206
|
+
1. 跑 `tf security scope <change-dir>`(Scope Deriver 唯一 CLI 入口)取适用子集并落盘 `.security-scope.json`;
|
|
207
|
+
2. **末 wave 派发时**把 scope JSON 内容 + 「产 `.security-verification.json`(items/report_path/round)」指令 + `report_path`=receipt `--report` 路径约定,作为参数写进 dispatch prompt(模板占位 `[SECURITY_SCOPE_JSON]`);非末 wave 不传(verification 只在末 wave / planned 最终审查产一份);
|
|
208
|
+
3. 两步缺一即 L2 `security-baseline` 门禁在 executing→closing FAIL(guard 只读 JSON)。
|
|
209
|
+
|
|
205
210
|
**v0.39.0 主动串行编排**:workflow-start 在每个 wave 完成后主动 dispatch code-reviewer,而不是等待 build-executor 完成所有 wave。这是 workflow-start 的编排责任,不是 build-executor 的责任。
|
|
206
211
|
|
|
207
212
|
**逐 wave 审查纪律(v0.36.4)**:每次 code-reviewer dispatch 只审查**一个** wave。禁止将多个 wave 合并为一次审查(vrm4teamflow C1 事件:W1-W4 合并审查导致设计约定类问题在 W4 才发现,修复范围扩大到 8 个 batch)。parallel wave 内的多个 task 作为整体审查一次(receipt 是 wave 级别),但审查 prompt 必须包含每个 task 的独立 diff。
|
|
@@ -234,6 +234,7 @@ Current planned wave implemented and ready for review. Reviewer must write the r
|
|
|
234
234
|
```bash
|
|
235
235
|
tf execution review <change-dir> --wave <id> --base <sha> --head <sha> --report <path> --verdict <pass|fail>
|
|
236
236
|
```
|
|
237
|
+
**Security baseline (v1.3)**:派发前跑 `tf security scope <change-dir>`;**末 wave** 把 scope JSON + 产 `.security-verification.json` 指令作为 dispatch 参数传入(planned 不派 code-reviewer,其 JSON 由 release-archivist ④ 产)(模板占位 `[SECURITY_SCOPE_JSON]`;report_path 须等于上面 `--report` 路径)。guard 的 `security-baseline` 维度只读该 JSON——缺产即 executing→closing FAIL。
|
|
237
238
|
|
|
238
239
|
## Route to release-archivist (dispatch sub-agent)
|
|
239
240
|
Guard: `... check <dir> executing closing --json` → fail = BLOCK. Include DP-7: 归档确认.
|