@saptools/cf-debugger 0.2.0 → 0.2.1
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/dist/{chunk-ZWAQD7KL.js → chunk-AKQR4Y74.js} +167 -101
- package/dist/chunk-AKQR4Y74.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-ZWAQD7KL.js.map +0 -1
|
@@ -846,8 +846,91 @@ var NODE_INSPECTOR_SCRIPT = [
|
|
|
846
846
|
|
|
847
847
|
// src/cloud-foundry/ssh.ts
|
|
848
848
|
import { spawn } from "child_process";
|
|
849
|
-
import
|
|
849
|
+
import nodeProcess3 from "process";
|
|
850
850
|
import { StringDecoder } from "string_decoder";
|
|
851
|
+
|
|
852
|
+
// src/debug-session/process-identity.ts
|
|
853
|
+
import { execFile as execFile2 } from "child_process";
|
|
854
|
+
import { readFile } from "fs/promises";
|
|
855
|
+
import nodeProcess2 from "process";
|
|
856
|
+
import { promisify } from "util";
|
|
857
|
+
var execFileAsync = promisify(execFile2);
|
|
858
|
+
function errorCode(error) {
|
|
859
|
+
if (typeof error !== "object" || error === null) {
|
|
860
|
+
return void 0;
|
|
861
|
+
}
|
|
862
|
+
const code = Reflect.get(error, "code");
|
|
863
|
+
return typeof code === "string" ? code : void 0;
|
|
864
|
+
}
|
|
865
|
+
function parseLinuxProcessStartTime(statLine) {
|
|
866
|
+
const commandEnd = statLine.lastIndexOf(")");
|
|
867
|
+
if (commandEnd < 0) {
|
|
868
|
+
return void 0;
|
|
869
|
+
}
|
|
870
|
+
const fieldsAfterCommand = statLine.slice(commandEnd + 1).trim().split(/\s+/);
|
|
871
|
+
const startTime = fieldsAfterCommand[19];
|
|
872
|
+
return startTime !== void 0 && /^\d+$/.test(startTime) ? startTime : void 0;
|
|
873
|
+
}
|
|
874
|
+
function throwIfAborted(signal) {
|
|
875
|
+
if (signal?.aborted) {
|
|
876
|
+
throw new CfDebuggerError("ABORTED", "Process identity inspection was aborted.");
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
async function linuxProcessIdentity(pid, signal) {
|
|
880
|
+
try {
|
|
881
|
+
const statLine = await readFile(`/proc/${pid.toString()}/stat`, {
|
|
882
|
+
encoding: "utf8",
|
|
883
|
+
...signal === void 0 ? {} : { signal }
|
|
884
|
+
});
|
|
885
|
+
const startTime = parseLinuxProcessStartTime(statLine);
|
|
886
|
+
return startTime === void 0 ? void 0 : `linux:${startTime}`;
|
|
887
|
+
} catch (error) {
|
|
888
|
+
throwIfAborted(signal);
|
|
889
|
+
if (errorCode(error) === "ENOENT") {
|
|
890
|
+
return void 0;
|
|
891
|
+
}
|
|
892
|
+
return void 0;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
async function darwinProcessIdentity(pid, signal) {
|
|
896
|
+
try {
|
|
897
|
+
const { stdout } = await execFileAsync("ps", ["-p", pid.toString(), "-o", "lstart="], {
|
|
898
|
+
...signal === void 0 ? {} : { signal },
|
|
899
|
+
timeout: 2e3
|
|
900
|
+
});
|
|
901
|
+
const startedAt = stdout.trim();
|
|
902
|
+
return startedAt.length === 0 ? void 0 : `darwin:${startedAt}`;
|
|
903
|
+
} catch {
|
|
904
|
+
throwIfAborted(signal);
|
|
905
|
+
return void 0;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
async function readProcessIdentity(pid, signal) {
|
|
909
|
+
throwIfAborted(signal);
|
|
910
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) {
|
|
911
|
+
return void 0;
|
|
912
|
+
}
|
|
913
|
+
if (nodeProcess2.platform === "linux") {
|
|
914
|
+
return await linuxProcessIdentity(pid, signal);
|
|
915
|
+
}
|
|
916
|
+
if (nodeProcess2.platform === "darwin") {
|
|
917
|
+
return await darwinProcessIdentity(pid, signal);
|
|
918
|
+
}
|
|
919
|
+
return void 0;
|
|
920
|
+
}
|
|
921
|
+
async function inspectProcessIdentity(pid, expected, signal) {
|
|
922
|
+
throwIfAborted(signal);
|
|
923
|
+
if (expected === void 0) {
|
|
924
|
+
return "match";
|
|
925
|
+
}
|
|
926
|
+
const current = await readProcessIdentity(pid, signal);
|
|
927
|
+
if (current === void 0) {
|
|
928
|
+
return "unavailable";
|
|
929
|
+
}
|
|
930
|
+
return current === expected ? "match" : "mismatch";
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// src/cloud-foundry/ssh.ts
|
|
851
934
|
var DEFAULT_MAX_OUTPUT_BYTES = 65536;
|
|
852
935
|
var LIVE_LINE_LIMIT_BYTES = 65536;
|
|
853
936
|
var MAX_REDACTION_OVERLAP_BYTES = 4096;
|
|
@@ -986,14 +1069,77 @@ function createSshExecutionState(context, outputLimit) {
|
|
|
986
1069
|
redaction,
|
|
987
1070
|
settled: false,
|
|
988
1071
|
aborted: false,
|
|
989
|
-
timedOut: false
|
|
1072
|
+
timedOut: false,
|
|
1073
|
+
terminationStarted: false
|
|
990
1074
|
};
|
|
991
1075
|
}
|
|
992
|
-
function
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1076
|
+
function childIsOpen(child) {
|
|
1077
|
+
return child.exitCode === null && child.signalCode === null;
|
|
1078
|
+
}
|
|
1079
|
+
async function captureSshChildIdentity(child) {
|
|
1080
|
+
if (nodeProcess3.platform === "win32" || child.pid === void 0) {
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
try {
|
|
1084
|
+
return await readProcessIdentity(child.pid);
|
|
1085
|
+
} catch {
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
async function canSignalSshChild(child, childIdentity) {
|
|
1090
|
+
if (!childIsOpen(child) || child.pid === void 0) {
|
|
1091
|
+
return false;
|
|
1092
|
+
}
|
|
1093
|
+
if (nodeProcess3.platform === "win32") {
|
|
1094
|
+
return true;
|
|
1095
|
+
}
|
|
1096
|
+
const expectedIdentity = await childIdentity;
|
|
1097
|
+
if (expectedIdentity === void 0) {
|
|
1098
|
+
return false;
|
|
1099
|
+
}
|
|
1100
|
+
return await inspectProcessIdentity(child.pid, expectedIdentity) === "match" && childIsOpen(child);
|
|
1101
|
+
}
|
|
1102
|
+
function abandonUnverifiedSshChild(child) {
|
|
1103
|
+
try {
|
|
1104
|
+
child.stdout?.destroy();
|
|
1105
|
+
} catch {
|
|
1106
|
+
}
|
|
1107
|
+
try {
|
|
1108
|
+
child.stderr?.destroy();
|
|
1109
|
+
} catch {
|
|
1110
|
+
}
|
|
1111
|
+
try {
|
|
1112
|
+
child.unref();
|
|
1113
|
+
} catch {
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
function terminateSshExecution(child, childIdentity, state, settle) {
|
|
1117
|
+
if (state.settled || state.terminationStarted) {
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
1120
|
+
state.terminationStarted = true;
|
|
1121
|
+
const settleUnverified = () => {
|
|
1122
|
+
if (!state.settled) {
|
|
1123
|
+
abandonUnverifiedSshChild(child);
|
|
1124
|
+
settle(createResult(null, state));
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
void (async () => {
|
|
1128
|
+
if (!await canSignalSshChild(child, childIdentity) || state.settled) {
|
|
1129
|
+
settleUnverified();
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
signalChild(child, "SIGTERM");
|
|
1133
|
+
state.forceKillTimer = setTimeout(() => {
|
|
1134
|
+
void (async () => {
|
|
1135
|
+
if (!await canSignalSshChild(child, childIdentity) || state.settled) {
|
|
1136
|
+
settleUnverified();
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
signalChild(child, "SIGKILL");
|
|
1140
|
+
})().catch(settleUnverified);
|
|
1141
|
+
}, 1e3);
|
|
1142
|
+
})().catch(settleUnverified);
|
|
997
1143
|
}
|
|
998
1144
|
function sshAbortError(context) {
|
|
999
1145
|
if (context.deadlineAt !== void 0 && Date.now() >= context.deadlineAt) {
|
|
@@ -1023,16 +1169,16 @@ function createSshSettler(state, options, context, onAbort, resolve, reject) {
|
|
|
1023
1169
|
resolve(state.timedOut ? { ...result, timedOutAfterMs: options.timeoutMs } : result);
|
|
1024
1170
|
};
|
|
1025
1171
|
}
|
|
1026
|
-
function attachSshExecution(child, context, options, resolve, reject) {
|
|
1172
|
+
function attachSshExecution(child, childIdentity, context, options, resolve, reject) {
|
|
1027
1173
|
const state = createSshExecutionState(context, options.maxOutputBytes);
|
|
1028
1174
|
const onAbort = () => {
|
|
1029
1175
|
state.aborted = true;
|
|
1030
|
-
terminateSshExecution(child, state);
|
|
1176
|
+
terminateSshExecution(child, childIdentity, state, settle);
|
|
1031
1177
|
};
|
|
1032
1178
|
const settle = createSshSettler(state, options, context, onAbort, resolve, reject);
|
|
1033
1179
|
state.timeoutTimer = setTimeout(() => {
|
|
1034
1180
|
state.timedOut = true;
|
|
1035
|
-
terminateSshExecution(child, state);
|
|
1181
|
+
terminateSshExecution(child, childIdentity, state, settle);
|
|
1036
1182
|
}, options.timeoutMs);
|
|
1037
1183
|
if (context.signal?.aborted) {
|
|
1038
1184
|
onAbort();
|
|
@@ -1061,16 +1207,17 @@ function runSshOneShot(args, context, options) {
|
|
|
1061
1207
|
return new Promise((resolve, reject) => {
|
|
1062
1208
|
const child = spawn(resolveBin(context), [...args], {
|
|
1063
1209
|
env: buildEnv(context.cfHome),
|
|
1064
|
-
detached:
|
|
1210
|
+
detached: nodeProcess3.platform !== "win32",
|
|
1065
1211
|
stdio: ["ignore", "pipe", "pipe"]
|
|
1066
1212
|
});
|
|
1067
|
-
|
|
1213
|
+
const childIdentity = captureSshChildIdentity(child);
|
|
1214
|
+
attachSshExecution(child, childIdentity, context, options, resolve, reject);
|
|
1068
1215
|
});
|
|
1069
1216
|
}
|
|
1070
1217
|
function signalChild(child, signal) {
|
|
1071
|
-
if (
|
|
1218
|
+
if (nodeProcess3.platform !== "win32" && child.pid !== void 0) {
|
|
1072
1219
|
try {
|
|
1073
|
-
|
|
1220
|
+
nodeProcess3.kill(-child.pid, signal);
|
|
1074
1221
|
return;
|
|
1075
1222
|
} catch {
|
|
1076
1223
|
}
|
|
@@ -1246,7 +1393,7 @@ function spawnSshTunnel(appName, localPort, remotePort, context, target = {}) {
|
|
|
1246
1393
|
const args = buildCfSshArgs(appName, target, ["-N", "-L", tunnelArg]);
|
|
1247
1394
|
const child = spawn(resolveBin(context), [...args], {
|
|
1248
1395
|
env: buildEnv(context.cfHome),
|
|
1249
|
-
detached:
|
|
1396
|
+
detached: nodeProcess3.platform !== "win32",
|
|
1250
1397
|
stdio: ["ignore", "pipe", "pipe"]
|
|
1251
1398
|
});
|
|
1252
1399
|
attachTunnelCapture(child, context);
|
|
@@ -1269,87 +1416,6 @@ var CHILD_SIGTERM_GRACE_MS = 2e3;
|
|
|
1269
1416
|
var CHILD_SIGKILL_GRACE_MS = 1e3;
|
|
1270
1417
|
var PID_TERMINATION_POLL_MS = 100;
|
|
1271
1418
|
|
|
1272
|
-
// src/debug-session/process-identity.ts
|
|
1273
|
-
import { execFile as execFile2 } from "child_process";
|
|
1274
|
-
import { readFile } from "fs/promises";
|
|
1275
|
-
import nodeProcess3 from "process";
|
|
1276
|
-
import { promisify } from "util";
|
|
1277
|
-
var execFileAsync = promisify(execFile2);
|
|
1278
|
-
function errorCode(error) {
|
|
1279
|
-
if (typeof error !== "object" || error === null) {
|
|
1280
|
-
return void 0;
|
|
1281
|
-
}
|
|
1282
|
-
const code = Reflect.get(error, "code");
|
|
1283
|
-
return typeof code === "string" ? code : void 0;
|
|
1284
|
-
}
|
|
1285
|
-
function parseLinuxProcessStartTime(statLine) {
|
|
1286
|
-
const commandEnd = statLine.lastIndexOf(")");
|
|
1287
|
-
if (commandEnd < 0) {
|
|
1288
|
-
return void 0;
|
|
1289
|
-
}
|
|
1290
|
-
const fieldsAfterCommand = statLine.slice(commandEnd + 1).trim().split(/\s+/);
|
|
1291
|
-
const startTime = fieldsAfterCommand[19];
|
|
1292
|
-
return startTime !== void 0 && /^\d+$/.test(startTime) ? startTime : void 0;
|
|
1293
|
-
}
|
|
1294
|
-
function throwIfAborted(signal) {
|
|
1295
|
-
if (signal?.aborted) {
|
|
1296
|
-
throw new CfDebuggerError("ABORTED", "Process identity inspection was aborted.");
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
async function linuxProcessIdentity(pid, signal) {
|
|
1300
|
-
try {
|
|
1301
|
-
const statLine = await readFile(`/proc/${pid.toString()}/stat`, {
|
|
1302
|
-
encoding: "utf8",
|
|
1303
|
-
...signal === void 0 ? {} : { signal }
|
|
1304
|
-
});
|
|
1305
|
-
const startTime = parseLinuxProcessStartTime(statLine);
|
|
1306
|
-
return startTime === void 0 ? void 0 : `linux:${startTime}`;
|
|
1307
|
-
} catch (error) {
|
|
1308
|
-
throwIfAborted(signal);
|
|
1309
|
-
if (errorCode(error) === "ENOENT") {
|
|
1310
|
-
return void 0;
|
|
1311
|
-
}
|
|
1312
|
-
return void 0;
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
async function darwinProcessIdentity(pid, signal) {
|
|
1316
|
-
try {
|
|
1317
|
-
const { stdout } = await execFileAsync("ps", ["-p", pid.toString(), "-o", "lstart="], {
|
|
1318
|
-
...signal === void 0 ? {} : { signal },
|
|
1319
|
-
timeout: 2e3
|
|
1320
|
-
});
|
|
1321
|
-
const startedAt = stdout.trim();
|
|
1322
|
-
return startedAt.length === 0 ? void 0 : `darwin:${startedAt}`;
|
|
1323
|
-
} catch {
|
|
1324
|
-
throwIfAborted(signal);
|
|
1325
|
-
return void 0;
|
|
1326
|
-
}
|
|
1327
|
-
}
|
|
1328
|
-
async function readProcessIdentity(pid, signal) {
|
|
1329
|
-
throwIfAborted(signal);
|
|
1330
|
-
if (!Number.isSafeInteger(pid) || pid <= 0) {
|
|
1331
|
-
return void 0;
|
|
1332
|
-
}
|
|
1333
|
-
if (nodeProcess3.platform === "linux") {
|
|
1334
|
-
return await linuxProcessIdentity(pid, signal);
|
|
1335
|
-
}
|
|
1336
|
-
if (nodeProcess3.platform === "darwin") {
|
|
1337
|
-
return await darwinProcessIdentity(pid, signal);
|
|
1338
|
-
}
|
|
1339
|
-
return void 0;
|
|
1340
|
-
}
|
|
1341
|
-
async function inspectProcessIdentity(pid, expected, signal) {
|
|
1342
|
-
throwIfAborted(signal);
|
|
1343
|
-
if (expected === void 0) {
|
|
1344
|
-
return "match";
|
|
1345
|
-
}
|
|
1346
|
-
const current = await readProcessIdentity(pid, signal);
|
|
1347
|
-
if (current === void 0) {
|
|
1348
|
-
return "unavailable";
|
|
1349
|
-
}
|
|
1350
|
-
return current === expected ? "match" : "mismatch";
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
1419
|
// src/lock.ts
|
|
1354
1420
|
import { randomUUID } from "crypto";
|
|
1355
1421
|
import { chmod, mkdir, open, readFile as readFile2, stat, unlink } from "fs/promises";
|
|
@@ -2962,7 +3028,7 @@ async function tryRemoveOwnedSessionCfHome(sessionId, candidate) {
|
|
|
2962
3028
|
|
|
2963
3029
|
// src/debug-session/lifecycle.ts
|
|
2964
3030
|
var handleLifecycles = /* @__PURE__ */ new WeakMap();
|
|
2965
|
-
function
|
|
3031
|
+
function childIsOpen2(child) {
|
|
2966
3032
|
return child.exitCode === null && child.signalCode === null;
|
|
2967
3033
|
}
|
|
2968
3034
|
function signalExitCode(signal) {
|
|
@@ -3094,12 +3160,12 @@ function createTunnelLifecycle(session, emit) {
|
|
|
3094
3160
|
const verifyBeforeSignal = async (signal) => {
|
|
3095
3161
|
const tunnelChild = child;
|
|
3096
3162
|
const childPid = tunnelChild?.pid;
|
|
3097
|
-
if (tunnelChild === void 0 || childPid === void 0 || !
|
|
3163
|
+
if (tunnelChild === void 0 || childPid === void 0 || !childIsOpen2(tunnelChild)) {
|
|
3098
3164
|
return false;
|
|
3099
3165
|
}
|
|
3100
3166
|
const expectedIdentity = await childIdentity;
|
|
3101
3167
|
if (expectedIdentity !== void 0) {
|
|
3102
|
-
return await inspectProcessIdentity(childPid, expectedIdentity) === "match" &&
|
|
3168
|
+
return await inspectProcessIdentity(childPid, expectedIdentity) === "match" && childIsOpen2(tunnelChild);
|
|
3103
3169
|
}
|
|
3104
3170
|
if (signal === "SIGKILL") {
|
|
3105
3171
|
return await expectedTunnelStillOwned(session, tunnelChild) === true;
|
|
@@ -3126,7 +3192,7 @@ function createTunnelLifecycle(session, emit) {
|
|
|
3126
3192
|
return {
|
|
3127
3193
|
exitPromise,
|
|
3128
3194
|
assertRunning: () => {
|
|
3129
|
-
if (child === void 0 || !
|
|
3195
|
+
if (child === void 0 || !childIsOpen2(child) || childFailed) {
|
|
3130
3196
|
throw new CfDebuggerError(
|
|
3131
3197
|
"TUNNEL_NOT_READY",
|
|
3132
3198
|
`SSH tunnel for session ${session.sessionId} exited before readiness could be committed.`,
|
|
@@ -4731,4 +4797,4 @@ export {
|
|
|
4731
4797
|
listSessions,
|
|
4732
4798
|
getSession
|
|
4733
4799
|
};
|
|
4734
|
-
//# sourceMappingURL=chunk-
|
|
4800
|
+
//# sourceMappingURL=chunk-AKQR4Y74.js.map
|