From 13c83491641f8d068e18a27b551708e7c9ce15a9 Mon Sep 17 00:00:00 2001 From: Hamed Mohamed Date: Wed, 3 Jun 2026 18:13:41 +0300 Subject: [PATCH 1/2] fix(cli): add early Node.js version check wrapper This adds a CJS wrapper to cleanly validate the Node.js version against engines.node before executing the ESM entry point. Resolves #763. --- bin/check-and-run.cjs | 24 ++++++++++++++++++ package.json | 4 +-- test/commands/bin.test.js | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 bin/check-and-run.cjs create mode 100644 test/commands/bin.test.js diff --git a/bin/check-and-run.cjs b/bin/check-and-run.cjs new file mode 100644 index 00000000..4214ff4c --- /dev/null +++ b/bin/check-and-run.cjs @@ -0,0 +1,24 @@ +#!/usr/bin/env node + +"use strict"; + +const { createRequire } = require("node:module"); +const localRequire = createRequire(__filename); + +const manifest = localRequire("../package.json"); +const semver = localRequire("semver"); + +const currentVersion = process.versions.node; +const requiredRange = manifest.engines.node; + +if (!semver.satisfies(currentVersion, requiredRange)) { + console.error( + `\n @nodesecure/cli requires Node.js ${requiredRange}.` + + `\n Current version: v${currentVersion}\n` + ); + process.exit(1); +} + +if (require.main === module) { + import("./index.js"); +} diff --git a/package.json b/package.json index 75220e5e..06d658eb 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "Node.js security CLI", "main": "./bin/index.js", "bin": { - "node-secure": "./bin/index.js", - "nsecure": "./bin/index.js" + "node-secure": "./bin/check-and-run.cjs", + "nsecure": "./bin/check-and-run.cjs" }, "type": "module", "engines": { diff --git a/test/commands/bin.test.js b/test/commands/bin.test.js new file mode 100644 index 00000000..2a990ebc --- /dev/null +++ b/test/commands/bin.test.js @@ -0,0 +1,51 @@ +// Import Node.js Dependencies +import assert from "node:assert"; +import { createRequire } from "node:module"; +import { describe, it, mock, afterEach } from "node:test"; + +const require = createRequire(import.meta.url); + +describe("bin/check-and-run.cjs", () => { + afterEach(() => { + mock.restoreAll(); + // Clear the require cache so the file executes again for each test + delete require.cache[require.resolve("../../bin/check-and-run.cjs")]; + }); + + it("should exit with code 1 if semver.satisfies returns false", (ctx) => { + const logs = []; + ctx.mock.method(console, "error", (msg) => logs.push(msg)); + + ctx.mock.method(process, "exit", (code) => { + throw new Error(`process.exit(${code}) called`); + }); + + // Mock semver to simulate a failed version check + const semver = require("semver"); + ctx.mock.method(semver, "satisfies", () => false); + + assert.throws( + () => require("../../bin/check-and-run.cjs"), + { message: "process.exit(1) called" }, + "should halt execution and exit with code 1" + ); + + const allLogs = logs.join(""); + assert.ok(allLogs.includes("@nodesecure/cli requires Node.js"), "should print required Node.js version message"); + }); + + it("should not exit if semver.satisfies returns true", (ctx) => { + let exitCode; + ctx.mock.method(process, "exit", (code) => { + exitCode = code; + }); + + // Mock semver to simulate a successful version check + const semver = require("semver"); + ctx.mock.method(semver, "satisfies", () => true); + + require("../../bin/check-and-run.cjs"); + + assert.strictEqual(exitCode, undefined, "should not call process.exit"); + }); +}); From d06b5e3d1d7e2657e4d627d0183a371d2523b9e6 Mon Sep 17 00:00:00 2001 From: Hamed Mohamed Date: Thu, 4 Jun 2026 09:44:11 +0300 Subject: [PATCH 2/2] fix: remove trailing space in bin.test.js line 32 --- test/commands/bin.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/commands/bin.test.js b/test/commands/bin.test.js index 2a990ebc..b0fae5f8 100644 --- a/test/commands/bin.test.js +++ b/test/commands/bin.test.js @@ -29,7 +29,7 @@ describe("bin/check-and-run.cjs", () => { { message: "process.exit(1) called" }, "should halt execution and exit with code 1" ); - + const allLogs = logs.join(""); assert.ok(allLogs.includes("@nodesecure/cli requires Node.js"), "should print required Node.js version message"); });