@dotenvx/dotenvx
Advanced tools
+7
-1
@@ -5,4 +5,10 @@ # Changelog | ||
| [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.61.3...main) | ||
| [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.61.4...main) | ||
| ## [1.61.4](https://github.com/dotenvx/dotenvx/compare/v1.61.3...v1.61.4) (2026-04-21) | ||
| ### Changed | ||
| * Respect SIGINT handler completion ([#798](https://github.com/dotenvx/dotenvx/pull/798)) | ||
| ## [1.61.3](https://github.com/dotenvx/dotenvx/compare/v1.61.2...v1.61.3) (2026-04-21) | ||
@@ -9,0 +15,0 @@ |
+1
-1
| { | ||
| "version": "1.61.3", | ||
| "version": "1.61.4", | ||
| "name": "@dotenvx/dotenvx", | ||
@@ -4,0 +4,0 @@ "description": "secrets for agents–from the creator of `dotenv`", |
@@ -8,2 +8,4 @@ const path = require('path') | ||
| async function executeCommand (commandArgs, env) { | ||
| const FORWARD_SIGNAL_GRACE_MS = 1000 | ||
| const FORCE_KILL_GRACE_MS = 1000 | ||
| const signals = [ | ||
@@ -18,3 +20,48 @@ 'SIGHUP', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT', | ||
| let signalSent | ||
| let sigintCount = 0 | ||
| const signalForwardTimers = new Set() | ||
| const otherSignalHandlers = new Map() | ||
| const isInteractiveTTY = Boolean(process.stdin && process.stdin.isTTY) | ||
| const isChildRunning = () => { | ||
| return child && child.exitCode === null && child.signalCode === null | ||
| } | ||
| const queueSignalForward = (signal) => { | ||
| logger.debug(`queueing ${signal} to command process after ${FORWARD_SIGNAL_GRACE_MS}ms`) | ||
| const timer = setTimeout(() => { | ||
| signalForwardTimers.delete(timer) | ||
| if (!isChildRunning()) { | ||
| logger.debug(`skipping ${signal} forward because command process is already exiting`) | ||
| return | ||
| } | ||
| logger.debug(`sending ${signal} to command process`) | ||
| signalSent = signal | ||
| child.kill(signal) | ||
| }, FORWARD_SIGNAL_GRACE_MS) | ||
| if (typeof timer.unref === 'function') timer.unref() | ||
| signalForwardTimers.add(timer) | ||
| } | ||
| const queueForceKill = () => { | ||
| logger.debug(`queueing SIGKILL to command process after ${FORCE_KILL_GRACE_MS}ms`) | ||
| const timer = setTimeout(() => { | ||
| signalForwardTimers.delete(timer) | ||
| if (!isChildRunning()) { | ||
| logger.debug('skipping SIGKILL because command process is already exiting') | ||
| return | ||
| } | ||
| logger.debug('sending SIGKILL to command process') | ||
| child.kill('SIGKILL') | ||
| }, FORCE_KILL_GRACE_MS) | ||
| if (typeof timer.unref === 'function') timer.unref() | ||
| signalForwardTimers.add(timer) | ||
| } | ||
| /* c8 ignore start */ | ||
@@ -26,9 +73,21 @@ const sigintHandler = () => { | ||
| if (child) { | ||
| logger.debug('sending SIGINT to command process') | ||
| signalSent = 'SIGINT' | ||
| child.kill('SIGINT') // Send SIGINT to the command process | ||
| } else { | ||
| logger.debug('no command process to send SIGINT to') | ||
| if (!child) return | ||
| sigintCount += 1 | ||
| if (isInteractiveTTY) { | ||
| if (sigintCount === 1) { | ||
| logger.debug('TTY mode: not forwarding first SIGINT to command process') | ||
| return | ||
| } | ||
| logger.debug('TTY mode: forwarding SIGTERM on second SIGINT to command process') | ||
| signalSent = 'SIGTERM' | ||
| child.kill('SIGTERM') | ||
| if (sigintCount === 2) queueForceKill() | ||
| return | ||
| } | ||
| queueSignalForward('SIGINT') | ||
| } | ||
@@ -41,9 +100,5 @@ | ||
| if (child) { | ||
| logger.debug('sending SIGTERM to command process') | ||
| signalSent = 'SIGTERM' | ||
| child.kill('SIGTERM') // Send SIGTERM to the command process | ||
| } else { | ||
| logger.debug('no command process to send SIGTERM to') | ||
| } | ||
| if (!child) return | ||
| queueSignalForward('SIGTERM') | ||
| } | ||
@@ -53,3 +108,3 @@ | ||
| logger.debug(`received ${signal}`) | ||
| child.kill(signal) | ||
| if (child) child.kill(signal) | ||
| } | ||
@@ -92,3 +147,5 @@ /* c8 ignore stop */ | ||
| signals.forEach(signal => { | ||
| process.on(signal, () => handleOtherSignal(signal)) | ||
| const handler = () => handleOtherSignal(signal) | ||
| otherSignalHandlers.set(signal, handler) | ||
| process.on(signal, handler) | ||
| }) | ||
@@ -116,2 +173,5 @@ | ||
| } finally { | ||
| signalForwardTimers.forEach(timer => clearTimeout(timer)) | ||
| signalForwardTimers.clear() | ||
| // Clean up: Remove the SIGINT handler | ||
@@ -121,2 +181,6 @@ process.removeListener('SIGINT', sigintHandler) | ||
| process.removeListener('SIGTERM', sigtermHandler) | ||
| otherSignalHandlers.forEach((handler, signal) => { | ||
| process.removeListener(signal, handler) | ||
| }) | ||
| } | ||
@@ -123,0 +187,0 @@ } |
Sorry, the diff of this file is too big to display
Potential vulnerability
Supply chain riskInitial human review suggests the presence of a vulnerability in this package. It is pending further analysis and confirmation.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 10 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 3 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Potential vulnerability
Supply chain riskInitial human review suggests the presence of a vulnerability in this package. It is pending further analysis and confirmation.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 10 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 3 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
319840
0.75%5205
0.91%2738
0.22%