code-abyss 1.5.1

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.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +197 -0
  3. package/bin/install.js +193 -0
  4. package/bin/uninstall.js +42 -0
  5. package/config/AGENTS.md +247 -0
  6. package/config/CLAUDE.md +207 -0
  7. package/config/settings.example.json +27 -0
  8. package/output-styles/abyss-cultivator.md +399 -0
  9. package/package.json +41 -0
  10. package/skills/SKILL.md +115 -0
  11. package/skills/ai/SKILL.md +29 -0
  12. package/skills/ai/agent-dev.md +242 -0
  13. package/skills/ai/llm-security.md +288 -0
  14. package/skills/architecture/SKILL.md +41 -0
  15. package/skills/architecture/api-design.md +225 -0
  16. package/skills/architecture/caching.md +299 -0
  17. package/skills/architecture/cloud-native.md +285 -0
  18. package/skills/architecture/compliance.md +299 -0
  19. package/skills/architecture/data-security.md +184 -0
  20. package/skills/architecture/message-queue.md +329 -0
  21. package/skills/architecture/security-arch.md +210 -0
  22. package/skills/development/SKILL.md +43 -0
  23. package/skills/development/cpp.md +246 -0
  24. package/skills/development/go.md +323 -0
  25. package/skills/development/java.md +277 -0
  26. package/skills/development/python.md +288 -0
  27. package/skills/development/rust.md +313 -0
  28. package/skills/development/shell.md +313 -0
  29. package/skills/development/typescript.md +277 -0
  30. package/skills/devops/SKILL.md +36 -0
  31. package/skills/devops/cost-optimization.md +272 -0
  32. package/skills/devops/database.md +217 -0
  33. package/skills/devops/devsecops.md +198 -0
  34. package/skills/devops/git-workflow.md +181 -0
  35. package/skills/devops/observability.md +280 -0
  36. package/skills/devops/performance.md +273 -0
  37. package/skills/devops/testing.md +186 -0
  38. package/skills/gen-docs/SKILL.md +114 -0
  39. package/skills/gen-docs/scripts/doc_generator.py +491 -0
  40. package/skills/multi-agent/SKILL.md +268 -0
  41. package/skills/run_skill.py +88 -0
  42. package/skills/security/SKILL.md +51 -0
  43. package/skills/security/blue-team.md +379 -0
  44. package/skills/security/code-audit.md +265 -0
  45. package/skills/security/pentest.md +226 -0
  46. package/skills/security/red-team.md +321 -0
  47. package/skills/security/threat-intel.md +322 -0
  48. package/skills/security/vuln-research.md +369 -0
  49. package/skills/tests/README.md +225 -0
  50. package/skills/tests/SUMMARY.md +362 -0
  51. package/skills/tests/__init__.py +3 -0
  52. package/skills/tests/test_change_analyzer.py +558 -0
  53. package/skills/tests/test_doc_generator.py +538 -0
  54. package/skills/tests/test_module_scanner.py +376 -0
  55. package/skills/tests/test_quality_checker.py +516 -0
  56. package/skills/tests/test_security_scanner.py +426 -0
  57. package/skills/verify-change/SKILL.md +138 -0
  58. package/skills/verify-change/scripts/change_analyzer.py +529 -0
  59. package/skills/verify-module/SKILL.md +125 -0
  60. package/skills/verify-module/scripts/module_scanner.py +321 -0
  61. package/skills/verify-quality/SKILL.md +158 -0
  62. package/skills/verify-quality/scripts/quality_checker.py +481 -0
  63. package/skills/verify-security/SKILL.md +141 -0
  64. package/skills/verify-security/scripts/security_scanner.py +368 -0
@@ -0,0 +1,481 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 代码质量检查器
4
+ 检测代码复杂度、重复代码、命名规范、函数长度等
5
+ """
6
+
7
+ import os
8
+ import re
9
+ import sys
10
+ import json
11
+ import ast
12
+ from pathlib import Path
13
+ from dataclasses import dataclass, field
14
+ from typing import List, Dict, Optional, Set
15
+ from enum import Enum
16
+ from collections import defaultdict
17
+
18
+
19
+ class Severity(Enum):
20
+ ERROR = "error"
21
+ WARNING = "warning"
22
+ INFO = "info"
23
+
24
+
25
+ @dataclass
26
+ class Issue:
27
+ severity: Severity
28
+ category: str
29
+ message: str
30
+ file_path: str
31
+ line_number: Optional[int] = None
32
+ suggestion: Optional[str] = None
33
+
34
+
35
+ @dataclass
36
+ class FileMetrics:
37
+ path: str
38
+ lines: int = 0
39
+ code_lines: int = 0
40
+ comment_lines: int = 0
41
+ blank_lines: int = 0
42
+ functions: int = 0
43
+ classes: int = 0
44
+ max_complexity: int = 0
45
+ avg_function_length: float = 0
46
+
47
+
48
+ @dataclass
49
+ class QualityResult:
50
+ scan_path: str
51
+ files_scanned: int = 0
52
+ total_lines: int = 0
53
+ total_code_lines: int = 0
54
+ issues: List[Issue] = field(default_factory=list)
55
+ file_metrics: List[FileMetrics] = field(default_factory=list)
56
+
57
+ @property
58
+ def passed(self) -> bool:
59
+ return not any(i.severity == Severity.ERROR for i in self.issues)
60
+
61
+ @property
62
+ def error_count(self) -> int:
63
+ return sum(1 for i in self.issues if i.severity == Severity.ERROR)
64
+
65
+ @property
66
+ def warning_count(self) -> int:
67
+ return sum(1 for i in self.issues if i.severity == Severity.WARNING)
68
+
69
+
70
+ # 质量规则配置
71
+ MAX_LINE_LENGTH = 120
72
+ MAX_FUNCTION_LENGTH = 50
73
+ MAX_FILE_LENGTH = 500
74
+ MAX_COMPLEXITY = 10
75
+ MAX_PARAMETERS = 5
76
+ MIN_FUNCTION_NAME_LENGTH = 2
77
+ MAX_FUNCTION_NAME_LENGTH = 40
78
+ PYTHON_SPECIAL_METHODS = {"setUp", "tearDown", "setUpClass", "tearDownClass", "setUpModule", "tearDownModule"}
79
+
80
+
81
+ class PythonAnalyzer(ast.NodeVisitor):
82
+ """Python AST 分析器"""
83
+
84
+ def __init__(self, file_path: str, source: str):
85
+ self.file_path = file_path
86
+ self.source = source
87
+ self.lines = source.split('\n')
88
+ self.issues: List[Issue] = []
89
+ self.functions: List[Dict] = []
90
+ self.classes: List[Dict] = []
91
+ self.complexity = 0
92
+
93
+ def analyze(self) -> tuple[List[Issue], List[Dict], List[Dict], int]:
94
+ try:
95
+ tree = ast.parse(self.source)
96
+ self.visit(tree)
97
+ except SyntaxError as e:
98
+ self.issues.append(Issue(
99
+ severity=Severity.ERROR,
100
+ category="语法",
101
+ message=f"语法错误: {e.msg}",
102
+ file_path=self.file_path,
103
+ line_number=e.lineno
104
+ ))
105
+ return self.issues, self.functions, self.classes, self.complexity
106
+
107
+ def visit_FunctionDef(self, node):
108
+ self._analyze_function(node)
109
+ self.generic_visit(node)
110
+
111
+ def visit_AsyncFunctionDef(self, node):
112
+ self._analyze_function(node)
113
+ self.generic_visit(node)
114
+
115
+ def visit_ClassDef(self, node):
116
+ self.classes.append({
117
+ "name": node.name,
118
+ "line": node.lineno,
119
+ "methods": len([n for n in node.body if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))])
120
+ })
121
+
122
+ # 检查类名
123
+ if not re.match(r'^[A-Z][a-zA-Z0-9]*$', node.name):
124
+ self.issues.append(Issue(
125
+ severity=Severity.WARNING,
126
+ category="命名",
127
+ message=f"类名 '{node.name}' 不符合 PascalCase 规范",
128
+ file_path=self.file_path,
129
+ line_number=node.lineno,
130
+ suggestion="类名应使用 PascalCase,如 MyClassName"
131
+ ))
132
+
133
+ self.generic_visit(node)
134
+
135
+ def _analyze_function(self, node):
136
+ func_info = {
137
+ "name": node.name,
138
+ "line": node.lineno,
139
+ "length": self._get_function_length(node),
140
+ "complexity": self._calculate_complexity(node),
141
+ "parameters": len(node.args.args)
142
+ }
143
+ self.functions.append(func_info)
144
+ self.complexity = max(self.complexity, func_info["complexity"])
145
+
146
+ # 检查函数长度
147
+ if func_info["length"] > MAX_FUNCTION_LENGTH:
148
+ self.issues.append(Issue(
149
+ severity=Severity.WARNING,
150
+ category="复杂度",
151
+ message=f"函数 '{node.name}' 过长 ({func_info['length']} 行 > {MAX_FUNCTION_LENGTH})",
152
+ file_path=self.file_path,
153
+ line_number=node.lineno,
154
+ suggestion="考虑拆分为多个小函数"
155
+ ))
156
+
157
+ # 检查复杂度
158
+ if func_info["complexity"] > MAX_COMPLEXITY:
159
+ self.issues.append(Issue(
160
+ severity=Severity.WARNING,
161
+ category="复杂度",
162
+ message=f"函数 '{node.name}' 圈复杂度过高 ({func_info['complexity']} > {MAX_COMPLEXITY})",
163
+ file_path=self.file_path,
164
+ line_number=node.lineno,
165
+ suggestion="减少嵌套层级,提取子函数"
166
+ ))
167
+
168
+ # 检查参数数量
169
+ if func_info["parameters"] > MAX_PARAMETERS:
170
+ self.issues.append(Issue(
171
+ severity=Severity.WARNING,
172
+ category="设计",
173
+ message=f"函数 '{node.name}' 参数过多 ({func_info['parameters']} > {MAX_PARAMETERS})",
174
+ file_path=self.file_path,
175
+ line_number=node.lineno,
176
+ suggestion="考虑使用配置对象或数据类封装参数"
177
+ ))
178
+
179
+ # 检查函数命名
180
+ if not node.name.startswith('_') and node.name not in PYTHON_SPECIAL_METHODS and not node.name.startswith('visit_'):
181
+ if not re.match(r'^[a-z][a-z0-9_]*$', node.name):
182
+ self.issues.append(Issue(
183
+ severity=Severity.INFO,
184
+ category="命名",
185
+ message=f"函数名 '{node.name}' 不符合 snake_case 规范",
186
+ file_path=self.file_path,
187
+ line_number=node.lineno,
188
+ suggestion="函数名应使用 snake_case,如 my_function_name"
189
+ ))
190
+
191
+ if len(node.name) < MIN_FUNCTION_NAME_LENGTH:
192
+ self.issues.append(Issue(
193
+ severity=Severity.WARNING,
194
+ category="命名",
195
+ message=f"函数名 '{node.name}' 过短",
196
+ file_path=self.file_path,
197
+ line_number=node.lineno,
198
+ suggestion="使用更具描述性的函数名"
199
+ ))
200
+
201
+ def _get_function_length(self, node) -> int:
202
+ if hasattr(node, 'end_lineno'):
203
+ return node.end_lineno - node.lineno + 1
204
+ return len(ast.unparse(node).split('\n'))
205
+
206
+ def _calculate_complexity(self, node) -> int:
207
+ """计算圈复杂度"""
208
+ complexity = 1
209
+
210
+ for child in ast.walk(node):
211
+ if isinstance(child, (ast.If, ast.While, ast.For, ast.AsyncFor)):
212
+ complexity += 1
213
+ elif isinstance(child, ast.ExceptHandler):
214
+ complexity += 1
215
+ elif isinstance(child, (ast.And, ast.Or)):
216
+ complexity += 1
217
+ elif isinstance(child, ast.comprehension):
218
+ complexity += 1
219
+ if child.ifs:
220
+ complexity += len(child.ifs)
221
+
222
+ return complexity
223
+
224
+
225
+ def analyze_python_file(file_path: Path) -> tuple[FileMetrics, List[Issue]]:
226
+ """分析 Python 文件"""
227
+ metrics = FileMetrics(path=str(file_path))
228
+ issues = []
229
+
230
+ try:
231
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
232
+ lines = content.split('\n')
233
+ except Exception as e:
234
+ issues.append(Issue(
235
+ severity=Severity.ERROR,
236
+ category="文件",
237
+ message=f"无法读取文件: {e}",
238
+ file_path=str(file_path)
239
+ ))
240
+ return metrics, issues
241
+
242
+ # 基础行数统计
243
+ metrics.lines = len(lines)
244
+ in_multiline_string = False
245
+
246
+ for i, line in enumerate(lines, 1):
247
+ stripped = line.strip()
248
+
249
+ if not stripped:
250
+ metrics.blank_lines += 1
251
+ elif stripped.startswith('#'):
252
+ metrics.comment_lines += 1
253
+ elif '"""' in stripped or "'''" in stripped:
254
+ if stripped.count('"""') == 2 or stripped.count("'''") == 2:
255
+ metrics.comment_lines += 1
256
+ else:
257
+ in_multiline_string = not in_multiline_string
258
+ metrics.comment_lines += 1
259
+ elif in_multiline_string:
260
+ metrics.comment_lines += 1
261
+ else:
262
+ metrics.code_lines += 1
263
+
264
+ # 检查行长度
265
+ if len(line) > MAX_LINE_LENGTH:
266
+ issues.append(Issue(
267
+ severity=Severity.INFO,
268
+ category="格式",
269
+ message=f"行过长 ({len(line)} > {MAX_LINE_LENGTH})",
270
+ file_path=str(file_path),
271
+ line_number=i
272
+ ))
273
+
274
+ # 检查文件长度
275
+ if metrics.code_lines > MAX_FILE_LENGTH:
276
+ issues.append(Issue(
277
+ severity=Severity.WARNING,
278
+ category="复杂度",
279
+ message=f"文件过长 ({metrics.code_lines} 行代码 > {MAX_FILE_LENGTH})",
280
+ file_path=str(file_path),
281
+ suggestion="考虑拆分为多个模块"
282
+ ))
283
+
284
+ # AST 分析
285
+ analyzer = PythonAnalyzer(str(file_path), content)
286
+ ast_issues, functions, classes, complexity = analyzer.analyze()
287
+ issues.extend(ast_issues)
288
+
289
+ metrics.functions = len(functions)
290
+ metrics.classes = len(classes)
291
+ metrics.max_complexity = complexity
292
+
293
+ if functions:
294
+ metrics.avg_function_length = sum(f["length"] for f in functions) / len(functions)
295
+
296
+ return metrics, issues
297
+
298
+
299
+ def analyze_generic_file(file_path: Path) -> tuple[FileMetrics, List[Issue]]:
300
+ """分析通用代码文件"""
301
+ metrics = FileMetrics(path=str(file_path))
302
+ issues = []
303
+
304
+ try:
305
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
306
+ lines = content.split('\n')
307
+ except Exception:
308
+ return metrics, issues
309
+
310
+ metrics.lines = len(lines)
311
+
312
+ comment_patterns = {
313
+ '.js': '//',
314
+ '.ts': '//',
315
+ '.go': '//',
316
+ '.java': '//',
317
+ '.c': '//',
318
+ '.cpp': '//',
319
+ '.rs': '//',
320
+ }
321
+
322
+ suffix = file_path.suffix.lower()
323
+ comment_prefix = comment_patterns.get(suffix, '//')
324
+
325
+ for i, line in enumerate(lines, 1):
326
+ stripped = line.strip()
327
+
328
+ if not stripped:
329
+ metrics.blank_lines += 1
330
+ elif stripped.startswith(comment_prefix) or stripped.startswith('/*') or stripped.startswith('*'):
331
+ metrics.comment_lines += 1
332
+ else:
333
+ metrics.code_lines += 1
334
+
335
+ if len(line) > MAX_LINE_LENGTH:
336
+ issues.append(Issue(
337
+ severity=Severity.INFO,
338
+ category="格式",
339
+ message=f"行过长 ({len(line)} > {MAX_LINE_LENGTH})",
340
+ file_path=str(file_path),
341
+ line_number=i
342
+ ))
343
+
344
+ if metrics.code_lines > MAX_FILE_LENGTH:
345
+ issues.append(Issue(
346
+ severity=Severity.WARNING,
347
+ category="复杂度",
348
+ message=f"文件过长 ({metrics.code_lines} 行代码 > {MAX_FILE_LENGTH})",
349
+ file_path=str(file_path),
350
+ suggestion="考虑拆分为多个模块"
351
+ ))
352
+
353
+ return metrics, issues
354
+
355
+
356
+ def scan_directory(path: str, exclude_dirs: List[str] = None) -> QualityResult:
357
+ """扫描目录"""
358
+ scan_path = Path(path).resolve()
359
+ result = QualityResult(scan_path=str(scan_path))
360
+
361
+ if exclude_dirs is None:
362
+ exclude_dirs = ['.git', 'node_modules', '__pycache__', '.venv', 'venv', 'dist', 'build', '.tox']
363
+
364
+ code_extensions = {'.py', '.js', '.ts', '.go', '.java', '.rs', '.c', '.cpp'}
365
+
366
+ for file_path in scan_path.rglob('*'):
367
+ if any(ex in file_path.parts for ex in exclude_dirs):
368
+ continue
369
+
370
+ if file_path.is_file() and file_path.suffix.lower() in code_extensions:
371
+ result.files_scanned += 1
372
+
373
+ if file_path.suffix.lower() == '.py':
374
+ metrics, issues = analyze_python_file(file_path)
375
+ else:
376
+ metrics, issues = analyze_generic_file(file_path)
377
+
378
+ result.file_metrics.append(metrics)
379
+ result.issues.extend(issues)
380
+ result.total_lines += metrics.lines
381
+ result.total_code_lines += metrics.code_lines
382
+
383
+ return result
384
+
385
+
386
+ def format_report(result: QualityResult, verbose: bool = False) -> str:
387
+ """格式化报告"""
388
+ lines = []
389
+ lines.append("=" * 60)
390
+ lines.append("代码质量检查报告")
391
+ lines.append("=" * 60)
392
+
393
+ lines.append(f"\n扫描路径: {result.scan_path}")
394
+ lines.append(f"扫描文件: {result.files_scanned}")
395
+ lines.append(f"总行数: {result.total_lines}")
396
+ lines.append(f"代码行数: {result.total_code_lines}")
397
+ lines.append(f"检查结果: {'✓ 通过' if result.passed else '✗ 需要关注'}")
398
+ lines.append(f"错误: {result.error_count} | 警告: {result.warning_count}")
399
+
400
+ if result.issues:
401
+ lines.append("\n" + "-" * 40)
402
+ lines.append("问题列表:")
403
+ lines.append("-" * 40)
404
+
405
+ # 按类别分组
406
+ by_category = defaultdict(list)
407
+ for issue in result.issues:
408
+ by_category[issue.category].append(issue)
409
+
410
+ severity_icons = {"error": "✗", "warning": "⚠", "info": "ℹ"}
411
+
412
+ for category, issues in sorted(by_category.items()):
413
+ lines.append(f"\n【{category}】({len(issues)} 个)")
414
+ for issue in issues[:10]: # 每类最多显示 10 个
415
+ icon = severity_icons[issue.severity.value]
416
+ loc = f":{issue.line_number}" if issue.line_number else ""
417
+ lines.append(f" {icon} {issue.file_path}{loc}")
418
+ lines.append(f" {issue.message}")
419
+ if verbose and issue.suggestion:
420
+ lines.append(f" 💡 {issue.suggestion}")
421
+
422
+ if len(issues) > 10:
423
+ lines.append(f" ... 及其他 {len(issues) - 10} 个问题")
424
+
425
+ if verbose and result.file_metrics:
426
+ # 找出最复杂的文件
427
+ complex_files = sorted(result.file_metrics, key=lambda m: m.max_complexity, reverse=True)[:5]
428
+ if complex_files and complex_files[0].max_complexity > 0:
429
+ lines.append("\n" + "-" * 40)
430
+ lines.append("复杂度最高的文件:")
431
+ lines.append("-" * 40)
432
+ for m in complex_files:
433
+ if m.max_complexity > 0:
434
+ lines.append(f" {m.path}: 复杂度 {m.max_complexity}, {m.functions} 个函数")
435
+
436
+ lines.append("\n" + "=" * 60)
437
+ return "\n".join(lines)
438
+
439
+
440
+ def main():
441
+ import argparse
442
+
443
+ parser = argparse.ArgumentParser(description="代码质量检查器")
444
+ parser.add_argument("path", nargs="?", default=".", help="扫描路径")
445
+ parser.add_argument("-v", "--verbose", action="store_true", help="详细输出")
446
+ parser.add_argument("--json", action="store_true", help="JSON 格式输出")
447
+
448
+ args = parser.parse_args()
449
+
450
+ result = scan_directory(args.path)
451
+
452
+ if args.json:
453
+ output = {
454
+ "scan_path": result.scan_path,
455
+ "files_scanned": result.files_scanned,
456
+ "total_lines": result.total_lines,
457
+ "total_code_lines": result.total_code_lines,
458
+ "passed": result.passed,
459
+ "error_count": result.error_count,
460
+ "warning_count": result.warning_count,
461
+ "issues": [
462
+ {
463
+ "severity": i.severity.value,
464
+ "category": i.category,
465
+ "message": i.message,
466
+ "file_path": i.file_path,
467
+ "line_number": i.line_number,
468
+ "suggestion": i.suggestion
469
+ }
470
+ for i in result.issues
471
+ ]
472
+ }
473
+ print(json.dumps(output, ensure_ascii=False, indent=2))
474
+ else:
475
+ print(format_report(result, args.verbose))
476
+
477
+ sys.exit(0 if result.passed else 1)
478
+
479
+
480
+ if __name__ == "__main__":
481
+ main()
@@ -0,0 +1,141 @@
1
+ ---
2
+ name: verify-security
3
+ description: 安全校验关卡。自动扫描代码安全漏洞,检测危险模式,确保安全决策有文档记录。当魔尊提到安全扫描、漏洞检测、安全审计、代码安全、OWASP、注入检测、敏感信息泄露时使用。在新建模块、安全相关变更、攻防任务、重构完成时自动触发。
4
+ user-invocable: true
5
+ disable-model-invocation: false
6
+ allowed-tools: Bash, Read, Grep
7
+ argument-hint: <扫描路径>
8
+ ---
9
+
10
+ # ⚖ 校验关卡 · 安全校验
11
+
12
+
13
+ ## 核心原则
14
+
15
+ ```
16
+ 安全即道基,破则劫败
17
+ 安全决策必须可追溯
18
+ Critical/High 问题必须修复后才能交付
19
+ ```
20
+
21
+ ## 自动扫描
22
+
23
+ 运行安全扫描脚本(跨平台):
24
+
25
+ ```bash
26
+ # 在 skill 目录下运行
27
+ python scripts/security_scanner.py <扫描路径>
28
+ python scripts/security_scanner.py <扫描路径> -v # 详细模式
29
+ python scripts/security_scanner.py <扫描路径> --json # JSON 输出
30
+ python scripts/security_scanner.py <扫描路径> --exclude vendor # 排除目录
31
+ ```
32
+
33
+ ## 检测范围
34
+
35
+ ### 自动检测的漏洞类型
36
+
37
+ | 类别 | 检测项 | 严重度 |
38
+ |------|--------|--------|
39
+ | **注入** | SQL 注入、命令注入、代码注入 | 🔴 Critical |
40
+ | **敏感信息** | 硬编码密钥、AWS Key、私钥 | 🔴 Critical |
41
+ | **XSS** | innerHTML、dangerouslySetInnerHTML | 🟠 High |
42
+ | **反序列化** | pickle.loads、yaml.load | 🟠 High |
43
+ | **路径遍历** | 未验证的文件路径操作 | 🟠 High |
44
+ | **SSRF** | 未验证的 URL 请求 | 🟠 High |
45
+ | **XXE** | 不安全的 XML 解析 | 🟠 High |
46
+ | **弱加密** | MD5、SHA1 用于安全场景 | 🟡 Medium |
47
+ | **不安全随机** | random 模块用于安全场景 | 🟡 Medium |
48
+ | **调试代码** | console.log、print、debugger | 🔵 Low |
49
+
50
+ ### 文档层面检查
51
+
52
+ 安全相关代码必须在 DESIGN.md 中记录:
53
+
54
+ - [ ] **威胁模型** — 防御哪些攻击
55
+ - [ ] **安全决策** — 为何选择此方案
56
+ - [ ] **安全边界** — 信任边界在哪里
57
+ - [ ] **已知风险** — 接受了哪些风险
58
+
59
+ ## 危险模式速查
60
+
61
+ ### Python
62
+ ```python
63
+ # 🔴 危险 - 触犯道基
64
+ eval(), exec(), os.system()
65
+ subprocess(..., shell=True)
66
+ pickle.loads(), yaml.load()
67
+ cursor.execute(f"SELECT * FROM t WHERE id = {id}")
68
+
69
+ # ✅ 安全替代 - 道基稳固
70
+ ast.literal_eval()
71
+ subprocess([...], shell=False)
72
+ yaml.safe_load()
73
+ cursor.execute("SELECT * FROM t WHERE id = %s", (id,))
74
+ ```
75
+
76
+ ### JavaScript
77
+ ```javascript
78
+ // 🔴 危险 - 触犯道基
79
+ eval(), innerHTML, document.write()
80
+ new Function(userInput)
81
+
82
+ // ✅ 安全替代 - 道基稳固
83
+ JSON.parse(), textContent
84
+ 模板引擎自动转义
85
+ ```
86
+
87
+ ### Go
88
+ ```go
89
+ // 🔴 危险 - 触犯道基
90
+ exec.Command("sh", "-c", userInput)
91
+ template.HTML(userInput)
92
+
93
+ // ✅ 安全替代 - 道基稳固
94
+ exec.Command("cmd", args...)
95
+ html/template 自动转义
96
+ ```
97
+
98
+ ## 校验流程
99
+
100
+ ```
101
+ 1. 运行 security_scanner.py 自动扫描
102
+ 2. 分析扫描结果,按严重度排序
103
+ 3. 检查安全决策是否有文档记录
104
+ 4. 输出安全校验报告
105
+ 5. Critical/High 问题必须修复后才能交付
106
+ ```
107
+
108
+ ## 自动触发时机
109
+
110
+ | 场景 | 触发条件 |
111
+ |------|----------|
112
+ | 新建模块 | 模块创建完成时 |
113
+ | 安全相关变更 | 涉及认证、授权、加密、输入处理 |
114
+ | 攻防任务 | 红队/蓝队任务完成时 |
115
+ | 重构完成 | 重构任务完成时 |
116
+ | 提交前 | 代码提交前检查 |
117
+
118
+ ## 校验报告格式
119
+
120
+ ```
121
+ ## 安全校验报告
122
+
123
+ ✓ 通过 | ✗ 未通过
124
+
125
+ - 🔴 Critical: N
126
+ - 🟠 High: N
127
+ - 🟡 Medium: N
128
+ - 🔵 Low: N
129
+
130
+ ### 发现问题
131
+
132
+ | 文件 | 行号 | 类型 | 严重度 | 描述 |
133
+ |------|------|------|--------|------|
134
+ | ... | ... | ... | ... | ... |
135
+
136
+ ### 结论
137
+
138
+ 可交付 / 需修复后交付
139
+ ```
140
+
141
+ ---