@mycadet/cli 0.12.7 → 0.12.9
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.
- package/README.md +2 -2
- package/knip.json +1 -1
- package/node_modules/@mycadet/assistant-api/events/cloud-disconnected.ts +21 -0
- package/node_modules/@mycadet/assistant-api/events/host-bash.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/host-cu.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/host-file.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/notification-intent.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/show-cloud-login.ts +18 -0
- package/node_modules/@mycadet/assistant-api/index.ts +11 -11
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/package.json +2 -2
- package/node_modules/@mycadet/{service-contracts/src/platform-credential.ts → assistant-api/node_modules/@mycadet/service-contracts/src/cloud-credential.ts} +9 -9
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/node_modules/@mycadet/assistant-api/responses/home.ts +1 -1
- package/node_modules/@mycadet/assistant-api/surfaces.ts +4 -4
- package/node_modules/@mycadet/avatar-manifest/src/__tests__/notification-avatar.test.ts +1 -1
- package/node_modules/@mycadet/avatar-manifest/src/notification-avatar.ts +2 -2
- package/node_modules/@mycadet/environments/src/seeds.ts +6 -6
- package/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
- package/node_modules/@mycadet/environments/src/types.ts +6 -6
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/avatar-manifest/src/__tests__/notification-avatar.test.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/avatar-manifest/src/notification-avatar.ts +2 -2
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/seeds.ts +6 -6
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/types.ts +6 -6
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/package.json +2 -2
- package/node_modules/@mycadet/{assistant-api/node_modules/@mycadet/service-contracts/src/platform-credential.ts → local-mode/node_modules/@mycadet/service-contracts/src/cloud-credential.ts} +9 -9
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/node_modules/@mycadet/local-mode/src/__tests__/pair.test.ts +5 -5
- package/node_modules/@mycadet/local-mode/src/__tests__/retire.test.ts +1 -1
- package/node_modules/@mycadet/local-mode/src/config.ts +2 -2
- package/node_modules/@mycadet/local-mode/src/index.ts +1 -1
- package/node_modules/@mycadet/local-mode/src/lockfile-contract.test.ts +3 -3
- package/node_modules/@mycadet/local-mode/src/lockfile-contract.ts +10 -5
- package/node_modules/@mycadet/local-mode/src/lockfile.test.ts +15 -15
- package/node_modules/@mycadet/local-mode/src/lockfile.ts +9 -9
- package/node_modules/@mycadet/local-mode/src/pair.ts +2 -2
- package/node_modules/@mycadet/local-mode/src/retire.ts +3 -3
- package/node_modules/@mycadet/local-mode/src/teleport-backup-policy.ts +2 -2
- package/node_modules/@mycadet/local-mode/src/unpair.ts +2 -2
- package/node_modules/@mycadet/service-contracts/package.json +2 -2
- package/node_modules/@mycadet/{local-mode/node_modules/@mycadet/service-contracts/src/platform-credential.ts → service-contracts/src/cloud-credential.ts} +9 -9
- package/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/package.json +3 -2
- package/src/__tests__/assistant-api-key-resolution.test.ts +6 -6
- package/src/__tests__/{assistant-client-platform-auth.test.ts → assistant-client-cloud-auth.test.ts} +10 -10
- package/src/__tests__/assistant-client-refresh.test.ts +2 -2
- package/src/__tests__/backup.test.ts +86 -91
- package/src/__tests__/client-token.test.ts +1 -1
- package/src/__tests__/client-tui-refresh.test.ts +1 -1
- package/src/__tests__/client-web-config.test.ts +2 -2
- package/src/__tests__/{platform-client.test.ts → cloud-client.test.ts} +59 -59
- package/src/__tests__/{platform-releases.test.ts → cloud-releases.test.ts} +28 -18
- package/src/__tests__/{cloudflare-tunnel.test.ts → cloudflare.test.ts} +1 -1
- package/src/__tests__/connect-import.test.ts +55 -39
- package/src/__tests__/debug.test.ts +38 -38
- package/src/__tests__/ensure-binary.test.ts +182 -0
- package/src/__tests__/guardian-token.test.ts +149 -56
- package/src/__tests__/hatch-provider-secrets.test.ts +2 -2
- package/src/__tests__/helpers/guardian-token.ts +22 -0
- package/src/__tests__/helpers/http.ts +10 -0
- package/src/__tests__/nginx-ingress.test.ts +21 -20
- package/src/__tests__/ngrok-spawn.test.ts +49 -0
- package/src/__tests__/orphan-detection.test.ts +1 -1
- package/src/__tests__/pair.test.ts +1 -8
- package/src/__tests__/{ps-platform-status.test.ts → ps-cloud-status.test.ts} +79 -26
- package/src/__tests__/ps-table.test.ts +79 -0
- package/src/__tests__/{recover.test.ts → restore.test.ts} +29 -28
- package/src/__tests__/retire.test.ts +58 -199
- package/src/__tests__/root-process-lockfile.test.ts +99 -0
- package/src/__tests__/sleep.test.ts +19 -19
- package/src/__tests__/statefulset.test.ts +8 -8
- package/src/__tests__/{tailscale-tunnel.test.ts → tailscale.test.ts} +2 -2
- package/src/__tests__/teleport-backup.test.ts +3 -3
- package/src/__tests__/teleport.test.ts +181 -197
- package/src/__tests__/tunnel.test.ts +257 -222
- package/src/__tests__/uninstall.test.ts +13 -4
- package/src/__tests__/upgrade-local.test.ts +3 -3
- package/src/__tests__/upgrade-replay-env.test.ts +12 -12
- package/src/__tests__/wake.test.ts +260 -43
- package/src/__tests__/workos-pkce.test.ts +2 -2
- package/src/commands/backup.ts +24 -24
- package/src/commands/client.ts +76 -76
- package/src/commands/completions.test.ts +104 -0
- package/src/commands/completions.ts +87 -0
- package/src/commands/debug.ts +20 -20
- package/src/commands/exec.ts +12 -12
- package/src/commands/flags.ts +2 -2
- package/src/commands/hatch.ts +23 -23
- package/src/commands/login.ts +22 -22
- package/src/commands/logs.ts +8 -8
- package/src/commands/ps.ts +244 -86
- package/src/commands/restart.ts +30 -0
- package/src/commands/restore.ts +140 -22
- package/src/commands/retire.ts +48 -150
- package/src/commands/rollback.ts +20 -26
- package/src/commands/setup.ts +2 -2
- package/src/commands/sleep.ts +2 -2
- package/src/commands/teleport.ts +109 -109
- package/src/commands/terminal.ts +158 -18
- package/src/commands/tunnel.ts +138 -157
- package/src/commands/uninstall.ts +57 -9
- package/src/commands/unpair.ts +3 -3
- package/src/commands/upgrade.ts +30 -54
- package/src/commands/use.ts +1 -1
- package/src/commands/wake.ts +166 -50
- package/src/index.ts +18 -9
- package/src/lib/__tests__/{platform-client-signed-url.test.ts → cloud-client-signed-url.test.ts} +16 -16
- package/src/lib/__tests__/docker.test.ts +168 -20
- package/src/lib/__tests__/job-polling.test.ts +2 -2
- package/src/lib/__tests__/local-runtime-client.test.ts +4 -4
- package/src/lib/__tests__/runtime-url.test.ts +1 -1
- package/src/lib/assistant-api-key-resolution.ts +5 -5
- package/src/lib/assistant-client.ts +8 -8
- package/src/lib/assistant-config.ts +58 -12
- package/src/lib/{platform-client.ts → cloud-client.ts} +107 -98
- package/src/lib/cloud-login.ts +24 -24
- package/src/lib/{platform-releases.ts → cloud-releases.ts} +11 -9
- package/src/lib/cloud-values.ts +3 -0
- package/src/lib/config-utils.ts +1 -1
- package/src/lib/detached-process.ts +1 -1
- package/src/lib/docker.ts +260 -53
- package/src/lib/ensure-binary.ts +171 -0
- package/src/lib/environments/__tests__/paths.test.ts +2 -2
- package/src/lib/environments/__tests__/resolve.test.ts +26 -26
- package/src/lib/environments/resolve.ts +8 -8
- package/src/lib/flag-args.test.ts +1 -1
- package/src/lib/flag-args.ts +1 -1
- package/src/lib/guardian-token.ts +37 -5
- package/src/lib/hatch-local.ts +19 -23
- package/src/lib/health-check.ts +6 -6
- package/src/lib/ingress-config.ts +8 -35
- package/src/lib/job-polling.ts +2 -2
- package/src/lib/live-voice/connection.ts +12 -12
- package/src/lib/live-voice/tunnel.test.ts +11 -11
- package/src/lib/live-voice/tunnel.ts +15 -15
- package/src/lib/local-runtime-client.ts +20 -20
- package/src/lib/local.ts +10 -31
- package/src/lib/nginx-ingress.ts +42 -15
- package/src/lib/pair.ts +1 -1
- package/src/lib/process.ts +1 -1
- package/src/lib/provider-secrets.ts +3 -3
- package/src/lib/retire-apple-container.ts +1 -1
- package/src/lib/runtime-url.ts +8 -8
- package/src/lib/statefulset.ts +2 -2
- package/src/lib/sync-cloud-assistants.ts +19 -19
- package/src/lib/teleport-backup.ts +4 -4
- package/src/lib/terminal-client.ts +17 -17
- package/src/lib/terminal-session.ts +24 -24
- package/src/lib/{tunnel-edge.ts → tunnel.ts} +199 -11
- package/src/lib/tunnels/cadet.ts +29 -0
- package/src/lib/{cloudflare-tunnel.ts → tunnels/cloudflare.ts} +36 -15
- package/src/lib/tunnels/gateway-notify.ts +61 -0
- package/src/lib/{ngrok.ts → tunnels/ngrok.ts} +350 -89
- package/src/lib/{tailscale-tunnel.ts → tunnels/tailscale.ts} +53 -9
- package/src/lib/upgrade-lifecycle.ts +8 -21
- package/src/lib/upgrade-preflight.ts +2 -2
- package/src/lib/workos-pkce.ts +5 -5
- package/node_modules/@mycadet/assistant-api/events/platform-disconnected.ts +0 -21
- package/node_modules/@mycadet/assistant-api/events/show-platform-login.ts +0 -20
- package/src/commands/recover.ts +0 -131
- package/src/commands/roadmap.ts +0 -459
- package/src/commands/ssh.ts +0 -144
- package/src/commands/workflows.ts +0 -305
- package/src/lib/managed-cloud.ts +0 -3
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
spyOn,
|
|
9
9
|
test,
|
|
10
10
|
} from "bun:test";
|
|
11
|
+
import type { Mock } from "bun:test";
|
|
11
12
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
12
13
|
import { tmpdir } from "node:os";
|
|
13
14
|
import { join } from "node:path";
|
|
@@ -37,7 +38,7 @@ process.env.CADET_LOCKFILE_DIR = testDir;
|
|
|
37
38
|
|
|
38
39
|
import * as assistantConfig from "../lib/assistant-config.js";
|
|
39
40
|
import * as guardianToken from "../lib/guardian-token.js";
|
|
40
|
-
import * as
|
|
41
|
+
import * as cloudClient from "../lib/cloud-client.js";
|
|
41
42
|
import * as localRuntimeClient from "../lib/local-runtime-client.js";
|
|
42
43
|
import * as backupOps from "../lib/backup-ops.js";
|
|
43
44
|
import * as teleportBackup from "../lib/teleport-backup.js";
|
|
@@ -47,7 +48,8 @@ import * as teleportBackup from "../lib/teleport-backup.js";
|
|
|
47
48
|
// how Bun's loader treats namespace bindings post-mock.
|
|
48
49
|
const realAssistantConfig = { ...assistantConfig };
|
|
49
50
|
const realGuardianToken = { ...guardianToken };
|
|
50
|
-
|
|
51
|
+
|
|
52
|
+
const realCloudClient = { ...cloudClient };
|
|
51
53
|
const realLocalRuntimeClient = { ...localRuntimeClient };
|
|
52
54
|
const realBackupOps = { ...backupOps };
|
|
53
55
|
const realTeleportBackup = { ...teleportBackup };
|
|
@@ -73,22 +75,19 @@ mock.module("../lib/assistant-config.js", () => ({
|
|
|
73
75
|
removeAssistantEntry: removeAssistantEntryMock,
|
|
74
76
|
}));
|
|
75
77
|
|
|
76
|
-
const loadGuardianTokenMock = mock<typeof guardianToken.loadGuardianToken>(
|
|
77
|
-
(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}) as unknown as ReturnType<typeof guardianToken.loadGuardianToken>,
|
|
78
|
+
const loadGuardianTokenMock = mock<typeof guardianToken.loadGuardianToken>(() =>
|
|
79
|
+
makeGuardianTokenData({
|
|
80
|
+
accessToken: "local-token",
|
|
81
|
+
accessTokenExpiresAt: new Date(Date.now() + 60_000).toISOString(),
|
|
82
|
+
}),
|
|
82
83
|
);
|
|
83
84
|
|
|
84
85
|
const leaseGuardianTokenMock = mock<typeof guardianToken.leaseGuardianToken>(
|
|
85
86
|
async () =>
|
|
86
|
-
({
|
|
87
|
+
makeGuardianTokenData({
|
|
87
88
|
accessToken: "leased-token",
|
|
88
89
|
accessTokenExpiresAt: new Date(Date.now() + 60_000).toISOString(),
|
|
89
|
-
})
|
|
90
|
-
ReturnType<typeof guardianToken.leaseGuardianToken>
|
|
91
|
-
>,
|
|
90
|
+
}),
|
|
92
91
|
);
|
|
93
92
|
|
|
94
93
|
const computeDeviceIdMock = mock<typeof guardianToken.computeDeviceId>(
|
|
@@ -102,15 +101,15 @@ mock.module("../lib/guardian-token.js", () => ({
|
|
|
102
101
|
computeDeviceId: computeDeviceIdMock,
|
|
103
102
|
}));
|
|
104
103
|
|
|
105
|
-
const
|
|
104
|
+
const readCloudTokenMock = mock<typeof cloudClient.readCloudToken>(
|
|
106
105
|
() => "platform-token",
|
|
107
106
|
);
|
|
108
107
|
|
|
109
|
-
const
|
|
108
|
+
const getCloudUrlMock = mock<typeof cloudClient.getCloudUrl>(
|
|
110
109
|
() => "https://cloud.mycadet.ai",
|
|
111
110
|
);
|
|
112
111
|
|
|
113
|
-
const hatchAssistantMock = mock<typeof
|
|
112
|
+
const hatchAssistantMock = mock<typeof cloudClient.hatchAssistant>(
|
|
114
113
|
async () => ({
|
|
115
114
|
assistant: {
|
|
116
115
|
id: "platform-new-id",
|
|
@@ -122,7 +121,7 @@ const hatchAssistantMock = mock<typeof platformClient.hatchAssistant>(
|
|
|
122
121
|
);
|
|
123
122
|
|
|
124
123
|
const platformPollJobStatusMock = mock<
|
|
125
|
-
typeof
|
|
124
|
+
typeof cloudClient.platformPollJobStatus
|
|
126
125
|
>(async () => ({
|
|
127
126
|
jobId: "platform-job-1",
|
|
128
127
|
type: "export",
|
|
@@ -130,8 +129,8 @@ const platformPollJobStatusMock = mock<
|
|
|
130
129
|
bundleKey: "platform-bundle-key-abc",
|
|
131
130
|
}));
|
|
132
131
|
|
|
133
|
-
const
|
|
134
|
-
typeof
|
|
132
|
+
const cloudRequestSignedUrlMock = mock<
|
|
133
|
+
typeof cloudClient.cloudRequestSignedUrl
|
|
135
134
|
>(async (params) => ({
|
|
136
135
|
url:
|
|
137
136
|
params.operation === "upload"
|
|
@@ -142,7 +141,7 @@ const platformRequestSignedUrlMock = mock<
|
|
|
142
141
|
}));
|
|
143
142
|
|
|
144
143
|
const platformImportBundleFromGcsMock = mock<
|
|
145
|
-
typeof
|
|
144
|
+
typeof cloudClient.platformImportBundleFromGcs
|
|
146
145
|
>(async () => ({
|
|
147
146
|
statusCode: 200,
|
|
148
147
|
body: {
|
|
@@ -154,11 +153,11 @@ const platformImportBundleFromGcsMock = mock<
|
|
|
154
153
|
files_skipped: 0,
|
|
155
154
|
backups_created: 1,
|
|
156
155
|
},
|
|
157
|
-
}
|
|
156
|
+
},
|
|
158
157
|
}));
|
|
159
158
|
|
|
160
159
|
const platformImportPreflightFromGcsMock = mock<
|
|
161
|
-
typeof
|
|
160
|
+
typeof cloudClient.platformImportPreflightFromGcs
|
|
162
161
|
>(async () => ({
|
|
163
162
|
statusCode: 200,
|
|
164
163
|
body: {
|
|
@@ -169,60 +168,52 @@ const platformImportPreflightFromGcsMock = mock<
|
|
|
169
168
|
files_unchanged: 0,
|
|
170
169
|
total_files: 3,
|
|
171
170
|
},
|
|
172
|
-
}
|
|
171
|
+
},
|
|
173
172
|
}));
|
|
174
173
|
|
|
175
|
-
const
|
|
176
|
-
typeof
|
|
174
|
+
const checkExistingCloudAssistantMock = mock<
|
|
175
|
+
typeof cloudClient.checkExistingCloudAssistant
|
|
177
176
|
>(async () => null);
|
|
178
177
|
|
|
179
178
|
const ensureSelfHostedLocalRegistrationMock = mock<
|
|
180
|
-
typeof
|
|
181
|
-
>(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
webhook_secret: "webhook-secret-123",
|
|
192
|
-
}) as unknown as Awaited<
|
|
193
|
-
ReturnType<typeof platformClient.ensureSelfHostedLocalRegistration>
|
|
194
|
-
>,
|
|
195
|
-
);
|
|
179
|
+
typeof cloudClient.ensureSelfHostedLocalRegistration
|
|
180
|
+
>(async () => ({
|
|
181
|
+
assistant: { id: "platform-assistant-1", name: "my-assistant" },
|
|
182
|
+
registration: {
|
|
183
|
+
client_installation_id: "device-id-123",
|
|
184
|
+
runtime_assistant_id: "target-local",
|
|
185
|
+
client_platform: "cli",
|
|
186
|
+
},
|
|
187
|
+
assistant_api_key: "api-key-123",
|
|
188
|
+
webhook_secret: "webhook-secret-123",
|
|
189
|
+
}));
|
|
196
190
|
|
|
197
191
|
const injectCredentialsIntoAssistantMock = mock<
|
|
198
|
-
typeof
|
|
192
|
+
typeof cloudClient.injectCredentialsIntoAssistant
|
|
199
193
|
>(async () => true);
|
|
200
194
|
|
|
201
|
-
const fetchCurrentUserMock = mock<typeof
|
|
202
|
-
async () =>
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}) as unknown as Awaited<
|
|
208
|
-
ReturnType<typeof platformClient.fetchCurrentUser>
|
|
209
|
-
>,
|
|
195
|
+
const fetchCurrentUserMock = mock<typeof cloudClient.fetchCurrentUser>(
|
|
196
|
+
async () => ({
|
|
197
|
+
id: "user-1",
|
|
198
|
+
email: "test@example.com",
|
|
199
|
+
display: "Test",
|
|
200
|
+
}),
|
|
210
201
|
);
|
|
211
202
|
|
|
212
|
-
const fetchOrganizationIdMock = mock<typeof
|
|
203
|
+
const fetchOrganizationIdMock = mock<typeof cloudClient.fetchOrganizationId>(
|
|
213
204
|
async () => "org-1",
|
|
214
205
|
);
|
|
215
206
|
|
|
216
|
-
mock.module("../lib/
|
|
217
|
-
...
|
|
218
|
-
|
|
219
|
-
|
|
207
|
+
mock.module("../lib/cloud-client.js", () => ({
|
|
208
|
+
...realCloudClient,
|
|
209
|
+
readCloudToken: readCloudTokenMock,
|
|
210
|
+
getCloudUrl: getCloudUrlMock,
|
|
220
211
|
hatchAssistant: hatchAssistantMock,
|
|
221
212
|
platformPollJobStatus: platformPollJobStatusMock,
|
|
222
|
-
|
|
213
|
+
cloudRequestSignedUrl: cloudRequestSignedUrlMock,
|
|
223
214
|
platformImportBundleFromGcs: platformImportBundleFromGcsMock,
|
|
224
215
|
platformImportPreflightFromGcs: platformImportPreflightFromGcsMock,
|
|
225
|
-
|
|
216
|
+
checkExistingCloudAssistant: checkExistingCloudAssistantMock,
|
|
226
217
|
ensureSelfHostedLocalRegistration: ensureSelfHostedLocalRegistrationMock,
|
|
227
218
|
injectCredentialsIntoAssistant: injectCredentialsIntoAssistantMock,
|
|
228
219
|
fetchCurrentUser: fetchCurrentUserMock,
|
|
@@ -383,6 +374,8 @@ import {
|
|
|
383
374
|
resolveOrHatchTarget,
|
|
384
375
|
} from "../commands/teleport.js";
|
|
385
376
|
import type { AssistantEntry } from "../lib/assistant-config.js";
|
|
377
|
+
import { withPreconnect } from "./helpers/http.js";
|
|
378
|
+
import { makeGuardianTokenData } from "./helpers/guardian-token.js";
|
|
386
379
|
|
|
387
380
|
// ---------------------------------------------------------------------------
|
|
388
381
|
// Helpers
|
|
@@ -390,11 +383,11 @@ import type { AssistantEntry } from "../lib/assistant-config.js";
|
|
|
390
383
|
|
|
391
384
|
afterAll(() => {
|
|
392
385
|
// Restore the real module exports so the mocks do not leak into sibling
|
|
393
|
-
// test files (e.g. guardian-token.test.ts,
|
|
386
|
+
// test files (e.g. guardian-token.test.ts, cloud-client tests) that
|
|
394
387
|
// run in the same `bun test` invocation.
|
|
395
388
|
mock.module("../lib/assistant-config.js", () => realAssistantConfig);
|
|
396
389
|
mock.module("../lib/guardian-token.js", () => realGuardianToken);
|
|
397
|
-
mock.module("../lib/
|
|
390
|
+
mock.module("../lib/cloud-client.js", () => realCloudClient);
|
|
398
391
|
mock.module("../lib/local-runtime-client.js", () => realLocalRuntimeClient);
|
|
399
392
|
mock.module("../lib/backup-ops.js", () => realBackupOps);
|
|
400
393
|
mock.module("../lib/teleport-backup.js", () => realTeleportBackup);
|
|
@@ -408,7 +401,7 @@ afterAll(() => {
|
|
|
408
401
|
});
|
|
409
402
|
|
|
410
403
|
let originalArgv: string[];
|
|
411
|
-
let exitMock:
|
|
404
|
+
let exitMock: Mock<(code?: number | string | undefined) => never>;
|
|
412
405
|
let originalExit: typeof process.exit;
|
|
413
406
|
let consoleLogSpy: ReturnType<typeof spyOn>;
|
|
414
407
|
let consoleErrorSpy: ReturnType<typeof spyOn>;
|
|
@@ -455,16 +448,18 @@ beforeEach(() => {
|
|
|
455
448
|
removeAssistantEntryMock.mockImplementation(() => {});
|
|
456
449
|
|
|
457
450
|
loadGuardianTokenMock.mockReset();
|
|
458
|
-
loadGuardianTokenMock.mockReturnValue(
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
451
|
+
loadGuardianTokenMock.mockReturnValue(
|
|
452
|
+
makeGuardianTokenData({
|
|
453
|
+
accessToken: "local-token",
|
|
454
|
+
accessTokenExpiresAt: new Date(Date.now() + 60_000).toISOString(),
|
|
455
|
+
}),
|
|
456
|
+
);
|
|
462
457
|
leaseGuardianTokenMock.mockReset();
|
|
463
458
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
459
|
+
readCloudTokenMock.mockReset();
|
|
460
|
+
readCloudTokenMock.mockReturnValue("platform-token");
|
|
461
|
+
getCloudUrlMock.mockReset();
|
|
462
|
+
getCloudUrlMock.mockReturnValue("https://cloud.mycadet.ai");
|
|
468
463
|
hatchAssistantMock.mockReset();
|
|
469
464
|
hatchAssistantMock.mockResolvedValue({
|
|
470
465
|
assistant: {
|
|
@@ -481,8 +476,8 @@ beforeEach(() => {
|
|
|
481
476
|
status: "complete",
|
|
482
477
|
bundleKey: "platform-bundle-key-abc",
|
|
483
478
|
});
|
|
484
|
-
|
|
485
|
-
|
|
479
|
+
cloudRequestSignedUrlMock.mockReset();
|
|
480
|
+
cloudRequestSignedUrlMock.mockImplementation(async (params) => ({
|
|
486
481
|
url:
|
|
487
482
|
params.operation === "upload"
|
|
488
483
|
? "https://storage.googleapis.com/bucket/signed-upload"
|
|
@@ -517,8 +512,8 @@ beforeEach(() => {
|
|
|
517
512
|
},
|
|
518
513
|
},
|
|
519
514
|
});
|
|
520
|
-
|
|
521
|
-
|
|
515
|
+
checkExistingCloudAssistantMock.mockReset();
|
|
516
|
+
checkExistingCloudAssistantMock.mockResolvedValue(null);
|
|
522
517
|
ensureSelfHostedLocalRegistrationMock.mockReset();
|
|
523
518
|
ensureSelfHostedLocalRegistrationMock.mockResolvedValue({
|
|
524
519
|
assistant: { id: "platform-assistant-1", name: "my-assistant" },
|
|
@@ -597,11 +592,11 @@ beforeEach(() => {
|
|
|
597
592
|
stopProcessByPidFileMock.mockResolvedValue(true);
|
|
598
593
|
|
|
599
594
|
// Mock process.exit to throw so we can catch it
|
|
600
|
-
exitMock = mock((code?: number) => {
|
|
595
|
+
exitMock = mock((code?: number | string | undefined): never => {
|
|
601
596
|
throw new Error(`process.exit:${code}`);
|
|
602
597
|
});
|
|
603
598
|
originalExit = process.exit;
|
|
604
|
-
process.exit = exitMock
|
|
599
|
+
process.exit = exitMock;
|
|
605
600
|
|
|
606
601
|
consoleLogSpy = spyOn(console, "log").mockImplementation(() => {});
|
|
607
602
|
consoleErrorSpy = spyOn(console, "error").mockImplementation(() => {});
|
|
@@ -638,13 +633,13 @@ function makeEntry(
|
|
|
638
633
|
*/
|
|
639
634
|
function installTrackingFetch(): () => void {
|
|
640
635
|
const originalFetch = globalThis.fetch;
|
|
641
|
-
globalThis.fetch =
|
|
642
|
-
async (
|
|
643
|
-
const urlStr =
|
|
636
|
+
globalThis.fetch = withPreconnect(
|
|
637
|
+
async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
638
|
+
const urlStr = String(input);
|
|
644
639
|
fetchCalls.push({ url: urlStr, body: init?.body });
|
|
645
640
|
return new Response("not found", { status: 404 });
|
|
646
641
|
},
|
|
647
|
-
)
|
|
642
|
+
);
|
|
648
643
|
return () => {
|
|
649
644
|
globalThis.fetch = originalFetch;
|
|
650
645
|
};
|
|
@@ -890,17 +885,17 @@ describe("resolveOrHatchTarget", () => {
|
|
|
890
885
|
});
|
|
891
886
|
|
|
892
887
|
test("platform with existing ID -> returns existing without hatching", async () => {
|
|
893
|
-
const
|
|
888
|
+
const cloudEntry = makeEntry("uuid-123", {
|
|
894
889
|
cloud: "cadet",
|
|
895
890
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
896
891
|
});
|
|
897
892
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
898
|
-
if (name === "uuid-123") return
|
|
893
|
+
if (name === "uuid-123") return cloudEntry;
|
|
899
894
|
return null;
|
|
900
895
|
});
|
|
901
896
|
|
|
902
897
|
const result = await resolveOrHatchTarget("platform", "uuid-123");
|
|
903
|
-
expect(result).toBe(
|
|
898
|
+
expect(result).toBe(cloudEntry);
|
|
904
899
|
expect(hatchAssistantMock).not.toHaveBeenCalled();
|
|
905
900
|
});
|
|
906
901
|
|
|
@@ -927,7 +922,7 @@ describe("resolveOrHatchTarget", () => {
|
|
|
927
922
|
"process.exit:1",
|
|
928
923
|
);
|
|
929
924
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
930
|
-
expect.stringContaining("already have a
|
|
925
|
+
expect.stringContaining("already have a cloud assistant"),
|
|
931
926
|
);
|
|
932
927
|
});
|
|
933
928
|
|
|
@@ -976,9 +971,9 @@ describe("unified GCS flow — four directions", () => {
|
|
|
976
971
|
try {
|
|
977
972
|
await teleport();
|
|
978
973
|
|
|
979
|
-
// Signed-URL request for upload — pinned to the
|
|
974
|
+
// Signed-URL request for upload — pinned to the cloud target's URL
|
|
980
975
|
// so upload and download land on the same platform.
|
|
981
|
-
expect(
|
|
976
|
+
expect(cloudRequestSignedUrlMock).toHaveBeenCalledWith(
|
|
982
977
|
expect.objectContaining({
|
|
983
978
|
operation: "upload",
|
|
984
979
|
minRuntimeVersion: "0.6.5",
|
|
@@ -1014,9 +1009,8 @@ describe("unified GCS flow — four directions", () => {
|
|
|
1014
1009
|
|
|
1015
1010
|
// No download-URL request on the import side (platform target pulls
|
|
1016
1011
|
// directly from GCS).
|
|
1017
|
-
const downloadOps =
|
|
1018
|
-
(call
|
|
1019
|
-
(call[0] as { operation: string }).operation === "download",
|
|
1012
|
+
const downloadOps = cloudRequestSignedUrlMock.mock.calls.filter(
|
|
1013
|
+
(call) => call[0].operation === "download",
|
|
1020
1014
|
);
|
|
1021
1015
|
expect(downloadOps.length).toBe(0);
|
|
1022
1016
|
} finally {
|
|
@@ -1027,7 +1021,7 @@ describe("unified GCS flow — four directions", () => {
|
|
|
1027
1021
|
test("platform → local: drives platform export, reads bundle_key, requests download URL for runtime import", async () => {
|
|
1028
1022
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
1029
1023
|
|
|
1030
|
-
const
|
|
1024
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
1031
1025
|
cloud: "cadet",
|
|
1032
1026
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
1033
1027
|
});
|
|
@@ -1037,7 +1031,7 @@ describe("unified GCS flow — four directions", () => {
|
|
|
1037
1031
|
});
|
|
1038
1032
|
|
|
1039
1033
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
1040
|
-
if (name === "my-platform") return
|
|
1034
|
+
if (name === "my-platform") return cloudEntry;
|
|
1041
1035
|
if (name === "my-local") return localEntry;
|
|
1042
1036
|
return null;
|
|
1043
1037
|
});
|
|
@@ -1053,7 +1047,7 @@ describe("unified GCS flow — four directions", () => {
|
|
|
1053
1047
|
// The bundle key now flows from the upload signed-URL request rather than
|
|
1054
1048
|
// the job-status payload — pin it so the download-URL assertion below
|
|
1055
1049
|
// still uses the same expected key.
|
|
1056
|
-
|
|
1050
|
+
cloudRequestSignedUrlMock.mockImplementation(async (params) => ({
|
|
1057
1051
|
url:
|
|
1058
1052
|
params.operation === "upload"
|
|
1059
1053
|
? "https://storage.googleapis.com/bucket/signed-upload"
|
|
@@ -1069,7 +1063,7 @@ describe("unified GCS flow — four directions", () => {
|
|
|
1069
1063
|
|
|
1070
1064
|
// Platform side: requested an upload URL, kicked off a runtime export to
|
|
1071
1065
|
// GCS, and polled the unified job status.
|
|
1072
|
-
expect(
|
|
1066
|
+
expect(cloudRequestSignedUrlMock).toHaveBeenCalledWith(
|
|
1073
1067
|
expect.objectContaining({
|
|
1074
1068
|
operation: "upload",
|
|
1075
1069
|
minRuntimeVersion: "0.6.5",
|
|
@@ -1078,7 +1072,7 @@ describe("unified GCS flow — four directions", () => {
|
|
|
1078
1072
|
"platform-token",
|
|
1079
1073
|
"https://cloud.mycadet.ai",
|
|
1080
1074
|
);
|
|
1081
|
-
// For platform sources, export-to-gcs is reached via the
|
|
1075
|
+
// For platform sources, export-to-gcs is reached via the cloud's
|
|
1082
1076
|
// wildcard runtime proxy. The helper builds the assistant-scoped URL
|
|
1083
1077
|
// from the entry (`/v1/assistants/<id>/migrations/export-to-gcs`) and
|
|
1084
1078
|
// sends platform-token auth — no guardian-token bootstrap.
|
|
@@ -1116,7 +1110,7 @@ describe("unified GCS flow — four directions", () => {
|
|
|
1116
1110
|
// `/v1/identity` (mocked to "0.6.5"), NOT from the CLI's package
|
|
1117
1111
|
// version. The local target's daemon can be on a different version
|
|
1118
1112
|
// than the CLI orchestrating the teleport.
|
|
1119
|
-
expect(
|
|
1113
|
+
expect(cloudRequestSignedUrlMock).toHaveBeenCalledWith(
|
|
1120
1114
|
expect.objectContaining({
|
|
1121
1115
|
operation: "download",
|
|
1122
1116
|
bundleKey: "platform-exports/org-1/bundle-abc.vbundle",
|
|
@@ -1177,8 +1171,8 @@ describe("unified GCS flow — four directions", () => {
|
|
|
1177
1171
|
|
|
1178
1172
|
// Export and import must pin the same platform URL so the bundle
|
|
1179
1173
|
// lives in one place end-to-end. For local→docker neither side is
|
|
1180
|
-
// platform, so we default to
|
|
1181
|
-
expect(
|
|
1174
|
+
// platform, so we default to getCloudUrl() (resolved once).
|
|
1175
|
+
expect(cloudRequestSignedUrlMock).toHaveBeenCalledWith(
|
|
1182
1176
|
expect.objectContaining({
|
|
1183
1177
|
operation: "upload",
|
|
1184
1178
|
minRuntimeVersion: "0.6.5",
|
|
@@ -1192,7 +1186,7 @@ describe("unified GCS flow — four directions", () => {
|
|
|
1192
1186
|
// Import: download-URL for the docker target, then runtime import.
|
|
1193
1187
|
// targetRuntimeVersion comes from the docker target's runtime
|
|
1194
1188
|
// identity (mocked to "0.6.5"), not from cliPkg.version.
|
|
1195
|
-
expect(
|
|
1189
|
+
expect(cloudRequestSignedUrlMock).toHaveBeenCalledWith(
|
|
1196
1190
|
expect.objectContaining({
|
|
1197
1191
|
operation: "download",
|
|
1198
1192
|
bundleKey: "bundle-key-123",
|
|
@@ -1256,7 +1250,7 @@ describe("unified GCS flow — four directions", () => {
|
|
|
1256
1250
|
|
|
1257
1251
|
// Export leg: upload-URL (pinned to the same platform as import),
|
|
1258
1252
|
// then runtime export.
|
|
1259
|
-
expect(
|
|
1253
|
+
expect(cloudRequestSignedUrlMock).toHaveBeenCalledWith(
|
|
1260
1254
|
expect.objectContaining({
|
|
1261
1255
|
operation: "upload",
|
|
1262
1256
|
minRuntimeVersion: "0.6.5",
|
|
@@ -1305,16 +1299,16 @@ describe("signed-URL request targets the bundle-owning platform", () => {
|
|
|
1305
1299
|
setArgv("--from", "my-local", "--platform", "existing-platform");
|
|
1306
1300
|
|
|
1307
1301
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
1308
|
-
// Crucially, the target's runtimeUrl is NOT the default
|
|
1302
|
+
// Crucially, the target's runtimeUrl is NOT the default getCloudUrl()
|
|
1309
1303
|
// return value — this is the regression case Codex flagged.
|
|
1310
|
-
const
|
|
1304
|
+
const cloudEntry = makeEntry("existing-platform", {
|
|
1311
1305
|
cloud: "cadet",
|
|
1312
1306
|
runtimeUrl: "https://staging-cloud.mycadet.ai",
|
|
1313
1307
|
});
|
|
1314
1308
|
|
|
1315
1309
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
1316
1310
|
if (name === "my-local") return localEntry;
|
|
1317
|
-
if (name === "existing-platform") return
|
|
1311
|
+
if (name === "existing-platform") return cloudEntry;
|
|
1318
1312
|
return null;
|
|
1319
1313
|
});
|
|
1320
1314
|
|
|
@@ -1324,7 +1318,7 @@ describe("signed-URL request targets the bundle-owning platform", () => {
|
|
|
1324
1318
|
|
|
1325
1319
|
// The signed-URL request for upload MUST target the existing
|
|
1326
1320
|
// platform assistant's runtimeUrl, not the default platform URL.
|
|
1327
|
-
expect(
|
|
1321
|
+
expect(cloudRequestSignedUrlMock).toHaveBeenCalledWith(
|
|
1328
1322
|
expect.objectContaining({
|
|
1329
1323
|
operation: "upload",
|
|
1330
1324
|
minRuntimeVersion: "0.6.5",
|
|
@@ -1343,7 +1337,7 @@ describe("signed-URL request targets the bundle-owning platform", () => {
|
|
|
1343
1337
|
|
|
1344
1338
|
// Assert none of the signed-URL calls used the default URL — if any
|
|
1345
1339
|
// did, upload and download would hit different platforms.
|
|
1346
|
-
for (const call of
|
|
1340
|
+
for (const call of cloudRequestSignedUrlMock.mock.calls) {
|
|
1347
1341
|
expect(call[2]).toBe("https://staging-cloud.mycadet.ai");
|
|
1348
1342
|
}
|
|
1349
1343
|
} finally {
|
|
@@ -1354,14 +1348,14 @@ describe("signed-URL request targets the bundle-owning platform", () => {
|
|
|
1354
1348
|
test("platform → local with non-default source runtimeUrl: download URL pinned to source's runtimeUrl", async () => {
|
|
1355
1349
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
1356
1350
|
|
|
1357
|
-
const
|
|
1351
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
1358
1352
|
cloud: "cadet",
|
|
1359
1353
|
runtimeUrl: "https://dev-cloud.mycadet.ai",
|
|
1360
1354
|
});
|
|
1361
1355
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
1362
1356
|
|
|
1363
1357
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
1364
|
-
if (name === "my-platform") return
|
|
1358
|
+
if (name === "my-platform") return cloudEntry;
|
|
1365
1359
|
if (name === "my-local") return localEntry;
|
|
1366
1360
|
return null;
|
|
1367
1361
|
});
|
|
@@ -1375,7 +1369,7 @@ describe("signed-URL request targets the bundle-owning platform", () => {
|
|
|
1375
1369
|
|
|
1376
1370
|
// Bundle key flows from the upload signed-URL request now; pin it so the
|
|
1377
1371
|
// download-URL assertion below uses the same key.
|
|
1378
|
-
|
|
1372
|
+
cloudRequestSignedUrlMock.mockImplementation(async (params) => ({
|
|
1379
1373
|
url:
|
|
1380
1374
|
params.operation === "upload"
|
|
1381
1375
|
? "https://storage.googleapis.com/bucket/signed-upload"
|
|
@@ -1392,7 +1386,7 @@ describe("signed-URL request targets the bundle-owning platform", () => {
|
|
|
1392
1386
|
// the bundle was written by the runtime export), not the default.
|
|
1393
1387
|
// targetRuntimeVersion comes from the local target's `/v1/identity`
|
|
1394
1388
|
// (mocked to "0.6.5"), not from cliPkg.version.
|
|
1395
|
-
expect(
|
|
1389
|
+
expect(cloudRequestSignedUrlMock).toHaveBeenCalledWith(
|
|
1396
1390
|
expect.objectContaining({
|
|
1397
1391
|
operation: "download",
|
|
1398
1392
|
bundleKey: "dev-bundle-key",
|
|
@@ -1447,14 +1441,14 @@ describe("CLI never buffers bundle bytes", () => {
|
|
|
1447
1441
|
test("platform → local: no fetch call carries a bundle-sized body", async () => {
|
|
1448
1442
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
1449
1443
|
|
|
1450
|
-
const
|
|
1444
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
1451
1445
|
cloud: "cadet",
|
|
1452
1446
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
1453
1447
|
});
|
|
1454
1448
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
1455
1449
|
|
|
1456
1450
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
1457
|
-
if (name === "my-platform") return
|
|
1451
|
+
if (name === "my-platform") return cloudEntry;
|
|
1458
1452
|
if (name === "my-local") return localEntry;
|
|
1459
1453
|
return null;
|
|
1460
1454
|
});
|
|
@@ -1550,14 +1544,14 @@ describe("polling", () => {
|
|
|
1550
1544
|
test("local-runtime import failure → teleport exits 1", async () => {
|
|
1551
1545
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
1552
1546
|
|
|
1553
|
-
const
|
|
1547
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
1554
1548
|
cloud: "cadet",
|
|
1555
1549
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
1556
1550
|
});
|
|
1557
1551
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
1558
1552
|
|
|
1559
1553
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
1560
|
-
if (name === "my-platform") return
|
|
1554
|
+
if (name === "my-platform") return cloudEntry;
|
|
1561
1555
|
if (name === "my-local") return localEntry;
|
|
1562
1556
|
return null;
|
|
1563
1557
|
});
|
|
@@ -1647,14 +1641,14 @@ describe("MigrationInProgressError handling", () => {
|
|
|
1647
1641
|
test("local-runtime import already in flight → fail fast with existing job id", async () => {
|
|
1648
1642
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
1649
1643
|
|
|
1650
|
-
const
|
|
1644
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
1651
1645
|
cloud: "cadet",
|
|
1652
1646
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
1653
1647
|
});
|
|
1654
1648
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
1655
1649
|
|
|
1656
1650
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
1657
|
-
if (name === "my-platform") return
|
|
1651
|
+
if (name === "my-platform") return cloudEntry;
|
|
1658
1652
|
if (name === "my-local") return localEntry;
|
|
1659
1653
|
return null;
|
|
1660
1654
|
});
|
|
@@ -1697,7 +1691,7 @@ describe("MigrationInProgressError handling", () => {
|
|
|
1697
1691
|
});
|
|
1698
1692
|
|
|
1699
1693
|
// ---------------------------------------------------------------------------
|
|
1700
|
-
// VersionMismatchError handling — 422 from
|
|
1694
|
+
// VersionMismatchError handling — 422 from cloudRequestSignedUrl on the
|
|
1701
1695
|
// download leg is terminal: surface a friendly message + exit 1, no retry.
|
|
1702
1696
|
// ---------------------------------------------------------------------------
|
|
1703
1697
|
|
|
@@ -1705,14 +1699,14 @@ describe("VersionMismatchError handling", () => {
|
|
|
1705
1699
|
test("local target: 422 on download signed-URL exits 1 with friendly message", async () => {
|
|
1706
1700
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
1707
1701
|
|
|
1708
|
-
const
|
|
1702
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
1709
1703
|
cloud: "cadet",
|
|
1710
1704
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
1711
1705
|
});
|
|
1712
1706
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
1713
1707
|
|
|
1714
1708
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
1715
|
-
if (name === "my-platform") return
|
|
1709
|
+
if (name === "my-platform") return cloudEntry;
|
|
1716
1710
|
if (name === "my-local") return localEntry;
|
|
1717
1711
|
return null;
|
|
1718
1712
|
});
|
|
@@ -1725,9 +1719,9 @@ describe("VersionMismatchError handling", () => {
|
|
|
1725
1719
|
});
|
|
1726
1720
|
|
|
1727
1721
|
// Upload signed-URL succeeds; download signed-URL throws version-mismatch.
|
|
1728
|
-
|
|
1722
|
+
cloudRequestSignedUrlMock.mockImplementation(async (params) => {
|
|
1729
1723
|
if (params.operation === "download") {
|
|
1730
|
-
throw new
|
|
1724
|
+
throw new cloudClient.VersionMismatchError(
|
|
1731
1725
|
{ min_runtime_version: "99.0.0", max_runtime_version: null },
|
|
1732
1726
|
"0.7.1",
|
|
1733
1727
|
);
|
|
@@ -1749,8 +1743,8 @@ describe("VersionMismatchError handling", () => {
|
|
|
1749
1743
|
);
|
|
1750
1744
|
|
|
1751
1745
|
// Terminal: no retry of the download signed-URL request.
|
|
1752
|
-
const downloadCalls =
|
|
1753
|
-
(c) =>
|
|
1746
|
+
const downloadCalls = cloudRequestSignedUrlMock.mock.calls.filter(
|
|
1747
|
+
(c) => c[0].operation === "download",
|
|
1754
1748
|
);
|
|
1755
1749
|
expect(downloadCalls).toHaveLength(1);
|
|
1756
1750
|
|
|
@@ -1781,9 +1775,9 @@ describe("VersionMismatchError handling", () => {
|
|
|
1781
1775
|
return [localEntry];
|
|
1782
1776
|
});
|
|
1783
1777
|
|
|
1784
|
-
|
|
1778
|
+
cloudRequestSignedUrlMock.mockImplementation(async (params) => {
|
|
1785
1779
|
if (params.operation === "download") {
|
|
1786
|
-
throw new
|
|
1780
|
+
throw new cloudClient.VersionMismatchError(
|
|
1787
1781
|
{ min_runtime_version: "99.0.0", max_runtime_version: null },
|
|
1788
1782
|
"0.7.1",
|
|
1789
1783
|
);
|
|
@@ -1812,14 +1806,14 @@ describe("VersionMismatchError handling", () => {
|
|
|
1812
1806
|
test("non-VersionMismatchError on download signed-URL re-raises", async () => {
|
|
1813
1807
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
1814
1808
|
|
|
1815
|
-
const
|
|
1809
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
1816
1810
|
cloud: "cadet",
|
|
1817
1811
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
1818
1812
|
});
|
|
1819
1813
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
1820
1814
|
|
|
1821
1815
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
1822
|
-
if (name === "my-platform") return
|
|
1816
|
+
if (name === "my-platform") return cloudEntry;
|
|
1823
1817
|
if (name === "my-local") return localEntry;
|
|
1824
1818
|
return null;
|
|
1825
1819
|
});
|
|
@@ -1831,7 +1825,7 @@ describe("VersionMismatchError handling", () => {
|
|
|
1831
1825
|
bundleKey: "platform-bundle-key-abc",
|
|
1832
1826
|
});
|
|
1833
1827
|
|
|
1834
|
-
|
|
1828
|
+
cloudRequestSignedUrlMock.mockImplementation(async (params) => {
|
|
1835
1829
|
if (params.operation === "download") {
|
|
1836
1830
|
throw new Error("network blew up");
|
|
1837
1831
|
}
|
|
@@ -1861,14 +1855,14 @@ describe("target runtime version fetch", () => {
|
|
|
1861
1855
|
test("local target: targetRuntimeVersion comes from /v1/identity, not cliPkg", async () => {
|
|
1862
1856
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
1863
1857
|
|
|
1864
|
-
const
|
|
1858
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
1865
1859
|
cloud: "cadet",
|
|
1866
1860
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
1867
1861
|
});
|
|
1868
1862
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
1869
1863
|
|
|
1870
1864
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
1871
|
-
if (name === "my-platform") return
|
|
1865
|
+
if (name === "my-platform") return cloudEntry;
|
|
1872
1866
|
if (name === "my-local") return localEntry;
|
|
1873
1867
|
return null;
|
|
1874
1868
|
});
|
|
@@ -1888,8 +1882,8 @@ describe("target runtime version fetch", () => {
|
|
|
1888
1882
|
try {
|
|
1889
1883
|
await teleport();
|
|
1890
1884
|
|
|
1891
|
-
const downloadCall =
|
|
1892
|
-
(c) =>
|
|
1885
|
+
const downloadCall = cloudRequestSignedUrlMock.mock.calls.find(
|
|
1886
|
+
(c) => c[0].operation === "download",
|
|
1893
1887
|
);
|
|
1894
1888
|
expect(downloadCall).toBeDefined();
|
|
1895
1889
|
expect(downloadCall![0]).toMatchObject({
|
|
@@ -1913,14 +1907,14 @@ describe("target runtime version fetch", () => {
|
|
|
1913
1907
|
test("identity fetch failure aborts before requesting download URL", async () => {
|
|
1914
1908
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
1915
1909
|
|
|
1916
|
-
const
|
|
1910
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
1917
1911
|
cloud: "cadet",
|
|
1918
1912
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
1919
1913
|
});
|
|
1920
1914
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
1921
1915
|
|
|
1922
1916
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
1923
|
-
if (name === "my-platform") return
|
|
1917
|
+
if (name === "my-platform") return cloudEntry;
|
|
1924
1918
|
if (name === "my-local") return localEntry;
|
|
1925
1919
|
return null;
|
|
1926
1920
|
});
|
|
@@ -1953,8 +1947,8 @@ describe("target runtime version fetch", () => {
|
|
|
1953
1947
|
);
|
|
1954
1948
|
|
|
1955
1949
|
// No download signed-URL request was made — we aborted before that.
|
|
1956
|
-
const downloadCalls =
|
|
1957
|
-
(c) =>
|
|
1950
|
+
const downloadCalls = cloudRequestSignedUrlMock.mock.calls.filter(
|
|
1951
|
+
(c) => c[0].operation === "download",
|
|
1958
1952
|
);
|
|
1959
1953
|
expect(downloadCalls).toHaveLength(0);
|
|
1960
1954
|
expect(localRuntimeImportFromGcsMock).not.toHaveBeenCalled();
|
|
@@ -1998,14 +1992,14 @@ describe("dry-run", () => {
|
|
|
1998
1992
|
);
|
|
1999
1993
|
|
|
2000
1994
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
2001
|
-
const
|
|
1995
|
+
const cloudEntry = makeEntry("existing-platform", {
|
|
2002
1996
|
cloud: "cadet",
|
|
2003
1997
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2004
1998
|
});
|
|
2005
1999
|
|
|
2006
2000
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
2007
2001
|
if (name === "my-local") return localEntry;
|
|
2008
|
-
if (name === "existing-platform") return
|
|
2002
|
+
if (name === "existing-platform") return cloudEntry;
|
|
2009
2003
|
return null;
|
|
2010
2004
|
});
|
|
2011
2005
|
|
|
@@ -2026,14 +2020,14 @@ describe("dry-run", () => {
|
|
|
2026
2020
|
test("dry-run with existing local target calls preflight-from-gcs on runtime", async () => {
|
|
2027
2021
|
setArgv("--from", "my-platform", "--local", "my-local", "--dry-run");
|
|
2028
2022
|
|
|
2029
|
-
const
|
|
2023
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
2030
2024
|
cloud: "cadet",
|
|
2031
2025
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2032
2026
|
});
|
|
2033
2027
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
2034
2028
|
|
|
2035
2029
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
2036
|
-
if (name === "my-platform") return
|
|
2030
|
+
if (name === "my-platform") return cloudEntry;
|
|
2037
2031
|
if (name === "my-local") return localEntry;
|
|
2038
2032
|
return null;
|
|
2039
2033
|
});
|
|
@@ -2179,13 +2173,13 @@ describe("pre-export source backup", () => {
|
|
|
2179
2173
|
|
|
2180
2174
|
test("platform source: takes a PVC snapshot through the source platform before exporting", async () => {
|
|
2181
2175
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
2182
|
-
const
|
|
2176
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
2183
2177
|
cloud: "cadet",
|
|
2184
2178
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2185
2179
|
});
|
|
2186
2180
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
2187
2181
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
2188
|
-
if (name === "my-platform") return
|
|
2182
|
+
if (name === "my-platform") return cloudEntry;
|
|
2189
2183
|
if (name === "my-local") return localEntry;
|
|
2190
2184
|
return null;
|
|
2191
2185
|
});
|
|
@@ -2223,13 +2217,13 @@ describe("pre-export source backup", () => {
|
|
|
2223
2217
|
|
|
2224
2218
|
test("platform source with a recent ready snapshot: reuses it", async () => {
|
|
2225
2219
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
2226
|
-
const
|
|
2220
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
2227
2221
|
cloud: "cadet",
|
|
2228
2222
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2229
2223
|
});
|
|
2230
2224
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
2231
2225
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
2232
|
-
if (name === "my-platform") return
|
|
2226
|
+
if (name === "my-platform") return cloudEntry;
|
|
2233
2227
|
if (name === "my-local") return localEntry;
|
|
2234
2228
|
return null;
|
|
2235
2229
|
});
|
|
@@ -2273,13 +2267,13 @@ describe("pre-export source backup", () => {
|
|
|
2273
2267
|
|
|
2274
2268
|
test("platform snapshot failure (never ready) aborts too", async () => {
|
|
2275
2269
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
2276
|
-
const
|
|
2270
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
2277
2271
|
cloud: "cadet",
|
|
2278
2272
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2279
2273
|
});
|
|
2280
2274
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
2281
2275
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
2282
|
-
if (name === "my-platform") return
|
|
2276
|
+
if (name === "my-platform") return cloudEntry;
|
|
2283
2277
|
if (name === "my-local") return localEntry;
|
|
2284
2278
|
return null;
|
|
2285
2279
|
});
|
|
@@ -2323,7 +2317,7 @@ describe("pre-check: existing platform assistant", () => {
|
|
|
2323
2317
|
name === "my-local" ? localEntry : null,
|
|
2324
2318
|
);
|
|
2325
2319
|
|
|
2326
|
-
|
|
2320
|
+
checkExistingCloudAssistantMock.mockResolvedValue({
|
|
2327
2321
|
id: "existing-platform-id",
|
|
2328
2322
|
name: "existing-platform",
|
|
2329
2323
|
status: "active",
|
|
@@ -2331,17 +2325,17 @@ describe("pre-check: existing platform assistant", () => {
|
|
|
2331
2325
|
|
|
2332
2326
|
await expect(teleport()).rejects.toThrow("process.exit:1");
|
|
2333
2327
|
|
|
2334
|
-
expect(
|
|
2328
|
+
expect(checkExistingCloudAssistantMock).toHaveBeenCalledWith(
|
|
2335
2329
|
"platform-token",
|
|
2336
2330
|
undefined,
|
|
2337
2331
|
);
|
|
2338
2332
|
// No signed-URL or runtime calls
|
|
2339
|
-
expect(
|
|
2333
|
+
expect(cloudRequestSignedUrlMock).not.toHaveBeenCalled();
|
|
2340
2334
|
expect(localRuntimeExportToGcsMock).not.toHaveBeenCalled();
|
|
2341
2335
|
expect(hatchAssistantMock).not.toHaveBeenCalled();
|
|
2342
2336
|
|
|
2343
2337
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
2344
|
-
expect.stringContaining("already have a
|
|
2338
|
+
expect.stringContaining("already have a cloud assistant"),
|
|
2345
2339
|
);
|
|
2346
2340
|
});
|
|
2347
2341
|
});
|
|
@@ -2354,14 +2348,14 @@ describe("version guard", () => {
|
|
|
2354
2348
|
test("blocks platform→local when local version is behind", async () => {
|
|
2355
2349
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
2356
2350
|
|
|
2357
|
-
const
|
|
2351
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
2358
2352
|
cloud: "cadet",
|
|
2359
2353
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2360
2354
|
});
|
|
2361
2355
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
2362
2356
|
|
|
2363
2357
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
2364
|
-
if (name === "my-platform") return
|
|
2358
|
+
if (name === "my-platform") return cloudEntry;
|
|
2365
2359
|
if (name === "my-local") return localEntry;
|
|
2366
2360
|
return null;
|
|
2367
2361
|
});
|
|
@@ -2385,14 +2379,14 @@ describe("version guard", () => {
|
|
|
2385
2379
|
test("allows equal versions", async () => {
|
|
2386
2380
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
2387
2381
|
|
|
2388
|
-
const
|
|
2382
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
2389
2383
|
cloud: "cadet",
|
|
2390
2384
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2391
2385
|
});
|
|
2392
2386
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
2393
2387
|
|
|
2394
2388
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
2395
|
-
if (name === "my-platform") return
|
|
2389
|
+
if (name === "my-platform") return cloudEntry;
|
|
2396
2390
|
if (name === "my-local") return localEntry;
|
|
2397
2391
|
return null;
|
|
2398
2392
|
});
|
|
@@ -2419,21 +2413,21 @@ describe("version guard", () => {
|
|
|
2419
2413
|
test("newly hatched target is cleaned up when version check fails", async () => {
|
|
2420
2414
|
setArgv("--from", "my-platform", "--local");
|
|
2421
2415
|
|
|
2422
|
-
const
|
|
2416
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
2423
2417
|
cloud: "cadet",
|
|
2424
2418
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2425
2419
|
});
|
|
2426
2420
|
const newLocalEntry = makeEntry("new-local", { cloud: "local" });
|
|
2427
2421
|
|
|
2428
2422
|
findAssistantByNameMock.mockImplementation((name: string) =>
|
|
2429
|
-
name === "my-platform" ?
|
|
2423
|
+
name === "my-platform" ? cloudEntry : null,
|
|
2430
2424
|
);
|
|
2431
2425
|
|
|
2432
2426
|
loadAllAssistantsMock.mockImplementation(() => {
|
|
2433
2427
|
if (hatchLocalMock.mock.calls.length > 0) {
|
|
2434
|
-
return [
|
|
2428
|
+
return [cloudEntry, newLocalEntry];
|
|
2435
2429
|
}
|
|
2436
|
-
return [
|
|
2430
|
+
return [cloudEntry];
|
|
2437
2431
|
});
|
|
2438
2432
|
|
|
2439
2433
|
platformPollJobStatusMock.mockResolvedValue({
|
|
@@ -2533,7 +2527,7 @@ describe("platform credential injection", () => {
|
|
|
2533
2527
|
test("platform→local teleport calls ensureSelfHostedLocalRegistration and injectCredentialsIntoAssistant", async () => {
|
|
2534
2528
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
2535
2529
|
|
|
2536
|
-
const
|
|
2530
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
2537
2531
|
cloud: "cadet",
|
|
2538
2532
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2539
2533
|
});
|
|
@@ -2543,7 +2537,7 @@ describe("platform credential injection", () => {
|
|
|
2543
2537
|
});
|
|
2544
2538
|
|
|
2545
2539
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
2546
|
-
if (name === "my-platform") return
|
|
2540
|
+
if (name === "my-platform") return cloudEntry;
|
|
2547
2541
|
if (name === "my-local") return localEntry;
|
|
2548
2542
|
return null;
|
|
2549
2543
|
});
|
|
@@ -2565,15 +2559,15 @@ describe("platform credential injection", () => {
|
|
|
2565
2559
|
"my-local",
|
|
2566
2560
|
"cli",
|
|
2567
2561
|
undefined, // assistantVersion (gateway unreachable in test)
|
|
2568
|
-
expect.any(String), //
|
|
2562
|
+
expect.any(String), // cloudUrl from getCloudUrl()
|
|
2569
2563
|
undefined, // ingressUrl (gateway unreachable in test)
|
|
2570
2564
|
);
|
|
2571
2565
|
expect(injectCredentialsIntoAssistantMock).toHaveBeenCalledWith({
|
|
2572
2566
|
gatewayUrl: "http://localhost:7821",
|
|
2573
2567
|
bearerToken: "local-bearer",
|
|
2574
2568
|
assistantApiKey: "api-key-123",
|
|
2575
|
-
|
|
2576
|
-
|
|
2569
|
+
cloudAssistantId: "platform-assistant-1",
|
|
2570
|
+
cloudBaseUrl: "https://cloud.mycadet.ai",
|
|
2577
2571
|
organizationId: "org-1",
|
|
2578
2572
|
userId: "user-1",
|
|
2579
2573
|
webhookSecret: "webhook-secret-123",
|
|
@@ -2581,9 +2575,9 @@ describe("platform credential injection", () => {
|
|
|
2581
2575
|
expect(saveAssistantEntryMock).toHaveBeenCalledWith(
|
|
2582
2576
|
expect.objectContaining({
|
|
2583
2577
|
assistantId: "my-local",
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2578
|
+
cloudAssistantId: "platform-assistant-1",
|
|
2579
|
+
cloudBaseUrl: "https://cloud.mycadet.ai",
|
|
2580
|
+
cloudOrganizationId: "org-1",
|
|
2587
2581
|
}),
|
|
2588
2582
|
);
|
|
2589
2583
|
} finally {
|
|
@@ -2639,12 +2633,9 @@ describe("auth + transient-error resilience", () => {
|
|
|
2639
2633
|
}));
|
|
2640
2634
|
|
|
2641
2635
|
// Ensure the refresh path returns a distinguishable token.
|
|
2642
|
-
leaseGuardianTokenMock.mockResolvedValueOnce(
|
|
2643
|
-
accessToken: "refreshed-token",
|
|
2644
|
-
|
|
2645
|
-
} as unknown as Awaited<
|
|
2646
|
-
ReturnType<typeof guardianToken.leaseGuardianToken>
|
|
2647
|
-
>);
|
|
2636
|
+
leaseGuardianTokenMock.mockResolvedValueOnce(
|
|
2637
|
+
makeGuardianTokenData({ accessToken: "refreshed-token" }),
|
|
2638
|
+
);
|
|
2648
2639
|
|
|
2649
2640
|
const restoreFetch = installTrackingFetch();
|
|
2650
2641
|
try {
|
|
@@ -2669,14 +2660,14 @@ describe("auth + transient-error resilience", () => {
|
|
|
2669
2660
|
test("runtime 401 on import kickoff triggers token refresh and retry", async () => {
|
|
2670
2661
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
2671
2662
|
|
|
2672
|
-
const
|
|
2663
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
2673
2664
|
cloud: "cadet",
|
|
2674
2665
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2675
2666
|
});
|
|
2676
2667
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
2677
2668
|
|
|
2678
2669
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
2679
|
-
if (name === "my-platform") return
|
|
2670
|
+
if (name === "my-platform") return cloudEntry;
|
|
2680
2671
|
if (name === "my-local") return localEntry;
|
|
2681
2672
|
return null;
|
|
2682
2673
|
});
|
|
@@ -2697,12 +2688,9 @@ describe("auth + transient-error resilience", () => {
|
|
|
2697
2688
|
jobId: "local-import-after-refresh",
|
|
2698
2689
|
}));
|
|
2699
2690
|
|
|
2700
|
-
leaseGuardianTokenMock.mockResolvedValueOnce(
|
|
2701
|
-
accessToken: "refreshed-import-token",
|
|
2702
|
-
|
|
2703
|
-
} as unknown as Awaited<
|
|
2704
|
-
ReturnType<typeof guardianToken.leaseGuardianToken>
|
|
2705
|
-
>);
|
|
2691
|
+
leaseGuardianTokenMock.mockResolvedValueOnce(
|
|
2692
|
+
makeGuardianTokenData({ accessToken: "refreshed-import-token" }),
|
|
2693
|
+
);
|
|
2706
2694
|
|
|
2707
2695
|
const restoreFetch = installTrackingFetch();
|
|
2708
2696
|
try {
|
|
@@ -2770,12 +2758,9 @@ describe("auth + transient-error resilience", () => {
|
|
|
2770
2758
|
},
|
|
2771
2759
|
);
|
|
2772
2760
|
|
|
2773
|
-
leaseGuardianTokenMock.mockResolvedValueOnce(
|
|
2774
|
-
accessToken: "poll-refreshed-token",
|
|
2775
|
-
|
|
2776
|
-
} as unknown as Awaited<
|
|
2777
|
-
ReturnType<typeof guardianToken.leaseGuardianToken>
|
|
2778
|
-
>);
|
|
2761
|
+
leaseGuardianTokenMock.mockResolvedValueOnce(
|
|
2762
|
+
makeGuardianTokenData({ accessToken: "poll-refreshed-token" }),
|
|
2763
|
+
);
|
|
2779
2764
|
|
|
2780
2765
|
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
2781
2766
|
const restoreFetch = installTrackingFetch();
|
|
@@ -2836,7 +2821,7 @@ describe("auth + transient-error resilience", () => {
|
|
|
2836
2821
|
await teleport();
|
|
2837
2822
|
expect(pollCalls).toBeGreaterThanOrEqual(2);
|
|
2838
2823
|
expect(warnSpy).toHaveBeenCalledWith(
|
|
2839
|
-
expect.stringContaining("polling failed
|
|
2824
|
+
expect.stringContaining("polling failed:"),
|
|
2840
2825
|
);
|
|
2841
2826
|
} finally {
|
|
2842
2827
|
restoreFetch();
|
|
@@ -2868,7 +2853,7 @@ describe("upload signed-URL records source runtime version (not CLI version)", (
|
|
|
2868
2853
|
callOrder.push("identity");
|
|
2869
2854
|
return { version: "0.5.9" };
|
|
2870
2855
|
});
|
|
2871
|
-
|
|
2856
|
+
cloudRequestSignedUrlMock.mockImplementationOnce(async (params) => {
|
|
2872
2857
|
callOrder.push("signed-url");
|
|
2873
2858
|
return {
|
|
2874
2859
|
url: "https://storage.googleapis.com/bucket/signed-upload",
|
|
@@ -2886,7 +2871,7 @@ describe("upload signed-URL records source runtime version (not CLI version)", (
|
|
|
2886
2871
|
|
|
2887
2872
|
// Upload request stamps minRuntimeVersion with the daemon's version,
|
|
2888
2873
|
// NOT cliPkg.version.
|
|
2889
|
-
expect(
|
|
2874
|
+
expect(cloudRequestSignedUrlMock).toHaveBeenCalledWith(
|
|
2890
2875
|
expect.objectContaining({
|
|
2891
2876
|
operation: "upload",
|
|
2892
2877
|
minRuntimeVersion: "0.5.9",
|
|
@@ -2917,7 +2902,7 @@ describe("upload signed-URL records source runtime version (not CLI version)", (
|
|
|
2917
2902
|
await expect(teleport()).rejects.toThrow("process.exit:1");
|
|
2918
2903
|
|
|
2919
2904
|
// Must NOT have proceeded to signed URL or export.
|
|
2920
|
-
expect(
|
|
2905
|
+
expect(cloudRequestSignedUrlMock).not.toHaveBeenCalled();
|
|
2921
2906
|
expect(localRuntimeExportToGcsMock).not.toHaveBeenCalled();
|
|
2922
2907
|
|
|
2923
2908
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
@@ -2931,14 +2916,14 @@ describe("upload signed-URL records source runtime version (not CLI version)", (
|
|
|
2931
2916
|
test("platform source: managed runtime's identity is fetched and recorded", async () => {
|
|
2932
2917
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
2933
2918
|
|
|
2934
|
-
const
|
|
2919
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
2935
2920
|
cloud: "cadet",
|
|
2936
2921
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2937
2922
|
});
|
|
2938
2923
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
2939
2924
|
|
|
2940
2925
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
2941
|
-
if (name === "my-platform") return
|
|
2926
|
+
if (name === "my-platform") return cloudEntry;
|
|
2942
2927
|
if (name === "my-local") return localEntry;
|
|
2943
2928
|
return null;
|
|
2944
2929
|
});
|
|
@@ -2956,8 +2941,8 @@ describe("upload signed-URL records source runtime version (not CLI version)", (
|
|
|
2956
2941
|
try {
|
|
2957
2942
|
await teleport();
|
|
2958
2943
|
|
|
2959
|
-
// Identity was fetched against the
|
|
2960
|
-
// (cloud=cadet) with the
|
|
2944
|
+
// Identity was fetched against the cloud-managed runtime entry
|
|
2945
|
+
// (cloud=cadet) with the cloud token — not via guardian token.
|
|
2961
2946
|
expect(localRuntimeIdentityMock).toHaveBeenCalledWith(
|
|
2962
2947
|
expect.objectContaining({
|
|
2963
2948
|
cloud: "cadet",
|
|
@@ -2967,8 +2952,8 @@ describe("upload signed-URL records source runtime version (not CLI version)", (
|
|
|
2967
2952
|
"platform-token",
|
|
2968
2953
|
);
|
|
2969
2954
|
|
|
2970
|
-
// The recorded version came from the
|
|
2971
|
-
expect(
|
|
2955
|
+
// The recorded version came from the cloud runtime, not the CLI.
|
|
2956
|
+
expect(cloudRequestSignedUrlMock).toHaveBeenCalledWith(
|
|
2972
2957
|
expect.objectContaining({
|
|
2973
2958
|
operation: "upload",
|
|
2974
2959
|
minRuntimeVersion: "0.7.2",
|
|
@@ -2985,14 +2970,14 @@ describe("upload signed-URL records source runtime version (not CLI version)", (
|
|
|
2985
2970
|
test("platform source: identity fetch failure aborts before signed-URL request", async () => {
|
|
2986
2971
|
setArgv("--from", "my-platform", "--local", "my-local");
|
|
2987
2972
|
|
|
2988
|
-
const
|
|
2973
|
+
const cloudEntry = makeEntry("my-platform", {
|
|
2989
2974
|
cloud: "cadet",
|
|
2990
2975
|
runtimeUrl: "https://cloud.mycadet.ai",
|
|
2991
2976
|
});
|
|
2992
2977
|
const localEntry = makeEntry("my-local", { cloud: "local" });
|
|
2993
2978
|
|
|
2994
2979
|
findAssistantByNameMock.mockImplementation((name: string) => {
|
|
2995
|
-
if (name === "my-platform") return
|
|
2980
|
+
if (name === "my-platform") return cloudEntry;
|
|
2996
2981
|
if (name === "my-local") return localEntry;
|
|
2997
2982
|
return null;
|
|
2998
2983
|
});
|
|
@@ -3006,9 +2991,8 @@ describe("upload signed-URL records source runtime version (not CLI version)", (
|
|
|
3006
2991
|
await expect(teleport()).rejects.toThrow("process.exit:1");
|
|
3007
2992
|
|
|
3008
2993
|
// Signed-URL upload request must not have happened.
|
|
3009
|
-
const uploadCalls =
|
|
3010
|
-
(call
|
|
3011
|
-
(call[0] as { operation: string }).operation === "upload",
|
|
2994
|
+
const uploadCalls = cloudRequestSignedUrlMock.mock.calls.filter(
|
|
2995
|
+
(call) => call[0].operation === "upload",
|
|
3012
2996
|
);
|
|
3013
2997
|
expect(uploadCalls.length).toBe(0);
|
|
3014
2998
|
|