@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,139 @@
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.MssqlDatabaseInitService = void 0;
16
+ const tsyringe_1 = require("tsyringe");
17
+ const tokens_1 = require("../../../di/tokens");
18
+ const paths_1 = require("../../../constants/paths");
19
+ /**
20
+ * MSSQL 資料庫初始化服務
21
+ *
22
+ * 負責等待 MSSQL Pod 就緒和建立初始資料庫
23
+ */
24
+ let MssqlDatabaseInitService = class MssqlDatabaseInitService {
25
+ constructor(envFactory, logger) {
26
+ this.envFactory = envFactory;
27
+ this.logger = logger;
28
+ }
29
+ /**
30
+ * 等待 MSSQL Pod 完全就緒
31
+ * @param instanceName WSL 實例名稱
32
+ */
33
+ async waitForMssqlReady(instanceName) {
34
+ const env = this.envFactory.getForInstance(instanceName);
35
+ const builder = env.kubectl('wait')
36
+ .arg('--for=condition=ready')
37
+ .arg('pod')
38
+ .arg('-l', 'app.kubernetes.io/name=mssql-latest')
39
+ .arg('-n', 'mssql')
40
+ .arg('--timeout=300s');
41
+ const result = await builder.exec();
42
+ if (result.exitCode !== 0) {
43
+ throw new Error(`MSSQL Pod not ready: ${result.stderr}`);
44
+ }
45
+ }
46
+ /**
47
+ * 取得 MSSQL Pod 名稱
48
+ * @param instanceName WSL 實例名稱
49
+ * @returns Pod 名稱
50
+ */
51
+ async getMssqlPodName(instanceName) {
52
+ const env = this.envFactory.getForInstance(instanceName);
53
+ const builder = env.kubectl('get')
54
+ .arg('pod')
55
+ .arg('-l', 'app.kubernetes.io/name=mssql-latest')
56
+ .arg('-n', 'mssql')
57
+ .arg('-o', "jsonpath='{.items[0].metadata.name}'");
58
+ const result = await builder.exec();
59
+ if (result.exitCode !== 0 || !result.stdout.trim()) {
60
+ throw new Error(`Failed to get MSSQL Pod name: ${result.stderr}`);
61
+ }
62
+ return result.stdout.trim();
63
+ }
64
+ /**
65
+ * 等待 SQL Server 服務啟動並接受連線
66
+ * @param instanceName WSL 實例名稱
67
+ * @param podName Pod 名稱
68
+ * @param saPassword SA 密碼
69
+ */
70
+ async waitForSqlServerReady(instanceName, podName, saPassword) {
71
+ this.logger.debug('[Mssql] Waiting for SQL Server connection...');
72
+ await new Promise(resolve => setTimeout(resolve, 5000)); // 初始等待 5 秒
73
+ const maxRetries = 30; // 最多重試 30 次
74
+ const retryDelay = 2000; // 每次重試間隔 2 秒
75
+ const env = this.envFactory.getForInstance(instanceName);
76
+ for (let i = 0; i < maxRetries; i++) {
77
+ // 嘗試連線到 SQL Server
78
+ const builder = env.kubectl('exec')
79
+ .arg('-n', 'mssql')
80
+ .arg(podName)
81
+ .arg('--')
82
+ .arg(paths_1.LINUX_PATHS.SQLCMD_BIN)
83
+ .arg('-S', 'localhost')
84
+ .arg('-U', 'sa')
85
+ .sensitiveArg('-P', `'${saPassword}'`)
86
+ .arg('-C')
87
+ .arg('-Q', '"SELECT 1"');
88
+ const result = await builder.exec();
89
+ if (result.exitCode === 0) {
90
+ this.logger.debug('[Mssql] SQL Server is ready');
91
+ return;
92
+ }
93
+ // 如果不是最後一次重試,等待後再試
94
+ if (i < maxRetries - 1) {
95
+ await new Promise(resolve => setTimeout(resolve, retryDelay));
96
+ }
97
+ }
98
+ throw new Error('SQL Server failed to start accepting connections after 60 seconds');
99
+ }
100
+ /**
101
+ * 建立初始資料庫 (uofx_dev, uofx_search)
102
+ * @param instanceName WSL 實例名稱
103
+ * @param saPassword SA 密碼
104
+ */
105
+ async createInitialDatabases(instanceName, saPassword) {
106
+ this.logger.debug('[Mssql] Creating initial databases...');
107
+ // 等待 MSSQL Pod 完全就緒
108
+ await this.waitForMssqlReady(instanceName);
109
+ // 取得 Pod 名稱
110
+ const podName = await this.getMssqlPodName(instanceName);
111
+ // 等待 SQL Server 服務啟動並接受連線
112
+ await this.waitForSqlServerReady(instanceName, podName, saPassword);
113
+ // 建立資料庫的 SQL 命令
114
+ const env = this.envFactory.getForInstance(instanceName);
115
+ const builder = env.kubectl('exec')
116
+ .arg('-n', 'mssql')
117
+ .arg(podName)
118
+ .arg('--')
119
+ .arg(paths_1.LINUX_PATHS.SQLCMD_BIN)
120
+ .arg('-S', 'localhost')
121
+ .arg('-U', 'sa')
122
+ .sensitiveArg('-P', `'${saPassword}'`)
123
+ .arg('-C')
124
+ .arg('-Q', '"CREATE DATABASE uofx_dev; CREATE DATABASE uofx_search;"');
125
+ this.logger.debug(`[Mssql] Creating databases uofx_dev, uofx_search...`);
126
+ const result = await builder.exec();
127
+ if (result.exitCode !== 0) {
128
+ throw new Error(`Failed to create initial databases: ${result.stderr}`);
129
+ }
130
+ }
131
+ };
132
+ exports.MssqlDatabaseInitService = MssqlDatabaseInitService;
133
+ exports.MssqlDatabaseInitService = MssqlDatabaseInitService = __decorate([
134
+ (0, tsyringe_1.injectable)(),
135
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IExecutionEnvironmentFactory)),
136
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
137
+ __metadata("design:paramtypes", [Object, Object])
138
+ ], MssqlDatabaseInitService);
139
+ //# sourceMappingURL=mssql-database-init.service.js.map
@@ -0,0 +1,100 @@
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.MssqlHelmDeploymentService = void 0;
16
+ const tsyringe_1 = require("tsyringe");
17
+ const tokens_1 = require("../../../di/tokens");
18
+ const base_helm_deployment_service_1 = require("./base-helm-deployment.service");
19
+ /**
20
+ * MSSQL Helm 部署服務
21
+ *
22
+ * 負責使用 Helm 部署 MSSQL,繼承 BaseHelmDeploymentService
23
+ */
24
+ let MssqlHelmDeploymentService = class MssqlHelmDeploymentService extends base_helm_deployment_service_1.BaseHelmDeploymentService {
25
+ constructor(envFactory, helmRegistry, storageService, dbInitService, logger) {
26
+ super(helmRegistry, logger, envFactory);
27
+ this.storageService = storageService;
28
+ this.dbInitService = dbInitService;
29
+ }
30
+ /**
31
+ * 部署 MSSQL
32
+ * @param instanceName WSL 實例名稱
33
+ * @param params 部署參數
34
+ * @param chartVersion Chart 版本 (MSSQL 使用固定版本,此參數會被忽略)
35
+ * @param progress 進度通知回調
36
+ */
37
+ async deployMssql(instanceName, params, _chartVersion, output) {
38
+ output?.item('arrow', 'Deploying MSSQL database...').flush();
39
+ // MSSQL 使用固定版本,傳入空字串讓 getDeploymentConfig 決定版本
40
+ await this.deployWithHelm(instanceName, params, '', output);
41
+ }
42
+ // =========================================================================
43
+ // BaseHelmDeploymentService 抽象方法實作
44
+ // =========================================================================
45
+ getServiceName() {
46
+ return 'Mssql';
47
+ }
48
+ getDeploymentConfig(_chartVersion) {
49
+ // MSSQL 使用固定版本和特定 repository
50
+ return {
51
+ chartName: 'mssql-latest',
52
+ chartVersion: '0.0.0-dev',
53
+ repository: 'uofx-cli',
54
+ };
55
+ }
56
+ /**
57
+ * 安裝前處理:建立 MSSQL 所需的持久化存儲目錄
58
+ */
59
+ async preInstall(instanceName, _params, _output) {
60
+ await this.storageService.createMssqlDirectories(instanceName);
61
+ }
62
+ async installChart(instanceName, chartPath, params, _output) {
63
+ const env = this.envFactory.getForInstance(instanceName);
64
+ const builder = env.helm('install')
65
+ .arg('--wait')
66
+ .arg('--timeout', '10m')
67
+ .arg('-n', 'mssql')
68
+ .arg('database')
69
+ .arg(`"${chartPath}"`)
70
+ .arg('--create-namespace')
71
+ .sensitiveArg('--set', `sa_password='${params.saPassword}'`);
72
+ this.logger.debug('[Mssql] Installing MSSQL chart', {
73
+ chart: 'mssql-latest',
74
+ chartPath: chartPath,
75
+ namespace: 'mssql',
76
+ instance: instanceName,
77
+ });
78
+ const result = await builder.exec();
79
+ if (result.exitCode !== 0) {
80
+ throw new Error(`Failed to deploy MSSQL: ${result.stderr}`);
81
+ }
82
+ }
83
+ /**
84
+ * 安裝後處理:建立初始資料庫
85
+ */
86
+ async postInstall(instanceName, params, _output) {
87
+ await this.dbInitService.createInitialDatabases(instanceName, params.saPassword.toString());
88
+ }
89
+ };
90
+ exports.MssqlHelmDeploymentService = MssqlHelmDeploymentService;
91
+ exports.MssqlHelmDeploymentService = MssqlHelmDeploymentService = __decorate([
92
+ (0, tsyringe_1.injectable)(),
93
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IExecutionEnvironmentFactory)),
94
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IHelmRegistry)),
95
+ __param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IMssqlStorage)),
96
+ __param(3, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IMssqlDatabaseInit)),
97
+ __param(4, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
98
+ __metadata("design:paramtypes", [Object, Object, Object, Object, Object])
99
+ ], MssqlHelmDeploymentService);
100
+ //# sourceMappingURL=mssql-helm-deployment.service.js.map
@@ -0,0 +1,54 @@
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.MssqlStorageService = void 0;
16
+ const tsyringe_1 = require("tsyringe");
17
+ const tokens_1 = require("../../../di/tokens");
18
+ const paths_1 = require("../../../constants/paths");
19
+ /**
20
+ * MSSQL 存儲服務
21
+ *
22
+ * 負責建立 MSSQL 所需的持久化存儲目錄
23
+ */
24
+ let MssqlStorageService = class MssqlStorageService {
25
+ constructor(envFactory, logger) {
26
+ this.envFactory = envFactory;
27
+ this.logger = logger;
28
+ }
29
+ /**
30
+ * 建立 MSSQL 所需的持久化存儲目錄
31
+ * @param instanceName WSL 實例名稱
32
+ */
33
+ async createMssqlDirectories(instanceName) {
34
+ this.logger.debug(`[Mssql] Creating data directories for instance ${instanceName}...`);
35
+ const directories = (0, paths_1.getMssqlDataDirectories)();
36
+ const env = this.envFactory.getForInstance(instanceName);
37
+ const builder = env.shell('mkdir')
38
+ .arg('-p')
39
+ .args(...directories);
40
+ const result = await builder.exec();
41
+ if (result.exitCode !== 0) {
42
+ throw new Error(`Failed to create MSSQL directories: ${result.stderr}`);
43
+ }
44
+ this.logger.debug('[Mssql] Directories created successfully');
45
+ }
46
+ };
47
+ exports.MssqlStorageService = MssqlStorageService;
48
+ exports.MssqlStorageService = MssqlStorageService = __decorate([
49
+ (0, tsyringe_1.injectable)(),
50
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IExecutionEnvironmentFactory)),
51
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
52
+ __metadata("design:paramtypes", [Object, Object])
53
+ ], MssqlStorageService);
54
+ //# sourceMappingURL=mssql-storage.service.js.map
@@ -0,0 +1,66 @@
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.MssqlUserManagerService = void 0;
16
+ const tsyringe_1 = require("tsyringe");
17
+ const tokens_1 = require("../../../di/tokens");
18
+ const paths_1 = require("../../../constants/paths");
19
+ /**
20
+ * MSSQL 使用者管理服務
21
+ *
22
+ * 負責在 MSSQL 資料庫中建立管理員使用者
23
+ */
24
+ let MssqlUserManagerService = class MssqlUserManagerService {
25
+ constructor(envFactory, dbInitService, logger) {
26
+ this.envFactory = envFactory;
27
+ this.dbInitService = dbInitService;
28
+ this.logger = logger;
29
+ }
30
+ /**
31
+ * 建立 uofxadmin 管理員使用者
32
+ * @param instanceName WSL 實例名稱
33
+ * @param params 部署參數
34
+ */
35
+ async createAdminUser(instanceName, params) {
36
+ this.logger.debug('[Mssql] Creating uofxadmin user...');
37
+ const podName = await this.dbInitService.getMssqlPodName(instanceName);
38
+ const email = `admin@${instanceName}.com`;
39
+ const query = `EXECUTE [dbo].[usp_Admin_User_Upcert_v01] 'uofxadmin', '${params.adminPassword}', '${email}'`;
40
+ const env = this.envFactory.getForInstance(instanceName);
41
+ const builder = env.kubectl('exec')
42
+ .arg('-n', 'mssql')
43
+ .arg(podName)
44
+ .arg('--')
45
+ .arg(paths_1.LINUX_PATHS.SQLCMD_BIN)
46
+ .arg('-S', 'localhost')
47
+ .arg('-U', 'sa')
48
+ .sensitiveArg('-P', `'${params.saPassword}'`)
49
+ .arg('-d', 'uofx_dev')
50
+ .arg('-C')
51
+ .sensitiveArg('-Q', `"${query}"`);
52
+ const result = await builder.exec();
53
+ if (result.exitCode !== 0) {
54
+ throw new Error(`Failed to create admin user: ${result.stderr}`);
55
+ }
56
+ }
57
+ };
58
+ exports.MssqlUserManagerService = MssqlUserManagerService;
59
+ exports.MssqlUserManagerService = MssqlUserManagerService = __decorate([
60
+ (0, tsyringe_1.injectable)(),
61
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IExecutionEnvironmentFactory)),
62
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IMssqlDatabaseInit)),
63
+ __param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
64
+ __metadata("design:paramtypes", [Object, Object, Object])
65
+ ], MssqlUserManagerService);
66
+ //# sourceMappingURL=mssql-user-manager.service.js.map
@@ -0,0 +1,289 @@
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.OciArtifactService = 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
+ * OCI Artifact 下載服務
21
+ *
22
+ * 負責從 OCI registry 下載 artifacts(非 Helm Charts)
23
+ * 支援兩種模式:
24
+ * 1. Windows 側 HTTP 下載(用於 JSON 配置檔)
25
+ * 2. WSL 內透過 curl 下載(用於需要在 WSL 執行的腳本)
26
+ */
27
+ let OciArtifactService = class OciArtifactService {
28
+ constructor(httpClient, envFactory, logger) {
29
+ this.httpClient = httpClient;
30
+ this.envFactory = envFactory;
31
+ this.logger = logger;
32
+ }
33
+ /**
34
+ * 從 OCI registry 下載 JSON artifact 並解析
35
+ * 在 Windows 側執行
36
+ */
37
+ async fetchJson(repo, tag, credentials) {
38
+ const registry = `${credentials.name}.azurecr.io`;
39
+ const scope = `repository:${repo}:pull`;
40
+ this.logger.debug(`Fetching OCI artifact: ${repo}:${tag}`);
41
+ // 1. 取得 Token
42
+ const token = await this.getAcrToken(registry, scope, credentials.account, credentials.password);
43
+ // 2. 取得 Manifest
44
+ const manifestUrl = `https://${registry}/v2/${repo}/manifests/${tag}`;
45
+ const manifestResponse = await this.httpClient.getJson(manifestUrl, {
46
+ Authorization: `Bearer ${token}`,
47
+ Accept: 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json'
48
+ });
49
+ // 3. 取得 Blob Digest
50
+ const digest = this.extractDigest(manifestResponse);
51
+ if (!digest) {
52
+ throw new Error(`Could not find digest in manifest for ${repo}:${tag}`);
53
+ }
54
+ // 4. 下載 Blob
55
+ const blobUrl = `https://${registry}/v2/${repo}/blobs/${digest}`;
56
+ const blob = await this.httpClient.getJson(blobUrl, {
57
+ Authorization: `Bearer ${token}`
58
+ });
59
+ this.logger.debug(`Successfully fetched OCI artifact: ${repo}:${tag}`);
60
+ return blob;
61
+ }
62
+ /**
63
+ * 在實例內下載 OCI artifact
64
+ * 全程在實例內透過 curl 完成
65
+ * 透過 IExecutionEnvironmentFactory 自動選擇正確的執行環境
66
+ */
67
+ async downloadToInstance(instanceName, repo, tag, targetPath, credentials) {
68
+ const registry = `${credentials.name}.azurecr.io`;
69
+ const scope = `repository:${repo}:pull`;
70
+ this.logger.debug(`Downloading OCI artifact to instance: ${repo}:${tag} -> ${targetPath}`);
71
+ // 建立在實例內執行的下載腳本
72
+ const downloadScript = this.buildDownloadScript(registry, repo, tag, scope, targetPath, credentials.account, credentials.password);
73
+ const env = this.envFactory.getForInstance(instanceName);
74
+ // 使用 stdin 傳遞腳本以避免引號轉義問題
75
+ const result = await env.shell('bash').sensitiveStdin(downloadScript).exec();
76
+ if (result.exitCode !== 0) {
77
+ // 輸出詳細錯誤信息以幫助診斷
78
+ const errorDetail = result.stderr || result.stdout || 'No output';
79
+ this.logger.error(new Error(`OCI download script failed`), {
80
+ exitCode: result.exitCode,
81
+ stderr: result.stderr,
82
+ stdout: result.stdout,
83
+ instanceName,
84
+ repo,
85
+ tag
86
+ });
87
+ throw new Error(`Failed to download OCI artifact: ${errorDetail}`);
88
+ }
89
+ this.logger.debug(`Successfully downloaded OCI artifact to instance: ${targetPath}`);
90
+ }
91
+ /**
92
+ * 建立在實例內執行的下載腳本
93
+ */
94
+ buildDownloadScript(registry, repo, tag, scope, targetPath, user, password) {
95
+ // 使用 base64 編碼密碼以避免特殊字符問題
96
+ const passwordBase64 = Buffer.from(password).toString('base64');
97
+ // 腳本會:
98
+ // 1. 解碼密碼
99
+ // 2. 取得 Token
100
+ // 3. 取得 Manifest,解析 digest
101
+ // 4. 下載 Blob 到目標路徑
102
+ // 5. 設定執行權限(如果是 .sh 檔案)
103
+ return `
104
+ set -e
105
+
106
+ REGISTRY="${registry}"
107
+ REPO="${repo}"
108
+ TAG="${tag}"
109
+ SCOPE="${scope}"
110
+ TARGET="${targetPath}"
111
+ USER="${user}"
112
+ PASS_B64="${passwordBase64}"
113
+
114
+ echo "OCI Download: Starting..."
115
+
116
+ # 解碼密碼
117
+ PASS=$(echo "\${PASS_B64}" | base64 -d)
118
+
119
+ echo "OCI Download: Getting token..."
120
+ # 1. 取得 Token
121
+ TOKEN_RESPONSE=$(curl -sfL -u "\${USER}:\${PASS}" \\
122
+ "https://\${REGISTRY}/oauth2/token?service=\${REGISTRY}&scope=\${SCOPE}")
123
+
124
+ if [ -z "\${TOKEN_RESPONSE}" ]; then
125
+ echo "Failed to get ACR token response" >&2
126
+ exit 1
127
+ fi
128
+
129
+ TOKEN=$(echo "\${TOKEN_RESPONSE}" | sed -n 's/.*"access_token":"\\([^"]*\\)".*/\\1/p')
130
+
131
+ if [ -z "\${TOKEN}" ]; then
132
+ echo "Failed to parse ACR token from response" >&2
133
+ echo "Response: \${TOKEN_RESPONSE}" >&2
134
+ exit 1
135
+ fi
136
+
137
+ echo "OCI Download: Getting manifest..."
138
+ # 2. 取得 Manifest,解析 digest
139
+ MANIFEST=$(curl -sfL -H "Authorization: Bearer \${TOKEN}" \\
140
+ -H "Accept: application/vnd.oci.image.manifest.v1+json" \\
141
+ "https://\${REGISTRY}/v2/\${REPO}/manifests/\${TAG}")
142
+
143
+ if [ -z "\${MANIFEST}" ]; then
144
+ echo "Failed to get manifest for \${REPO}:\${TAG}" >&2
145
+ exit 1
146
+ fi
147
+
148
+ # 從 layers 區塊取得第一個 digest
149
+ # 先找到 layers 區塊,再從中提取 digest
150
+ DIGEST=$(echo "\${MANIFEST}" | sed 's/.*"layers"[^[]*\\[//' | grep -o '"digest"[ ]*:[ ]*"sha256:[^"]*"' | head -1 | sed 's/.*"\\(sha256:[^"]*\\)".*/\\1/')
151
+
152
+ if [ -z "\${DIGEST}" ]; then
153
+ echo "Failed to extract digest from manifest" >&2
154
+ echo "Manifest: \${MANIFEST}" >&2
155
+ exit 1
156
+ fi
157
+
158
+ echo "OCI Download: Downloading blob \${DIGEST}..."
159
+ # 3. 下載 Blob(可能是 tar 或直接檔案)
160
+ # 注意:ACR 會返回 302 重定向到 Azure Blob Storage,需要 -L 跟隨重定向
161
+ TEMP_BLOB="/tmp/oci-blob-$$"
162
+ curl -sfL -H "Authorization: Bearer \${TOKEN}" \\
163
+ -o "\${TEMP_BLOB}" \\
164
+ "https://\${REGISTRY}/v2/\${REPO}/blobs/\${DIGEST}"
165
+
166
+ if [ ! -f "\${TEMP_BLOB}" ]; then
167
+ echo "Failed to download blob" >&2
168
+ exit 1
169
+ fi
170
+
171
+ # 4. 檢查是否為 tar 檔案,如果是則解壓縮
172
+ TARGET_DIR=$(dirname "\${TARGET}")
173
+ TARGET_BASENAME=$(basename "\${TARGET}")
174
+
175
+ # 嘗試 tar -tf 列出內容,如果成功則是 tar
176
+ if tar -tf "\${TEMP_BLOB}" >/dev/null 2>&1; then
177
+ # 是 tar 檔案,解壓縮
178
+ echo "Blob is a tar archive, extracting..."
179
+
180
+ # 取得 tar 內的檔案列表
181
+ TAR_CONTENTS=$(tar -tf "\${TEMP_BLOB}")
182
+
183
+ # 解壓縮到目標目錄
184
+ tar -xf "\${TEMP_BLOB}" -C "\${TARGET_DIR}"
185
+
186
+ # 如果目標檔案不存在,找到解壓縮的檔案並重命名
187
+ if [ ! -f "\${TARGET}" ]; then
188
+ # 取得 tar 內第一個檔案名稱
189
+ FIRST_FILE=$(echo "\${TAR_CONTENTS}" | head -1)
190
+ EXTRACTED_PATH="\${TARGET_DIR}/\${FIRST_FILE}"
191
+
192
+ if [ -f "\${EXTRACTED_PATH}" ]; then
193
+ echo "Renaming extracted file: \${FIRST_FILE} -> \${TARGET_BASENAME}"
194
+ mv "\${EXTRACTED_PATH}" "\${TARGET}"
195
+ else
196
+ # 備用:尋找目錄中最新的檔案
197
+ EXTRACTED=$(find "\${TARGET_DIR}" -maxdepth 1 -type f -newer "\${TEMP_BLOB}" 2>/dev/null | head -1)
198
+ if [ -n "\${EXTRACTED}" ] && [ "\${EXTRACTED}" != "\${TARGET}" ]; then
199
+ echo "Moving extracted file: \${EXTRACTED} -> \${TARGET}"
200
+ mv "\${EXTRACTED}" "\${TARGET}"
201
+ fi
202
+ fi
203
+ fi
204
+ else
205
+ # 不是 tar,直接複製
206
+ cp "\${TEMP_BLOB}" "\${TARGET}"
207
+ fi
208
+
209
+ rm -f "\${TEMP_BLOB}"
210
+
211
+ if [ ! -f "\${TARGET}" ]; then
212
+ echo "Failed to extract/copy blob to \${TARGET}" >&2
213
+ exit 1
214
+ fi
215
+
216
+ echo "OCI Download: Converting line endings..."
217
+ # 5. 轉換 Windows 換行符 (CRLF) 為 Unix 格式 (LF)
218
+ sed -i 's/\\r$//' "\${TARGET}"
219
+
220
+ echo "OCI Download: Setting permissions..."
221
+ # 6. 如果是 .sh 檔案,設定執行權限
222
+ case "\${TARGET}" in
223
+ *.sh)
224
+ chmod +x "\${TARGET}"
225
+ ;;
226
+ esac
227
+
228
+ echo "OCI Download: Complete - \${TARGET} ($(wc -c < \${TARGET}) bytes)"
229
+ `;
230
+ }
231
+ /**
232
+ * 從 Manifest 回應中提取 Digest
233
+ */
234
+ extractDigest(manifest) {
235
+ // 優先從 layers[0] 取得
236
+ if (manifest.layers && manifest.layers.length > 0) {
237
+ return manifest.layers[0].digest;
238
+ }
239
+ // 備用:從 config 取得
240
+ if (manifest.config && manifest.config.digest) {
241
+ return manifest.config.digest;
242
+ }
243
+ return null;
244
+ }
245
+ /**
246
+ * 獲取 ACR 存取 Token(Windows 側)
247
+ */
248
+ async getAcrToken(registry, scope, user, password) {
249
+ const auth = Buffer.from(`${user}:${password}`).toString('base64');
250
+ const url = `https://${registry}/oauth2/token?service=${registry}&scope=${scope}`;
251
+ const response = await this.httpClient.getJson(url, {
252
+ Authorization: `Basic ${auth}`
253
+ });
254
+ return response.access_token;
255
+ }
256
+ };
257
+ exports.OciArtifactService = OciArtifactService;
258
+ __decorate([
259
+ __param(2, (0, sensitive_decorator_1.Sensitive)()),
260
+ __metadata("design:type", Function),
261
+ __metadata("design:paramtypes", [String, String, Object]),
262
+ __metadata("design:returntype", Promise)
263
+ ], OciArtifactService.prototype, "fetchJson", null);
264
+ __decorate([
265
+ __param(4, (0, sensitive_decorator_1.Sensitive)()),
266
+ __metadata("design:type", Function),
267
+ __metadata("design:paramtypes", [String, String, String, String, Object]),
268
+ __metadata("design:returntype", Promise)
269
+ ], OciArtifactService.prototype, "downloadToInstance", null);
270
+ __decorate([
271
+ __param(6, (0, sensitive_decorator_1.Sensitive)()),
272
+ __metadata("design:type", Function),
273
+ __metadata("design:paramtypes", [String, String, String, String, String, String, String]),
274
+ __metadata("design:returntype", String)
275
+ ], OciArtifactService.prototype, "buildDownloadScript", null);
276
+ __decorate([
277
+ __param(3, (0, sensitive_decorator_1.Sensitive)()),
278
+ __metadata("design:type", Function),
279
+ __metadata("design:paramtypes", [String, String, String, String]),
280
+ __metadata("design:returntype", Promise)
281
+ ], OciArtifactService.prototype, "getAcrToken", null);
282
+ exports.OciArtifactService = OciArtifactService = __decorate([
283
+ (0, tsyringe_1.injectable)(),
284
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IHttpClient)),
285
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IExecutionEnvironmentFactory)),
286
+ __param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
287
+ __metadata("design:paramtypes", [Object, Object, Object])
288
+ ], OciArtifactService);
289
+ //# sourceMappingURL=oci-artifact.service.js.map