@dbx-tools/lakebox 0.9.154 → 0.9.157
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/index.ts +7 -3
- package/lib/index.d.ts +7 -3
- package/lib/index.js +7 -4
- package/lib/src/_ssh_openssh.d.ts +1 -1
- package/lib/src/_ssh_openssh.js +13 -13
- package/lib/src/_ssh_ssh2.d.ts +1 -1
- package/lib/src/_ssh_ssh2.js +2 -2
- package/lib/src/key-store.js +3 -3
- package/lib/src/lifecycle.js +3 -3
- package/lib/src/rest.js +4 -4
- package/lib/src/session.d.ts +2 -3
- package/lib/src/session.js +6 -7
- package/lib/src/ssh.js +489 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -53
- package/src/_ssh_openssh.ts +13 -13
- package/src/_ssh_ssh2.ts +1 -1
- package/src/key-store.ts +2 -2
- package/src/lifecycle.ts +2 -2
- package/src/rest.ts +3 -3
- package/src/session.ts +5 -7
- package/src/{_ssh.ts → ssh.ts} +3 -3
- package/lib/src/_ssh.js +0 -489
- /package/lib/src/{_ssh.d.ts → ssh.d.ts} +0 -0
package/package.json
CHANGED
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"vitest": "3.2.4"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@dbx-tools/core": "^0.9.
|
|
29
|
-
"@dbx-tools/shared-core": "^0.9.
|
|
30
|
-
"@dbx-tools/shared-lakebox": "^0.9.
|
|
28
|
+
"@dbx-tools/core": "^0.9.157",
|
|
29
|
+
"@dbx-tools/shared-core": "^0.9.157",
|
|
30
|
+
"@dbx-tools/shared-lakebox": "^0.9.157",
|
|
31
31
|
"generic-pool": "^3.9.0",
|
|
32
32
|
"socks": "^2.8.10",
|
|
33
33
|
"ssh2": "^1.17.0",
|
|
@@ -44,34 +44,10 @@
|
|
|
44
44
|
"types": "./lib/index.d.ts",
|
|
45
45
|
"default": "./lib/index.js"
|
|
46
46
|
},
|
|
47
|
-
"./key-store": {
|
|
48
|
-
"types": "./lib/src/key-store.d.ts",
|
|
49
|
-
"default": "./lib/src/key-store.js"
|
|
50
|
-
},
|
|
51
|
-
"./lifecycle": {
|
|
52
|
-
"types": "./lib/src/lifecycle.d.ts",
|
|
53
|
-
"default": "./lib/src/lifecycle.js"
|
|
54
|
-
},
|
|
55
|
-
"./rest": {
|
|
56
|
-
"types": "./lib/src/rest.d.ts",
|
|
57
|
-
"default": "./lib/src/rest.js"
|
|
58
|
-
},
|
|
59
|
-
"./session": {
|
|
60
|
-
"types": "./lib/src/session.d.ts",
|
|
61
|
-
"default": "./lib/src/session.js"
|
|
62
|
-
},
|
|
63
|
-
"./transport": {
|
|
64
|
-
"types": "./lib/src/transport.d.ts",
|
|
65
|
-
"default": "./lib/src/transport.js"
|
|
66
|
-
},
|
|
67
|
-
"./*": {
|
|
68
|
-
"types": "./lib/src/*/index.d.ts",
|
|
69
|
-
"default": "./lib/src/*/index.js"
|
|
70
|
-
},
|
|
71
47
|
"./package.json": "./package.json"
|
|
72
48
|
}
|
|
73
49
|
},
|
|
74
|
-
"version": "0.9.
|
|
50
|
+
"version": "0.9.157",
|
|
75
51
|
"types": "./lib/index.d.ts",
|
|
76
52
|
"dbxToolsConfig": {
|
|
77
53
|
"tags": [
|
|
@@ -84,34 +60,10 @@
|
|
|
84
60
|
"types": "./lib/index.d.ts",
|
|
85
61
|
"default": "./lib/index.js"
|
|
86
62
|
},
|
|
87
|
-
"./key-store": {
|
|
88
|
-
"types": "./lib/src/key-store.d.ts",
|
|
89
|
-
"default": "./lib/src/key-store.js"
|
|
90
|
-
},
|
|
91
|
-
"./lifecycle": {
|
|
92
|
-
"types": "./lib/src/lifecycle.d.ts",
|
|
93
|
-
"default": "./lib/src/lifecycle.js"
|
|
94
|
-
},
|
|
95
|
-
"./rest": {
|
|
96
|
-
"types": "./lib/src/rest.d.ts",
|
|
97
|
-
"default": "./lib/src/rest.js"
|
|
98
|
-
},
|
|
99
|
-
"./session": {
|
|
100
|
-
"types": "./lib/src/session.d.ts",
|
|
101
|
-
"default": "./lib/src/session.js"
|
|
102
|
-
},
|
|
103
|
-
"./transport": {
|
|
104
|
-
"types": "./lib/src/transport.d.ts",
|
|
105
|
-
"default": "./lib/src/transport.js"
|
|
106
|
-
},
|
|
107
|
-
"./*": {
|
|
108
|
-
"types": "./lib/src/*/index.d.ts",
|
|
109
|
-
"default": "./lib/src/*/index.js"
|
|
110
|
-
},
|
|
111
63
|
"./package.json": "./package.json"
|
|
112
64
|
},
|
|
113
65
|
"files": [
|
|
114
|
-
"index
|
|
66
|
+
"index*.ts",
|
|
115
67
|
"src",
|
|
116
68
|
"lib"
|
|
117
69
|
],
|
package/src/_ssh_openssh.ts
CHANGED
|
@@ -4,9 +4,9 @@ import { tmpdir } from "node:os";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import type { Duplex } from "node:stream";
|
|
6
6
|
import { setTimeout as delay } from "node:timers/promises";
|
|
7
|
-
import {
|
|
8
|
-
import type { ChildProcessResult } from "@dbx-tools/core
|
|
9
|
-
import {
|
|
7
|
+
import { spawn, onParentTerminationSignal } from "@dbx-tools/core";
|
|
8
|
+
import type { ChildProcessResult } from "@dbx-tools/core";
|
|
9
|
+
import { log, toError, dedent } from "@dbx-tools/shared-core";
|
|
10
10
|
import { SocksClient } from "socks";
|
|
11
11
|
import {
|
|
12
12
|
PooledSshTransport,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
type SshPoolOptions,
|
|
15
15
|
type SshResourceLifecycle,
|
|
16
16
|
type SshTransportOptions,
|
|
17
|
-
} from "./
|
|
17
|
+
} from "./ssh.ts";
|
|
18
18
|
|
|
19
19
|
const SOCKS_HOST = "127.0.0.1";
|
|
20
20
|
const OPENSSH_HELPER_TIMEOUT_MS = 2_000;
|
|
@@ -26,7 +26,7 @@ let stopParentTerminationSignal: (() => void) | undefined;
|
|
|
26
26
|
let processExitHookInstalled = false;
|
|
27
27
|
/** @internal JavaScript watchdog that terminates one child when its parent pipe closes. */
|
|
28
28
|
export const OPENSSH_PARENT_WATCH_SOURCE =
|
|
29
|
-
|
|
29
|
+
dedent(// ============================================================================
|
|
30
30
|
/*js*/ `
|
|
31
31
|
const { spawn } = require("node:child_process");
|
|
32
32
|
|
|
@@ -176,7 +176,7 @@ class NativeOpenSshResource implements OpenSshResource {
|
|
|
176
176
|
const socksPort = await availableLoopbackPort();
|
|
177
177
|
const target = `${options.username}@${options.connectHost}`;
|
|
178
178
|
const master = trackNativeOpenSshProcess(
|
|
179
|
-
|
|
179
|
+
spawn(
|
|
180
180
|
process.execPath,
|
|
181
181
|
[
|
|
182
182
|
"-e",
|
|
@@ -228,7 +228,7 @@ class NativeOpenSshResource implements OpenSshResource {
|
|
|
228
228
|
|
|
229
229
|
async run(script: string, execution: SshCommandExecution): Promise<number> {
|
|
230
230
|
const child = trackNativeOpenSshProcess(
|
|
231
|
-
|
|
231
|
+
spawn(
|
|
232
232
|
this.command,
|
|
233
233
|
[
|
|
234
234
|
...nativeOpenSshArgs(this.options),
|
|
@@ -253,7 +253,7 @@ class NativeOpenSshResource implements OpenSshResource {
|
|
|
253
253
|
let shutdown: Promise<void> | undefined;
|
|
254
254
|
execution.setCancel(() => {
|
|
255
255
|
shutdown ??= child.shutdown({ terminateTimeout: 0, killTimeout: 1_000 }).catch((error) => {
|
|
256
|
-
logger.warn("failed to stop native SSH command", { error:
|
|
256
|
+
logger.warn("failed to stop native SSH command", { error: toError(error) });
|
|
257
257
|
});
|
|
258
258
|
return shutdown;
|
|
259
259
|
});
|
|
@@ -293,7 +293,7 @@ class NativeOpenSshResource implements OpenSshResource {
|
|
|
293
293
|
} finally {
|
|
294
294
|
await this.master.shutdown({ terminateTimeout: 0, killTimeout: 1_000 }).catch((error) =>
|
|
295
295
|
logger.warn("failed to stop native SSH ControlMaster", {
|
|
296
|
-
error:
|
|
296
|
+
error: toError(error),
|
|
297
297
|
}),
|
|
298
298
|
);
|
|
299
299
|
await rm(this.directory, { recursive: true, force: true });
|
|
@@ -319,7 +319,7 @@ class NativeOpenSshResource implements OpenSshResource {
|
|
|
319
319
|
|
|
320
320
|
private control(operation: "check" | "exit") {
|
|
321
321
|
const child = trackNativeOpenSshProcess(
|
|
322
|
-
|
|
322
|
+
spawn(
|
|
323
323
|
this.command,
|
|
324
324
|
[
|
|
325
325
|
"-p",
|
|
@@ -346,7 +346,7 @@ async function probeNativeOpenSsh(command: string): Promise<boolean> {
|
|
|
346
346
|
try {
|
|
347
347
|
const version = await waitForNativeOpenSshChild(
|
|
348
348
|
trackNativeOpenSshProcess(
|
|
349
|
-
|
|
349
|
+
spawn(command, ["-V"], {
|
|
350
350
|
stdin: "ignore",
|
|
351
351
|
stdout: "capture",
|
|
352
352
|
stderr: "capture",
|
|
@@ -359,7 +359,7 @@ async function probeNativeOpenSsh(command: string): Promise<boolean> {
|
|
|
359
359
|
if (version.exitCode !== 0 || !/(?:^|\s)OpenSSH_/m.test(versionOutput)) return false;
|
|
360
360
|
const dynamicForward = await waitForNativeOpenSshChild(
|
|
361
361
|
trackNativeOpenSshProcess(
|
|
362
|
-
|
|
362
|
+
spawn(command, ["-G", "-D", `${SOCKS_HOST}:1`, "localhost"], {
|
|
363
363
|
stdin: "ignore",
|
|
364
364
|
stdout: "ignore",
|
|
365
365
|
stderr: "ignore",
|
|
@@ -402,7 +402,7 @@ function trackNativeOpenSshProcess(
|
|
|
402
402
|
activeNativeOpenSshProcesses.add(child);
|
|
403
403
|
if (parentBound) parentBoundNativeOpenSshProcesses.add(child);
|
|
404
404
|
if (!stopParentTerminationSignal) {
|
|
405
|
-
stopParentTerminationSignal =
|
|
405
|
+
stopParentTerminationSignal = onParentTerminationSignal(forceStopNativeOpenSshProcesses);
|
|
406
406
|
}
|
|
407
407
|
if (!processExitHookInstalled) {
|
|
408
408
|
processExitHookInstalled = true;
|
package/src/_ssh_ssh2.ts
CHANGED
package/src/key-store.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { createHash, randomBytes } from "node:crypto";
|
|
|
2
2
|
import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { withFileLock } from "@dbx-tools/core";
|
|
6
6
|
import ssh2 from "ssh2";
|
|
7
7
|
import type { LakeboxClient } from "./rest.ts";
|
|
8
8
|
|
|
@@ -103,7 +103,7 @@ export class SshKeyStore {
|
|
|
103
103
|
const stored = await readStoredKey(privatePath, publicPath);
|
|
104
104
|
if (stored) return stored;
|
|
105
105
|
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
106
|
-
return
|
|
106
|
+
return withFileLock(["lakebox-ssh-key", privatePath], async () => {
|
|
107
107
|
const rechecked = await readStoredKey(privatePath, publicPath);
|
|
108
108
|
if (rechecked) return rechecked;
|
|
109
109
|
|
package/src/lifecycle.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sleep } from "@dbx-tools/shared-core";
|
|
2
2
|
import type { LakeboxStatus } from "@dbx-tools/shared-lakebox";
|
|
3
3
|
import type { LakeboxClient, LakeboxEntry } from "./rest.ts";
|
|
4
4
|
|
|
@@ -81,7 +81,7 @@ async function waitForLakeboxStatus(
|
|
|
81
81
|
if (Date.now() >= deadline) {
|
|
82
82
|
throw new Error(`Timed out waiting for Lakebox ${entry.sandboxId} to become ${expected}`);
|
|
83
83
|
}
|
|
84
|
-
await
|
|
84
|
+
await sleep(POLL_INTERVAL_MS, signal);
|
|
85
85
|
entry = await api.get(entry.sandboxId, signal);
|
|
86
86
|
}
|
|
87
87
|
return entry;
|
package/src/rest.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { log, toError, urlBuilder } from "@dbx-tools/shared-core";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
const LAKEBOX_ROOT = "/api/2.0/lakebox";
|
|
@@ -94,7 +94,7 @@ export class LakeboxClient {
|
|
|
94
94
|
return (
|
|
95
95
|
process.env.DATABRICKS_WORKSPACE_ID?.trim() ||
|
|
96
96
|
this.auth.workspaceId?.trim() ||
|
|
97
|
-
|
|
97
|
+
urlBuilder(this.auth.host ?? "")?.origin ||
|
|
98
98
|
"workspace"
|
|
99
99
|
);
|
|
100
100
|
}
|
|
@@ -201,7 +201,7 @@ export class LakeboxClient {
|
|
|
201
201
|
logger.warn("lakebox REST request failed", {
|
|
202
202
|
...metadata,
|
|
203
203
|
durationMs: Date.now() - startedAt,
|
|
204
|
-
error:
|
|
204
|
+
error: toError(error),
|
|
205
205
|
});
|
|
206
206
|
throw error;
|
|
207
207
|
}
|
package/src/session.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { isIP } from "node:net";
|
|
3
3
|
import type { Duplex } from "node:stream";
|
|
4
|
-
import {
|
|
4
|
+
import { log, toError } from "@dbx-tools/shared-core";
|
|
5
5
|
import ssh2, { type Client as Ssh2Client } from "ssh2";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import {
|
|
@@ -10,11 +10,9 @@ import {
|
|
|
10
10
|
sshCommandScript,
|
|
11
11
|
type SshCommandIdentity,
|
|
12
12
|
type SshTransport,
|
|
13
|
-
} from "./
|
|
13
|
+
} from "./ssh.ts";
|
|
14
14
|
import type { Ssh2PatchMode, SshTransportMode } from "./transport.ts";
|
|
15
15
|
|
|
16
|
-
export { SshCommand, sshCommandScript, type SshCommandIdentity } from "./_ssh.ts";
|
|
17
|
-
|
|
18
16
|
const { Client } = ssh2;
|
|
19
17
|
const logger = log.logger("lakebox:ssh");
|
|
20
18
|
const SERVICE_DIRECT_SUFFIX = ".service-direct.cloud.databricks.com";
|
|
@@ -66,7 +64,7 @@ export interface SshSessionOptions {
|
|
|
66
64
|
|
|
67
65
|
/**
|
|
68
66
|
* Verified SSH session that delegates commands and remote TCP connections to
|
|
69
|
-
* the transport selected by `src/
|
|
67
|
+
* the transport selected by `src/ssh.ts`.
|
|
70
68
|
*
|
|
71
69
|
* The initial ssh2 handshake verifies and persists the Databricks gateway host
|
|
72
70
|
* key. The selected transport then starts its pooled command and forwarding
|
|
@@ -114,7 +112,7 @@ export class SshSession {
|
|
|
114
112
|
} catch (resolveError) {
|
|
115
113
|
logger.warn("public Lakebox gateway resolution failed", {
|
|
116
114
|
host: this.options.host,
|
|
117
|
-
error:
|
|
115
|
+
error: toError(resolveError),
|
|
118
116
|
});
|
|
119
117
|
throw error;
|
|
120
118
|
}
|
|
@@ -329,7 +327,7 @@ export class SshSession {
|
|
|
329
327
|
for (const result of results) {
|
|
330
328
|
if (result.status === "rejected") {
|
|
331
329
|
logger.warn("failed to close SSH session resource", {
|
|
332
|
-
error:
|
|
330
|
+
error: toError(result.reason),
|
|
333
331
|
});
|
|
334
332
|
}
|
|
335
333
|
}
|
package/src/{_ssh.ts → ssh.ts}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PassThrough, type Duplex, type Readable } from "node:stream";
|
|
2
2
|
import { StringDecoder } from "node:string_decoder";
|
|
3
|
-
import {
|
|
3
|
+
import { log, toError } from "@dbx-tools/shared-core";
|
|
4
4
|
import type { LakeboxCommandResult } from "@dbx-tools/shared-lakebox";
|
|
5
5
|
import { createPool, type Factory, type Options, type Pool } from "generic-pool";
|
|
6
6
|
import type { Client as Ssh2Client } from "ssh2";
|
|
@@ -324,7 +324,7 @@ export abstract class PooledSshTransport<T> implements SshTransport {
|
|
|
324
324
|
.catch((error) =>
|
|
325
325
|
logger.warn("failed to close SSH transport after startup failure", {
|
|
326
326
|
kind: this.kind,
|
|
327
|
-
error:
|
|
327
|
+
error: toError(error),
|
|
328
328
|
}),
|
|
329
329
|
);
|
|
330
330
|
return this.starting;
|
|
@@ -436,7 +436,7 @@ export abstract class PooledSshTransport<T> implements SshTransport {
|
|
|
436
436
|
} catch (error) {
|
|
437
437
|
logger.warn("failed to destroy pooled SSH resource", {
|
|
438
438
|
kind: this.kind,
|
|
439
|
-
error:
|
|
439
|
+
error: toError(error),
|
|
440
440
|
});
|
|
441
441
|
}
|
|
442
442
|
}
|