@coana-tech/cli 14.12.159 → 14.12.160

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/cli.mjs CHANGED
@@ -205220,55 +205220,34 @@ var Spinner = class _Spinner {
205220
205220
 
205221
205221
  // ../utils/src/telemetry/telemetry-collector.ts
205222
205222
  import { execFile } from "child_process";
205223
- import { platform } from "os";
205223
+ import { platform } from "process";
205224
205224
  import { promisify } from "util";
205225
205225
  var execFileAsync = promisify(execFile);
205226
- var TelemetryCollector = class {
205227
- /**
205228
- * Collect memory metrics for a child process by PID.
205229
- * Uses OS-specific commands to query memory usage.
205230
- *
205231
- * @param pid - The process ID to query
205232
- * @returns TelemetryMetrics or undefined if the process doesn't exist or query fails
205233
- */
205234
- async collectChildProcessMetrics(pid) {
205235
- if (!Number.isInteger(pid) || pid <= 0) {
205236
- return void 0;
205237
- }
205238
- try {
205239
- const currentPlatform = platform();
205240
- if (currentPlatform === "darwin" || currentPlatform === "linux") {
205241
- return await this.collectUnixProcessMetrics(pid);
205242
- }
205243
- return void 0;
205244
- } catch {
205245
- return void 0;
205246
- }
205226
+ var TelemetryCollector = class _TelemetryCollector {
205227
+ constructor(pid) {
205228
+ this.pid = pid;
205229
+ }
205230
+ static create(pid) {
205231
+ if (!Number.isInteger(pid) || pid <= 0 || !["darwin", "linux"].includes(platform)) return void 0;
205232
+ return new _TelemetryCollector(pid);
205247
205233
  }
205248
205234
  /**
205249
205235
  * Collect metrics for a Unix-like system (macOS, Linux) using ps command.
205250
205236
  */
205251
- async collectUnixProcessMetrics(pid) {
205237
+ async collectChildProcessMetrics() {
205252
205238
  try {
205253
- const { stdout } = await execFileAsync("ps", ["-o", "rss=,pcpu=", "-p", String(pid)], {
205239
+ const { stdout } = await execFileAsync("ps", ["-o", "rss=,pcpu=", "-p", String(this.pid)], {
205254
205240
  timeout: 5e3
205255
205241
  });
205256
- const trimmed = stdout.trim();
205257
- if (!trimmed) {
205258
- return void 0;
205259
- }
205260
- const parts = trimmed.split(/\s+/);
205261
- if (parts.length < 2) {
205262
- return void 0;
205263
- }
205242
+ const parts = stdout.trim().split(/\s+/);
205243
+ if (parts.length < 2) return void 0;
205264
205244
  const rssKb = parseInt(parts[0], 10);
205265
205245
  const cpuPercent = parseFloat(parts[1]);
205266
- if (isNaN(rssKb) || isNaN(cpuPercent)) {
205267
- return void 0;
205268
- }
205269
- const rssBytes = rssKb * 1024;
205246
+ if (isNaN(rssKb) || isNaN(cpuPercent)) return void 0;
205270
205247
  return {
205271
- rss: rssBytes,
205248
+ rss: rssKb * 1024,
205249
+ // Convert KB to bytes
205250
+ // Note: cpuPercent can exceed 100% on multi-core systems (e.g., 250% = 2.5 cores used)
205272
205251
  cpuPercent
205273
205252
  };
205274
205253
  } catch {
@@ -205376,14 +205355,14 @@ function startHeartbeat(options) {
205376
205355
  return () => clearInterval(timer);
205377
205356
  }
205378
205357
  var DEFAULT_TELEMETRY_INTERVAL_MS = 5e3;
205379
- function startTelemetry(pid, handler) {
205380
- const collector = new TelemetryCollector();
205358
+ function startTelemetry(subprocess, handler) {
205359
+ const collector = TelemetryCollector.create(subprocess.pid);
205360
+ if (!collector) return;
205361
+ handler.onInit?.(subprocess);
205381
205362
  const intervalMs = handler.intervalMs ?? DEFAULT_TELEMETRY_INTERVAL_MS;
205382
205363
  const collectAndReport = async () => {
205383
- const metrics = await collector.collectChildProcessMetrics(pid);
205384
- if (metrics) {
205385
- handler.onTelemetry(metrics);
205386
- }
205364
+ const metrics = await collector.collectChildProcessMetrics();
205365
+ if (metrics) handler.onTelemetry(metrics);
205387
205366
  };
205388
205367
  collectAndReport().catch((err) => {
205389
205368
  logger.debug("Initial telemetry collection failed:", err);
@@ -205395,6 +205374,48 @@ function startTelemetry(pid, handler) {
205395
205374
  timer.unref?.();
205396
205375
  return () => clearInterval(timer);
205397
205376
  }
205377
+ function wrapWithMemoryLimit(cmd, options) {
205378
+ const memoryLimitKiB = Math.ceil(options.memoryLimitInMB * 1024);
205379
+ if (memoryLimitKiB <= 0)
205380
+ throw new Error(`memoryLimitInMB * 1024 must be a positive number, got: ${memoryLimitKiB}`);
205381
+ switch (process.platform) {
205382
+ case "darwin":
205383
+ {
205384
+ const prevHandler = options.telemetryHandler;
205385
+ let subprocess;
205386
+ options.telemetryHandler = {
205387
+ intervalMs: prevHandler?.intervalMs ?? 2e3,
205388
+ onInit: (sp) => {
205389
+ subprocess = sp;
205390
+ prevHandler?.onInit?.(sp);
205391
+ },
205392
+ onTelemetry(metrics) {
205393
+ if (subprocess?.exitCode === null && metrics.rss >= memoryLimitKiB * 1024) {
205394
+ logger.debug(
205395
+ `Memory limit of ${options.memoryLimitInMB} MiB exceeded (RSS: ${(metrics.rss / 1024 / 1024).toFixed(
205396
+ 2
205397
+ )} MiB). Terminating process.`
205398
+ );
205399
+ subprocess.kill(options.killSignal ?? "SIGTERM");
205400
+ subprocess = void 0;
205401
+ }
205402
+ prevHandler?.onTelemetry(metrics);
205403
+ }
205404
+ };
205405
+ }
205406
+ break;
205407
+ case "linux":
205408
+ return [
205409
+ "sh",
205410
+ ...typeof cmd === "string" ? ["-c", `ulimit -v ${memoryLimitKiB} && eval "$1"`, "_", cmd] : ["-c", `ulimit -v ${memoryLimitKiB} && exec "$@"`, "_", ...cmd]
205411
+ ];
205412
+ default:
205413
+ logger.debug(
205414
+ `Memory limit enforcement is not supported on platform: ${process.platform}. Ignoring memory limit option.`
205415
+ );
205416
+ }
205417
+ return cmd;
205418
+ }
205398
205419
  async function execNeverFail(cmd, dir, options) {
205399
205420
  const stopHeartbeat = options?.heartbeat ? startHeartbeat(options.heartbeat) : void 0;
205400
205421
  let stopTelemetry;
@@ -205404,6 +205425,8 @@ async function execNeverFail(cmd, dir, options) {
205404
205425
  analyzerTelemetryServer = new AnalyzerTelemetryServer(options.analyzerTelemetryHandler);
205405
205426
  analyzerTelemetryFilePath = await analyzerTelemetryServer.start();
205406
205427
  }
205428
+ if (options?.memoryLimitInMB !== void 0)
205429
+ cmd = wrapWithMemoryLimit(cmd, options);
205407
205430
  try {
205408
205431
  return await new Promise((resolve45) => {
205409
205432
  let args2;
@@ -205418,9 +205441,8 @@ async function execNeverFail(cmd, dir, options) {
205418
205441
  resolve45({ error, stdout, stderr });
205419
205442
  }
205420
205443
  );
205421
- if (options?.telemetryHandler && childProcess.pid) {
205422
- stopTelemetry = startTelemetry(childProcess.pid, options.telemetryHandler);
205423
- }
205444
+ if (options?.telemetryHandler && childProcess.pid)
205445
+ stopTelemetry = startTelemetry(childProcess, options.telemetryHandler);
205424
205446
  if (options?.pipe) {
205425
205447
  childProcess.stdout?.on("data", (data2) => {
205426
205448
  Spinner.instance().suspend(() => {
@@ -224295,55 +224317,38 @@ var Spinner2 = class _Spinner {
224295
224317
 
224296
224318
  // ../utils/dist/telemetry/telemetry-collector.js
224297
224319
  import { execFile as execFile3 } from "child_process";
224298
- import { platform as platform7 } from "os";
224320
+ import { platform as platform7 } from "process";
224299
224321
  import { promisify as promisify2 } from "util";
224300
224322
  var execFileAsync2 = promisify2(execFile3);
224301
- var TelemetryCollector2 = class {
224302
- /**
224303
- * Collect memory metrics for a child process by PID.
224304
- * Uses OS-specific commands to query memory usage.
224305
- *
224306
- * @param pid - The process ID to query
224307
- * @returns TelemetryMetrics or undefined if the process doesn't exist or query fails
224308
- */
224309
- async collectChildProcessMetrics(pid) {
224310
- if (!Number.isInteger(pid) || pid <= 0) {
224311
- return void 0;
224312
- }
224313
- try {
224314
- const currentPlatform = platform7();
224315
- if (currentPlatform === "darwin" || currentPlatform === "linux") {
224316
- return await this.collectUnixProcessMetrics(pid);
224317
- }
224318
- return void 0;
224319
- } catch {
224323
+ var TelemetryCollector2 = class _TelemetryCollector {
224324
+ pid;
224325
+ constructor(pid) {
224326
+ this.pid = pid;
224327
+ }
224328
+ static create(pid) {
224329
+ if (!Number.isInteger(pid) || pid <= 0 || !["darwin", "linux"].includes(platform7))
224320
224330
  return void 0;
224321
- }
224331
+ return new _TelemetryCollector(pid);
224322
224332
  }
224323
224333
  /**
224324
224334
  * Collect metrics for a Unix-like system (macOS, Linux) using ps command.
224325
224335
  */
224326
- async collectUnixProcessMetrics(pid) {
224336
+ async collectChildProcessMetrics() {
224327
224337
  try {
224328
- const { stdout } = await execFileAsync2("ps", ["-o", "rss=,pcpu=", "-p", String(pid)], {
224338
+ const { stdout } = await execFileAsync2("ps", ["-o", "rss=,pcpu=", "-p", String(this.pid)], {
224329
224339
  timeout: 5e3
224330
224340
  });
224331
- const trimmed = stdout.trim();
224332
- if (!trimmed) {
224333
- return void 0;
224334
- }
224335
- const parts = trimmed.split(/\s+/);
224336
- if (parts.length < 2) {
224341
+ const parts = stdout.trim().split(/\s+/);
224342
+ if (parts.length < 2)
224337
224343
  return void 0;
224338
- }
224339
224344
  const rssKb = parseInt(parts[0], 10);
224340
224345
  const cpuPercent = parseFloat(parts[1]);
224341
- if (isNaN(rssKb) || isNaN(cpuPercent)) {
224346
+ if (isNaN(rssKb) || isNaN(cpuPercent))
224342
224347
  return void 0;
224343
- }
224344
- const rssBytes = rssKb * 1024;
224345
224348
  return {
224346
- rss: rssBytes,
224349
+ rss: rssKb * 1024,
224350
+ // Convert KB to bytes
224351
+ // Note: cpuPercent can exceed 100% on multi-core systems (e.g., 250% = 2.5 cores used)
224347
224352
  cpuPercent
224348
224353
  };
224349
224354
  } catch {
@@ -224452,14 +224457,16 @@ function startHeartbeat2(options) {
224452
224457
  return () => clearInterval(timer);
224453
224458
  }
224454
224459
  var DEFAULT_TELEMETRY_INTERVAL_MS2 = 5e3;
224455
- function startTelemetry2(pid, handler) {
224456
- const collector = new TelemetryCollector2();
224460
+ function startTelemetry2(subprocess, handler) {
224461
+ const collector = TelemetryCollector2.create(subprocess.pid);
224462
+ if (!collector)
224463
+ return;
224464
+ handler.onInit?.(subprocess);
224457
224465
  const intervalMs = handler.intervalMs ?? DEFAULT_TELEMETRY_INTERVAL_MS2;
224458
224466
  const collectAndReport = async () => {
224459
- const metrics = await collector.collectChildProcessMetrics(pid);
224460
- if (metrics) {
224467
+ const metrics = await collector.collectChildProcessMetrics();
224468
+ if (metrics)
224461
224469
  handler.onTelemetry(metrics);
224462
- }
224463
224470
  };
224464
224471
  collectAndReport().catch((err) => {
224465
224472
  logger.debug("Initial telemetry collection failed:", err);
@@ -224471,6 +224478,42 @@ function startTelemetry2(pid, handler) {
224471
224478
  timer.unref?.();
224472
224479
  return () => clearInterval(timer);
224473
224480
  }
224481
+ function wrapWithMemoryLimit2(cmd, options) {
224482
+ const memoryLimitKiB = Math.ceil(options.memoryLimitInMB * 1024);
224483
+ if (memoryLimitKiB <= 0)
224484
+ throw new Error(`memoryLimitInMB * 1024 must be a positive number, got: ${memoryLimitKiB}`);
224485
+ switch (process.platform) {
224486
+ case "darwin":
224487
+ {
224488
+ const prevHandler = options.telemetryHandler;
224489
+ let subprocess;
224490
+ options.telemetryHandler = {
224491
+ intervalMs: prevHandler?.intervalMs ?? 2e3,
224492
+ onInit: (sp) => {
224493
+ subprocess = sp;
224494
+ prevHandler?.onInit?.(sp);
224495
+ },
224496
+ onTelemetry(metrics) {
224497
+ if (subprocess?.exitCode === null && metrics.rss >= memoryLimitKiB * 1024) {
224498
+ logger.debug(`Memory limit of ${options.memoryLimitInMB} MiB exceeded (RSS: ${(metrics.rss / 1024 / 1024).toFixed(2)} MiB). Terminating process.`);
224499
+ subprocess.kill(options.killSignal ?? "SIGTERM");
224500
+ subprocess = void 0;
224501
+ }
224502
+ prevHandler?.onTelemetry(metrics);
224503
+ }
224504
+ };
224505
+ }
224506
+ break;
224507
+ case "linux":
224508
+ return [
224509
+ "sh",
224510
+ ...typeof cmd === "string" ? ["-c", `ulimit -v ${memoryLimitKiB} && eval "$1"`, "_", cmd] : ["-c", `ulimit -v ${memoryLimitKiB} && exec "$@"`, "_", ...cmd]
224511
+ ];
224512
+ default:
224513
+ logger.debug(`Memory limit enforcement is not supported on platform: ${process.platform}. Ignoring memory limit option.`);
224514
+ }
224515
+ return cmd;
224516
+ }
224474
224517
  async function execNeverFail3(cmd, dir, options) {
224475
224518
  const stopHeartbeat = options?.heartbeat ? startHeartbeat2(options.heartbeat) : void 0;
224476
224519
  let stopTelemetry;
@@ -224480,6 +224523,8 @@ async function execNeverFail3(cmd, dir, options) {
224480
224523
  analyzerTelemetryServer = new AnalyzerTelemetryServer2(options.analyzerTelemetryHandler);
224481
224524
  analyzerTelemetryFilePath = await analyzerTelemetryServer.start();
224482
224525
  }
224526
+ if (options?.memoryLimitInMB !== void 0)
224527
+ cmd = wrapWithMemoryLimit2(cmd, options);
224483
224528
  try {
224484
224529
  return await new Promise((resolve45) => {
224485
224530
  let args2;
@@ -224490,9 +224535,8 @@ async function execNeverFail3(cmd, dir, options) {
224490
224535
  const childProcess = execFile4(cmd, args2, { ...options, env, cwd: dir, maxBuffer: 1024 * 1024 * 1024, shell: args2 === void 0, timeout }, (error, stdout, stderr) => {
224491
224536
  resolve45({ error, stdout, stderr });
224492
224537
  });
224493
- if (options?.telemetryHandler && childProcess.pid) {
224494
- stopTelemetry = startTelemetry2(childProcess.pid, options.telemetryHandler);
224495
- }
224538
+ if (options?.telemetryHandler && childProcess.pid)
224539
+ stopTelemetry = startTelemetry2(childProcess, options.telemetryHandler);
224496
224540
  if (options?.pipe) {
224497
224541
  childProcess.stdout?.on("data", (data2) => {
224498
224542
  Spinner2.instance().suspend(() => {
@@ -250903,7 +250947,7 @@ async function onlineScan(dependencyTree, apiKey, timeout) {
250903
250947
  }
250904
250948
 
250905
250949
  // dist/version.js
250906
- var version3 = "14.12.159";
250950
+ var version3 = "14.12.160";
250907
250951
 
250908
250952
  // dist/cli-core.js
250909
250953
  var { mapValues, omit, partition, pickBy: pickBy2 } = import_lodash15.default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coana-tech/cli",
3
- "version": "14.12.159",
3
+ "version": "14.12.160",
4
4
  "description": "Coana CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -80900,55 +80900,34 @@ import { execFile as execFile2 } from "child_process";
80900
80900
 
80901
80901
  // ../utils/src/telemetry/telemetry-collector.ts
80902
80902
  import { execFile } from "child_process";
80903
- import { platform } from "os";
80903
+ import { platform } from "process";
80904
80904
  import { promisify } from "util";
80905
80905
  var execFileAsync = promisify(execFile);
80906
- var TelemetryCollector = class {
80907
- /**
80908
- * Collect memory metrics for a child process by PID.
80909
- * Uses OS-specific commands to query memory usage.
80910
- *
80911
- * @param pid - The process ID to query
80912
- * @returns TelemetryMetrics or undefined if the process doesn't exist or query fails
80913
- */
80914
- async collectChildProcessMetrics(pid) {
80915
- if (!Number.isInteger(pid) || pid <= 0) {
80916
- return void 0;
80917
- }
80918
- try {
80919
- const currentPlatform = platform();
80920
- if (currentPlatform === "darwin" || currentPlatform === "linux") {
80921
- return await this.collectUnixProcessMetrics(pid);
80922
- }
80923
- return void 0;
80924
- } catch {
80925
- return void 0;
80926
- }
80906
+ var TelemetryCollector = class _TelemetryCollector {
80907
+ constructor(pid) {
80908
+ this.pid = pid;
80909
+ }
80910
+ static create(pid) {
80911
+ if (!Number.isInteger(pid) || pid <= 0 || !["darwin", "linux"].includes(platform)) return void 0;
80912
+ return new _TelemetryCollector(pid);
80927
80913
  }
80928
80914
  /**
80929
80915
  * Collect metrics for a Unix-like system (macOS, Linux) using ps command.
80930
80916
  */
80931
- async collectUnixProcessMetrics(pid) {
80917
+ async collectChildProcessMetrics() {
80932
80918
  try {
80933
- const { stdout } = await execFileAsync("ps", ["-o", "rss=,pcpu=", "-p", String(pid)], {
80919
+ const { stdout } = await execFileAsync("ps", ["-o", "rss=,pcpu=", "-p", String(this.pid)], {
80934
80920
  timeout: 5e3
80935
80921
  });
80936
- const trimmed = stdout.trim();
80937
- if (!trimmed) {
80938
- return void 0;
80939
- }
80940
- const parts = trimmed.split(/\s+/);
80941
- if (parts.length < 2) {
80942
- return void 0;
80943
- }
80922
+ const parts = stdout.trim().split(/\s+/);
80923
+ if (parts.length < 2) return void 0;
80944
80924
  const rssKb = parseInt(parts[0], 10);
80945
80925
  const cpuPercent = parseFloat(parts[1]);
80946
- if (isNaN(rssKb) || isNaN(cpuPercent)) {
80947
- return void 0;
80948
- }
80949
- const rssBytes = rssKb * 1024;
80926
+ if (isNaN(rssKb) || isNaN(cpuPercent)) return void 0;
80950
80927
  return {
80951
- rss: rssBytes,
80928
+ rss: rssKb * 1024,
80929
+ // Convert KB to bytes
80930
+ // Note: cpuPercent can exceed 100% on multi-core systems (e.g., 250% = 2.5 cores used)
80952
80931
  cpuPercent
80953
80932
  };
80954
80933
  } catch {
@@ -81053,14 +81032,14 @@ function startHeartbeat(options) {
81053
81032
  return () => clearInterval(timer);
81054
81033
  }
81055
81034
  var DEFAULT_TELEMETRY_INTERVAL_MS = 5e3;
81056
- function startTelemetry(pid, handler) {
81057
- const collector = new TelemetryCollector();
81035
+ function startTelemetry(subprocess, handler) {
81036
+ const collector = TelemetryCollector.create(subprocess.pid);
81037
+ if (!collector) return;
81038
+ handler.onInit?.(subprocess);
81058
81039
  const intervalMs = handler.intervalMs ?? DEFAULT_TELEMETRY_INTERVAL_MS;
81059
81040
  const collectAndReport = async () => {
81060
- const metrics = await collector.collectChildProcessMetrics(pid);
81061
- if (metrics) {
81062
- handler.onTelemetry(metrics);
81063
- }
81041
+ const metrics = await collector.collectChildProcessMetrics();
81042
+ if (metrics) handler.onTelemetry(metrics);
81064
81043
  };
81065
81044
  collectAndReport().catch((err) => {
81066
81045
  logger.debug("Initial telemetry collection failed:", err);
@@ -81072,6 +81051,48 @@ function startTelemetry(pid, handler) {
81072
81051
  timer.unref?.();
81073
81052
  return () => clearInterval(timer);
81074
81053
  }
81054
+ function wrapWithMemoryLimit(cmd, options) {
81055
+ const memoryLimitKiB = Math.ceil(options.memoryLimitInMB * 1024);
81056
+ if (memoryLimitKiB <= 0)
81057
+ throw new Error(`memoryLimitInMB * 1024 must be a positive number, got: ${memoryLimitKiB}`);
81058
+ switch (process.platform) {
81059
+ case "darwin":
81060
+ {
81061
+ const prevHandler = options.telemetryHandler;
81062
+ let subprocess;
81063
+ options.telemetryHandler = {
81064
+ intervalMs: prevHandler?.intervalMs ?? 2e3,
81065
+ onInit: (sp) => {
81066
+ subprocess = sp;
81067
+ prevHandler?.onInit?.(sp);
81068
+ },
81069
+ onTelemetry(metrics) {
81070
+ if (subprocess?.exitCode === null && metrics.rss >= memoryLimitKiB * 1024) {
81071
+ logger.debug(
81072
+ `Memory limit of ${options.memoryLimitInMB} MiB exceeded (RSS: ${(metrics.rss / 1024 / 1024).toFixed(
81073
+ 2
81074
+ )} MiB). Terminating process.`
81075
+ );
81076
+ subprocess.kill(options.killSignal ?? "SIGTERM");
81077
+ subprocess = void 0;
81078
+ }
81079
+ prevHandler?.onTelemetry(metrics);
81080
+ }
81081
+ };
81082
+ }
81083
+ break;
81084
+ case "linux":
81085
+ return [
81086
+ "sh",
81087
+ ...typeof cmd === "string" ? ["-c", `ulimit -v ${memoryLimitKiB} && eval "$1"`, "_", cmd] : ["-c", `ulimit -v ${memoryLimitKiB} && exec "$@"`, "_", ...cmd]
81088
+ ];
81089
+ default:
81090
+ logger.debug(
81091
+ `Memory limit enforcement is not supported on platform: ${process.platform}. Ignoring memory limit option.`
81092
+ );
81093
+ }
81094
+ return cmd;
81095
+ }
81075
81096
  async function execNeverFail(cmd, dir, options) {
81076
81097
  const stopHeartbeat = options?.heartbeat ? startHeartbeat(options.heartbeat) : void 0;
81077
81098
  let stopTelemetry;
@@ -81081,6 +81102,8 @@ async function execNeverFail(cmd, dir, options) {
81081
81102
  analyzerTelemetryServer = new AnalyzerTelemetryServer(options.analyzerTelemetryHandler);
81082
81103
  analyzerTelemetryFilePath = await analyzerTelemetryServer.start();
81083
81104
  }
81105
+ if (options?.memoryLimitInMB !== void 0)
81106
+ cmd = wrapWithMemoryLimit(cmd, options);
81084
81107
  try {
81085
81108
  return await new Promise((resolve23) => {
81086
81109
  let args;
@@ -81095,9 +81118,8 @@ async function execNeverFail(cmd, dir, options) {
81095
81118
  resolve23({ error, stdout, stderr });
81096
81119
  }
81097
81120
  );
81098
- if (options?.telemetryHandler && childProcess.pid) {
81099
- stopTelemetry = startTelemetry(childProcess.pid, options.telemetryHandler);
81100
- }
81121
+ if (options?.telemetryHandler && childProcess.pid)
81122
+ stopTelemetry = startTelemetry(childProcess, options.telemetryHandler);
81101
81123
  if (options?.pipe) {
81102
81124
  childProcess.stdout?.on("data", (data2) => {
81103
81125
  Spinner.instance().suspend(() => {
@@ -111156,7 +111178,8 @@ var GoCodeAwareVulnerabilityScanner = class {
111156
111178
  ${this.projectDir} ${vulnAccPaths}`, void 0, {
111157
111179
  timeout: timeoutInSeconds * 1e3,
111158
111180
  killSignal: "SIGKILL",
111159
- env: memoryLimitInMB ? { ...process.env, GOMEMLIMIT: `${memoryLimitInMB}MiB` } : void 0,
111181
+ memoryLimitInMB,
111182
+ env: memoryLimitInMB ? { ...process.env, GOMEMLIMIT: `${Math.max(Math.ceil(memoryLimitInMB - 256), 0)}MiB` } : void 0,
111160
111183
  heartbeat: HEARTBEATS.go,
111161
111184
  telemetryHandler,
111162
111185
  analyzerTelemetryHandler
@@ -112033,16 +112056,6 @@ function getVersion(analysisName) {
112033
112056
 
112034
112057
  // dist/whole-program-code-aware-vulnerability-scanner/python/python-code-aware-vulnerability-scanner.js
112035
112058
  var { omit, once: once3, pick, sortedUniq, uniqBy } = import_lodash14.default;
112036
- var memlimitWrapper = `import sys, runpy, resource
112037
- if memory_limit := int(sys.argv.pop(1)):
112038
- try:
112039
- resource.setrlimit(resource.RLIMIT_AS, (memory_limit * 1024 ** 2, resource.RLIM_INFINITY))
112040
- except ValueError as e:
112041
- # If we're running on PyPy, memory is bounded by PYPY_GC_MAX env var
112042
- if sys.implementation.name != "pypy":
112043
- print("ERROR: Failed to set memory limit", e, file=sys.stderr)
112044
- runpy.run_module("mambalade", alter_sys=True)
112045
- `;
112046
112059
  var PythonCodeAwareVulnerabilityScanner = class {
112047
112060
  state;
112048
112061
  projectDir;
@@ -112071,10 +112084,10 @@ var PythonCodeAwareVulnerabilityScanner = class {
112071
112084
  this.mambaladeVenvPath ??= await setupMambalade();
112072
112085
  logger.info("Started instantiating Python code-aware analysis");
112073
112086
  logger.debug(`Trying to find files to analyze from projectDir: ${this.projectDir}`);
112074
- const { rootWorkingDir, reachabilityAnalysisOptions } = this.state;
112087
+ const { rootWorkingDir, reachabilityAnalysisOptions: { excludeDirs, memoryLimitInMB } } = this.state;
112075
112088
  let filesToAnalyze = await findFilesToAnalyze(this.projectDir);
112076
- if (reachabilityAnalysisOptions.excludeDirs)
112077
- filesToAnalyze = excludeFiles(rootWorkingDir, this.projectDir, filesToAnalyze, reachabilityAnalysisOptions.excludeDirs);
112089
+ if (excludeDirs)
112090
+ filesToAnalyze = excludeFiles(rootWorkingDir, this.projectDir, filesToAnalyze, excludeDirs);
112078
112091
  logger.info(`Found ${filesToAnalyze.length} files to analyze`);
112079
112092
  logger.debug("%O", filesToAnalyze);
112080
112093
  if (filesToAnalyze.length === 0)
@@ -112097,7 +112110,7 @@ var PythonCodeAwareVulnerabilityScanner = class {
112097
112110
  const reachedPackagesOutputFile = join17(tmpDir, "reached-packages.json");
112098
112111
  const pythonExecutable = join17(this.mambaladeVenvPath, "bin", "python");
112099
112112
  const mambaladeArgs = cmdt`\
112100
- ${pythonExecutable} - ${reachabilityAnalysisOptions.memoryLimitInMB ?? 0}
112113
+ ${pythonExecutable} -m mambalade
112101
112114
  --vulnerabilities ${vulnAccPaths}
112102
112115
  --unsound-class-decorators --context-sensitivity=heuristics
112103
112116
  --path ${this.virtualEnvInfo.virtualEnvPathToSitePackages}
@@ -112111,10 +112124,11 @@ var PythonCodeAwareVulnerabilityScanner = class {
112111
112124
  ${filesToAnalyze}`;
112112
112125
  try {
112113
112126
  const { stderr } = await exec2(mambaladeArgs, this.projectDir, {
112114
- stdin: memlimitWrapper,
112115
112127
  env: {
112116
112128
  ...process.env,
112117
- PYPY_GC_MAX: `${reachabilityAnalysisOptions.memoryLimitInMB ?? 0}MB`
112129
+ // Set PyPy-specific the memory limit 256MiB lower than the overall memory limit
112130
+ // to (hopefully) handle OOM gracefully within mambalade (instead of the OS killing the process).
112131
+ PYPY_GC_MAX: `${memoryLimitInMB ? Math.max(Math.ceil(memoryLimitInMB - 256), 1) : 0}MB`
112118
112132
  },
112119
112133
  // Forcefully kill the process if the internal timeout mechanism fails.
112120
112134
  // Use SIGKILL to ensure termination even if the process is unresponsive.
@@ -112122,7 +112136,8 @@ var PythonCodeAwareVulnerabilityScanner = class {
112122
112136
  killSignal: "SIGKILL",
112123
112137
  heartbeat: HEARTBEATS.python,
112124
112138
  telemetryHandler,
112125
- analyzerTelemetryHandler
112139
+ analyzerTelemetryHandler,
112140
+ memoryLimitInMB
112126
112141
  });
112127
112142
  logger.debug("Done running mambalade");
112128
112143
  const errors = stderr.split("\n").filter((line) => line.startsWith("ERROR:") && !/^ERROR: Excluded distribution/.test(line));