@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,219 @@
1
+ # 敏感信息硬编码漏洞修复流程
2
+
3
+ 修复漏洞分为以下三个步骤:
4
+ 1. 读取漏洞报告
5
+ 2. 修复硬编码漏洞
6
+ 3. 引入SDK(如果需要)
7
+
8
+ ## 读取漏洞报告
9
+
10
+ 基于凭证配置网页回传的数据获取漏洞报告,示例如下:
11
+ ```json
12
+ {
13
+ "scanChatID": "从 credential_poll 返回的 chatUUID",
14
+ "repo": {
15
+ "language": "java",
16
+ "framework": "springboot"
17
+ },
18
+ "deployment": {
19
+ "platform": 2,
20
+ "platformName": "ipipe"
21
+ },
22
+ "files": [
23
+ {
24
+ "name": "src/main/resources/application.properties",
25
+ "hash": "文件SHA256",
26
+ "vulList": [
27
+ {
28
+ "ruleID": "codescan_generic_password-config_sensitive",
29
+ "line": 35,
30
+ "hash": "漏洞hash",
31
+ "extra": {
32
+ "secret": {
33
+ "credentialName": "KL_SPRING_DATASOURCE_PASSWORD",
34
+ "start": {"col": 28, "line": 35},
35
+ "end": {"col": 43, "line": 35}
36
+ }
37
+ }
38
+ }
39
+ ]
40
+ }
41
+ ],
42
+ "trigger": 1,
43
+ "type": 4
44
+ }
45
+ ```
46
+ 各字段说明如下:
47
+ * repo:代码库信息
48
+ * language:代码语言
49
+ * framework:代码框架
50
+ * deployment:部署信息
51
+ * platform:部署平台,1 表示 cnap,2 表示 ipipe,3 表示 opera,4 表示 datamanage
52
+ * platformName:部署平台名称(如 ipipe、cnap、opera、datamanage)
53
+ * credential_id:凭证 ID(platform 为 4 时使用,用于引入 keyless-sdk)
54
+ * files:文件信息
55
+ * name:漏洞文件的相对路径
56
+ * vulList:漏洞列表
57
+ * extra.secret.start:敏感信息的开始位置(行、列)
58
+ * extra.secret.end:敏感信息的结束位置(行、列)
59
+ * extra.secret.credentialName:建议使用的环境变量名称
60
+
61
+ ## 修复漏洞
62
+ 硬编码漏洞修复的本质就是改变原来在代码中的硬编码敏感信息写法,改为从环境变量中读取敏感信息。修复时遍历漏洞报告中的所有文件和漏洞,逐个修复,按以下流程进行处理。
63
+
64
+ ### 代码文件
65
+ 如果漏洞文件是代码文件,比如 java、go、php、py 等,则根据各语言的写法生成读取环境变量的代码,并替换掉原来的硬编码敏感信息,注意有以下几点要求:
66
+ 1. 与环境变量读取无关的其他代码和字符不要做任何改动
67
+ 2. 如果漏洞行是被引号包裹的纯字符串,输出时保留其结构不变,仍然可以直接执行字符串操作,但要避免空字符串的拼接
68
+ 3. 不要给出环境变量默认值
69
+ 4. 如果代码开头存在空格、tab等缩进,保留原始代码的缩进,不要清除两端的空白字符
70
+ 5. 如果是 python 语言,使用 os.environ 的方式获取环境变量,而不是 os.getenv
71
+ 6. 如果是 go 语言,不能在 const 中读取环境变量,在 const 下方重新定义读取代码,并删除 const 的硬编码的值
72
+ 7. 如果是 java 语言,且 platform 为 4 时,则采用 System.getProperty 的语法读取变量
73
+ 8. 如果原文件中缺失读取环境变量所需的第三方库,则自动引入,比如 python 的 os 库,go 的 os 库等
74
+
75
+ ### 配置文件
76
+ 如果漏洞文件是配置文件,比如 yml、properties、ini 等,则结合语言和框架共同决定如何修改代码,修改原则如下:
77
+ 1. 如果语言为 go,框架为 gdp,toml 后缀的文件直接使用特定的占位符替换敏感信息,占位符的环境变量名称根据 credential_name 命名,示例如下:
78
+ ```toml
79
+ // 修复前
80
+ password=123123123
81
+ // 修复后
82
+ password=${env.KL_PASSWORD}
83
+ ```
84
+ 2. 除第一种情况之外,其他语言、框架、配置文件类型,使用常规的环境变量占位符替换敏感信息,占位符的环境变量名称根据 credential_name 命名。
85
+ ```toml
86
+ // 修复前
87
+ password=123123123
88
+ // 修复后
89
+ password=${KL_PASSWORD}
90
+ ```
91
+
92
+ 漏洞报告可能涉及多个文件,修复时按文件进行聚合,优先将一个文件中的漏洞全部修复完成再修复其他漏洞。
93
+
94
+ ## 引入SDK
95
+ 从第一个漏洞报告读取数据,如果 platform 为 4 时需要引入 keyless-sdk 并添加初始化代码。通过该 sdk 将凭证注入到环境变量中,然后其他位置的代码才能读取到环境变量。注意,只有平台为 4 时才需要引入 sdk,其他平台不需要。不同语言 sdk 及初始化代码添加方式如下。
96
+
97
+ #### java 语言
98
+ pom.xml 文件中添加 keyless-sdk 依赖,其中的注释需要保留。
99
+ ```xml
100
+ <!-- keyless-sdk dependency -->
101
+ <dependency>
102
+ <groupId>com.baidu.xbu-data</groupId>
103
+ <artifactId>keyless-sdk</artifactId>
104
+ <version>1.0.2</version>
105
+ </dependency>
106
+ ```
107
+ 项目启动的函数中添加以下初始化代码,注意其中的 credentialID 需要与漏洞报告中的 credential_id 保持一致。
108
+ ```java
109
+ import com.baidu.keyless.KeylessClient;
110
+
111
+ public class KeylessAppCredentialDemo {
112
+ public static void main(String[] args) {
113
+ // 初始化 keyless-sdk 开始
114
+ // step1: 设置 credentialID 构建 client,详情可参考 https://ku.baidu-int.com/d/BRnvQROwD8akQY
115
+ String credentialID = "appDemo_prod";
116
+ KeylessClient keylessClient = KeylessClient.builder()
117
+ .credentialId(credentialID)
118
+ .build();
119
+ // step2: 获取凭证信息并注入到系统环境变量中
120
+ try {
121
+ keylessClient.load();
122
+ } catch (Exception e) {
123
+ System.out.println("load keyless client error: " + e.getMessage());
124
+ }
125
+ // 初始化 keyless-sdk 结束
126
+ // 以下为其他原始代码
127
+ ... ...
128
+ }
129
+ }
130
+ ```
131
+
132
+ #### go 语言
133
+ go.mod 文件中添加 keyless-sdk 依赖,其中的注释需要保留。
134
+ ```mod
135
+ require (
136
+ icode.baidu.com/baidu/xbu-data/things-go keyless-sdk-2.2.0 // keyless-sdk dependency
137
+ )
138
+ ```
139
+ 项目启动的函数中添加以下初始化代码,注意其中的 CredentialID 需要与漏洞报告中的 credential_id 保持一致。
140
+ ```go
141
+ package main
142
+
143
+ import (
144
+ "icode.baidu.com/baidu/xbu-data/things-go/pkg/keyless"
145
+ )
146
+
147
+ func main() {
148
+ // 初始化 keyless-sdk 开始
149
+ // step1: 设置 CredentialID 构建 client,详情可参考 https://ku.baidu-int.com/d/G_QqzMQrQR9_K_
150
+ req := &keyless.GetCredentialReq{
151
+ CredentialID: "appDemo_prod", // 凭证标识
152
+ }
153
+ // step2: 获取凭证信息并注入到系统环境变量中
154
+ client := keyless.NewClient(req)
155
+ err := client.Load()
156
+ if err != nil {
157
+ fmt.Println(err.Error())
158
+ return
159
+ }
160
+ // 初始化 keyless-sdk 结束
161
+ // 以下为其他原始代码
162
+ ... ...
163
+ }
164
+ ```
165
+
166
+ #### python 语言
167
+ requirements.txt 文件中添加 keyless-sdk 依赖,其中的注释需要保留。
168
+ ```txt
169
+ // keyless-sdk dependency
170
+ credential-vault-sdk>=0.1.12(Python3 版本添加此依赖)
171
+ credential-vault-sdk-py2>=0.1.9(Python2 版本添加此依赖)
172
+ ```
173
+ 初始化代码如下,注意
174
+ * 其中的 credential_id 需要与漏洞报告中的 credential_id 保持一致;
175
+ * 如果是完整的服务或项目,初始化代码要添加在项目启动的函数中;
176
+ * 如果是独立的 Python 脚本文件,每个独立的文件都要添加 keyless-sdk 依赖和初始化代码。
177
+ ```python
178
+ from credential_vault_sdk.keyless_client import KeylessClient
179
+
180
+ def main():
181
+ # 初始化 keyless-sdk 开始
182
+ # step1: 设置 credential_id 构建 client,详情可参考 https://ku.baidu-int.com/d/HWaSIaQSThk88b
183
+ client = KeylessClient(credential_id="appDemo_prod")
184
+ # step2: 获取凭证信息并注入到系统环境变量中
185
+ client.load()
186
+ # 初始化 keyless-sdk 结束
187
+ # 以下为其他原始代码
188
+ ... ...
189
+ ```
190
+
191
+ #### C++ 语言
192
+ 在文件开始引入头文件和命名空间,其中的注释需要保留:
193
+ ```C++
194
+ // keyless-sdk dependency
195
+ #include "keyless/keyless_client.h"
196
+
197
+ using namespace baidu::credentialvault::cppsdk;
198
+ ```
199
+
200
+ 项目启动的函数中添加以下初始化代码,注意其中的 credentialID 需要与漏洞报告中的 credential_id 保持一致。
201
+ ```C++
202
+ #include "keyless/keyless_client.h"
203
+
204
+ using namespace baidu::credentialvault::cppsdk;
205
+
206
+ int main(int argc, char *argv[]) {
207
+ // 初始化 keyless-sdk 开始
208
+ // step1: 设置 credential_id 构建 client,详情可参考 https://ku.baidu-int.com/d/x5s_A3YHll0PvR
209
+ KeylessClient client = KeylessClient("appDemo_prod");
210
+ // step2: 获取凭证信息并注入到系统环境变量中
211
+ KeylessStatus load_result = client.load();
212
+ if (!load_result.ok()) {
213
+ return 0;
214
+ }
215
+ // 初始化 keyless-sdk 结束
216
+ // 以下为其他原始代码
217
+ ... ...
218
+ }
219
+ ```
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 凭证托管工具 - 将凭证托管到第三方平台(iPipe/CNAP/datamanage)。
4
+
5
+ 用法:
6
+ python3 credential_hosting.py --poll-result <poll_result.json路径> --username <用户名>
7
+
8
+ 也可手动指定各参数(不推荐,仅向后兼容):
9
+ python3 credential_hosting.py --chat-id <chatID> --platform <platformName> --username <用户名> --credentials '<JSON>'
10
+
11
+ 使用 --poll-result 时,自动从 credential_poll.py 的输出文件中提取 chatUUID、deployment.platformName、data.credentials。
12
+ """
13
+
14
+ import argparse
15
+ import json
16
+ import logging
17
+ import sys
18
+
19
+ import http_client # noqa: F401 (triggers shared logging config)
20
+ import utils
21
+
22
+ logger = logging.getLogger("credential_hosting")
23
+
24
+
25
+ def hosting_credentials(chat_id, platform, credentials, username, user_id):
26
+ """将凭证托管到指定平台。"""
27
+ url = "{}/api/v1/deployments/{}/credentials".format(utils.HOST, platform)
28
+ payload = {
29
+ "configs": credentials,
30
+ "scanChatID": chat_id,
31
+ }
32
+
33
+ logger.info("credential_hosting: chat_id=%s, platform=%s, credentials_count=%d",
34
+ chat_id, platform, len(credentials))
35
+ print("正在托管凭证到 {} 平台...".format(platform), file=sys.stderr)
36
+ return http_client.post(
37
+ url,
38
+ headers=utils.build_headers(username, user_id, chat_id),
39
+ json_body=payload,
40
+ )
41
+
42
+
43
+ def main():
44
+ parser = argparse.ArgumentParser(description="凭证托管工具")
45
+ parser.add_argument("--poll-result", default=None, help="credential_poll.py 输出的结果文件路径,自动提取所需参数")
46
+ parser.add_argument("--chat-id", default=None, help="scanChatID(使用 --poll-result 时可省略)")
47
+ parser.add_argument("--platform", default=None, help="托管平台名称(使用 --poll-result 时可省略)")
48
+ parser.add_argument("--username", required=True, help="Comate 用户名")
49
+ parser.add_argument("--credentials", default=None, help="凭证配置 JSON(使用 --poll-result 时可省略)")
50
+ args = parser.parse_args()
51
+
52
+ user_id = utils.make_user_id(args.username)
53
+
54
+ chat_id = args.chat_id
55
+ platform = args.platform
56
+ credentials = None
57
+
58
+ if args.poll_result:
59
+ # 从 poll_result 文件提取所有参数
60
+ try:
61
+ with open(args.poll_result, "r", encoding="utf-8") as f:
62
+ poll_data = json.load(f)
63
+ except Exception as e:
64
+ print("错误: 读取 poll-result 失败 {}: {}".format(args.poll_result, e), file=sys.stderr)
65
+ sys.exit(1)
66
+
67
+ chat_id = chat_id or poll_data.get("chatUUID", "")
68
+ data = poll_data.get("data", {})
69
+ platform = platform or data.get("deployment", {}).get("platformName", "")
70
+ credentials = data.get("credentials")
71
+ elif args.credentials:
72
+ try:
73
+ credentials = json.loads(args.credentials)
74
+ except json.JSONDecodeError as e:
75
+ print("错误: 凭证 JSON 解析失败: {}".format(e), file=sys.stderr)
76
+ sys.exit(1)
77
+
78
+ if not chat_id or not platform or credentials is None:
79
+ print("错误: 缺少必要参数。使用 --poll-result 或同时提供 --chat-id、--platform、--credentials", file=sys.stderr)
80
+ sys.exit(1)
81
+
82
+ result = hosting_credentials(chat_id, platform, credentials, args.username, user_id)
83
+ print(json.dumps(result, ensure_ascii=False, indent=2))
84
+
85
+
86
+ if __name__ == "__main__":
87
+ main()
@@ -0,0 +1,345 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 凭证配置轮询工具 - 通过 WebSocket 监听凭证托管助手网页的配置结果。
4
+
5
+ 用法:
6
+ python3 credential_poll.py --chat-id <chatID> --username <用户名>
7
+
8
+ 流程:
9
+ 1. 连接 WebSocket 端点
10
+ 2. 等待用户在网页完成凭证配置并点击「生成代码」
11
+ 3. 收到 msgType=repair 消息后输出配置数据
12
+
13
+ 注意: 使用 Python 标准库实现 WebSocket 客户端,无需第三方依赖。
14
+ """
15
+
16
+ import argparse
17
+ import base64
18
+ import json
19
+ import logging
20
+ import os
21
+ import socket
22
+ import struct
23
+ import sys
24
+ import time
25
+
26
+ try:
27
+ import ssl
28
+ _SSL_AVAILABLE = True
29
+ except ImportError:
30
+ _SSL_AVAILABLE = False
31
+
32
+ # 触发共享日志配置
33
+ import http_client # noqa: F401
34
+ import utils
35
+
36
+ logger = logging.getLogger("credential_poll")
37
+
38
+ WS_TIMEOUT = 30 * 60 # 30 分钟超时
39
+ RECV_TIMEOUT = 5 # 每次 recv 超时秒数
40
+ MAX_RECONNECT = 10
41
+ RECONNECT_BASE_INTERVAL = 1 # 秒
42
+
43
+ # WebSocket opcodes
44
+ OP_TEXT = 0x1
45
+ OP_CLOSE = 0x8
46
+ OP_PING = 0x9
47
+ OP_PONG = 0xA
48
+
49
+
50
+ def _generate_ws_key():
51
+ """生成随机的 Sec-WebSocket-Key。"""
52
+ return base64.b64encode(os.urandom(16)).decode("ascii")
53
+
54
+
55
+ def _ws_connect(host, port, path, headers, use_ssl=True, timeout=10):
56
+ """
57
+ 建立 WebSocket 连接,返回 socket 对象。
58
+ 执行 HTTP Upgrade 握手,验证 101 响应。
59
+ """
60
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
61
+ sock.settimeout(timeout)
62
+
63
+ if use_ssl:
64
+ if not _SSL_AVAILABLE:
65
+ raise RuntimeError(
66
+ "WebSocket 需要 SSL 但 ssl 模块不可用。"
67
+ "请安装 libssl1.1 或重新编译 Python 以支持 ssl。"
68
+ )
69
+ ctx = ssl.create_default_context()
70
+ ctx.check_hostname = False
71
+ ctx.verify_mode = ssl.CERT_NONE
72
+ sock = ctx.wrap_socket(sock, server_hostname=host)
73
+
74
+ sock.connect((host, port))
75
+
76
+ # 构造握手请求
77
+ ws_key = _generate_ws_key()
78
+ lines = [
79
+ "GET {} HTTP/1.1".format(path),
80
+ "Host: {}".format(host),
81
+ "Upgrade: websocket",
82
+ "Connection: Upgrade",
83
+ "Sec-WebSocket-Version: 13",
84
+ "Sec-WebSocket-Key: {}".format(ws_key),
85
+ ]
86
+ for k, v in headers.items():
87
+ lines.append("{}: {}".format(k, v))
88
+ lines.append("")
89
+ lines.append("")
90
+
91
+ request = "\r\n".join(lines)
92
+ sock.sendall(request.encode("utf-8"))
93
+
94
+ # 读取响应头
95
+ response = b""
96
+ while b"\r\n\r\n" not in response:
97
+ chunk = sock.recv(4096)
98
+ if not chunk:
99
+ raise ConnectionError("连接在握手期间被关闭")
100
+ response += chunk
101
+
102
+ header_end = response.index(b"\r\n\r\n")
103
+ header_part = response[:header_end].decode("utf-8")
104
+ status_line = header_part.split("\r\n")[0]
105
+
106
+ # 验证 101 状态码
107
+ parts = status_line.split(" ", 2)
108
+ status_code = int(parts[1])
109
+ if status_code != 101:
110
+ # 尝试读取 body 获取错误信息
111
+ body_part = response[header_end + 4:]
112
+ error_msg = body_part.decode("utf-8", errors="replace") if body_part else ""
113
+ raise ConnectionError("WebSocket 握手失败: HTTP {} - {}".format(status_code, error_msg))
114
+
115
+ return sock
116
+
117
+
118
+ def _ws_recv_frame(sock):
119
+ """
120
+ 接收一个 WebSocket 帧,返回 (opcode, payload_bytes)。
121
+ """
122
+ def _recv_exact(n):
123
+ data = b""
124
+ while len(data) < n:
125
+ chunk = sock.recv(n - len(data))
126
+ if not chunk:
127
+ raise ConnectionError("连接被关闭")
128
+ data += chunk
129
+ return data
130
+
131
+ # 读取 2 字节头
132
+ head = _recv_exact(2)
133
+ opcode = head[0] & 0x0F
134
+ masked = (head[1] & 0x80) != 0
135
+ payload_len = head[1] & 0x7F
136
+
137
+ # 扩展长度
138
+ if payload_len == 126:
139
+ payload_len = struct.unpack("!H", _recv_exact(2))[0]
140
+ elif payload_len == 127:
141
+ payload_len = struct.unpack("!Q", _recv_exact(8))[0]
142
+
143
+ # mask (服务端发给客户端通常不 mask,但保留处理)
144
+ mask_key = None
145
+ if masked:
146
+ mask_key = _recv_exact(4)
147
+
148
+ # payload
149
+ payload = _recv_exact(payload_len)
150
+
151
+ if mask_key:
152
+ payload = bytes(b ^ mask_key[i % 4] for i, b in enumerate(payload))
153
+
154
+ return opcode, payload
155
+
156
+
157
+ def _ws_send_frame(sock, opcode, payload=b""):
158
+ """
159
+ 发送一个 WebSocket 帧(客户端发送需要 mask)。
160
+ """
161
+ mask_key = os.urandom(4)
162
+ masked_payload = bytes(b ^ mask_key[i % 4] for i, b in enumerate(payload))
163
+
164
+ frame = bytearray()
165
+ frame.append(0x80 | opcode) # FIN + opcode
166
+
167
+ length = len(payload)
168
+ if length < 126:
169
+ frame.append(0x80 | length) # MASK bit + length
170
+ elif length < 65536:
171
+ frame.append(0x80 | 126)
172
+ frame.extend(struct.pack("!H", length))
173
+ else:
174
+ frame.append(0x80 | 127)
175
+ frame.extend(struct.pack("!Q", length))
176
+
177
+ frame.extend(mask_key)
178
+ frame.extend(masked_payload)
179
+
180
+ sock.sendall(bytes(frame))
181
+
182
+
183
+ def _ws_send_pong(sock, payload=b""):
184
+ """回复 pong 帧。"""
185
+ _ws_send_frame(sock, OP_PONG, payload)
186
+
187
+
188
+ def _ws_send_close(sock, code=1000, reason=""):
189
+ """发送 close 帧。"""
190
+ payload = struct.pack("!H", code) + reason.encode("utf-8")
191
+ _ws_send_frame(sock, OP_CLOSE, payload)
192
+
193
+
194
+ def _parse_ws_url(url):
195
+ """解析 wss://host/path,返回 (host, port, path, use_ssl)。"""
196
+ if url.startswith("wss://"):
197
+ use_ssl = True
198
+ default_port = 443
199
+ rest = url[6:]
200
+ elif url.startswith("ws://"):
201
+ use_ssl = False
202
+ default_port = 80
203
+ rest = url[5:]
204
+ else:
205
+ raise ValueError("不支持的 URL scheme: {}".format(url))
206
+
207
+ if "/" in rest:
208
+ host_port, path = rest.split("/", 1)
209
+ path = "/" + path
210
+ else:
211
+ host_port = rest
212
+ path = "/"
213
+
214
+ if ":" in host_port:
215
+ host, port_str = host_port.split(":", 1)
216
+ port = int(port_str)
217
+ else:
218
+ host = host_port
219
+ port = default_port
220
+
221
+ return host, port, path, use_ssl
222
+
223
+
224
+ def poll_credential_config(chat_id, user_id):
225
+ """通过 WebSocket 监听凭证配置,返回配置数据 dict 或 None。"""
226
+ url = "{}/api/v1/ws/credential/events".format(utils.WS_HOST)
227
+ host, port, path, use_ssl = _parse_ws_url(url)
228
+ logger.info("credential_poll start: chat_id=%s", chat_id)
229
+
230
+ ws_headers = {
231
+ "SAST-Chat-ID": chat_id,
232
+ "Comate-User-Id": user_id,
233
+ }
234
+
235
+ reconnect_attempts = 0
236
+ start_time = time.time()
237
+
238
+ while time.time() - start_time < WS_TIMEOUT:
239
+ sock = None
240
+ try:
241
+ sock = _ws_connect(host, port, path, ws_headers, use_ssl, timeout=RECV_TIMEOUT)
242
+ print("WebSocket 已连接,等待凭证配置...", file=sys.stderr)
243
+ reconnect_attempts = 0 # 连接成功,重置重连计数
244
+
245
+ while time.time() - start_time < WS_TIMEOUT:
246
+ try:
247
+ opcode, payload = _ws_recv_frame(sock)
248
+
249
+ if opcode == OP_TEXT:
250
+ msg = payload.decode("utf-8")
251
+ if not msg:
252
+ continue
253
+ data = json.loads(msg)
254
+ msg_type = data.get("msgType", "")
255
+
256
+ if msg_type == "repair":
257
+ print("收到凭证配置数据", file=sys.stderr)
258
+ logger.info("credential_poll received repair data")
259
+ try:
260
+ _ws_send_close(sock)
261
+ except Exception:
262
+ pass
263
+ return data
264
+ elif msg_type == "openFile":
265
+ continue
266
+
267
+ elif opcode == OP_PING:
268
+ _ws_send_pong(sock, payload)
269
+
270
+ elif opcode == OP_CLOSE:
271
+ print("服务端关闭连接,尝试重连...", file=sys.stderr)
272
+ break
273
+
274
+ except socket.timeout:
275
+ # recv 超时,继续等待
276
+ continue
277
+ except (ConnectionError, OSError):
278
+ print("WebSocket 连接断开,尝试重连...", file=sys.stderr)
279
+ break
280
+ except ValueError as e:
281
+ print("JSON 解析失败: {}".format(e), file=sys.stderr)
282
+ continue
283
+
284
+ except ConnectionError as e:
285
+ err_msg = str(e)
286
+ print("WebSocket 连接失败: {}".format(err_msg), file=sys.stderr)
287
+ # 400004 表示会话不存在(用户还未打开网页),继续重试等待用户打开
288
+ # 其他业务错误直接退出
289
+ if "400004" in err_msg:
290
+ print("会话不存在,等待用户打开凭证托管网页...", file=sys.stderr)
291
+ elif "HTTP 200" in err_msg or "400" in err_msg:
292
+ print("服务端拒绝连接,请检查 chatID 是否有效", file=sys.stderr)
293
+ return None
294
+
295
+ except Exception as e:
296
+ print("WebSocket 连接失败: {}".format(e), file=sys.stderr)
297
+
298
+ finally:
299
+ if sock:
300
+ try:
301
+ sock.close()
302
+ except Exception:
303
+ pass
304
+
305
+ # 重连逻辑:指数退避
306
+ reconnect_attempts += 1
307
+ if reconnect_attempts > MAX_RECONNECT:
308
+ print("达到最大重连次数,退出", file=sys.stderr)
309
+ return None
310
+
311
+ delay = RECONNECT_BASE_INTERVAL * (2 ** (reconnect_attempts - 1))
312
+ print("{}秒后重连 (第{}/{})次...".format(delay, reconnect_attempts, MAX_RECONNECT), file=sys.stderr)
313
+ time.sleep(delay)
314
+
315
+ print("超时,未收到凭证配置", file=sys.stderr)
316
+ logger.warning("credential_poll timeout: chat_id=%s", chat_id)
317
+ return None
318
+
319
+
320
+ def main():
321
+ parser = argparse.ArgumentParser(description="凭证配置轮询工具")
322
+ parser.add_argument("--chat-id", required=True, help="scanChatID,用于关联扫描会话")
323
+ parser.add_argument("--username", required=True, help="Comate 用户名")
324
+ parser.add_argument("--output", default=None, help="将结果保存到指定文件路径(同时仍输出到标准输出)")
325
+ args = parser.parse_args()
326
+
327
+ user_id = utils.make_user_id(args.username)
328
+
329
+ result = poll_credential_config(args.chat_id, user_id)
330
+ if result:
331
+ output_json = json.dumps(result, ensure_ascii=False, indent=2)
332
+ print(output_json)
333
+ if args.output:
334
+ output_dir = os.path.dirname(os.path.abspath(args.output))
335
+ os.makedirs(output_dir, exist_ok=True)
336
+ with open(args.output, "w", encoding="utf-8") as f:
337
+ f.write(output_json)
338
+ print("已保存: {}".format(args.output), file=sys.stderr)
339
+ else:
340
+ print(json.dumps({"error": "未收到凭证配置数据"}, ensure_ascii=False))
341
+ sys.exit(1)
342
+
343
+
344
+ if __name__ == "__main__":
345
+ main()