@comate/zulu 1.2.1-beta.1 → 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 +8 -8
  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,173 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 基于 urllib 的轻量 HTTP 客户端,零第三方依赖。
4
+ 提供 GET / POST / PUT 方法,支持 JSON 请求和响应。
5
+ 当 ssl 模块不可用时(如 libssl 版本不匹配),自动回退到 curl 子进程。
6
+ 所有脚本共用日志配置,写入 skill/logs/<日期>.log,自动清理 7 天前的日志。
7
+ """
8
+
9
+ import datetime
10
+ import glob
11
+ import json
12
+ import logging
13
+ import os
14
+ import subprocess
15
+
16
+ try:
17
+ import ssl
18
+ _SSL_AVAILABLE = True
19
+ except ImportError:
20
+ _SSL_AVAILABLE = False
21
+
22
+ try:
23
+ from urllib.request import Request, urlopen
24
+ from urllib.error import HTTPError, URLError
25
+ except ImportError:
26
+ from urllib2 import Request, urlopen, HTTPError, URLError
27
+
28
+ # ---- 统一日志配置 ----
29
+ _scripts_dir = os.path.dirname(os.path.abspath(__file__))
30
+ _skill_dir = os.path.dirname(_scripts_dir)
31
+ _log_dir = os.path.join(_skill_dir, "logs")
32
+ os.makedirs(_log_dir, exist_ok=True)
33
+
34
+ # 清理超过 7 天的日志文件
35
+ _now = datetime.datetime.now()
36
+ for _f in glob.glob(os.path.join(_log_dir, "*.log")):
37
+ try:
38
+ _mtime = datetime.datetime.fromtimestamp(os.path.getmtime(_f))
39
+ if (_now - _mtime).days > 7:
40
+ os.remove(_f)
41
+ except OSError:
42
+ pass
43
+
44
+ _log_file = os.path.join(_log_dir, _now.strftime("%Y-%m-%d") + ".log")
45
+ logging.basicConfig(
46
+ filename=_log_file,
47
+ level=logging.INFO,
48
+ format="%(asctime)s [%(name)s] %(levelname)s %(message)s",
49
+ )
50
+ logger = logging.getLogger("http")
51
+
52
+
53
+ def _build_request(url, method="GET", headers=None, json_body=None):
54
+ """构造 urllib Request 对象。"""
55
+ data = None
56
+ if json_body is not None:
57
+ data = json.dumps(json_body).encode("utf-8")
58
+
59
+ req = Request(url, data=data)
60
+ req.get_method = lambda: method
61
+
62
+ if headers:
63
+ for k, v in headers.items():
64
+ req.add_header(k, v)
65
+
66
+ if data is not None and not req.has_header("Content-type"):
67
+ req.add_header("Content-Type", "application/json; charset=utf-8")
68
+
69
+ return req
70
+
71
+
72
+ def _create_ssl_context():
73
+ """创建 SSL 上下文。"""
74
+ ctx = ssl.create_default_context()
75
+ ctx.check_hostname = False
76
+ ctx.verify_mode = ssl.CERT_NONE
77
+ return ctx
78
+
79
+
80
+ def _log_safe_headers(headers):
81
+ """提取可安全记录的请求头。"""
82
+ safe = {}
83
+ if headers:
84
+ for k in ("SAST-Chat-ID", "SAST-Request-ID", "Comate-User-Id", "Comate-Username"):
85
+ if k in headers:
86
+ safe[k] = headers[k]
87
+ return safe
88
+
89
+
90
+ def _request_curl(url, method="GET", headers=None, json_body=None, timeout=120):
91
+ """ssl 不可用时,通过 curl 子进程发送请求。"""
92
+ cmd = ["curl", "-s", "-S", "--insecure", "-X", method, "--max-time", str(timeout)]
93
+
94
+ if headers:
95
+ for k, v in headers.items():
96
+ cmd += ["-H", "{}: {}".format(k, v)]
97
+
98
+ if json_body is not None:
99
+ cmd += ["-H", "Content-Type: application/json; charset=utf-8"]
100
+ cmd += ["-d", json.dumps(json_body)]
101
+
102
+ cmd.append(url)
103
+
104
+ logger.info("[curl] %s %s headers=%s", method, url, json.dumps(_log_safe_headers(headers)))
105
+ try:
106
+ proc = subprocess.run(cmd, capture_output=True, timeout=timeout + 10)
107
+ except FileNotFoundError:
108
+ raise RuntimeError(
109
+ "ssl 模块不可用且未找到 curl 命令。"
110
+ "请安装 curl 或修复 Python ssl 依赖(安装 libssl1.1 或重新编译 Python)。"
111
+ )
112
+
113
+ if proc.returncode != 0:
114
+ stderr_text = proc.stderr.decode("utf-8", errors="replace").strip()
115
+ logger.error("[curl] %s %s -> curl exit %d: %s", method, url, proc.returncode, stderr_text)
116
+ raise RuntimeError("curl 请求失败 (exit {}): {}".format(proc.returncode, stderr_text))
117
+
118
+ body = proc.stdout.decode("utf-8")
119
+ logger.info("[curl] %s %s -> OK (%d bytes)", method, url, len(body))
120
+ return json.loads(body)
121
+
122
+
123
+ def request(url, method="GET", headers=None, json_body=None, timeout=120):
124
+ """
125
+ 发送 HTTP 请求,返回解析后的 JSON dict。
126
+ 当 ssl 模块不可用时自动回退到 curl。
127
+
128
+ :param url: 请求 URL
129
+ :param method: HTTP 方法 (GET/POST/PUT)
130
+ :param headers: 请求头 dict
131
+ :param json_body: JSON 请求体 (自动序列化)
132
+ :param timeout: 超时秒数
133
+ :return: 响应 JSON dict
134
+ :raises: HTTPError, URLError, RuntimeError
135
+ """
136
+ if not _SSL_AVAILABLE:
137
+ return _request_curl(url, method, headers, json_body, timeout)
138
+
139
+ # 记录请求(仅 URL 和关键 header,不记录 body 避免日志过大)
140
+ logger.info("%s %s headers=%s", method, url, json.dumps(_log_safe_headers(headers)))
141
+
142
+ req = _build_request(url, method, headers, json_body)
143
+ ctx = _create_ssl_context()
144
+
145
+ try:
146
+ resp = urlopen(req, timeout=timeout, context=ctx)
147
+ status = resp.getcode()
148
+ body = resp.read().decode("utf-8")
149
+ logger.info("%s %s -> %d (%d bytes)", method, url, status, len(body))
150
+ return json.loads(body)
151
+ except HTTPError as e:
152
+ error_body = ""
153
+ try:
154
+ error_body = e.read().decode("utf-8")[:500]
155
+ except Exception:
156
+ pass
157
+ logger.error("%s %s -> HTTP %d: %s", method, url, e.code, error_body)
158
+ raise
159
+
160
+
161
+ def get(url, headers=None, timeout=120):
162
+ """发送 GET 请求,返回 JSON。"""
163
+ return request(url, method="GET", headers=headers, timeout=timeout)
164
+
165
+
166
+ def post(url, headers=None, json_body=None, timeout=120):
167
+ """发送 POST 请求,返回 JSON。"""
168
+ return request(url, method="POST", headers=headers, json_body=json_body, timeout=timeout)
169
+
170
+
171
+ def put(url, headers=None, json_body=None, timeout=120):
172
+ """发送 PUT 请求,返回 JSON。"""
173
+ return request(url, method="PUT", headers=headers, json_body=json_body, timeout=timeout)
@@ -0,0 +1,392 @@
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
+ "false_positive_count": 2,
18
+ "analyzing_count": 1,
19
+ "bundle_hash": "xxx",
20
+ "common_vuls": [ ... ],
21
+ "sensitive_vuls": [ ... ],
22
+ "false_positive_vuls": [ ... ],
23
+ "analyzing_vuls": [ ... ]
24
+ }
25
+
26
+ 每个漏洞条目包含:
27
+ {
28
+ "ruleID": "codescan_java_mybatis-java_sqli",
29
+ "name": "Sql 注入漏洞",
30
+ "description": "...",
31
+ "suggestion": "...",
32
+ "level": "ERROR",
33
+ "level_cn": "严重",
34
+ "file": "src/main/java/...",
35
+ "startLine": 12,
36
+ "endLine": 12,
37
+ "hash": "abc123...",
38
+ "is_sensitive": false,
39
+ "aiAnalysisStatus": 0,
40
+ "aiAnalysisStatusText": "无需分析",
41
+ "codeFlows": [ {"file": "...", "line": 63, "message": "..."}, ... ]
42
+ }
43
+
44
+ aiAnalysisStatus 说明:
45
+ 0 - 无需分析
46
+ 1 - 分析中
47
+ 2 - 真实漏洞
48
+ 3 - 误报(不进入修复流程)
49
+ """
50
+
51
+ import argparse
52
+ from collections import OrderedDict
53
+ import json
54
+ import os
55
+ import sys
56
+
57
+
58
+ LEVEL_MAP = {
59
+ "ERROR": "严重",
60
+ "WARNING": "高危",
61
+ "NOTE": "中危",
62
+ "NONE": "低危",
63
+ }
64
+
65
+ # 等级排序优先级(越小越严重)
66
+ LEVEL_PRIORITY = {
67
+ "ERROR": 0,
68
+ "WARNING": 1,
69
+ "NOTE": 2,
70
+ "NONE": 3,
71
+ }
72
+
73
+ # AI 分析状态映射
74
+ AI_ANALYSIS_STATUS_MAP = {
75
+ 0: "无需分析",
76
+ 1: "分析中",
77
+ 2: "真实漏洞",
78
+ 3: "误报",
79
+ }
80
+
81
+
82
+ def parse_scan_result(scan_result):
83
+ # type: (dict) -> dict
84
+ """解析扫描结果,返回结构化漏洞数据。
85
+
86
+ aiAnalysisStatus=3 (误报) 和 aiAnalysisStatus=1 (分析中) 的漏洞会被单独归类,不进入修复流程。
87
+ """
88
+ data = scan_result.get("data", {})
89
+ runs = data.get("sarif", {}).get("runs", []) or data.get("runs", [])
90
+
91
+ # 提取 bundleHash(由 scan_vulnerability.py 写入顶层)
92
+ bundle_hash = scan_result.get("bundleHash", "")
93
+
94
+ # 建立 ruleID -> rule 映射
95
+ rule_map = {}
96
+ for run in runs:
97
+ tool = run.get("tool", {})
98
+ # 兼容 rules 在 tool 或 tool.driver 下
99
+ rules = tool.get("rules", []) or tool.get("driver", {}).get("rules", [])
100
+ for rule in rules:
101
+ rule_id = rule.get("id", "")
102
+ if rule_id:
103
+ rule_map[rule_id] = rule
104
+
105
+ # 解析漏洞结果
106
+ common_vuls = []
107
+ sensitive_vuls = []
108
+ false_positive_vuls = [] # 误报漏洞单独存放
109
+ analyzing_vuls = [] # AI 分析中的漏洞单独存放(不进入修复流程)
110
+
111
+ for run in runs:
112
+ results = run.get("results", []) or run.get("result", [])
113
+ for result in results:
114
+ rule_id = result.get("ruleID", "") or result.get("ruleId", "")
115
+ rule = rule_map.get(rule_id, {})
116
+
117
+ # 基础信息
118
+ name = rule.get("name", rule_id)
119
+ description = rule.get("description", "") or result.get("message", {}).get("text", "")
120
+ suggestion = rule.get("suggestion", "")
121
+ level_config = rule.get("defaultConfiguration", {})
122
+ level = level_config.get("level", "NONE") if level_config else "NONE"
123
+ level_cn = LEVEL_MAP.get(level, "低危")
124
+ vul_hash = result.get("properties", {}).get("hash", "")
125
+
126
+ # AI 分析状态
127
+ ai_status = result.get("properties", {}).get("aiAnalysisStatus", 0)
128
+ ai_status_text = AI_ANALYSIS_STATUS_MAP.get(ai_status, "未知")
129
+
130
+ # 位置信息
131
+ locations = result.get("locations", [])
132
+ file_uri = ""
133
+ start_line = 0
134
+ end_line = 0
135
+ if locations:
136
+ phys = locations[0].get("physicalLocation", {})
137
+ artifact = phys.get("artifactLocation", {})
138
+ file_uri = artifact.get("uri", "")
139
+ region = artifact.get("region", {})
140
+ start_line = region.get("startLine", 0)
141
+ end_line = region.get("endLine", start_line)
142
+
143
+ # 数据流信息
144
+ code_flows_raw = result.get("codeFlows", [])
145
+ code_flows = []
146
+ if code_flows_raw:
147
+ thread_flows = code_flows_raw[0].get("threadFlows", [])
148
+ if thread_flows:
149
+ for loc_wrapper in thread_flows[0].get("locations", []):
150
+ loc = loc_wrapper.get("location", {})
151
+ loc_phys = loc.get("physicalLocation", {})
152
+ loc_file = loc_phys.get("artifactLocation", {}).get("uri", "")
153
+ loc_region = loc_phys.get("region", {})
154
+ loc_line = loc_region.get("startLine", 0)
155
+ loc_msg = loc.get("message", {}).get("text", "")
156
+ code_flows.append({
157
+ "file": loc_file,
158
+ "line": loc_line,
159
+ "message": loc_msg,
160
+ })
161
+
162
+ is_sensitive = "sensitive" in rule_id.lower()
163
+
164
+ vul_entry = {
165
+ "ruleID": rule_id,
166
+ "name": name,
167
+ "description": description,
168
+ "suggestion": suggestion,
169
+ "level": level,
170
+ "level_cn": level_cn,
171
+ "file": file_uri,
172
+ "startLine": start_line,
173
+ "endLine": end_line,
174
+ "hash": vul_hash,
175
+ "is_sensitive": is_sensitive,
176
+ "aiAnalysisStatus": ai_status,
177
+ "aiAnalysisStatusText": ai_status_text,
178
+ "codeFlows": code_flows,
179
+ }
180
+
181
+ # 根据 AI 分析状态分类
182
+ if ai_status == 3: # 误报
183
+ false_positive_vuls.append(vul_entry)
184
+ elif ai_status == 1: # 分析中,不进入修复流程
185
+ analyzing_vuls.append(vul_entry)
186
+ elif is_sensitive:
187
+ sensitive_vuls.append(vul_entry)
188
+ else:
189
+ common_vuls.append(vul_entry)
190
+
191
+ # 按严重程度排序
192
+ def sort_key(v):
193
+ return (LEVEL_PRIORITY.get(v["level"], 99), v["file"], v["startLine"])
194
+
195
+ common_vuls.sort(key=sort_key)
196
+ sensitive_vuls.sort(key=sort_key)
197
+ false_positive_vuls.sort(key=sort_key)
198
+ analyzing_vuls.sort(key=sort_key)
199
+
200
+ return {
201
+ "total": len(common_vuls) + len(sensitive_vuls) + len(false_positive_vuls) + len(analyzing_vuls),
202
+ "common_count": len(common_vuls),
203
+ "sensitive_count": len(sensitive_vuls),
204
+ "false_positive_count": len(false_positive_vuls),
205
+ "analyzing_count": len(analyzing_vuls),
206
+ "bundle_hash": bundle_hash,
207
+ "common_vuls": common_vuls,
208
+ "sensitive_vuls": sensitive_vuls,
209
+ "false_positive_vuls": false_positive_vuls,
210
+ "analyzing_vuls": analyzing_vuls,
211
+ }
212
+
213
+
214
+ def _make_file_link(file_path, line, project_dir=""):
215
+ # type: (str, int, str) -> str
216
+ """生成可点击的文件链接。"""
217
+ if not file_path:
218
+ return "未知位置"
219
+ basename = os.path.basename(file_path)
220
+ label = "{}:{}".format(basename, line)
221
+ if project_dir:
222
+ abs_path = os.path.join(project_dir, file_path)
223
+ else:
224
+ abs_path = file_path
225
+ return "[{}]({}#L{})".format(label, abs_path, line)
226
+
227
+
228
+ def format_vul_report(vuls, title="漏洞报告", project_dir=""):
229
+ # type: (list, str, str) -> str
230
+ """将漏洞列表按类型分组格式化为 Markdown 报告。
231
+
232
+ 同一 ruleID 的漏洞归为一组,描述/等级/修复建议只展示一次,
233
+ 漏洞位置列表化展示,数据流用 <details> 折叠。
234
+ """
235
+ if not vuls:
236
+ return ""
237
+
238
+ # 按 ruleID 分组,保持原有排序
239
+ groups = OrderedDict() # type: OrderedDict[str, list]
240
+ for vul in vuls:
241
+ rule_id = vul["ruleID"]
242
+ if rule_id not in groups:
243
+ groups[rule_id] = []
244
+ groups[rule_id].append(vul)
245
+
246
+ lines = ["**{}**\n".format(title)]
247
+
248
+ for group_idx, (rule_id, group_vuls) in enumerate(groups.items(), 1):
249
+ rep = group_vuls[0] # 取第一个作为代表获取公共信息
250
+ count = len(group_vuls)
251
+ count_suffix = "({} 处)".format(count) if count > 1 else ""
252
+
253
+ lines.append("{}. **{}**{}".format(group_idx, rep["name"], count_suffix))
254
+ if rep["description"]:
255
+ lines.append("- **漏洞描述**:{}".format(rep["description"]))
256
+ lines.append("- **漏洞等级**:{}".format(rep["level_cn"]))
257
+ if rep["suggestion"]:
258
+ lines.append("- **修复建议**:{}".format(rep["suggestion"]))
259
+
260
+ # 漏洞位置列表
261
+ lines.append("- **漏洞位置**:")
262
+ for vul in group_vuls:
263
+ loc_link = _make_file_link(vul["file"], vul["startLine"], project_dir)
264
+ lines.append(" - {}".format(loc_link))
265
+
266
+ # 数据流折叠展示
267
+ if vul["codeFlows"]:
268
+ lines.append(" <details><summary>数据流</summary>\n")
269
+ for hop_idx, hop in enumerate(vul["codeFlows"], 1):
270
+ hop_link = _make_file_link(hop["file"], hop["line"], project_dir)
271
+ hop_msg = hop.get("message", "")
272
+ if hop_msg:
273
+ lines.append(" {}. {} — {}".format(hop_idx, hop_link, hop_msg))
274
+ else:
275
+ lines.append(" {}. {}".format(hop_idx, hop_link))
276
+ lines.append("\n </details>")
277
+ lines.append("")
278
+
279
+ return "\n".join(lines)
280
+
281
+
282
+ def format_full_report(parsed, project_dir=""):
283
+ # type: (dict, str) -> str
284
+ """生成完整的展示报告(包含各类漏洞)。"""
285
+ parts = []
286
+
287
+ common_count = parsed["common_count"]
288
+ sensitive_count = parsed["sensitive_count"]
289
+ false_positive_count = parsed.get("false_positive_count", 0)
290
+ analyzing_count = parsed.get("analyzing_count", 0)
291
+ real_vul_count = common_count + sensitive_count # 需要处理的真实漏洞数
292
+
293
+ # 汇总信息
294
+ summary_parts = []
295
+ if real_vul_count > 0:
296
+ if common_count > 0 and sensitive_count > 0:
297
+ summary_parts.append("**{}** 个普通漏洞和 **{}** 个硬编码漏洞".format(common_count, sensitive_count))
298
+ elif common_count > 0:
299
+ summary_parts.append("**{}** 个普通漏洞".format(common_count))
300
+ elif sensitive_count > 0:
301
+ summary_parts.append("**{}** 个硬编码漏洞".format(sensitive_count))
302
+
303
+ if false_positive_count > 0:
304
+ summary_parts.append("**{}** 个误报(已由 AI 分析确认,无需修复)".format(false_positive_count))
305
+
306
+ if summary_parts:
307
+ parts.append("扫描发现 {}。\n".format(",".join(summary_parts)))
308
+ else:
309
+ if analyzing_count > 0:
310
+ parts.append("扫描完成,**{}** 个漏洞正在 AI 分析中,暂未发现已确认的漏洞。\n".format(analyzing_count))
311
+ else:
312
+ parts.append("扫描完成,未发现漏洞。\n")
313
+ return "\n".join(parts)
314
+
315
+ if analyzing_count > 0:
316
+ parts.append("另有 **{}** 个漏洞正在 AI 分析中,分析完成后可能会被判定为误报而排除,分析期间暂不处理。\n".format(analyzing_count))
317
+
318
+ # 只有误报没有真实漏洞的情况
319
+ if real_vul_count == 0 and false_positive_count > 0:
320
+ parts.append("所有检测到的漏洞均已被 AI 分析确认为误报,无需进行修复。\n")
321
+ if parsed.get("false_positive_vuls"):
322
+ parts.append(format_vul_report(parsed["false_positive_vuls"], "误报漏洞列表(仅供参考)", project_dir))
323
+ return "\n".join(parts)
324
+
325
+ if parsed["common_vuls"]:
326
+ parts.append(format_vul_report(parsed["common_vuls"], "普通漏洞报告", project_dir))
327
+
328
+ if parsed["sensitive_vuls"]:
329
+ parts.append(format_vul_report(parsed["sensitive_vuls"], "硬编码漏洞报告", project_dir))
330
+
331
+ # 误报漏洞折叠展示
332
+ if false_positive_count > 0:
333
+ parts.append("\n<details><summary>误报漏洞({} 个,已由 AI 确认无需修复)</summary>\n".format(false_positive_count))
334
+ for vul in parsed.get("false_positive_vuls", []):
335
+ loc_link = _make_file_link(vul["file"], vul["startLine"], project_dir)
336
+ parts.append("- {} - {}".format(vul["name"], loc_link))
337
+ parts.append("\n</details>")
338
+
339
+ # AI 分析中漏洞折叠展示
340
+ if analyzing_count > 0:
341
+ parts.append("\n<details><summary>AI 分析中({} 个,分析完成前暂不处理)</summary>\n".format(analyzing_count))
342
+ for vul in parsed.get("analyzing_vuls", []):
343
+ loc_link = _make_file_link(vul["file"], vul["startLine"], project_dir)
344
+ parts.append("- {} - {}".format(vul["name"], loc_link))
345
+ parts.append("\n</details>")
346
+
347
+ return "\n".join(parts)
348
+
349
+
350
+ def main():
351
+ """
352
+ 主函数入口,解析命令行参数并处理扫描结果
353
+
354
+ Args:
355
+ 无(通过命令行参数 --scan-result 和 --output-dir 传入)
356
+
357
+ Returns:
358
+ 无(结果直接输出到标准输出和文件)
359
+ """
360
+ parser = argparse.ArgumentParser(description="扫描结果解析与展示工具")
361
+ parser.add_argument("--scan-result", required=True, help="扫描结果文件路径 (scan_result.json)")
362
+ parser.add_argument("--output-dir", default=None, help="结构化结果输出目录,默认与输入文件同目录")
363
+ parser.add_argument("--project-dir", default="", help="项目根目录,用于生成可点击的绝对路径链接")
364
+ args = parser.parse_args()
365
+
366
+ # 读取扫描结果
367
+ try:
368
+ with open(args.scan_result, "r", encoding="utf-8") as f:
369
+ scan_result = json.load(f)
370
+ except Exception as e:
371
+ print("错误: 读取扫描结果失败 {}: {}".format(args.scan_result, e), file=sys.stderr)
372
+ sys.exit(1)
373
+
374
+ # 解析
375
+ parsed = parse_scan_result(scan_result)
376
+
377
+ # 输出 Markdown 报告到标准输出
378
+ report = format_full_report(parsed, args.project_dir)
379
+ print(report)
380
+
381
+ # 保存结构化 JSON
382
+ # 默认输出到输入文件同目录,自然跟随项目隔离
383
+ output_dir = args.output_dir or os.path.dirname(os.path.abspath(args.scan_result))
384
+ os.makedirs(output_dir, exist_ok=True)
385
+ output_file = os.path.join(output_dir, "parsed_result.json")
386
+ with open(output_file, "w", encoding="utf-8") as f:
387
+ json.dump(parsed, f, ensure_ascii=False, indent=2)
388
+ print(output_file, file=sys.stderr)
389
+
390
+
391
+ if __name__ == "__main__":
392
+ main()