@exagone313/dsh-podman 0.2.0-rc.2

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 (165) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +41 -0
  3. package/README.zh.md +41 -0
  4. package/cordis.patch.yml +17 -0
  5. package/dist/approval-reasons.d.ts +129 -0
  6. package/dist/approval-reasons.js +253 -0
  7. package/dist/approval-reasons.test.d.ts +1 -0
  8. package/dist/approval-reasons.test.js +115 -0
  9. package/dist/approval.d.ts +29 -0
  10. package/dist/approval.js +412 -0
  11. package/dist/approval.test.d.ts +1 -0
  12. package/dist/approval.test.js +462 -0
  13. package/dist/card-route.d.ts +15 -0
  14. package/dist/card-route.js +478 -0
  15. package/dist/card-route.test.d.ts +1 -0
  16. package/dist/card-route.test.js +181 -0
  17. package/dist/card-test-support.d.ts +15 -0
  18. package/dist/card-test-support.js +160 -0
  19. package/dist/client/ContainerCard.d.ts +6 -0
  20. package/dist/client/ContainerCard.js +79 -0
  21. package/dist/client/card-client.d.ts +6 -0
  22. package/dist/client/card-client.js +47 -0
  23. package/dist/client/card-protocol.d.ts +101 -0
  24. package/dist/client/card-protocol.js +10 -0
  25. package/dist/client/container-card-caches.d.ts +10 -0
  26. package/dist/client/container-card-caches.js +31 -0
  27. package/dist/client/container-card-controller.d.ts +107 -0
  28. package/dist/client/container-card-controller.js +207 -0
  29. package/dist/client/container-card-create-modal.d.ts +24 -0
  30. package/dist/client/container-card-create-modal.js +109 -0
  31. package/dist/client/container-card-directory-styles.d.ts +5 -0
  32. package/dist/client/container-card-directory-styles.js +246 -0
  33. package/dist/client/container-card-directory.d.ts +12 -0
  34. package/dist/client/container-card-directory.js +144 -0
  35. package/dist/client/container-card-editors.d.ts +30 -0
  36. package/dist/client/container-card-editors.js +116 -0
  37. package/dist/client/container-card-images.d.ts +37 -0
  38. package/dist/client/container-card-images.js +35 -0
  39. package/dist/client/container-card-paths.d.ts +20 -0
  40. package/dist/client/container-card-paths.js +88 -0
  41. package/dist/client/container-card-row.d.ts +30 -0
  42. package/dist/client/container-card-row.js +54 -0
  43. package/dist/client/container-card-secrets.d.ts +21 -0
  44. package/dist/client/container-card-secrets.js +71 -0
  45. package/dist/client/container-card-shared.d.ts +55 -0
  46. package/dist/client/container-card-shared.js +152 -0
  47. package/dist/client/container-card-styles.d.ts +21 -0
  48. package/dist/client/container-card-styles.js +143 -0
  49. package/dist/client/container-card-volumes.d.ts +12 -0
  50. package/dist/client/container-card-volumes.js +37 -0
  51. package/dist/client/container-card-workspace.d.ts +31 -0
  52. package/dist/client/container-card-workspace.js +24 -0
  53. package/dist/client/directory-picker.d.ts +12 -0
  54. package/dist/client/directory-picker.js +30 -0
  55. package/dist/client/index.d.ts +5 -0
  56. package/dist/client/index.js +4419 -0
  57. package/dist/client/locales.d.ts +9 -0
  58. package/dist/client/locales.js +370 -0
  59. package/dist/client/read-only-approval.d.ts +8 -0
  60. package/dist/client/read-only-approval.js +63 -0
  61. package/dist/client/slot-contract.d.ts +12 -0
  62. package/dist/client/slot-contract.js +4 -0
  63. package/dist/client/terminal-styles.d.ts +5 -0
  64. package/dist/client/terminal-styles.js +31 -0
  65. package/dist/client/tool-views.d.ts +8 -0
  66. package/dist/client/tool-views.js +241 -0
  67. package/dist/containers.test.d.ts +1 -0
  68. package/dist/containers.test.js +443 -0
  69. package/dist/daemons.test.d.ts +1 -0
  70. package/dist/daemons.test.js +153 -0
  71. package/dist/fs-provider.d.ts +23 -0
  72. package/dist/fs-provider.js +184 -0
  73. package/dist/fs-provider.test.d.ts +1 -0
  74. package/dist/fs-provider.test.js +260 -0
  75. package/dist/generated/version.d.ts +2 -0
  76. package/dist/generated/version.js +6 -0
  77. package/dist/grpc/proto/dshctl/v1/control.proto +133 -0
  78. package/dist/grpc/proto/dshguest/v1/guest.proto +79 -0
  79. package/dist/grpc/runtime-client.d.ts +5 -0
  80. package/dist/grpc/runtime-client.js +43 -0
  81. package/dist/guest-rpc.d.ts +62 -0
  82. package/dist/guest-rpc.js +391 -0
  83. package/dist/images.test.d.ts +1 -0
  84. package/dist/images.test.js +79 -0
  85. package/dist/index.d.ts +22 -0
  86. package/dist/index.js +140 -0
  87. package/dist/misc.test.d.ts +1 -0
  88. package/dist/misc.test.js +141 -0
  89. package/dist/mount-enums.d.ts +22 -0
  90. package/dist/mount-enums.js +81 -0
  91. package/dist/mount-input.d.ts +14 -0
  92. package/dist/mount-input.js +64 -0
  93. package/dist/mounts.test.d.ts +1 -0
  94. package/dist/mounts.test.js +408 -0
  95. package/dist/output-reader.d.ts +34 -0
  96. package/dist/output-reader.js +87 -0
  97. package/dist/paths.test.d.ts +1 -0
  98. package/dist/paths.test.js +74 -0
  99. package/dist/preferences.d.ts +6 -0
  100. package/dist/preferences.js +27 -0
  101. package/dist/project-path.d.ts +6 -0
  102. package/dist/project-path.js +73 -0
  103. package/dist/project-path.test.d.ts +1 -0
  104. package/dist/project-path.test.js +52 -0
  105. package/dist/prompts.d.ts +13 -0
  106. package/dist/prompts.js +149 -0
  107. package/dist/public.d.ts +4 -0
  108. package/dist/public.js +63 -0
  109. package/dist/read-only-shell.d.ts +14 -0
  110. package/dist/read-only-shell.js +150 -0
  111. package/dist/read-only-shell.test.d.ts +1 -0
  112. package/dist/read-only-shell.test.js +127 -0
  113. package/dist/secrets.test.d.ts +1 -0
  114. package/dist/secrets.test.js +181 -0
  115. package/dist/settings-commands.test.d.ts +1 -0
  116. package/dist/settings-commands.test.js +549 -0
  117. package/dist/settings-create.test.d.ts +1 -0
  118. package/dist/settings-create.test.js +394 -0
  119. package/dist/settings-mounts.test.d.ts +1 -0
  120. package/dist/settings-mounts.test.js +467 -0
  121. package/dist/settings-paths.test.d.ts +1 -0
  122. package/dist/settings-paths.test.js +65 -0
  123. package/dist/settings-schema.d.ts +14 -0
  124. package/dist/settings-schema.js +14 -0
  125. package/dist/settings-workspaces.test.d.ts +1 -0
  126. package/dist/settings-workspaces.test.js +265 -0
  127. package/dist/spill-store.d.ts +17 -0
  128. package/dist/spill-store.js +54 -0
  129. package/dist/spill-store.test.d.ts +1 -0
  130. package/dist/spill-store.test.js +59 -0
  131. package/dist/subprocess.d.ts +9 -0
  132. package/dist/subprocess.js +369 -0
  133. package/dist/subprocess.test.d.ts +1 -0
  134. package/dist/subprocess.test.js +234 -0
  135. package/dist/test-support.d.ts +328 -0
  136. package/dist/test-support.js +437 -0
  137. package/dist/tool-defs.d.ts +26 -0
  138. package/dist/tool-defs.js +188 -0
  139. package/dist/tool-handlers.d.ts +2 -0
  140. package/dist/tool-handlers.js +546 -0
  141. package/dist/tool-params.d.ts +803 -0
  142. package/dist/tool-params.js +494 -0
  143. package/dist/tool-schemas.d.ts +2 -0
  144. package/dist/tool-schemas.js +5 -0
  145. package/dist/tool-views.d.ts +2 -0
  146. package/dist/tool-views.js +56 -0
  147. package/dist/views.test.d.ts +1 -0
  148. package/dist/views.test.js +23 -0
  149. package/dist/volumes.test.d.ts +1 -0
  150. package/dist/volumes.test.js +40 -0
  151. package/dist/workspace-binding.d.ts +40 -0
  152. package/dist/workspace-binding.js +275 -0
  153. package/dist/workspace-binding.test.d.ts +1 -0
  154. package/dist/workspace-binding.test.js +337 -0
  155. package/docs/architecture.md +173 -0
  156. package/docs/architecture.zh.md +129 -0
  157. package/docs/configuration.md +160 -0
  158. package/docs/configuration.zh.md +147 -0
  159. package/docs/development.md +142 -0
  160. package/docs/development.zh.md +135 -0
  161. package/docs/install-dsh-and-dsh-podman.md +165 -0
  162. package/docs/install-dsh-and-dsh-podman.zh.md +145 -0
  163. package/docs/usage.md +393 -0
  164. package/docs/usage.zh.md +315 -0
  165. package/package.json +119 -0
@@ -0,0 +1,549 @@
1
+ // SPDX-FileCopyrightText: 2026 Elouan Martinet <exa@elou.world>
2
+ //
3
+ // SPDX-License-Identifier: MIT
4
+ import { test } from "node:test";
5
+ import { strict as assert } from "node:assert";
6
+ import { fakeScope, fakeContext, baseValue, installedMountScope, mountCommand, } from "./card-test-support.js";
7
+ import { installCardCommandDriver } from "./card-test-support.js";
8
+ test("remove command drives removeContainer and clears the command", async () => {
9
+ const scope = fakeScope(baseValue());
10
+ const calls = [];
11
+ const resolver = {
12
+ getConfig: () => ({}),
13
+ setConfig: () => { },
14
+ async control(method, request) {
15
+ calls.push([method, request]);
16
+ if (method === "listContainers")
17
+ return { containers: [] };
18
+ if (method === "listImages")
19
+ return { images: [] };
20
+ return {};
21
+ },
22
+ };
23
+ await installCardCommandDriver(fakeContext(scope), resolver);
24
+ await scope.update({
25
+ command: { op: "remove", workspace: "w1", image: "", at: 1 },
26
+ });
27
+ await new Promise((resolve) => setImmediate(resolve));
28
+ const removeCall = calls.find(([method]) => method === "removeContainer");
29
+ assert.deepEqual(removeCall?.[1], { workspaceSlug: "w1" });
30
+ assert.equal(scope.value.command, null);
31
+ });
32
+ test("workspace_remove command drives removeWorkspace and clears the command", async () => {
33
+ const scope = fakeScope(baseValue());
34
+ const calls = [];
35
+ const resolver = {
36
+ getConfig: () => ({}),
37
+ setConfig: () => { },
38
+ async control(method, request) {
39
+ calls.push([method, request]);
40
+ if (method === "listContainers")
41
+ return { containers: [] };
42
+ if (method === "listImages")
43
+ return { images: [] };
44
+ return {};
45
+ },
46
+ };
47
+ await installCardCommandDriver(fakeContext(scope), resolver);
48
+ await scope.update({
49
+ command: { op: "workspace_remove", workspace: "w1", image: "", at: 2 },
50
+ });
51
+ await new Promise((resolve) => setImmediate(resolve));
52
+ const removeCall = calls.find(([method]) => method === "removeWorkspace");
53
+ assert.deepEqual(removeCall?.[1], { workspaceSlug: "w1" });
54
+ assert.equal(scope.value.command, null);
55
+ });
56
+ test("cache_clean command drives cleanCaches, maps the mode, and reports the result", async () => {
57
+ const scope = fakeScope(baseValue());
58
+ const calls = [];
59
+ const resolver = {
60
+ getConfig: () => ({}),
61
+ setConfig: () => { },
62
+ async control(method, request) {
63
+ calls.push([method, request]);
64
+ if (method === "listContainers")
65
+ return { containers: [] };
66
+ if (method === "listImages")
67
+ return { images: [] };
68
+ if (method === "cleanCaches")
69
+ return { removedFiles: 2, removedBytes: "2048" };
70
+ if (method === "listCaches") {
71
+ return { caches: [{ manager: "pacman", path: "/cache", files: 1, bytes: "1024" }] };
72
+ }
73
+ return {};
74
+ },
75
+ };
76
+ await installCardCommandDriver(fakeContext(scope), resolver);
77
+ await scope.update({
78
+ command: { op: "cache_clean", workspace: "", image: "", at: 3, cacheMode: "all" },
79
+ });
80
+ await new Promise((resolve) => setImmediate(resolve));
81
+ await scope.update({
82
+ command: { op: "cache_clean", workspace: "", image: "", at: 4, cacheMode: "keep-latest" },
83
+ });
84
+ await new Promise((resolve) => setImmediate(resolve));
85
+ const modes = calls
86
+ .filter(([method]) => method === "cleanCaches")
87
+ .map(([, request]) => request.mode);
88
+ assert.deepEqual(modes, ["CACHE_CLEAN_MODE_ALL", "CACHE_CLEAN_MODE_KEEP_LATEST"]);
89
+ assert.equal(scope.value.command, null);
90
+ assert.equal(scope.value.notice, "removed 2 cached files");
91
+ const caches = scope.value.caches;
92
+ assert.equal(caches.length, 1);
93
+ assert.equal(caches[0].manager, "pacman");
94
+ // The control plane reports int64 as a string.
95
+ assert.equal(caches[0].bytes, 1024);
96
+ });
97
+ test("volume_remove command drives removeVolume with the name", async () => {
98
+ const scope = fakeScope(baseValue());
99
+ const calls = [];
100
+ const resolver = {
101
+ getConfig: () => ({}),
102
+ setConfig: () => { },
103
+ async control(method, request) {
104
+ calls.push([method, request]);
105
+ if (method === "listContainers")
106
+ return { containers: [] };
107
+ if (method === "listImages")
108
+ return { images: [] };
109
+ if (method === "listWorkspaces")
110
+ return { workspaces: [] };
111
+ if (method === "listVolumes")
112
+ return { volumes: [] };
113
+ return {};
114
+ },
115
+ };
116
+ await installCardCommandDriver(fakeContext(scope), resolver);
117
+ await scope.update({
118
+ command: { op: "volume_remove", workspace: "cache", image: "", at: 4 },
119
+ });
120
+ await new Promise((resolve) => setImmediate(resolve));
121
+ const removeCall = calls.find(([method]) => method === "removeVolume");
122
+ assert.deepEqual(removeCall?.[1], { name: "cache" });
123
+ assert.equal(scope.value.command, null);
124
+ });
125
+ test("image_remove command drives removeImage with the imageId", async () => {
126
+ const scope = fakeScope(baseValue());
127
+ const calls = [];
128
+ const resolver = {
129
+ getConfig: () => ({}),
130
+ setConfig: () => { },
131
+ async control(method, request) {
132
+ calls.push([method, request]);
133
+ if (method === "listContainers")
134
+ return { containers: [] };
135
+ if (method === "listImages")
136
+ return { images: [] };
137
+ if (method === "listWorkspaces")
138
+ return { workspaces: [] };
139
+ if (method === "listVolumes")
140
+ return { volumes: [] };
141
+ return {};
142
+ },
143
+ };
144
+ await installCardCommandDriver(fakeContext(scope), resolver);
145
+ await scope.update({
146
+ command: { op: "image_remove", workspace: "valkey", image: "", at: 5 },
147
+ });
148
+ await new Promise((resolve) => setImmediate(resolve));
149
+ const removeCall = calls.find(([method]) => method === "removeImage");
150
+ assert.deepEqual(removeCall?.[1], { imageId: "valkey" });
151
+ assert.equal(scope.value.command, null);
152
+ });
153
+ test("secret_remove command drives removeSecret with the name", async () => {
154
+ const scope = fakeScope(baseValue());
155
+ const calls = [];
156
+ const resolver = {
157
+ getConfig: () => ({}),
158
+ setConfig: () => { },
159
+ async control(method, request) {
160
+ calls.push([method, request]);
161
+ if (method === "listContainers")
162
+ return { containers: [] };
163
+ if (method === "listImages")
164
+ return { images: [] };
165
+ if (method === "listWorkspaces")
166
+ return { workspaces: [] };
167
+ if (method === "listVolumes")
168
+ return { volumes: [] };
169
+ if (method === "listSecrets")
170
+ return { secrets: [] };
171
+ return {};
172
+ },
173
+ };
174
+ await installCardCommandDriver(fakeContext(scope), resolver);
175
+ await scope.update({
176
+ command: { op: "secret_remove", workspace: "db-pass", image: "", at: 7, mounts: [], value: "" },
177
+ });
178
+ await new Promise((resolve) => setImmediate(resolve));
179
+ const removeCall = calls.find(([method]) => method === "removeSecret");
180
+ assert.deepEqual(removeCall?.[1], { name: "db-pass" });
181
+ assert.equal(scope.value.command, null);
182
+ });
183
+ test("secret_set command drives writeSecretValue with the name and value", async () => {
184
+ const scope = fakeScope(baseValue());
185
+ const calls = [];
186
+ const resolver = {
187
+ getConfig: () => ({}),
188
+ setConfig: () => { },
189
+ async control(method, request) {
190
+ calls.push([method, request]);
191
+ if (method === "listContainers")
192
+ return { containers: [] };
193
+ if (method === "listImages")
194
+ return { images: [] };
195
+ if (method === "listWorkspaces")
196
+ return { workspaces: [] };
197
+ if (method === "listVolumes")
198
+ return { volumes: [] };
199
+ if (method === "listSecrets")
200
+ return { secrets: [] };
201
+ return {};
202
+ },
203
+ };
204
+ await installCardCommandDriver(fakeContext(scope), resolver);
205
+ await scope.update({
206
+ command: { op: "secret_set", workspace: "db-pass", image: "", at: 8, mounts: [], value: "s3cr3t" },
207
+ });
208
+ await new Promise((resolve) => setImmediate(resolve));
209
+ const setCall = calls.find(([method]) => method === "writeSecretValue");
210
+ assert.deepEqual(setCall?.[1], { name: "db-pass", value: "s3cr3t" });
211
+ assert.equal(scope.value.command, null);
212
+ });
213
+ test("image_rebuild command drives rebuildImage with the imageId", async () => {
214
+ const scope = fakeScope(baseValue());
215
+ const calls = [];
216
+ const resolver = {
217
+ getConfig: () => ({}),
218
+ setConfig: () => { },
219
+ async control(method, request) {
220
+ calls.push([method, request]);
221
+ if (method === "listContainers")
222
+ return { containers: [] };
223
+ if (method === "listImages")
224
+ return { images: [] };
225
+ if (method === "listWorkspaces")
226
+ return { workspaces: [] };
227
+ if (method === "listVolumes")
228
+ return { volumes: [] };
229
+ if (method === "listSecrets")
230
+ return { secrets: [] };
231
+ return {};
232
+ },
233
+ };
234
+ await installCardCommandDriver(fakeContext(scope), resolver);
235
+ await scope.update({
236
+ command: { op: "image_rebuild", workspace: "valkey", image: "", at: 9 },
237
+ });
238
+ await new Promise((resolve) => setImmediate(resolve));
239
+ const rebuildCall = calls.find(([method]) => method === "rebuildImage");
240
+ assert.deepEqual(rebuildCall?.[1], { imageId: "valkey" });
241
+ assert.equal(scope.value.command, null);
242
+ });
243
+ test("image_rebuild_all command drives rebuildAllImages with an empty payload", async () => {
244
+ const scope = fakeScope(baseValue());
245
+ const calls = [];
246
+ const resolver = {
247
+ getConfig: () => ({}),
248
+ setConfig: () => { },
249
+ async control(method, request) {
250
+ calls.push([method, request]);
251
+ if (method === "listContainers")
252
+ return { containers: [] };
253
+ if (method === "listImages")
254
+ return { images: [] };
255
+ if (method === "listWorkspaces")
256
+ return { workspaces: [] };
257
+ if (method === "listVolumes")
258
+ return { volumes: [] };
259
+ if (method === "listSecrets")
260
+ return { secrets: [] };
261
+ return {};
262
+ },
263
+ };
264
+ await installCardCommandDriver(fakeContext(scope), resolver);
265
+ await scope.update({
266
+ command: { op: "image_rebuild_all", workspace: "", image: "", at: 10 },
267
+ });
268
+ await new Promise((resolve) => setImmediate(resolve));
269
+ const rebuildCall = calls.find(([method]) => method === "rebuildAllImages");
270
+ assert.deepEqual(rebuildCall?.[1], {});
271
+ assert.equal(scope.value.command, null);
272
+ });
273
+ test("image_base_rebuild command drives rebuildBaseImage with the name", async () => {
274
+ const scope = fakeScope(baseValue());
275
+ const calls = [];
276
+ const resolver = {
277
+ getConfig: () => ({}),
278
+ setConfig: () => { },
279
+ async control(method, request) {
280
+ calls.push([method, request]);
281
+ if (method === "listContainers")
282
+ return { containers: [] };
283
+ if (method === "listImages")
284
+ return { images: [] };
285
+ if (method === "listWorkspaces")
286
+ return { workspaces: [] };
287
+ if (method === "listVolumes")
288
+ return { volumes: [] };
289
+ if (method === "listSecrets")
290
+ return { secrets: [] };
291
+ return {};
292
+ },
293
+ };
294
+ await installCardCommandDriver(fakeContext(scope), resolver);
295
+ await scope.update({
296
+ command: { op: "image_base_rebuild", workspace: "archlinux", image: "", at: 21 },
297
+ });
298
+ await new Promise((resolve) => setImmediate(resolve));
299
+ const rebuildCall = calls.find(([method]) => method === "rebuildBaseImage");
300
+ assert.deepEqual(rebuildCall?.[1], { name: "archlinux" });
301
+ assert.equal(scope.value.command, null);
302
+ });
303
+ test("image_base_pull command drives pullBaseImage with the name", async () => {
304
+ const scope = fakeScope(baseValue());
305
+ const calls = [];
306
+ const resolver = {
307
+ getConfig: () => ({}),
308
+ setConfig: () => { },
309
+ async control(method, request) {
310
+ calls.push([method, request]);
311
+ if (method === "listContainers")
312
+ return { containers: [] };
313
+ if (method === "listImages")
314
+ return { images: [] };
315
+ if (method === "listWorkspaces")
316
+ return { workspaces: [] };
317
+ if (method === "listVolumes")
318
+ return { volumes: [] };
319
+ if (method === "listSecrets")
320
+ return { secrets: [] };
321
+ return {};
322
+ },
323
+ };
324
+ await installCardCommandDriver(fakeContext(scope), resolver);
325
+ await scope.update({
326
+ command: { op: "image_base_pull", workspace: "archlinux", image: "", at: 22 },
327
+ });
328
+ await new Promise((resolve) => setImmediate(resolve));
329
+ const pullCall = calls.find(([method]) => method === "pullBaseImage");
330
+ assert.deepEqual(pullCall?.[1], { name: "archlinux" });
331
+ assert.equal(scope.value.command, null);
332
+ });
333
+ test("image_build command drives buildImage with the imageId, parent and packages", async () => {
334
+ const scope = fakeScope(baseValue());
335
+ const calls = [];
336
+ const resolver = {
337
+ getConfig: () => ({}),
338
+ setConfig: () => { },
339
+ async control(method, request) {
340
+ calls.push([method, request]);
341
+ if (method === "listContainers")
342
+ return { containers: [] };
343
+ if (method === "listImages")
344
+ return { images: [] };
345
+ if (method === "listWorkspaces")
346
+ return { workspaces: [] };
347
+ if (method === "listVolumes")
348
+ return { volumes: [] };
349
+ if (method === "listSecrets")
350
+ return { secrets: [] };
351
+ return {};
352
+ },
353
+ };
354
+ await installCardCommandDriver(fakeContext(scope), resolver);
355
+ await scope.update({
356
+ command: {
357
+ op: "image_build",
358
+ workspace: "valkey",
359
+ image: "archlinux",
360
+ packages: ["valkey", "git"],
361
+ at: 20,
362
+ },
363
+ });
364
+ await new Promise((resolve) => setImmediate(resolve));
365
+ const buildCall = calls.find(([method]) => method === "buildImage");
366
+ assert.deepEqual(buildCall?.[1], {
367
+ imageId: "valkey",
368
+ parent: "archlinux",
369
+ packages: ["valkey", "git"],
370
+ });
371
+ assert.equal(scope.value.command, null);
372
+ });
373
+ test("container_secret_add command drives addContainerSecret with env and secret", async () => {
374
+ const scope = fakeScope(baseValue());
375
+ const calls = [];
376
+ const resolver = {
377
+ getConfig: () => ({}),
378
+ setConfig: () => { },
379
+ async control(method, request) {
380
+ calls.push([method, request]);
381
+ if (method === "listContainers")
382
+ return { containers: [] };
383
+ if (method === "listImages")
384
+ return { images: [] };
385
+ if (method === "listWorkspaces")
386
+ return { workspaces: [] };
387
+ if (method === "listVolumes")
388
+ return { volumes: [] };
389
+ if (method === "listSecrets")
390
+ return { secrets: [] };
391
+ return {};
392
+ },
393
+ };
394
+ await installCardCommandDriver(fakeContext(scope), resolver);
395
+ await scope.update({
396
+ command: {
397
+ op: "container_secret_add",
398
+ workspace: "w",
399
+ container: "web",
400
+ secret: "tok",
401
+ secretEnv: "TOKEN",
402
+ image: "",
403
+ at: 16,
404
+ },
405
+ });
406
+ await new Promise((resolve) => setImmediate(resolve));
407
+ const addCall = calls.find(([method]) => method === "addContainerSecret");
408
+ assert.deepEqual(addCall?.[1], {
409
+ workspaceSlug: "w",
410
+ container: "web",
411
+ env: "TOKEN",
412
+ secret: "tok",
413
+ });
414
+ assert.equal(scope.value.command, null);
415
+ });
416
+ test("container_secret_add command uses the default container when omitted", async () => {
417
+ const scope = fakeScope(baseValue());
418
+ const calls = [];
419
+ const resolver = {
420
+ getConfig: () => ({}),
421
+ setConfig: () => { },
422
+ async control(method, request) {
423
+ calls.push([method, request]);
424
+ if (method === "listContainers")
425
+ return { containers: [] };
426
+ if (method === "listImages")
427
+ return { images: [] };
428
+ if (method === "listWorkspaces")
429
+ return { workspaces: [] };
430
+ if (method === "listVolumes")
431
+ return { volumes: [] };
432
+ if (method === "listSecrets")
433
+ return { secrets: [] };
434
+ return {};
435
+ },
436
+ };
437
+ await installCardCommandDriver(fakeContext(scope), resolver);
438
+ await scope.update({
439
+ command: {
440
+ op: "container_secret_add",
441
+ workspace: "w",
442
+ container: "",
443
+ secret: "tok",
444
+ secretEnv: "TOKEN",
445
+ image: "",
446
+ at: 17,
447
+ },
448
+ });
449
+ await new Promise((resolve) => setImmediate(resolve));
450
+ const addCall = calls.find(([method]) => method === "addContainerSecret");
451
+ assert.deepEqual(addCall?.[1], {
452
+ workspaceSlug: "w",
453
+ container: "default",
454
+ env: "TOKEN",
455
+ secret: "tok",
456
+ });
457
+ assert.equal(scope.value.command, null);
458
+ });
459
+ test("container_secret_remove command drives removeContainerSecret with the default container", async () => {
460
+ const scope = fakeScope(baseValue());
461
+ const calls = [];
462
+ const resolver = {
463
+ getConfig: () => ({}),
464
+ setConfig: () => { },
465
+ async control(method, request) {
466
+ calls.push([method, request]);
467
+ if (method === "listContainers")
468
+ return { containers: [] };
469
+ if (method === "listImages")
470
+ return { images: [] };
471
+ if (method === "listWorkspaces")
472
+ return { workspaces: [] };
473
+ if (method === "listVolumes")
474
+ return { volumes: [] };
475
+ if (method === "listSecrets")
476
+ return { secrets: [] };
477
+ return {};
478
+ },
479
+ };
480
+ await installCardCommandDriver(fakeContext(scope), resolver);
481
+ await scope.update({
482
+ command: {
483
+ op: "container_secret_remove",
484
+ workspace: "w",
485
+ container: "",
486
+ secretEnv: "TOKEN",
487
+ image: "",
488
+ at: 18,
489
+ },
490
+ });
491
+ await new Promise((resolve) => setImmediate(resolve));
492
+ const removeCall = calls.find(([method]) => method === "removeContainerSecret");
493
+ assert.deepEqual(removeCall?.[1], {
494
+ workspaceSlug: "w",
495
+ container: "default",
496
+ env: "TOKEN",
497
+ });
498
+ assert.equal(scope.value.command, null);
499
+ });
500
+ test("unset kind and mode strings map to project and read_only", async () => {
501
+ const { scope, calls } = await installedMountScope();
502
+ await scope.update({
503
+ command: mountCommand("container_mount_add", { project: "team" }),
504
+ });
505
+ await new Promise((resolve) => setImmediate(resolve));
506
+ await scope.update({
507
+ command: {
508
+ op: "create",
509
+ workspace: "w1",
510
+ projectName: "team",
511
+ image: "",
512
+ at: 2,
513
+ mounts: [{
514
+ kind: "",
515
+ project: "team",
516
+ destination: "",
517
+ mode: "",
518
+ volume: "",
519
+ secret: "",
520
+ }],
521
+ env: {},
522
+ container: "",
523
+ secretEnvMap: {},
524
+ mount: null,
525
+ },
526
+ });
527
+ await new Promise((resolve) => setImmediate(resolve));
528
+ const addCall = calls.find(([method]) => method === "addContainerMount");
529
+ assert.deepEqual(addCall?.[1], {
530
+ workspaceSlug: "w1",
531
+ container: "web",
532
+ kind: "MOUNT_KIND_PROJECT",
533
+ project: "team",
534
+ mode: "MOUNT_MODE_READ_ONLY",
535
+ });
536
+ const createCall = calls.find(([method]) => method === "createWorkspace");
537
+ assert.deepEqual(createCall?.[1], {
538
+ workspaceSlug: "w1",
539
+ projectName: "team",
540
+ imageId: undefined,
541
+ mounts: [{
542
+ projectName: "team",
543
+ kind: "MOUNT_KIND_PROJECT",
544
+ mode: "MOUNT_MODE_READ_ONLY",
545
+ }],
546
+ });
547
+ assert.equal(scope.value.notice, "");
548
+ assert.equal(scope.value.command, null);
549
+ });
@@ -0,0 +1 @@
1
+ export {};