@comate/zulu 1.2.1-beta.2 → 1.3.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.
Files changed (169) hide show
  1. package/comate-engine/assets/skills/auto-commit-comate/SKILL.md +260 -0
  2. package/comate-engine/assets/skills/auto-commit-comate/references/data_structures.md +189 -0
  3. package/comate-engine/assets/skills/auto-commit-comate/references/new_version_instruction.md +209 -0
  4. package/comate-engine/assets/skills/auto-commit-comate/references/old_version_instruction.md +208 -0
  5. package/comate-engine/assets/skills/auto-commit-comate/scripts/git_diff_cli.py +196 -0
  6. package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/git_utils.py +20 -10
  7. package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/icafe/client.py +69 -40
  8. package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/icafe/farseer.py +8 -9
  9. package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/icafe/matching.py +65 -9
  10. package/comate-engine/assets/skills/auto-commit-comate/scripts/match_card_cli.py +37 -0
  11. package/comate-engine/assets/skills/cnap-comate/SKILL.md +157 -0
  12. package/comate-engine/assets/skills/cnap-comate/references/cases.md +198 -0
  13. package/comate-engine/assets/skills/cnap-comate/references/deploy-troubleshoot.md +15 -0
  14. package/comate-engine/assets/skills/cnap-comate/references/install.md +43 -0
  15. package/comate-engine/assets/skills/cnap-comate/references/kubectl.md +55 -0
  16. package/comate-engine/assets/skills/cnap-comate/references/login.md +125 -0
  17. package/comate-engine/assets/skills/cnap-comate/references/oncall.md +24 -0
  18. package/comate-engine/assets/skills/cnap-comate/scripts/install_cnap_cli.sh +36 -0
  19. package/comate-engine/assets/skills/code-security/SKILL.md +176 -0
  20. package/comate-engine/assets/skills/code-security/references/credential_hosting.md +102 -0
  21. package/comate-engine/assets/skills/code-security/references/vul_repair_sensitive.md +219 -0
  22. package/comate-engine/assets/skills/code-security/scripts/build_repair_info.py +0 -0
  23. package/comate-engine/assets/skills/code-security/scripts/credential_hosting.py +99 -0
  24. package/comate-engine/assets/skills/code-security/scripts/credential_poll.py +350 -0
  25. package/comate-engine/assets/skills/code-security/scripts/http_client.py +173 -0
  26. package/comate-engine/assets/skills/code-security/scripts/parse_scan_result.py +301 -0
  27. package/comate-engine/assets/skills/code-security/scripts/repair_vulnerability.py +261 -0
  28. package/comate-engine/assets/skills/code-security/scripts/report_chat.py +198 -0
  29. package/comate-engine/assets/skills/code-security/scripts/scan_vulnerability.py +316 -0
  30. package/comate-engine/assets/skills/code-security-comate/SKILL.md +219 -0
  31. package/comate-engine/assets/skills/code-security-comate/references/credential_hosting.md +102 -0
  32. package/comate-engine/assets/skills/code-security-comate/references/vul_repair-go_sql_injection.md +399 -0
  33. package/comate-engine/assets/skills/code-security-comate/references/vul_repair-java_sql_injection.md +591 -0
  34. package/comate-engine/assets/skills/code-security-comate/references/vul_repair-php_sql_injection.md +318 -0
  35. package/comate-engine/assets/skills/code-security-comate/references/vul_repair-python_sql_injection.md +198 -0
  36. package/comate-engine/assets/skills/code-security-comate/references/vul_repair_sensitive.md +219 -0
  37. package/comate-engine/assets/skills/code-security-comate/scripts/credential_hosting.py +87 -0
  38. package/comate-engine/assets/skills/code-security-comate/scripts/credential_poll.py +345 -0
  39. package/comate-engine/assets/skills/code-security-comate/scripts/http_client.py +173 -0
  40. package/comate-engine/assets/skills/code-security-comate/scripts/parse_scan_result.py +392 -0
  41. package/comate-engine/assets/skills/code-security-comate/scripts/repair_vulnerability.py +245 -0
  42. package/comate-engine/assets/skills/code-security-comate/scripts/report_chat.py +145 -0
  43. package/comate-engine/assets/skills/code-security-comate/scripts/scan_vulnerability.py +444 -0
  44. package/comate-engine/assets/skills/code-security-comate/scripts/utils.py +153 -0
  45. package/comate-engine/assets/skills/comate-docs-comate/SKILL.md +148 -0
  46. package/comate-engine/assets/skills/comate-docs-comate/references/doc-map-extended.md +78 -0
  47. package/comate-engine/assets/skills/comate-docs-comate/references/models-and-billing.md +51 -0
  48. package/comate-engine/assets/skills/comate-docs-comate/references/product-overview.md +73 -0
  49. package/comate-engine/assets/skills/comate-docs-comate/references/query_content.md +83 -0
  50. package/comate-engine/assets/skills/comate-docs-comate/references/query_repo.md +57 -0
  51. package/comate-engine/assets/skills/comate-docs-comate/scripts/ku_operator.py +1575 -0
  52. package/comate-engine/assets/skills/create-image-comate/SKILL.md +278 -0
  53. package/comate-engine/assets/skills/create-skill-comate/SKILL.md +308 -217
  54. package/comate-engine/assets/skills/create-skill-comate/agents/analyzer.md +274 -0
  55. package/comate-engine/assets/skills/create-skill-comate/agents/comparator.md +202 -0
  56. package/comate-engine/assets/skills/create-skill-comate/agents/grader.md +223 -0
  57. package/comate-engine/assets/skills/create-skill-comate/assets/eval_review.html +146 -0
  58. package/comate-engine/assets/skills/create-skill-comate/eval-viewer/generate_review.py +489 -0
  59. package/comate-engine/assets/skills/create-skill-comate/eval-viewer/viewer.html +1325 -0
  60. package/comate-engine/assets/skills/create-skill-comate/references/schemas.md +430 -0
  61. package/comate-engine/assets/skills/create-skill-comate/scripts/__init__.py +0 -0
  62. package/comate-engine/assets/skills/create-skill-comate/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  63. package/comate-engine/assets/skills/create-skill-comate/scripts/__pycache__/aggregate_benchmark.cpython-311.pyc +0 -0
  64. package/comate-engine/assets/skills/create-skill-comate/scripts/aggregate_benchmark.py +412 -0
  65. package/comate-engine/assets/skills/create-skill-comate/scripts/generate_report.py +334 -0
  66. package/comate-engine/assets/skills/create-skill-comate/scripts/package_skill.py +140 -0
  67. package/comate-engine/assets/skills/create-skill-comate/scripts/utils.py +53 -0
  68. package/comate-engine/assets/skills/find-skills-comate/SKILL.md +15 -12
  69. package/comate-engine/assets/skills/find-skills-comate/scripts/fetch_skills.py +32 -3
  70. package/comate-engine/assets/skills/get-ugate-token-comate/SKILL.md +159 -0
  71. package/comate-engine/assets/skills/get-ugate-token-comate/getUgateToken.py +150 -0
  72. package/comate-engine/assets/skills/icafe-comate/SKILL.md +240 -0
  73. package/comate-engine/assets/skills/icafe-comate/references/ai-workflows.md +233 -0
  74. package/comate-engine/assets/skills/icafe-comate/references/commands.md +1147 -0
  75. package/comate-engine/assets/skills/icafe-comate/references/error-handling.md +164 -0
  76. package/comate-engine/assets/skills/icafe-comate/references/git-auto-bindcard-workflow.md +201 -0
  77. package/comate-engine/assets/skills/icafe-comate/references/git-bindcard-workflow.md +327 -0
  78. package/comate-engine/assets/skills/icafe-comate/references/iql-syntax.md +327 -0
  79. package/comate-engine/assets/skills/icafe-comate/references/platform-concepts.md +317 -0
  80. package/comate-engine/assets/skills/icafe-comate/references/smart-create-workflow.md +171 -0
  81. package/comate-engine/assets/skills/icafe-comate/references/smart-find-workflow.md +127 -0
  82. package/comate-engine/assets/skills/icafe-comate/references/smart-update-workflow.md +118 -0
  83. package/comate-engine/assets/skills/icode-comate/SKILL.md +366 -0
  84. package/comate-engine/assets/skills/icode-comate/references/api/add_reviewers.md +44 -0
  85. package/comate-engine/assets/skills/icode-comate/references/api/build_fetch_command.md +89 -0
  86. package/comate-engine/assets/skills/icode-comate/references/api/check_repo_permission.md +89 -0
  87. package/comate-engine/assets/skills/icode-comate/references/api/create_branch.md +79 -0
  88. package/comate-engine/assets/skills/icode-comate/references/api/create_draft_comment.md +109 -0
  89. package/comate-engine/assets/skills/icode-comate/references/api/get_ai_cr_result.md +190 -0
  90. package/comate-engine/assets/skills/icode-comate/references/api/get_ai_review.md +97 -0
  91. package/comate-engine/assets/skills/icode-comate/references/api/get_diff_content.md +92 -0
  92. package/comate-engine/assets/skills/icode-comate/references/api/get_diff_file.md +88 -0
  93. package/comate-engine/assets/skills/icode-comate/references/api/get_machine_check.md +73 -0
  94. package/comate-engine/assets/skills/icode-comate/references/api/get_my_reviews.md +115 -0
  95. package/comate-engine/assets/skills/icode-comate/references/api/get_person_commit.md +89 -0
  96. package/comate-engine/assets/skills/icode-comate/references/api/get_person_repo.md +63 -0
  97. package/comate-engine/assets/skills/icode-comate/references/api/get_repo_branch.md +62 -0
  98. package/comate-engine/assets/skills/icode-comate/references/api/get_repo_config.md +91 -0
  99. package/comate-engine/assets/skills/icode-comate/references/api/get_repo_members.md +118 -0
  100. package/comate-engine/assets/skills/icode-comate/references/api/get_repo_reviews.md +91 -0
  101. package/comate-engine/assets/skills/icode-comate/references/api/get_review_comments.md +87 -0
  102. package/comate-engine/assets/skills/icode-comate/references/api/get_review_info.md +81 -0
  103. package/comate-engine/assets/skills/icode-comate/references/api/get_submit_settings.md +105 -0
  104. package/comate-engine/assets/skills/icode-comate/references/api/icode-api.md +86 -0
  105. package/comate-engine/assets/skills/icode-comate/references/api/publish_comments.md +72 -0
  106. package/comate-engine/assets/skills/icode-comate/references/api/set_review_score.md +58 -0
  107. package/comate-engine/assets/skills/icode-comate/references/api/start_ai_review.md +77 -0
  108. package/comate-engine/assets/skills/icode-comate/references/api/submit_review.md +50 -0
  109. package/comate-engine/assets/skills/icode-comate/references/api/trigger_ai_cr.md +63 -0
  110. package/comate-engine/assets/skills/icode-comate/references/feature/add-reviewer.md +92 -0
  111. package/comate-engine/assets/skills/icode-comate/references/feature/fix-machine-check.md +144 -0
  112. package/comate-engine/assets/skills/icode-comate/references/feature/merge-cr.md +100 -0
  113. package/comate-engine/assets/skills/icode-comate/references/feature/ssh-setup.md +106 -0
  114. package/comate-engine/assets/skills/icode-comate/references/feature/submit-acr.md +135 -0
  115. package/comate-engine/assets/skills/icode-comate/references/feature/submit-cr.md +123 -0
  116. package/comate-engine/assets/skills/icode-comate/references/git/clone.md +67 -0
  117. package/comate-engine/assets/skills/icode-comate/references/git/icode-git.md +68 -0
  118. package/comate-engine/assets/skills/icode-comate/references/git/push.md +64 -0
  119. package/comate-engine/assets/skills/icode-comate/references/git/push_cr.md +103 -0
  120. package/comate-engine/assets/skills/icode-comate/references/install.md +144 -0
  121. package/comate-engine/assets/skills/icode-comate/references/login.md +111 -0
  122. package/comate-engine/assets/skills/icode-comate/scripts/add-reviewer.sh +154 -0
  123. package/comate-engine/assets/skills/icode-comate/scripts/common.sh +145 -0
  124. package/comate-engine/assets/skills/icode-comate/scripts/fix-machine-check.sh +131 -0
  125. package/comate-engine/assets/skills/icode-comate/scripts/merge-cr.sh +105 -0
  126. package/comate-engine/assets/skills/icode-comate/scripts/ssh-setup.sh +159 -0
  127. package/comate-engine/assets/skills/icode-comate/scripts/submit-acr.sh +236 -0
  128. package/comate-engine/assets/skills/icode-comate/scripts/submit-cr.sh +104 -0
  129. package/comate-engine/assets/skills/icode-comate/scripts/test-preflight.sh +89 -0
  130. package/comate-engine/assets/skills/ku-operator-comate/SKILL.md +121 -0
  131. package/comate-engine/assets/skills/ku-operator-comate/examples.md +190 -0
  132. package/comate-engine/assets/skills/ku-operator-comate/references/add_member.md +49 -0
  133. package/comate-engine/assets/skills/ku-operator-comate/references/change_scope.md +38 -0
  134. package/comate-engine/assets/skills/ku-operator-comate/references/copy_doc.md +50 -0
  135. package/comate-engine/assets/skills/ku-operator-comate/references/create_doc.md +61 -0
  136. package/comate-engine/assets/skills/ku-operator-comate/references/delete_doc.md +31 -0
  137. package/comate-engine/assets/skills/ku-operator-comate/references/edit_content.md +568 -0
  138. package/comate-engine/assets/skills/ku-operator-comate/references/move_doc.md +45 -0
  139. package/comate-engine/assets/skills/ku-operator-comate/references/query_comment.md +79 -0
  140. package/comate-engine/assets/skills/ku-operator-comate/references/query_content.md +83 -0
  141. package/comate-engine/assets/skills/ku-operator-comate/references/query_flowchart.md +84 -0
  142. package/comate-engine/assets/skills/ku-operator-comate/references/query_permission.md +38 -0
  143. package/comate-engine/assets/skills/ku-operator-comate/references/query_recent_view.md +67 -0
  144. package/comate-engine/assets/skills/ku-operator-comate/references/query_repo.md +57 -0
  145. package/comate-engine/assets/skills/ku-operator-comate/references/query_user_info.md +37 -0
  146. package/comate-engine/assets/skills/ku-operator-comate/references/update_member.md +41 -0
  147. package/comate-engine/assets/skills/ku-operator-comate/references/upload_attachment.md +52 -0
  148. package/comate-engine/assets/skills/ku-operator-comate/scripts/ku_operator.py +1575 -0
  149. package/comate-engine/node_modules/better-sqlite3/node_modules/.bin/prebuild-install +2 -2
  150. package/comate-engine/node_modules/tree-sitter-bash/node_modules/.bin/node-gyp-build +2 -2
  151. package/comate-engine/node_modules/tree-sitter-bash/node_modules/.bin/node-gyp-build-optional +2 -2
  152. package/comate-engine/node_modules/tree-sitter-bash/node_modules/.bin/node-gyp-build-test +2 -2
  153. package/comate-engine/package.json +2 -0
  154. package/comate-engine/server.js +263 -79
  155. package/dist/bundle/index.js +3 -3
  156. package/package.json +1 -1
  157. package/comate-engine/assets/skills/figma2code-comate/codeConnect.md +0 -37
  158. package/comate-engine/assets/skills/figma2code-comate/designToken.md +0 -3
  159. package/comate-engine/assets/skills/figma2code-comate/f2cMcp.md +0 -59
  160. package/comate-engine/assets/skills/smart-commit/SKILL.md +0 -646
  161. package/comate-engine/node_modules/@comate/plugin-host/dist/index-AZIho4HV.js +0 -1
  162. package/comate-engine/node_modules/@comate/plugin-host/dist/user-BIpzRUfb.js +0 -44
  163. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/references/issue_type_mapping.json +0 -0
  164. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/references/query_reference.md +0 -0
  165. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/compat.py +0 -0
  166. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/create_card_cli.py +0 -0
  167. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/icafe/__init__.py +0 -0
  168. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/logger.py +0 -0
  169. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/recognize_card_cli.py +0 -0
@@ -0,0 +1,301 @@
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()
@@ -0,0 +1,261 @@
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()