@comate/zulu 1.2.1-beta.2 → 1.3.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 (170) 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 +170 -46
  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/node_modules/better-sqlite3/build/Release/better_sqlite3.node +0 -0
  164. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/references/issue_type_mapping.json +0 -0
  165. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/references/query_reference.md +0 -0
  166. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/compat.py +0 -0
  167. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/create_card_cli.py +0 -0
  168. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/icafe/__init__.py +0 -0
  169. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/logger.py +0 -0
  170. /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()