@comate/zulu 1.3.5 → 1.3.6

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 (47) hide show
  1. package/comate-engine/server.js +21 -21
  2. package/dist/bundle/index.js +2 -2
  3. package/package.json +1 -1
  4. package/comate-engine/assets/skills/auto-commit/SKILL.md +0 -436
  5. package/comate-engine/assets/skills/auto-commit/references/issue_type_mapping.json +0 -19
  6. package/comate-engine/assets/skills/auto-commit/references/new_version_instruction.md +0 -196
  7. package/comate-engine/assets/skills/auto-commit/references/old_version_instruction.md +0 -189
  8. package/comate-engine/assets/skills/auto-commit/references/query_reference.md +0 -176
  9. package/comate-engine/assets/skills/auto-commit/scripts/compat.py +0 -86
  10. package/comate-engine/assets/skills/auto-commit/scripts/create_card_cli.py +0 -67
  11. package/comate-engine/assets/skills/auto-commit/scripts/git_diff_cli.py +0 -196
  12. package/comate-engine/assets/skills/auto-commit/scripts/git_utils.py +0 -230
  13. package/comate-engine/assets/skills/auto-commit/scripts/icafe/__init__.py +0 -66
  14. package/comate-engine/assets/skills/auto-commit/scripts/icafe/client.py +0 -473
  15. package/comate-engine/assets/skills/auto-commit/scripts/icafe/farseer.py +0 -52
  16. package/comate-engine/assets/skills/auto-commit/scripts/icafe/matching.py +0 -781
  17. package/comate-engine/assets/skills/auto-commit/scripts/logger.py +0 -32
  18. package/comate-engine/assets/skills/auto-commit/scripts/match_card_cli.py +0 -37
  19. package/comate-engine/assets/skills/auto-commit/scripts/recognize_card_cli.py +0 -63
  20. package/comate-engine/assets/skills/auto-commit-comate/references/new_version_instruction.md +0 -209
  21. package/comate-engine/assets/skills/auto-commit-comate/references/old_version_instruction.md +0 -208
  22. package/comate-engine/assets/skills/auto-commit-comate/scripts/compat.py +0 -86
  23. package/comate-engine/assets/skills/build-web-page-comate/SKILL.md +0 -160
  24. package/comate-engine/assets/skills/build-web-page-comate/setup-html-scaffold.md +0 -49
  25. package/comate-engine/assets/skills/build-web-page-comate/setup-react-scaffold.md +0 -103
  26. package/comate-engine/assets/skills/build-web-page-comate/work-with-user-intent.md +0 -112
  27. package/comate-engine/assets/skills/code-security/SKILL.md +0 -176
  28. package/comate-engine/assets/skills/code-security/references/credential_hosting.md +0 -102
  29. package/comate-engine/assets/skills/code-security/references/vul_repair_sensitive.md +0 -219
  30. package/comate-engine/assets/skills/code-security/scripts/build_repair_info.py +0 -0
  31. package/comate-engine/assets/skills/code-security/scripts/credential_hosting.py +0 -99
  32. package/comate-engine/assets/skills/code-security/scripts/credential_poll.py +0 -350
  33. package/comate-engine/assets/skills/code-security/scripts/http_client.py +0 -173
  34. package/comate-engine/assets/skills/code-security/scripts/parse_scan_result.py +0 -301
  35. package/comate-engine/assets/skills/code-security/scripts/repair_vulnerability.py +0 -261
  36. package/comate-engine/assets/skills/code-security/scripts/report_chat.py +0 -198
  37. package/comate-engine/assets/skills/code-security/scripts/scan_vulnerability.py +0 -316
  38. package/comate-engine/assets/skills/comate-docs-comate/references/query_content.md +0 -83
  39. package/comate-engine/assets/skills/comate-docs-comate/references/query_repo.md +0 -57
  40. package/comate-engine/assets/skills/comate-docs-comate/scripts/ku_operator.py +0 -1575
  41. package/comate-engine/assets/skills/create-skill-comate/references/output-patterns.md +0 -82
  42. package/comate-engine/assets/skills/create-skill-comate/references/workflows.md +0 -28
  43. package/comate-engine/assets/skills/create-skill-comate/scripts/init_skill.py +0 -308
  44. package/comate-engine/node_modules/@comate/plugin-host/dist/index-B8VdZIx4.js +0 -1
  45. package/comate-engine/node_modules/@comate/plugin-host/dist/index-QEN4ay0E.js +0 -1
  46. package/comate-engine/node_modules/@comate/plugin-host/dist/user-DAIE9qbz.js +0 -44
  47. package/comate-engine/node_modules/@comate/plugin-host/dist/user-vP8ulngb.js +0 -44
@@ -1,301 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- 扫描结果解析与展示工具 - 解析 scan_result.json 文件,输出标准化漏洞报告。
4
-
5
- 用法:
6
- python3 parse_scan_result.py --scan-result <扫描结果文件路径> [--output-dir <输出目录>]
7
-
8
- 输出:
9
- 1. 标准输出打印 Markdown 格式漏洞报告(供直接展示给用户)
10
- 2. 在输出目录生成 parsed_result.json,包含结构化漏洞数据(供后续修复脚本使用)
11
-
12
- parsed_result.json 格式:
13
- {
14
- "total": 10,
15
- "common_count": 7,
16
- "sensitive_count": 3,
17
- "bundle_hash": "xxx",
18
- "common_vuls": [ ... ],
19
- "sensitive_vuls": [ ... ]
20
- }
21
-
22
- 每个漏洞条目包含:
23
- {
24
- "ruleID": "codescan_java_mybatis-java_sqli",
25
- "name": "Sql 注入漏洞",
26
- "description": "...",
27
- "suggestion": "...",
28
- "level": "ERROR",
29
- "level_cn": "严重",
30
- "file": "src/main/java/...",
31
- "startLine": 12,
32
- "endLine": 12,
33
- "hash": "abc123...",
34
- "is_sensitive": false,
35
- "codeFlows": [ {"file": "...", "line": 63, "message": "..."}, ... ]
36
- }
37
- """
38
-
39
- import argparse
40
- from collections import OrderedDict
41
- import json
42
- import os
43
- import sys
44
-
45
-
46
- LEVEL_MAP = {
47
- "ERROR": "严重",
48
- "WARNING": "高危",
49
- "NOTE": "中危",
50
- "NONE": "低危",
51
- }
52
-
53
- # 等级排序优先级(越小越严重)
54
- LEVEL_PRIORITY = {
55
- "ERROR": 0,
56
- "WARNING": 1,
57
- "NOTE": 2,
58
- "NONE": 3,
59
- }
60
-
61
-
62
- def parse_scan_result(scan_result):
63
- # type: (dict) -> dict
64
- """解析扫描结果,返回结构化漏洞数据。"""
65
- data = scan_result.get("data", {})
66
- runs = data.get("sarif", {}).get("runs", []) or data.get("runs", [])
67
-
68
- # 提取 bundleHash(由 scan_vulnerability.py 写入顶层)
69
- bundle_hash = scan_result.get("bundleHash", "")
70
-
71
- # 建立 ruleID -> rule 映射
72
- rule_map = {}
73
- for run in runs:
74
- tool = run.get("tool", {})
75
- # 兼容 rules 在 tool 或 tool.driver 下
76
- rules = tool.get("rules", []) or tool.get("driver", {}).get("rules", [])
77
- for rule in rules:
78
- rule_id = rule.get("id", "")
79
- if rule_id:
80
- rule_map[rule_id] = rule
81
-
82
- # 解析漏洞结果
83
- common_vuls = []
84
- sensitive_vuls = []
85
-
86
- for run in runs:
87
- results = run.get("results", []) or run.get("result", [])
88
- for result in results:
89
- rule_id = result.get("ruleID", "") or result.get("ruleId", "")
90
- rule = rule_map.get(rule_id, {})
91
-
92
- # 基础信息
93
- name = rule.get("name", rule_id)
94
- description = rule.get("description", "") or result.get("message", {}).get("text", "")
95
- suggestion = rule.get("suggestion", "")
96
- level_config = rule.get("defaultConfiguration", {})
97
- level = level_config.get("level", "NONE") if level_config else "NONE"
98
- level_cn = LEVEL_MAP.get(level, "低危")
99
- vul_hash = result.get("properties", {}).get("hash", "")
100
-
101
- # 位置信息
102
- locations = result.get("locations", [])
103
- file_uri = ""
104
- start_line = 0
105
- end_line = 0
106
- if locations:
107
- phys = locations[0].get("physicalLocation", {})
108
- artifact = phys.get("artifactLocation", {})
109
- file_uri = artifact.get("uri", "")
110
- region = artifact.get("region", {})
111
- start_line = region.get("startLine", 0)
112
- end_line = region.get("endLine", start_line)
113
-
114
- # 数据流信息
115
- code_flows_raw = result.get("codeFlows", [])
116
- code_flows = []
117
- if code_flows_raw:
118
- thread_flows = code_flows_raw[0].get("threadFlows", [])
119
- if thread_flows:
120
- for loc_wrapper in thread_flows[0].get("locations", []):
121
- loc = loc_wrapper.get("location", {})
122
- loc_phys = loc.get("physicalLocation", {})
123
- loc_file = loc_phys.get("artifactLocation", {}).get("uri", "")
124
- loc_region = loc_phys.get("region", {})
125
- loc_line = loc_region.get("startLine", 0)
126
- loc_msg = loc.get("message", {}).get("text", "")
127
- code_flows.append({
128
- "file": loc_file,
129
- "line": loc_line,
130
- "message": loc_msg,
131
- })
132
-
133
- is_sensitive = "sensitive" in rule_id.lower()
134
-
135
- vul_entry = {
136
- "ruleID": rule_id,
137
- "name": name,
138
- "description": description,
139
- "suggestion": suggestion,
140
- "level": level,
141
- "level_cn": level_cn,
142
- "file": file_uri,
143
- "startLine": start_line,
144
- "endLine": end_line,
145
- "hash": vul_hash,
146
- "is_sensitive": is_sensitive,
147
- "codeFlows": code_flows,
148
- }
149
-
150
- if is_sensitive:
151
- sensitive_vuls.append(vul_entry)
152
- else:
153
- common_vuls.append(vul_entry)
154
-
155
- # 按严重程度排序
156
- def sort_key(v):
157
- return (LEVEL_PRIORITY.get(v["level"], 99), v["file"], v["startLine"])
158
-
159
- common_vuls.sort(key=sort_key)
160
- sensitive_vuls.sort(key=sort_key)
161
-
162
- return {
163
- "total": len(common_vuls) + len(sensitive_vuls),
164
- "common_count": len(common_vuls),
165
- "sensitive_count": len(sensitive_vuls),
166
- "bundle_hash": bundle_hash,
167
- "common_vuls": common_vuls,
168
- "sensitive_vuls": sensitive_vuls,
169
- }
170
-
171
-
172
- def _file_basename(file_path):
173
- # type: (str) -> str
174
- return os.path.basename(file_path) if file_path else ""
175
-
176
-
177
- def format_vul_report(vuls, title="漏洞报告"):
178
- # type: (list, str) -> str
179
- """将漏洞列表按类型分组格式化为 Markdown 报告。
180
-
181
- 同一 ruleID 的漏洞归为一组,描述/等级/修复建议只展示一次,
182
- 漏洞位置列表化展示,数据流用 <details> 折叠。
183
- """
184
- if not vuls:
185
- return ""
186
-
187
- # 按 ruleID 分组,保持原有排序
188
- groups = OrderedDict() # type: OrderedDict[str, list]
189
- for vul in vuls:
190
- rule_id = vul["ruleID"]
191
- if rule_id not in groups:
192
- groups[rule_id] = []
193
- groups[rule_id].append(vul)
194
-
195
- lines = ["**{}**\n".format(title)]
196
-
197
- for group_idx, (rule_id, group_vuls) in enumerate(groups.items(), 1):
198
- rep = group_vuls[0] # 取第一个作为代表获取公共信息
199
- count = len(group_vuls)
200
- count_suffix = "({} 处)".format(count) if count > 1 else ""
201
-
202
- lines.append("{}. **{}**{}".format(group_idx, rep["name"], count_suffix))
203
- if rep["description"]:
204
- lines.append("- **漏洞描述**:{}".format(rep["description"]))
205
- lines.append("- **漏洞等级**:{}".format(rep["level_cn"]))
206
- if rep["suggestion"]:
207
- lines.append("- **修复建议**:{}".format(rep["suggestion"]))
208
-
209
- # 漏洞位置列表
210
- lines.append("- **漏洞位置**:")
211
- for vul in group_vuls:
212
- fname = _file_basename(vul["file"])
213
- loc_label = "{}:{}".format(fname, vul["startLine"]) if fname else "未知位置"
214
- loc_link = "[{}]({}#L{})".format(loc_label, vul["file"], vul["startLine"]) if vul["file"] else loc_label
215
- lines.append(" - {}".format(loc_link))
216
-
217
- # 数据流折叠展示
218
- if vul["codeFlows"]:
219
- lines.append(" <details><summary>数据流</summary>\n")
220
- for hop_idx, hop in enumerate(vul["codeFlows"], 1):
221
- hop_fname = _file_basename(hop["file"])
222
- hop_label = "{}:{}".format(hop_fname, hop["line"]) if hop_fname else "未知"
223
- hop_link = "[{}]({}#L{})".format(hop_label, hop["file"], hop["line"]) if hop["file"] else hop_label
224
- hop_msg = hop.get("message", "")
225
- if hop_msg:
226
- lines.append(" {}. {} — {}".format(hop_idx, hop_link, hop_msg))
227
- else:
228
- lines.append(" {}. {}".format(hop_idx, hop_link))
229
- lines.append("\n </details>")
230
- lines.append("")
231
-
232
- return "\n".join(lines)
233
-
234
-
235
- def format_full_report(parsed):
236
- # type: (dict) -> str
237
- """生成完整的展示报告(包含两类漏洞)。"""
238
- parts = []
239
-
240
- if parsed["common_count"] > 0 and parsed["sensitive_count"] > 0:
241
- parts.append("扫描发现 **{}** 个普通漏洞和 **{}** 个硬编码漏洞。\n".format(
242
- parsed["common_count"], parsed["sensitive_count"]))
243
- elif parsed["common_count"] > 0:
244
- parts.append("扫描发现 **{}** 个普通漏洞。\n".format(parsed["common_count"]))
245
- elif parsed["sensitive_count"] > 0:
246
- parts.append("扫描发现 **{}** 个硬编码漏洞。\n".format(parsed["sensitive_count"]))
247
- else:
248
- parts.append("扫描完成,未发现漏洞。\n")
249
- return "\n".join(parts)
250
-
251
- if parsed["common_vuls"]:
252
- parts.append(format_vul_report(parsed["common_vuls"], "普通漏洞报告"))
253
-
254
- if parsed["sensitive_vuls"]:
255
- parts.append(format_vul_report(parsed["sensitive_vuls"], "硬编码漏洞报告"))
256
-
257
- return "\n".join(parts)
258
-
259
-
260
- def main():
261
- """
262
- 主函数入口,解析命令行参数并处理扫描结果
263
-
264
- Args:
265
- 无(通过命令行参数 --scan-result 和 --output-dir 传入)
266
-
267
- Returns:
268
- 无(结果直接输出到标准输出和文件)
269
- """
270
- parser = argparse.ArgumentParser(description="扫描结果解析与展示工具")
271
- parser.add_argument("--scan-result", required=True, help="扫描结果文件路径 (scan_result.json)")
272
- parser.add_argument("--output-dir", default=None, help="结构化结果输出目录,默认与输入文件同目录")
273
- args = parser.parse_args()
274
-
275
- # 读取扫描结果
276
- try:
277
- with open(args.scan_result, "r", encoding="utf-8") as f:
278
- scan_result = json.load(f)
279
- except Exception as e:
280
- print("错误: 读取扫描结果失败 {}: {}".format(args.scan_result, e), file=sys.stderr)
281
- sys.exit(1)
282
-
283
- # 解析
284
- parsed = parse_scan_result(scan_result)
285
-
286
- # 输出 Markdown 报告到标准输出
287
- report = format_full_report(parsed)
288
- print(report)
289
-
290
- # 保存结构化 JSON
291
- # 默认输出到输入文件同目录,自然跟随项目隔离
292
- output_dir = args.output_dir or os.path.dirname(os.path.abspath(args.scan_result))
293
- os.makedirs(output_dir, exist_ok=True)
294
- output_file = os.path.join(output_dir, "parsed_result.json")
295
- with open(output_file, "w", encoding="utf-8") as f:
296
- json.dump(parsed, f, ensure_ascii=False, indent=2)
297
- print(output_file, file=sys.stderr)
298
-
299
-
300
- if __name__ == "__main__":
301
- main()
@@ -1,261 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- 漏洞修复工具 - 根据扫描结果修复指定文件的漏洞。
4
-
5
- 用法:
6
- python3 repair_vulnerability.py --root-path <项目目录> --username <用户名> --parsed-result <parsed_result.json路径>
7
- python3 repair_vulnerability.py --root-path <项目目录> --username <用户名> --vulnerability-info '<漏洞信息JSON>'
8
-
9
- 支持两种输入方式(二选一):
10
- --parsed-result: 直接传入 parsed_result.json 路径,脚本自动提取普通漏洞并构建修复信息
11
- --vulnerability-info: 传入漏洞信息 JSON 字符串
12
-
13
- 流程:
14
- 1. 解析漏洞信息,计算待修复文件的哈希
15
- 2. 调用修复接口
16
- 3. 如有缺失文件则上传后重试
17
- 4. 返回包含 diff_content 的修复结果
18
- """
19
-
20
- import argparse
21
- import base64
22
- import hashlib
23
- import json
24
- import logging
25
- import os
26
- import sys
27
- import time
28
- import uuid
29
- from typing import Dict, List, Tuple
30
-
31
- import http_client # noqa: F401 (triggers shared logging config)
32
-
33
- HOST = "https://comate-sec.baidu-int.com"
34
-
35
- USERNAME = ""
36
- USER_ID = ""
37
-
38
- logger = logging.getLogger("repair")
39
-
40
-
41
- def build_headers():
42
- # type: () -> Dict[str, str]
43
- return {
44
- "Comate-Username": USERNAME,
45
- "Comate-User-Id": USER_ID,
46
- "SAST-Request-ID": str(uuid.uuid4()),
47
- }
48
-
49
-
50
- def calc_sha256(file_path):
51
- # type: (str) -> str
52
- sha256_hash = hashlib.sha256()
53
- with open(file_path, "rb") as f:
54
- for chunk in iter(lambda: f.read(4096), b""):
55
- sha256_hash.update(chunk)
56
- return sha256_hash.hexdigest()
57
-
58
-
59
- def read_file_content(file_path):
60
- # type: (str) -> str
61
- """读取文件内容,二进制文件用 base64 编码。"""
62
- try:
63
- with open(file_path, "r", encoding="utf-8") as f:
64
- return f.read()
65
- except UnicodeDecodeError:
66
- with open(file_path, "rb") as f:
67
- return base64.b64encode(f.read()).decode("ascii")
68
-
69
-
70
- def diff_file_content(file_path, new_content):
71
- # type: (str, str) -> str
72
- """比较原文件与修复后内容,返回 {from_content, to_content} JSON。"""
73
- with open(file_path, "r", encoding="utf-8") as f:
74
- old_content = f.read()
75
-
76
- old_lines = old_content.split("\n")
77
- new_lines = new_content.split("\n")
78
-
79
- from_parts = [] # type: List[str]
80
- to_parts = [] # type: List[str]
81
-
82
- oi, ni = 0, 0
83
- while oi < len(old_lines) and ni < len(new_lines):
84
- if old_lines[oi] == new_lines[ni]:
85
- oi += 1
86
- ni += 1
87
- else:
88
- from_parts.append(old_lines[oi] + "\n")
89
- to_parts.append(new_lines[ni] + "\n")
90
- oi += 1
91
- ni += 1
92
-
93
- while oi < len(old_lines):
94
- from_parts.append(old_lines[oi] + "\n")
95
- oi += 1
96
-
97
- while ni < len(new_lines):
98
- to_parts.append(new_lines[ni] + "\n")
99
- ni += 1
100
-
101
- return json.dumps(
102
- {"from_content": "".join(from_parts), "to_content": "".join(to_parts)},
103
- ensure_ascii=False,
104
- indent=2,
105
- )
106
-
107
-
108
- def upload_files_for_repair(root_path, missing_files):
109
- # type: (str, List[str]) -> None
110
- """上传修复过程中缺失的文件。"""
111
- payload = {"files": {}}
112
- for name in missing_files:
113
- file_path = os.path.join(root_path, name)
114
- try:
115
- content = read_file_content(file_path)
116
- file_hash = calc_sha256(file_path)
117
- payload["files"][name] = {"hash": file_hash, "content": content}
118
- except Exception as e:
119
- print("警告: 读取文件失败 {}: {}".format(file_path, e), file=sys.stderr)
120
-
121
- http_client.put("{}/api/v1/upload".format(HOST), headers=build_headers(), json_body=payload)
122
-
123
-
124
- def repair_vulnerability(root_path, vulnerability_info):
125
- # type: (str, Dict) -> Dict
126
- """执行漏洞修复,返回包含 diff 的修复结果。"""
127
- # 计算待修复文件的哈希
128
- for file_info in vulnerability_info.get("files", []):
129
- file_path = os.path.join(root_path, file_info["name"])
130
- if os.path.isfile(file_path):
131
- file_info["hash"] = calc_sha256(file_path)
132
-
133
- repair_type = vulnerability_info.get("type", 2)
134
- file_count = len(vulnerability_info.get("files", []))
135
- logger.info("repair start: type=%d, files=%d", repair_type, file_count)
136
- api_url = "{}/api/v2/repair_file".format(HOST)
137
- print("开始修复...", file=sys.stderr)
138
-
139
- while True:
140
- result = http_client.post(
141
- api_url,
142
- headers=build_headers(),
143
- json_body=vulnerability_info,
144
- )
145
-
146
- # 如有缺失文件,先上传
147
- missing = result.get("data", {}).get("missingFiles", [])
148
- if missing:
149
- print("上传缺失文件: {} 个".format(len(missing)), file=sys.stderr)
150
- upload_files_for_repair(root_path, missing)
151
- time.sleep(3)
152
- continue
153
-
154
- # status != 0 表示完成
155
- if result.get("status") != 0:
156
- # 生成 diff
157
- files_data = result.get("data", {}).get("files", [])
158
- for file_data in files_data:
159
- repaired_content = file_data.get("repairedContent", "")
160
- if repaired_content:
161
- file_path = os.path.join(root_path, file_data["name"])
162
- if os.path.isfile(file_path):
163
- diff_json = diff_file_content(file_path, repaired_content)
164
- file_data["diff_content"] = diff_json
165
- # 置空防止泄露完整源码
166
- file_data["repairedContent"] = ""
167
- return result
168
-
169
- print("修复中,等待结果...", file=sys.stderr)
170
- time.sleep(3)
171
-
172
-
173
- def build_vulnerability_info(parsed):
174
- # type: (dict) -> dict
175
- """从 parsed_result.json 构建修复接口所需的 vulnerability-info。"""
176
- bundle_hash = parsed.get("bundle_hash", "")
177
- common_vuls = parsed.get("common_vuls", [])
178
-
179
- file_map = {} # type: dict
180
- for vul in common_vuls:
181
- fname = vul.get("file", "")
182
- if not fname:
183
- continue
184
- if fname not in file_map:
185
- file_map[fname] = {"name": fname, "vulList": []}
186
- file_map[fname]["vulList"].append({
187
- "ruleID": vul.get("ruleID", ""),
188
- "line": vul.get("startLine", 0),
189
- "hash": vul.get("hash", ""),
190
- })
191
-
192
- return {
193
- "files": list(file_map.values()),
194
- "type": 2,
195
- "extra": {
196
- "bundleHash": bundle_hash,
197
- },
198
- }
199
-
200
-
201
- def main():
202
- global USERNAME, USER_ID
203
- parser = argparse.ArgumentParser(description="代码安全漏洞修复工具")
204
- parser.add_argument("--root-path", required=True, help="项目根目录")
205
- parser.add_argument("--username", required=True, help="Comate 用户名")
206
- parser.add_argument("--vulnerability-info", default=None, help="漏洞信息 JSON 字符串")
207
- parser.add_argument("--parsed-result", default=None,
208
- help="解析结果文件路径 (parsed_result.json),与 --vulnerability-info 二选一")
209
- parser.add_argument("--output-dir", default=None, help="结果输出目录,默认为 skill 临时目录")
210
- args = parser.parse_args()
211
-
212
- if not args.vulnerability_info and not args.parsed_result:
213
- print("错误: 必须提供 --vulnerability-info 或 --parsed-result 之一", file=sys.stderr)
214
- sys.exit(1)
215
-
216
- USERNAME = args.username
217
- USER_ID = hashlib.md5(USERNAME.encode("utf-8")).hexdigest()[:12]
218
-
219
- logger.info("repair_vulnerability start: username=%s, root_path=%s", USERNAME, args.root_path)
220
-
221
- root_path = os.path.realpath(args.root_path)
222
- if not os.path.isdir(root_path):
223
- print("错误: 目录不存在 {}".format(root_path), file=sys.stderr)
224
- sys.exit(1)
225
-
226
- # 默认输出到 skill 临时目录,按项目路径隔离子目录避免并发冲突
227
- skill_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
228
- project_name = os.path.basename(root_path)
229
- path_hash = hashlib.md5(root_path.encode("utf-8")).hexdigest()[:8]
230
- default_output = os.path.join(skill_dir, ".tmp", "{}_{}".format(project_name, path_hash))
231
- output_dir = os.path.realpath(args.output_dir) if args.output_dir else default_output
232
- os.makedirs(output_dir, exist_ok=True)
233
-
234
- if args.parsed_result:
235
- try:
236
- with open(args.parsed_result, "r", encoding="utf-8") as f:
237
- parsed = json.load(f)
238
- except Exception as e:
239
- print("错误: 读取解析结果失败 {}: {}".format(args.parsed_result, e), file=sys.stderr)
240
- sys.exit(1)
241
- if not parsed.get("common_vuls"):
242
- print("无普通漏洞需要修复", file=sys.stderr)
243
- sys.exit(0)
244
- vulnerability_info = build_vulnerability_info(parsed)
245
- else:
246
- try:
247
- vulnerability_info = json.loads(args.vulnerability_info)
248
- except json.JSONDecodeError as e:
249
- print("错误: 漏洞信息 JSON 解析失败: {}".format(e), file=sys.stderr)
250
- sys.exit(1)
251
-
252
- result = repair_vulnerability(root_path, vulnerability_info)
253
-
254
- output_file = os.path.join(output_dir, "repair_result.json")
255
- with open(output_file, "w", encoding="utf-8") as f:
256
- json.dump(result, f, ensure_ascii=False, indent=2)
257
- print(output_file)
258
-
259
-
260
- if __name__ == "__main__":
261
- main()