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,368 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 代码安全扫描器
4
+ 检测常见安全漏洞模式:注入、硬编码密钥、危险函数等
5
+ """
6
+
7
+ import os
8
+ import re
9
+ import sys
10
+ import json
11
+ from pathlib import Path
12
+ from dataclasses import dataclass, field
13
+ from typing import List, Dict, Optional, Tuple
14
+ from enum import Enum
15
+
16
+
17
+ class Severity(Enum):
18
+ CRITICAL = "critical"
19
+ HIGH = "high"
20
+ MEDIUM = "medium"
21
+ LOW = "low"
22
+ INFO = "info"
23
+
24
+
25
+ @dataclass
26
+ class Finding:
27
+ severity: Severity
28
+ category: str
29
+ message: str
30
+ file_path: str
31
+ line_number: int
32
+ line_content: str
33
+ recommendation: str
34
+
35
+
36
+ @dataclass
37
+ class ScanResult:
38
+ scan_path: str
39
+ files_scanned: int = 0
40
+ findings: List[Finding] = field(default_factory=list)
41
+
42
+ @property
43
+ def passed(self) -> bool:
44
+ return not any(f.severity in [Severity.CRITICAL, Severity.HIGH] for f in self.findings)
45
+
46
+ def count_by_severity(self) -> Dict[str, int]:
47
+ counts = {s.value: 0 for s in Severity}
48
+ for f in self.findings:
49
+ counts[f.severity.value] += 1
50
+ return counts
51
+
52
+
53
+ # 安全检测规则
54
+ SECURITY_RULES = [
55
+ # SQL 注入
56
+ {
57
+ "id": "SQL_INJECTION_DYNAMIC",
58
+ "category": "注入",
59
+ "severity": Severity.CRITICAL,
60
+ "pattern": r'\b(execute|query|raw)\s*\(\s*(f["\']|["\'][^"\'\n]*["\']\s*\+\s*|["\'][^"\'\n]*["\']\s*%\s*[^,\)]|["\'][^"\'\n]*["\']\.format\s*\()',
61
+ "extensions": [".py", ".js", ".ts", ".go", ".java", ".php"],
62
+ "message": "可能存在 SQL 注入风险",
63
+ "recommendation": "使用参数化查询或 ORM"
64
+ },
65
+ {
66
+ "id": "SQL_INJECTION_FSTRING",
67
+ "category": "注入",
68
+ "severity": Severity.CRITICAL,
69
+ "pattern": r'cursor\.(execute|executemany)\s*\(\s*f["\']',
70
+ "extensions": [".py"],
71
+ "message": "使用 f-string 构造 SQL 语句",
72
+ "recommendation": "使用参数化查询: cursor.execute('SELECT * FROM t WHERE id = %s', (id,))"
73
+ },
74
+ # 命令注入
75
+ {
76
+ "id": "COMMAND_INJECTION",
77
+ "category": "注入",
78
+ "severity": Severity.CRITICAL,
79
+ "pattern": r'(os\.system|os\.popen|subprocess\.call|subprocess\.run|subprocess\.Popen)\s*\([^)]*shell\s*=\s*True',
80
+ "extensions": [".py"],
81
+ "message": "使用 shell=True 可能导致命令注入",
82
+ "recommendation": "避免 shell=True,使用列表参数"
83
+ },
84
+ {
85
+ "id": "COMMAND_INJECTION_EVAL",
86
+ "category": "注入",
87
+ "severity": Severity.CRITICAL,
88
+ "pattern": r'\b(eval|exec)\s*\([^)]*\b(input|request|argv|args)',
89
+ "extensions": [".py"],
90
+ "message": "eval/exec 执行用户输入",
91
+ "recommendation": "避免对用户输入使用 eval/exec"
92
+ },
93
+ # 硬编码密钥
94
+ {
95
+ "id": "HARDCODED_SECRET",
96
+ "category": "敏感信息",
97
+ "severity": Severity.HIGH,
98
+ "pattern": r'(password|passwd|pwd|secret|api_key|apikey|token|auth)\s*=\s*["\'][^"\']{8,}["\']',
99
+ "extensions": [".py", ".js", ".ts", ".go", ".java", ".php", ".rb", ".yaml", ".yml", ".json", ".env"],
100
+ "message": "可能存在硬编码密钥/密码",
101
+ "recommendation": "使用环境变量或密钥管理服务"
102
+ },
103
+ {
104
+ "id": "HARDCODED_AWS_KEY",
105
+ "category": "敏感信息",
106
+ "severity": Severity.CRITICAL,
107
+ "pattern": r'AKIA[0-9A-Z]{16}',
108
+ "extensions": ["*"],
109
+ "message": "发现 AWS Access Key",
110
+ "recommendation": "立即轮换密钥,使用 IAM 角色或环境变量"
111
+ },
112
+ {
113
+ "id": "HARDCODED_PRIVATE_KEY",
114
+ "category": "敏感信息",
115
+ "severity": Severity.CRITICAL,
116
+ "pattern": r'-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----',
117
+ "extensions": ["*"],
118
+ "message": "发现私钥",
119
+ "recommendation": "私钥不应提交到代码库"
120
+ },
121
+ # XSS
122
+ {
123
+ "id": "XSS_INNERHTML",
124
+ "category": "XSS",
125
+ "severity": Severity.HIGH,
126
+ "pattern": r'\.innerHTML\s*=|\.outerHTML\s*=|document\.write\s*\(',
127
+ "extensions": [".js", ".ts", ".jsx", ".tsx", ".html"],
128
+ "message": "直接操作 innerHTML 可能导致 XSS",
129
+ "recommendation": "使用 textContent 或框架的安全绑定"
130
+ },
131
+ {
132
+ "id": "XSS_DANGEROUSLY",
133
+ "category": "XSS",
134
+ "severity": Severity.MEDIUM,
135
+ "pattern": r'dangerouslySetInnerHTML',
136
+ "extensions": [".js", ".ts", ".jsx", ".tsx"],
137
+ "message": "使用 dangerouslySetInnerHTML",
138
+ "recommendation": "确保内容已经过净化处理"
139
+ },
140
+ # 不安全的反序列化
141
+ {
142
+ "id": "UNSAFE_PICKLE",
143
+ "category": "反序列化",
144
+ "severity": Severity.HIGH,
145
+ "pattern": r'pickle\.loads?\s*\(|yaml\.load\s*\([^)]*Loader\s*=\s*yaml\.Loader',
146
+ "extensions": [".py"],
147
+ "message": "不安全的反序列化",
148
+ "recommendation": "使用 yaml.safe_load() 或验证数据来源"
149
+ },
150
+ # 弱加密
151
+ {
152
+ "id": "WEAK_CRYPTO_MD5",
153
+ "category": "加密",
154
+ "severity": Severity.MEDIUM,
155
+ "pattern": r'\b(md5|MD5)\s*\(|hashlib\.md5\s*\(',
156
+ "extensions": [".py", ".js", ".ts", ".go", ".java", ".php"],
157
+ "message": "使用弱哈希算法 MD5",
158
+ "recommendation": "密码存储使用 bcrypt/argon2,完整性校验使用 SHA-256+"
159
+ },
160
+ {
161
+ "id": "WEAK_CRYPTO_SHA1",
162
+ "category": "加密",
163
+ "severity": Severity.LOW,
164
+ "pattern": r'\b(sha1|SHA1)\s*\(|hashlib\.sha1\s*\(',
165
+ "extensions": [".py", ".js", ".ts", ".go", ".java", ".php"],
166
+ "message": "使用弱哈希算法 SHA1",
167
+ "recommendation": "使用 SHA-256 或更强的算法"
168
+ },
169
+ # 路径遍历
170
+ {
171
+ "id": "PATH_TRAVERSAL",
172
+ "category": "路径遍历",
173
+ "severity": Severity.HIGH,
174
+ "pattern": r'(open|read|write|Path|os\.path\.join)\s*\([^\n]*(request|input|argv|args|params|query|form|path_param)\b',
175
+ "extensions": [".py"],
176
+ "message": "可能存在路径遍历风险",
177
+ "recommendation": "验证并规范化用户输入的路径"
178
+ },
179
+ # SSRF
180
+ {
181
+ "id": "SSRF",
182
+ "category": "SSRF",
183
+ "severity": Severity.HIGH,
184
+ "pattern": r'(requests\.(get|post|put|delete|head)|urllib\.request\.urlopen)\s*\([^\n]*(request|input|argv|args|params|query|url)\b',
185
+ "extensions": [".py"],
186
+ "message": "可能存在 SSRF 风险",
187
+ "recommendation": "验证并限制目标 URL"
188
+ },
189
+ # 调试代码
190
+ {
191
+ "id": "DEBUG_CODE",
192
+ "category": "调试",
193
+ "severity": Severity.LOW,
194
+ "pattern": r'\b(console\.log|debugger|pdb\.set_trace|breakpoint)\s*\(',
195
+ "extensions": [".py", ".js", ".ts"],
196
+ "message": "发现调试代码",
197
+ "recommendation": "生产环境移除调试代码"
198
+ },
199
+ # 不安全的随机数
200
+ {
201
+ "id": "INSECURE_RANDOM",
202
+ "category": "加密",
203
+ "severity": Severity.MEDIUM,
204
+ "pattern": r'\brandom\.(random|randint|choice|shuffle)\s*\(',
205
+ "extensions": [".py"],
206
+ "message": "使用不安全的随机数生成器",
207
+ "recommendation": "安全场景使用 secrets 模块"
208
+ },
209
+ # XXE
210
+ {
211
+ "id": "XXE",
212
+ "category": "XXE",
213
+ "severity": Severity.HIGH,
214
+ "pattern": r'etree\.(parse|fromstring)\s*\([^)]*\)|xml\.dom\.minidom\.parse',
215
+ "extensions": [".py"],
216
+ "message": "XML 解析可能存在 XXE 风险",
217
+ "recommendation": "禁用外部实体: parser = etree.XMLParser(resolve_entities=False)"
218
+ },
219
+ ]
220
+
221
+
222
+ def scan_file(file_path: Path, rules: List[Dict]) -> List[Finding]:
223
+ """扫描单个文件"""
224
+ findings = []
225
+ suffix = file_path.suffix.lower()
226
+
227
+ try:
228
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
229
+ lines = content.split('\n')
230
+ except Exception:
231
+ return findings
232
+
233
+ for rule in rules:
234
+ # 检查文件扩展名
235
+ extensions = rule.get("extensions", ["*"])
236
+ if "*" not in extensions and suffix not in extensions:
237
+ continue
238
+
239
+ pattern = re.compile(rule["pattern"], re.IGNORECASE)
240
+
241
+ for line_num, line in enumerate(lines, 1):
242
+ # 跳过注释行
243
+ stripped = line.strip()
244
+ if stripped.startswith('#') or stripped.startswith('//') or stripped.startswith('*') or stripped.startswith('/*'):
245
+ continue
246
+
247
+ if pattern.search(line):
248
+ findings.append(Finding(
249
+ severity=rule["severity"],
250
+ category=rule["category"],
251
+ message=rule["message"],
252
+ file_path=str(file_path),
253
+ line_number=line_num,
254
+ line_content=line.strip()[:100],
255
+ recommendation=rule["recommendation"]
256
+ ))
257
+
258
+ return findings
259
+
260
+
261
+ def scan_directory(path: str, exclude_dirs: List[str] = None) -> ScanResult:
262
+ """扫描目录"""
263
+ scan_path = Path(path).resolve()
264
+ result = ScanResult(scan_path=str(scan_path))
265
+
266
+ if exclude_dirs is None:
267
+ exclude_dirs = ['.git', 'node_modules', '__pycache__', '.venv', 'venv', 'dist', 'build', '.tox', 'tests', 'test', '__tests__', 'spec']
268
+
269
+ code_extensions = {'.py', '.js', '.ts', '.jsx', '.tsx', '.go', '.java', '.php', '.rb', '.yaml', '.yml', '.json'}
270
+
271
+ for file_path in scan_path.rglob('*'):
272
+ # 跳过排除目录
273
+ if any(ex in file_path.parts for ex in exclude_dirs):
274
+ continue
275
+
276
+ if file_path.is_file() and file_path.suffix.lower() in code_extensions:
277
+ result.files_scanned += 1
278
+ findings = scan_file(file_path, SECURITY_RULES)
279
+ result.findings.extend(findings)
280
+
281
+ # 按严重程度排序
282
+ severity_order = {Severity.CRITICAL: 0, Severity.HIGH: 1, Severity.MEDIUM: 2, Severity.LOW: 3, Severity.INFO: 4}
283
+ result.findings.sort(key=lambda f: severity_order[f.severity])
284
+
285
+ return result
286
+
287
+
288
+ def format_report(result: ScanResult, verbose: bool = False) -> str:
289
+ """格式化扫描报告"""
290
+ lines = []
291
+ lines.append("=" * 60)
292
+ lines.append("代码安全扫描报告")
293
+ lines.append("=" * 60)
294
+ lines.append(f"\n扫描路径: {result.scan_path}")
295
+ lines.append(f"扫描文件: {result.files_scanned}")
296
+ lines.append(f"扫描结果: {'✓ 通过' if result.passed else '✗ 发现高危问题'}")
297
+
298
+ counts = result.count_by_severity()
299
+ lines.append(f"\n严重: {counts['critical']} | 高危: {counts['high']} | 中危: {counts['medium']} | 低危: {counts['low']}")
300
+
301
+ if result.findings:
302
+ lines.append("\n" + "-" * 40)
303
+ lines.append("发现问题:")
304
+ lines.append("-" * 40)
305
+
306
+ severity_icons = {
307
+ "critical": "🔴",
308
+ "high": "🟠",
309
+ "medium": "🟡",
310
+ "low": "🔵",
311
+ "info": "⚪"
312
+ }
313
+
314
+ for finding in result.findings:
315
+ icon = severity_icons[finding.severity.value]
316
+ lines.append(f"\n{icon} [{finding.severity.value.upper()}] {finding.category}")
317
+ lines.append(f" 文件: {finding.file_path}:{finding.line_number}")
318
+ lines.append(f" 问题: {finding.message}")
319
+ if verbose:
320
+ lines.append(f" 代码: {finding.line_content}")
321
+ lines.append(f" 建议: {finding.recommendation}")
322
+
323
+ lines.append("\n" + "=" * 60)
324
+ return "\n".join(lines)
325
+
326
+
327
+ def main():
328
+ import argparse
329
+
330
+ parser = argparse.ArgumentParser(description="代码安全扫描器")
331
+ parser.add_argument("path", nargs="?", default=".", help="扫描路径")
332
+ parser.add_argument("-v", "--verbose", action="store_true", help="详细输出")
333
+ parser.add_argument("--json", action="store_true", help="JSON 格式输出")
334
+ parser.add_argument("--exclude", nargs="*", default=[], help="排除目录")
335
+
336
+ args = parser.parse_args()
337
+
338
+ exclude_dirs = ['.git', 'node_modules', '__pycache__', '.venv', 'venv', 'dist', 'build', 'tests', 'test', '__tests__', 'spec'] + args.exclude
339
+ result = scan_directory(args.path, exclude_dirs)
340
+
341
+ if args.json:
342
+ output = {
343
+ "scan_path": result.scan_path,
344
+ "files_scanned": result.files_scanned,
345
+ "passed": result.passed,
346
+ "counts": result.count_by_severity(),
347
+ "findings": [
348
+ {
349
+ "severity": f.severity.value,
350
+ "category": f.category,
351
+ "message": f.message,
352
+ "file_path": f.file_path,
353
+ "line_number": f.line_number,
354
+ "line_content": f.line_content,
355
+ "recommendation": f.recommendation
356
+ }
357
+ for f in result.findings
358
+ ]
359
+ }
360
+ print(json.dumps(output, ensure_ascii=False, indent=2))
361
+ else:
362
+ print(format_report(result, args.verbose))
363
+
364
+ sys.exit(0 if result.passed else 1)
365
+
366
+
367
+ if __name__ == "__main__":
368
+ main()