@uofx/cli 1.0.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 (238) hide show
  1. package/LICENSE +40 -0
  2. package/README.md +444 -0
  3. package/THIRD-PARTY-NOTICES.txt +894 -0
  4. package/dist/application/dtos/index.js +24 -0
  5. package/dist/application/dtos/request/delete-instance.request.dto.js +3 -0
  6. package/dist/application/dtos/request/get-config.request.dto.js +3 -0
  7. package/dist/application/dtos/request/get-credentials.request.dto.js +3 -0
  8. package/dist/application/dtos/request/index.js +27 -0
  9. package/dist/application/dtos/request/install-instance.request.dto.js +3 -0
  10. package/dist/application/dtos/request/list-charts.request.dto.js +3 -0
  11. package/dist/application/dtos/request/set-config.request.dto.js +16 -0
  12. package/dist/application/dtos/request/setup-environment.request.dto.js +16 -0
  13. package/dist/application/dtos/request/show-logs.request.dto.js +19 -0
  14. package/dist/application/dtos/request/start-instance.request.dto.js +3 -0
  15. package/dist/application/dtos/request/stop-instance.request.dto.js +3 -0
  16. package/dist/application/dtos/response/credentials.response.dto.js +3 -0
  17. package/dist/application/dtos/response/delete-instance.response.dto.js +3 -0
  18. package/dist/application/dtos/response/index.js +26 -0
  19. package/dist/application/dtos/response/install-instance.response.dto.js +3 -0
  20. package/dist/application/dtos/response/instance-list.response.dto.js +3 -0
  21. package/dist/application/dtos/response/instance-status.response.dto.js +3 -0
  22. package/dist/application/dtos/response/setup-result.response.dto.js +3 -0
  23. package/dist/application/dtos/response/show-logs.response.dto.js +3 -0
  24. package/dist/application/dtos/response/start-instance.response.dto.js +3 -0
  25. package/dist/application/dtos/response/stop-instance.response.dto.js +3 -0
  26. package/dist/application/index.js +25 -0
  27. package/dist/application/interfaces/index.js +24 -0
  28. package/dist/application/interfaces/use-case.interface.js +3 -0
  29. package/dist/application/use-cases/config/get-config.use-case.js +66 -0
  30. package/dist/application/use-cases/config/set-config.use-case.js +49 -0
  31. package/dist/application/use-cases/credentials/get-credentials.use-case.js +57 -0
  32. package/dist/application/use-cases/index.js +28 -0
  33. package/dist/application/use-cases/instance/delete-instance.use-case.js +81 -0
  34. package/dist/application/use-cases/instance/index.js +23 -0
  35. package/dist/application/use-cases/instance/install-instance.use-case.js +424 -0
  36. package/dist/application/use-cases/instance/list-charts.use-case.js +43 -0
  37. package/dist/application/use-cases/instance/list-instances.use-case.js +62 -0
  38. package/dist/application/use-cases/instance/start-instance.use-case.js +154 -0
  39. package/dist/application/use-cases/instance/stop-instance.use-case.js +55 -0
  40. package/dist/application/use-cases/logs/show-logs.use-case.js +66 -0
  41. package/dist/application/use-cases/setup/setup-environment.use-case.js +53 -0
  42. package/dist/cli.js +286 -0
  43. package/dist/constants/config-defaults.js +23 -0
  44. package/dist/constants/defaults.js +89 -0
  45. package/dist/constants/deployment.js +39 -0
  46. package/dist/constants/environments.js +93 -0
  47. package/dist/constants/index.js +53 -0
  48. package/dist/constants/oci-artifacts.js +25 -0
  49. package/dist/constants/paths.js +92 -0
  50. package/dist/constants/timeouts.js +60 -0
  51. package/dist/di/container.js +34 -0
  52. package/dist/di/index.js +22 -0
  53. package/dist/di/modules/application.module.js +54 -0
  54. package/dist/di/modules/infrastructure.module.js +206 -0
  55. package/dist/di/modules/interceptor.module.js +68 -0
  56. package/dist/di/modules/presentation.module.js +31 -0
  57. package/dist/di/tokens.js +149 -0
  58. package/dist/domain/decorators/sensitive.decorator.js +39 -0
  59. package/dist/domain/entities/credentials-resolver.entity.js +127 -0
  60. package/dist/domain/entities/credentials.entity.js +65 -0
  61. package/dist/domain/entities/delete-instance-validation.entity.js +100 -0
  62. package/dist/domain/entities/deployment-parameters.entity.js +120 -0
  63. package/dist/domain/entities/environment-validation.entity.js +125 -0
  64. package/dist/domain/entities/index.js +29 -0
  65. package/dist/domain/entities/instance-lifecycle-state.entity.js +100 -0
  66. package/dist/domain/entities/instance-list-aggregator.entity.js +104 -0
  67. package/dist/domain/entities/instance-metadata.entity.js +86 -0
  68. package/dist/domain/entities/instance-status.entity.js +79 -0
  69. package/dist/domain/entities/instance.entity.js +128 -0
  70. package/dist/domain/entities/log-filter.entity.js +141 -0
  71. package/dist/domain/index.js +29 -0
  72. package/dist/domain/interfaces/safe-loggable.interface.js +3 -0
  73. package/dist/domain/ports/app-config.port.js +3 -0
  74. package/dist/domain/ports/base-image.port.js +3 -0
  75. package/dist/domain/ports/chart-version.port.js +3 -0
  76. package/dist/domain/ports/correlation-id.port.js +3 -0
  77. package/dist/domain/ports/credentials.port.js +3 -0
  78. package/dist/domain/ports/deployment.port.js +3 -0
  79. package/dist/domain/ports/error-handler.port.js +3 -0
  80. package/dist/domain/ports/index.js +46 -0
  81. package/dist/domain/ports/instance-manager.port.js +3 -0
  82. package/dist/domain/ports/instance-metadata.port.js +8 -0
  83. package/dist/domain/ports/instance-storage.port.js +3 -0
  84. package/dist/domain/ports/k8s-deployer.port.js +3 -0
  85. package/dist/domain/ports/logger.port.js +14 -0
  86. package/dist/domain/ports/output.port.js +3 -0
  87. package/dist/domain/ports/runtime-environment.port.js +6 -0
  88. package/dist/domain/ports/user-interaction.port.js +9 -0
  89. package/dist/domain/ports/user-settings.port.js +3 -0
  90. package/dist/domain/types/index.js +22 -0
  91. package/dist/domain/types/logger.types.js +29 -0
  92. package/dist/domain/types/validation.types.js +9 -0
  93. package/dist/domain/value-objects/acr-credentials.value-object.js +92 -0
  94. package/dist/domain/value-objects/chart-version.value-object.js +124 -0
  95. package/dist/domain/value-objects/config-log-level.value-object.js +84 -0
  96. package/dist/domain/value-objects/connection-info.value-object.js +65 -0
  97. package/dist/domain/value-objects/index.js +25 -0
  98. package/dist/domain/value-objects/instance-name.value-object.js +91 -0
  99. package/dist/domain/value-objects/jwt-key.value-object.js +97 -0
  100. package/dist/domain/value-objects/mssql-password.value-object.js +140 -0
  101. package/dist/domain/value-objects/rsa-key-pair.value-object.js +181 -0
  102. package/dist/index.js +6 -0
  103. package/dist/infrastructure/config/app-config.interface.js +3 -0
  104. package/dist/infrastructure/config/app-config.service.js +280 -0
  105. package/dist/infrastructure/config/config-validator.js +31 -0
  106. package/dist/infrastructure/config/crypto.service.js +125 -0
  107. package/dist/infrastructure/deployment/deployment.adapter.js +118 -0
  108. package/dist/infrastructure/deployment/interfaces/acr-credential-manager.interface.js +3 -0
  109. package/dist/infrastructure/deployment/interfaces/app-manager.interface.js +3 -0
  110. package/dist/infrastructure/deployment/interfaces/helm-registry.interface.js +3 -0
  111. package/dist/infrastructure/deployment/interfaces/infra-manager.interface.js +3 -0
  112. package/dist/infrastructure/deployment/interfaces/k8s-job-runner.interface.js +3 -0
  113. package/dist/infrastructure/deployment/interfaces/mssql-database-init.interface.js +3 -0
  114. package/dist/infrastructure/deployment/interfaces/mssql-helm-deployment.interface.js +3 -0
  115. package/dist/infrastructure/deployment/interfaces/mssql-storage.interface.js +3 -0
  116. package/dist/infrastructure/deployment/interfaces/mssql-user-manager.interface.js +3 -0
  117. package/dist/infrastructure/deployment/interfaces/oci-artifact.interface.js +3 -0
  118. package/dist/infrastructure/deployment/interfaces/secret-manager.interface.js +3 -0
  119. package/dist/infrastructure/deployment/interfaces/service-manager.interface.js +3 -0
  120. package/dist/infrastructure/deployment/interfaces/version-compatibility.interface.js +3 -0
  121. package/dist/infrastructure/deployment/services/acr-credential-manager.service.js +144 -0
  122. package/dist/infrastructure/deployment/services/app-manager.service.js +193 -0
  123. package/dist/infrastructure/deployment/services/base-helm-deployment.service.js +163 -0
  124. package/dist/infrastructure/deployment/services/helm-registry.service.js +126 -0
  125. package/dist/infrastructure/deployment/services/infra-manager.service.js +130 -0
  126. package/dist/infrastructure/deployment/services/k8s-job-runner.service.js +194 -0
  127. package/dist/infrastructure/deployment/services/mssql-database-init.service.js +139 -0
  128. package/dist/infrastructure/deployment/services/mssql-helm-deployment.service.js +100 -0
  129. package/dist/infrastructure/deployment/services/mssql-storage.service.js +54 -0
  130. package/dist/infrastructure/deployment/services/mssql-user-manager.service.js +66 -0
  131. package/dist/infrastructure/deployment/services/oci-artifact.service.js +289 -0
  132. package/dist/infrastructure/deployment/services/secret-manager.service.js +179 -0
  133. package/dist/infrastructure/deployment/services/service-manager.service.js +82 -0
  134. package/dist/infrastructure/deployment/services/version-compatibility.service.js +291 -0
  135. package/dist/infrastructure/environment/interfaces/hardware-info.interface.js +3 -0
  136. package/dist/infrastructure/environment/interfaces/network-checker.interface.js +3 -0
  137. package/dist/infrastructure/environment/services/hardware-info.service.js +135 -0
  138. package/dist/infrastructure/environment/services/network-checker.service.js +142 -0
  139. package/dist/infrastructure/environment/windows-environment.adapter.js +162 -0
  140. package/dist/infrastructure/errors/app-error.js +73 -0
  141. package/dist/infrastructure/errors/error-handler.interface.js +3 -0
  142. package/dist/infrastructure/errors/error-handler.js +218 -0
  143. package/dist/infrastructure/errors/exit-codes.js +27 -0
  144. package/dist/infrastructure/errors/index.js +25 -0
  145. package/dist/infrastructure/execution/builders/base-command.builder.js +122 -0
  146. package/dist/infrastructure/execution/builders/host-command.builder.js +58 -0
  147. package/dist/infrastructure/execution/builders/windows-host-command.builder.js +50 -0
  148. package/dist/infrastructure/execution/builders/wsl-command.builder.js +29 -0
  149. package/dist/infrastructure/execution/command-builder.js +252 -0
  150. package/dist/infrastructure/execution/command-executor.service.js +230 -0
  151. package/dist/infrastructure/execution/environments/wsl-execution.environment.js +70 -0
  152. package/dist/infrastructure/execution/execution-environment.factory.js +53 -0
  153. package/dist/infrastructure/execution/index.js +25 -0
  154. package/dist/infrastructure/execution/interfaces/command-builder.interface.js +3 -0
  155. package/dist/infrastructure/execution/interfaces/command-executor.interface.js +3 -0
  156. package/dist/infrastructure/execution/interfaces/execution-environment-factory.interface.js +3 -0
  157. package/dist/infrastructure/execution/interfaces/execution-environment.interface.js +7 -0
  158. package/dist/infrastructure/execution/interfaces/host-command-builder.interface.js +3 -0
  159. package/dist/infrastructure/execution/interfaces/index.js +23 -0
  160. package/dist/infrastructure/execution/interfaces/script-executor.interface.js +3 -0
  161. package/dist/infrastructure/execution/script-executor.service.js +171 -0
  162. package/dist/infrastructure/http/http-client.service.js +176 -0
  163. package/dist/infrastructure/http/index.js +18 -0
  164. package/dist/infrastructure/http/interfaces/http-client.interface.js +3 -0
  165. package/dist/infrastructure/interceptors/index.js +8 -0
  166. package/dist/infrastructure/interceptors/interceptor.factory.js +44 -0
  167. package/dist/infrastructure/interceptors/interceptor.interface.js +3 -0
  168. package/dist/infrastructure/interceptors/logging.interceptor.js +171 -0
  169. package/dist/infrastructure/logger/correlation-id.adapter.js +68 -0
  170. package/dist/infrastructure/logger/index.js +23 -0
  171. package/dist/infrastructure/logger/interfaces/index.js +22 -0
  172. package/dist/infrastructure/logger/interfaces/log-reader.repository.interface.js +7 -0
  173. package/dist/infrastructure/logger/interfaces/log-writer.repository.interface.js +7 -0
  174. package/dist/infrastructure/logger/logger.adapter.js +274 -0
  175. package/dist/infrastructure/logger/services/file-log-reader.repository.js +148 -0
  176. package/dist/infrastructure/logger/services/file-log-writer.repository.js +307 -0
  177. package/dist/infrastructure/logger/services/index.js +22 -0
  178. package/dist/infrastructure/persistence/index.js +25 -0
  179. package/dist/infrastructure/persistence/instance-metadata.adapter.js +100 -0
  180. package/dist/infrastructure/persistence/instance-storage.adapter.js +64 -0
  181. package/dist/infrastructure/persistence/interfaces/config.repository.interface.js +3 -0
  182. package/dist/infrastructure/persistence/interfaces/index.js +22 -0
  183. package/dist/infrastructure/persistence/interfaces/instance.repository.interface.js +3 -0
  184. package/dist/infrastructure/persistence/services/file-system-config.repository.js +168 -0
  185. package/dist/infrastructure/persistence/services/file-system-instance.repository.js +170 -0
  186. package/dist/infrastructure/persistence/services/index.js +22 -0
  187. package/dist/infrastructure/persistence/user-settings.adapter.js +55 -0
  188. package/dist/infrastructure/platform-detector.js +71 -0
  189. package/dist/infrastructure/platforms/windows/interfaces/microk8s.interface.js +3 -0
  190. package/dist/infrastructure/platforms/windows/interfaces/rootfs-manager.interface.js +3 -0
  191. package/dist/infrastructure/platforms/windows/interfaces/windows-features.interface.js +3 -0
  192. package/dist/infrastructure/platforms/windows/interfaces/windows-info.interface.js +3 -0
  193. package/dist/infrastructure/platforms/windows/interfaces/wsl-config.interface.js +3 -0
  194. package/dist/infrastructure/platforms/windows/interfaces/wsl-info.interface.js +3 -0
  195. package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-inspection.interface.js +3 -0
  196. package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-lifecycle.interface.js +3 -0
  197. package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-naming.interface.js +3 -0
  198. package/dist/infrastructure/platforms/windows/interfaces/wsl-manager.interface.js +3 -0
  199. package/dist/infrastructure/platforms/windows/interfaces/wsl-resources.interface.js +8 -0
  200. package/dist/infrastructure/platforms/windows/interfaces/wsl-updater.interface.js +3 -0
  201. package/dist/infrastructure/platforms/windows/interfaces/wslconfig-parser.interface.js +3 -0
  202. package/dist/infrastructure/platforms/windows/parsers/wsl-version.parser.js +133 -0
  203. package/dist/infrastructure/platforms/windows/services/microk8s.service.js +168 -0
  204. package/dist/infrastructure/platforms/windows/services/rootfs-manager.service.js +336 -0
  205. package/dist/infrastructure/platforms/windows/services/windows-features.service.js +191 -0
  206. package/dist/infrastructure/platforms/windows/services/windows-info.service.js +138 -0
  207. package/dist/infrastructure/platforms/windows/services/wsl-config.service.js +171 -0
  208. package/dist/infrastructure/platforms/windows/services/wsl-info.service.js +226 -0
  209. package/dist/infrastructure/platforms/windows/services/wsl-instance-inspection.service.js +325 -0
  210. package/dist/infrastructure/platforms/windows/services/wsl-instance-lifecycle.service.js +442 -0
  211. package/dist/infrastructure/platforms/windows/services/wsl-instance-naming.service.js +93 -0
  212. package/dist/infrastructure/platforms/windows/services/wsl-updater.service.js +273 -0
  213. package/dist/infrastructure/platforms/windows/services/wslconfig-parser.service.js +222 -0
  214. package/dist/infrastructure/platforms/windows/wsl-base-image.adapter.js +41 -0
  215. package/dist/infrastructure/platforms/windows/wsl-instance-manager.adapter.js +150 -0
  216. package/dist/infrastructure/utils/error-formatter.util.js +29 -0
  217. package/dist/infrastructure/utils/file-operations.util.js +201 -0
  218. package/dist/infrastructure/utils/input-validator.util.js +152 -0
  219. package/dist/infrastructure/utils/retry.util.js +98 -0
  220. package/dist/presentation/controllers/config.controller.js +146 -0
  221. package/dist/presentation/controllers/credentials.controller.js +105 -0
  222. package/dist/presentation/controllers/index.js +25 -0
  223. package/dist/presentation/controllers/instance.controller.js +363 -0
  224. package/dist/presentation/controllers/logs.controller.js +103 -0
  225. package/dist/presentation/controllers/setup.controller.js +175 -0
  226. package/dist/presentation/interfaces/cli-options.interface.js +8 -0
  227. package/dist/presentation/prompts/acr-credentials.prompt.js +76 -0
  228. package/dist/presentation/prompts/index.js +21 -0
  229. package/dist/presentation/ui/cli-progress.service.js +193 -0
  230. package/dist/presentation/ui/constants/output-symbols.js +42 -0
  231. package/dist/presentation/ui/index.js +27 -0
  232. package/dist/presentation/ui/interaction.service.js +276 -0
  233. package/dist/presentation/ui/interfaces/cli-progress.interface.js +9 -0
  234. package/dist/presentation/ui/interfaces/output-formatter.interface.js +23 -0
  235. package/dist/presentation/ui/log-level.enum.js +66 -0
  236. package/dist/presentation/ui/output-builder.service.js +378 -0
  237. package/dist/presentation/ui/output-formatter.service.js +393 -0
  238. package/package.json +65 -0
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.SecretManagerService = void 0;
16
+ const tsyringe_1 = require("tsyringe");
17
+ const tokens_1 = require("../../../di/tokens");
18
+ const sensitive_decorator_1 = require("../../../domain/decorators/sensitive.decorator");
19
+ /**
20
+ * Secret 管理服務
21
+ *
22
+ * 管理 Kubernetes Secret 的建立與讀取
23
+ * 透過 DI 注入 CommandExecutorService,所有操作需傳入 instanceName 指定目標 WSL 實例
24
+ *
25
+ * 實作 ISecretManagerService
26
+ */
27
+ let SecretManagerService = class SecretManagerService {
28
+ constructor(envFactory, logger) {
29
+ this.envFactory = envFactory;
30
+ this.logger = logger;
31
+ }
32
+ /**
33
+ * 檢查命名空間是否存在
34
+ */
35
+ async checkNamespaceExists(instanceName, namespace) {
36
+ try {
37
+ const env = this.envFactory.getForInstance(instanceName);
38
+ const builder = env.kubectl('get namespace')
39
+ .arg(namespace);
40
+ const res = await builder.exec();
41
+ return res.exitCode === 0;
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
47
+ /**
48
+ * 建立命名空間
49
+ */
50
+ async createNamespace(instanceName, namespace) {
51
+ const env = this.envFactory.getForInstance(instanceName);
52
+ const builder = env.kubectl('create namespace')
53
+ .arg(namespace);
54
+ const result = await builder.exec();
55
+ if (result.exitCode !== 0) {
56
+ throw new Error(`Failed to create namespace: ${result.stderr}`);
57
+ }
58
+ }
59
+ /**
60
+ * 建立全域設定 Secret
61
+ * @param instanceName 實例名稱
62
+ * @param saPassword SA 密碼
63
+ * @param adminPassword 管理員密碼
64
+ * @param rsaKeys RSA 金鑰組
65
+ * @param jwtKey JWT 金鑰
66
+ * @param progress 進度通知回調
67
+ */
68
+ async createGlobalConfigSecret(instanceName, saPassword, adminPassword, rsaKeys, jwtKey, output) {
69
+ const secretName = 'uofx-install-config';
70
+ const namespace = 'uofx-system';
71
+ // 確保命名空間存在
72
+ if (!(await this.checkNamespaceExists(instanceName, namespace))) {
73
+ this.logger.debug(`[Secret] Creating namespace ${namespace}...`);
74
+ await this.createNamespace(instanceName, namespace);
75
+ }
76
+ // 使用 stringData 建立 Secret (kubectl 會處理 base64 編碼)
77
+ this.logger.debug(`[Secret] Creating global config secret...`);
78
+ const secretManifest = {
79
+ apiVersion: 'v1',
80
+ kind: 'Secret',
81
+ metadata: {
82
+ name: secretName,
83
+ namespace: namespace,
84
+ },
85
+ type: 'Opaque',
86
+ stringData: {
87
+ 'sa-password': saPassword,
88
+ 'admin-password': adminPassword,
89
+ 'rsa-signin-private': rsaKeys.signInRsa.privateKey,
90
+ 'rsa-signin-public': rsaKeys.signInRsa.publicKey,
91
+ 'rsa-uofx-private': rsaKeys.uofxRsa.privateKey,
92
+ 'rsa-uofx-public': rsaKeys.uofxRsa.publicKey,
93
+ 'jwt-signing-key': jwtKey,
94
+ },
95
+ };
96
+ // 使用 kubectl apply -f - 從 stdin 輸入
97
+ const env = this.envFactory.getForInstance(instanceName);
98
+ const builder = env.kubectl('apply')
99
+ .arg('-f', '-')
100
+ .sensitiveStdin(JSON.stringify(secretManifest));
101
+ const result = await builder.exec();
102
+ if (result.exitCode !== 0) {
103
+ throw new Error(`Failed to create global config secret: ${result.stderr}`);
104
+ }
105
+ output?.success(`Global config secret created in ${namespace}`).flush();
106
+ }
107
+ /**
108
+ * 取得全域設定 Secret
109
+ * @param instanceName 實例名稱
110
+ * @returns 全域設定物件,若不存在則回傳 null
111
+ */
112
+ async getGlobalConfigSecret(instanceName) {
113
+ const secretName = 'uofx-install-config';
114
+ const namespace = 'uofx-system';
115
+ try {
116
+ const env = this.envFactory.getForInstance(instanceName);
117
+ const builder = env.kubectl('get secret')
118
+ .arg(secretName)
119
+ .arg('-n', namespace)
120
+ .arg('-o', 'json');
121
+ const result = await builder.exec();
122
+ if (result.exitCode !== 0) {
123
+ this.logger.error(new Error(`kubectl exited with code ${result.exitCode}`));
124
+ this.logger.error(new Error(`Stderr: ${result.stderr}`));
125
+ return null;
126
+ }
127
+ const secret = JSON.parse(result.stdout);
128
+ const data = secret.data;
129
+ // 驗證必要欄位
130
+ if (!data['sa-password']) {
131
+ this.logger.error(new Error('sa-password not found in secret data'));
132
+ return null;
133
+ }
134
+ if (!data['admin-password']) {
135
+ this.logger.error(new Error('admin-password not found in secret data'));
136
+ return null;
137
+ }
138
+ return {
139
+ instanceName,
140
+ saPassword: Buffer.from(data['sa-password'], 'base64').toString('utf-8'),
141
+ adminPassword: Buffer.from(data['admin-password'], 'base64').toString('utf-8'),
142
+ signInRsaPrivateKey: Buffer.from(data['rsa-signin-private'], 'base64').toString('utf-8'),
143
+ signInRsaPublicKey: Buffer.from(data['rsa-signin-public'], 'base64').toString('utf-8'),
144
+ uofxRsaPrivateKey: Buffer.from(data['rsa-uofx-private'], 'base64').toString('utf-8'),
145
+ uofxRsaPublicKey: Buffer.from(data['rsa-uofx-public'], 'base64').toString('utf-8'),
146
+ jwtSigningKey: Buffer.from(data['jwt-signing-key'], 'base64').toString('utf-8'),
147
+ connectionStringUofxDb: Buffer.from(data['connection-string-uofxdb'] || '', 'base64').toString('utf-8'),
148
+ connectionStringUofxSearchDb: Buffer.from(data['connection-string-uofxsearchdb'] || '', 'base64').toString('utf-8')
149
+ };
150
+ }
151
+ catch (error) {
152
+ this.logger.error(error, { context: 'Error reading global config secret' });
153
+ return null;
154
+ }
155
+ }
156
+ };
157
+ exports.SecretManagerService = SecretManagerService;
158
+ __decorate([
159
+ __param(1, (0, sensitive_decorator_1.Sensitive)()),
160
+ __param(2, (0, sensitive_decorator_1.Sensitive)()),
161
+ __param(3, (0, sensitive_decorator_1.Sensitive)()),
162
+ __param(4, (0, sensitive_decorator_1.Sensitive)()),
163
+ __metadata("design:type", Function),
164
+ __metadata("design:paramtypes", [String, String, String, Object, String, Object]),
165
+ __metadata("design:returntype", Promise)
166
+ ], SecretManagerService.prototype, "createGlobalConfigSecret", null);
167
+ __decorate([
168
+ (0, sensitive_decorator_1.SensitiveReturn)(),
169
+ __metadata("design:type", Function),
170
+ __metadata("design:paramtypes", [String]),
171
+ __metadata("design:returntype", Promise)
172
+ ], SecretManagerService.prototype, "getGlobalConfigSecret", null);
173
+ exports.SecretManagerService = SecretManagerService = __decorate([
174
+ (0, tsyringe_1.injectable)(),
175
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IExecutionEnvironmentFactory)),
176
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
177
+ __metadata("design:paramtypes", [Object, Object])
178
+ ], SecretManagerService);
179
+ //# sourceMappingURL=secret-manager.service.js.map
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ServiceManagerService = void 0;
16
+ const tsyringe_1 = require("tsyringe");
17
+ const tokens_1 = require("../../../di/tokens");
18
+ const deployment_parameters_entity_1 = require("../../../domain/entities/deployment-parameters.entity");
19
+ const sensitive_decorator_1 = require("../../../domain/decorators/sensitive.decorator");
20
+ const base_helm_deployment_service_1 = require("./base-helm-deployment.service");
21
+ /**
22
+ * Service Manager Service
23
+ *
24
+ * 負責 uofx-service Helm chart 的部署管理
25
+ * 繼承 BaseHelmDeploymentService 使用模板方法模式
26
+ */
27
+ let ServiceManagerService = class ServiceManagerService extends base_helm_deployment_service_1.BaseHelmDeploymentService {
28
+ constructor(envFactory, helmRegistry, logger) {
29
+ super(helmRegistry, logger, envFactory);
30
+ }
31
+ /**
32
+ * 部署 uofx-service 服務定義
33
+ */
34
+ async deployService(instanceName, params, chartVersion, output) {
35
+ output?.item('arrow', 'Deploying uofx-service chart...').flush();
36
+ await this.deployWithHelm(instanceName, params, chartVersion, output);
37
+ }
38
+ // =========================================================================
39
+ // BaseHelmDeploymentService 抽象方法實作
40
+ // =========================================================================
41
+ getServiceName() {
42
+ return 'Service';
43
+ }
44
+ getDeploymentConfig(chartVersion) {
45
+ return {
46
+ chartName: 'uofx-service',
47
+ chartVersion,
48
+ };
49
+ }
50
+ async installChart(instanceName, chartPath, _params, output) {
51
+ const builder = this.createHelmUpgradeBuilder(instanceName, {
52
+ releaseName: 'uofx-service',
53
+ chartPath,
54
+ wait: true,
55
+ timeout: '10m',
56
+ setArgs: ['podspec.selector.deploy=blue'],
57
+ });
58
+ this.logger.debug('[Service] Deploying service definition chart', {
59
+ chart: 'uofx-service',
60
+ chartPath: chartPath,
61
+ namespace: 'uofx',
62
+ instance: instanceName,
63
+ });
64
+ output?.indent().item('arrow', 'Installing uofx-service chart...').outdent().flush();
65
+ await this.executeWithRetry(builder, 'uofx-service', output);
66
+ }
67
+ };
68
+ exports.ServiceManagerService = ServiceManagerService;
69
+ __decorate([
70
+ __param(1, (0, sensitive_decorator_1.Sensitive)()),
71
+ __metadata("design:type", Function),
72
+ __metadata("design:paramtypes", [String, deployment_parameters_entity_1.DeploymentParameters, String, Object]),
73
+ __metadata("design:returntype", Promise)
74
+ ], ServiceManagerService.prototype, "deployService", null);
75
+ exports.ServiceManagerService = ServiceManagerService = __decorate([
76
+ (0, tsyringe_1.injectable)(),
77
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IExecutionEnvironmentFactory)),
78
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IHelmRegistry)),
79
+ __param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
80
+ __metadata("design:paramtypes", [Object, Object, Object])
81
+ ], ServiceManagerService);
82
+ //# sourceMappingURL=service-manager.service.js.map
@@ -0,0 +1,291 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
44
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
45
+ return function (target, key) { decorator(target, key, paramIndex); }
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.VersionCompatibilityService = void 0;
49
+ const tsyringe_1 = require("tsyringe");
50
+ const semver = __importStar(require("semver"));
51
+ const tokens_1 = require("../../../di/tokens");
52
+ const sensitive_decorator_1 = require("../../../domain/decorators/sensitive.decorator");
53
+ const errors_1 = require("../../errors");
54
+ const index_1 = require("../../../constants/index");
55
+ /**
56
+ * 版本相容性檢查服務
57
+ *
58
+ * 負責檢查 Chart 版本與當前 CLI 版本的相容性,包含:
59
+ * - 檢查 Chart 相容性清單
60
+ * - 驗證 Chart 版本
61
+ * - 解析最新的相容 Chart 版本
62
+ *
63
+ * 實作 IVersionCompatibility Domain Port
64
+ */
65
+ let VersionCompatibilityService = class VersionCompatibilityService {
66
+ constructor(httpClient, appConfig, acrCreds, logger) {
67
+ this.httpClient = httpClient;
68
+ this.appConfig = appConfig;
69
+ this.acrCreds = acrCreds;
70
+ this.logger = logger;
71
+ this.cachedManifest = null;
72
+ this.cliVersion = this.appConfig.getCliVersion();
73
+ }
74
+ /**
75
+ * 取得 Chart 相容性資訊
76
+ * @returns Chart 相容性物件
77
+ */
78
+ async getCompatibility() {
79
+ try {
80
+ const manifest = await this.fetchCompatibilityManifest(index_1.OCI_ARTIFACTS.CHART_COMPATIBILITY);
81
+ return this.parseCompatibility(manifest);
82
+ }
83
+ catch (error) {
84
+ this.logger.error(error instanceof Error ? error : new Error(String(error)), {
85
+ message: 'Failed to fetch chart compatibility'
86
+ });
87
+ // 失敗時拋出錯誤,讓呼叫者處理
88
+ throw error;
89
+ }
90
+ }
91
+ /**
92
+ * 驗證 Chart 版本是否與當前 CLI 相容
93
+ * @param chartVersion - Chart 版本
94
+ * @throws AppBusinessError 若版本不相容
95
+ */
96
+ async validateChartVersion(chartVersion) {
97
+ // 如果版本是 'latest' 或本地路徑,跳過檢查
98
+ if (chartVersion === 'latest' || chartVersion.startsWith('.') || chartVersion.startsWith('/') || chartVersion.match(/^[a-zA-Z]:/)) {
99
+ this.logger.debug(`Skipping compatibility check for version: ${chartVersion}`);
100
+ return;
101
+ }
102
+ const compatibility = await this.getCompatibility();
103
+ // 如果找不到兼容的 Chart(例如配置遺失或提取失敗但未拋出錯誤),我們假設 getCompatibility 成功執行
104
+ if (compatibility.compatibleCharts.length === 0) {
105
+ // 找不到符合此 CLI 版本的規則
106
+ // 或者相容性清單為空
107
+ this.logger.warn(`No compatibility rules found for CLI v${this.cliVersion}`);
108
+ return;
109
+ }
110
+ if (!compatibility.compatibleCharts.includes(chartVersion)) {
111
+ throw new errors_1.AppError(`Chart version ${chartVersion} is not compatible with CLI v${this.cliVersion}`, {
112
+ exitCode: errors_1.EXIT_CODES.BUSINESS_ERROR,
113
+ solution: `Use one of these compatible versions: ${compatibility.compatibleCharts.join(', ')}`,
114
+ context: {
115
+ chartVersion,
116
+ cliVersion: this.cliVersion,
117
+ compatibleCharts: compatibility.compatibleCharts
118
+ }
119
+ });
120
+ }
121
+ }
122
+ /**
123
+ * 取得與當前 CLI 相容的最新 Chart 版本
124
+ * @returns 最新的相容版本字串
125
+ * @throws AppBusinessError 若無相容版本
126
+ */
127
+ async getLatestCompatibleVersion() {
128
+ const compatibility = await this.getCompatibility();
129
+ if (compatibility.compatibleCharts.length === 0) {
130
+ throw new errors_1.AppError(`No compatible chart versions available for CLI v${this.cliVersion}`, {
131
+ exitCode: errors_1.EXIT_CODES.BUSINESS_ERROR,
132
+ solution: 'Check the compatibility manifest configuration or consider updating the CLI version',
133
+ context: {
134
+ cliVersion: this.cliVersion
135
+ }
136
+ });
137
+ }
138
+ // 過濾出有效的語義化版本
139
+ const validVersions = compatibility.compatibleCharts.filter((v) => semver.valid(v));
140
+ if (validVersions.length === 0) {
141
+ throw new errors_1.AppError(`No valid semver versions in compatibility list for CLI v${this.cliVersion}`, {
142
+ exitCode: errors_1.EXIT_CODES.BUSINESS_ERROR,
143
+ solution: 'Check the compatibility manifest - all chart versions must follow semantic versioning format (e.g., 1.0.0)',
144
+ context: {
145
+ cliVersion: this.cliVersion,
146
+ rawVersions: compatibility.compatibleCharts
147
+ }
148
+ });
149
+ }
150
+ // 降冪排序並返回第一個(最新)版本
151
+ const sorted = semver.rsort(validVersions);
152
+ const latestVersion = sorted[0];
153
+ this.logger.debug(`Latest compatible version selected: ${latestVersion}`, {
154
+ cliVersion: this.cliVersion,
155
+ allCompatibleVersions: validVersions
156
+ });
157
+ return latestVersion;
158
+ }
159
+ /**
160
+ * 解析相容性清單,找出符合當前 CLI 的規則
161
+ * @param manifest - 相容性清單
162
+ * @returns Chart 相容性物件
163
+ */
164
+ parseCompatibility(manifest) {
165
+ // 尋找符合當前 CLI 版本的規則
166
+ const rule = manifest.compatibility.find(r => semver.satisfies(this.cliVersion, r.cliRange));
167
+ if (!rule) {
168
+ this.logger.warn(`No compatibility rule matches CLI v${this.cliVersion}`);
169
+ return {
170
+ cliVersion: this.cliVersion,
171
+ compatibleCharts: []
172
+ };
173
+ }
174
+ return {
175
+ cliVersion: this.cliVersion,
176
+ compatibleCharts: rule.charts
177
+ };
178
+ }
179
+ /**
180
+ * 從 ACR 獲取相容性清單 (Manifest)
181
+ * 使用快取避免重複請求
182
+ * @param repo - Repository 名稱
183
+ * @returns 相容性清單物件
184
+ */
185
+ async fetchCompatibilityManifest(repo) {
186
+ // 使用快取
187
+ if (this.cachedManifest) {
188
+ return this.cachedManifest;
189
+ }
190
+ const creds = this.acrCreds.getDefaultCredentials();
191
+ if (!creds) {
192
+ throw new Error('ACR credentials not found');
193
+ }
194
+ const registry = `${creds.name}.azurecr.io`;
195
+ const scope = `repository:${repo}:pull`;
196
+ // 1. 取得 Token
197
+ const token = await this.getAcrToken(registry, scope, creds.account, creds.password);
198
+ // 2. 取得 Manifest 以查找 Blob Digest
199
+ const tag = index_1.OCI_ARTIFACT_TAGS.CHART_COMPATIBILITY;
200
+ const manifestUrl = `https://${registry}/v2/${repo}/manifests/${tag}`;
201
+ const manifestResponse = await this.httpClient.getJson(manifestUrl, {
202
+ Authorization: `Bearer ${token}`,
203
+ Accept: 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json'
204
+ });
205
+ // 3. 取得 Config Blob
206
+ // Manifest 包含 Layers。我們預期 JSON 檔案是其中一層或 Config Blob。
207
+ // 故事需求: "Blob: GET /v2/<repo>/blobs/<digest>"
208
+ // 我們需要知道是哪個 digest。
209
+ // 如果是單一檔案的神器,通常是第一層。
210
+ let digest = '';
211
+ if (manifestResponse.layers && manifestResponse.layers.length > 0) {
212
+ digest = manifestResponse.layers[0].digest;
213
+ }
214
+ else if (manifestResponse.config) {
215
+ // 有時 Config Blob 本身包含資訊,但對於 chart-compatibility,通常是 Layer。
216
+ // 如果它是作為單一檔案推播的,它會是一個 Layer。
217
+ digest = manifestResponse.config.digest;
218
+ }
219
+ if (!digest) {
220
+ throw new Error('Could not find digest in manifest');
221
+ }
222
+ const blobUrl = `https://${registry}/v2/${repo}/blobs/${digest}`;
223
+ const blob = await this.httpClient.getJson(blobUrl, {
224
+ Authorization: `Bearer ${token}`
225
+ });
226
+ // 存入快取
227
+ this.cachedManifest = blob;
228
+ return blob;
229
+ }
230
+ /**
231
+ * 獲取 ACR 存取 Token
232
+ * @param registry - Registry Host
233
+ * @param scope - 權限範圍
234
+ * @param user - 使用者名稱
235
+ * @param pass - 密碼
236
+ * @returns Access Token
237
+ */
238
+ async getAcrToken(registry, scope, user, pass) {
239
+ const auth = Buffer.from(`${user}:${pass}`).toString('base64');
240
+ const url = `https://${registry}/oauth2/token?service=${registry}&scope=${scope}`;
241
+ const response = await this.httpClient.getJson(url, {
242
+ Authorization: `Basic ${auth}`
243
+ });
244
+ return response.access_token;
245
+ }
246
+ /**
247
+ * 取得指定 Chart 版本對應的 Environment 版本
248
+ * @param chartVersion - Chart 版本(如 "2.123.301")
249
+ * @returns Environment 版本(如 "1.26.100")
250
+ * @throws AppError 若找不到對應的 environment 規則
251
+ */
252
+ async getEnvironmentVersion(chartVersion) {
253
+ const manifest = await this.fetchCompatibilityManifest(index_1.OCI_ARTIFACTS.CHART_COMPATIBILITY);
254
+ // 如果沒有 environment 規則,使用預設版本
255
+ if (!manifest.environment || manifest.environment.length === 0) {
256
+ this.logger.warn('No environment rules in compatibility manifest, using default');
257
+ // 預設回傳 K8s 1.26 對應的版本
258
+ return '1.26.100';
259
+ }
260
+ // 使用 semver.satisfies 匹配 chart 版本到 environment 規則
261
+ const rule = manifest.environment.find(r => semver.satisfies(chartVersion, r.chartRange));
262
+ if (!rule) {
263
+ throw new errors_1.AppError(`No environment version found for chart ${chartVersion}`, {
264
+ exitCode: errors_1.EXIT_CODES.BUSINESS_ERROR,
265
+ solution: 'Check the compatibility manifest for environment rules',
266
+ context: {
267
+ chartVersion,
268
+ availableRules: manifest.environment.map(r => r.chartRange)
269
+ }
270
+ });
271
+ }
272
+ this.logger.debug(`Environment version for chart ${chartVersion}: ${rule.version}`);
273
+ return rule.version;
274
+ }
275
+ };
276
+ exports.VersionCompatibilityService = VersionCompatibilityService;
277
+ __decorate([
278
+ __param(3, (0, sensitive_decorator_1.Sensitive)()),
279
+ __metadata("design:type", Function),
280
+ __metadata("design:paramtypes", [String, String, String, String]),
281
+ __metadata("design:returntype", Promise)
282
+ ], VersionCompatibilityService.prototype, "getAcrToken", null);
283
+ exports.VersionCompatibilityService = VersionCompatibilityService = __decorate([
284
+ (0, tsyringe_1.injectable)(),
285
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IHttpClient)),
286
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.IAppConfig)),
287
+ __param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IAcrCredentialManager)),
288
+ __param(3, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
289
+ __metadata("design:paramtypes", [Object, Object, Object, Object])
290
+ ], VersionCompatibilityService);
291
+ //# sourceMappingURL=version-compatibility.service.js.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=hardware-info.interface.js.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=network-checker.interface.js.map