Preserve child signal failures in the npm wrapper (#57352)

## Why

The npm wrapper can exit successfully after its native child is terminated by a signal if Node ignores the re-emitted signal or a forwarding handler intercepts it.

## What changed

Set a fallback exit status of `128 + signal number` and remove listeners for the terminating signal before re-emitting it, preserving signal termination where supported.

## Testing

Add a non-Windows integration test using a built Codex binary to cover numeric argument-error exits, forwarded `SIGHUP` termination, and the fallback exit status for `SIGXFSZ`, which Node ignores by default.

GitOrigin-RevId: cad18a47aa50fd78517c367f8d8aae83bbbf7843
This commit is contained in:
Dmitriy Kovalenko
2026-10-27 04:39:05 +00:00
committed by copyberry
parent b7f7e7f7e8
commit 9510f36df2
2 changed files with 124 additions and 2 deletions
+4 -2
View File
@@ -4,6 +4,7 @@
import { spawn } from "node:child_process";
import { existsSync, readFileSync, realpathSync } from "fs";
import { createRequire } from "node:module";
import { constants } from "node:os";
import path from "path";
import { fileURLToPath } from "url";
@@ -287,8 +288,9 @@ const childResult = await new Promise((resolve) => {
});
if (childResult.type === "signal") {
// Re-emit the same signal so that the parent terminates with the expected
// semantics (this also sets the correct exit code of 128 + n).
// Preserve a failure exit code even if Node ignores the re-emitted signal.
process.exitCode = 128 + constants.signals[childResult.signal];
process.removeAllListeners(childResult.signal);
process.kill(process.pid, childResult.signal);
} else {
process.exit(childResult.exitCode);