| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import { describe, it } from "node:test"; |
| import assert from "node:assert/strict"; |
|
|
| |
|
|
| describe("CLI Memory Limit Sanitization", () => { |
| |
| |
| |
| function sanitizeMemoryLimit(envValue) { |
| const rawMemory = parseInt(envValue || "512", 10); |
| return Number.isFinite(rawMemory) && rawMemory >= 64 && rawMemory <= 16384 ? rawMemory : 512; |
| } |
|
|
| it("should default to 512 when no env var set", () => { |
| assert.equal(sanitizeMemoryLimit(undefined), 512); |
| assert.equal(sanitizeMemoryLimit(null), 512); |
| assert.equal(sanitizeMemoryLimit(""), 512); |
| }); |
|
|
| it("should accept valid numeric values", () => { |
| assert.equal(sanitizeMemoryLimit("128"), 128); |
| assert.equal(sanitizeMemoryLimit("256"), 256); |
| assert.equal(sanitizeMemoryLimit("512"), 512); |
| assert.equal(sanitizeMemoryLimit("1024"), 1024); |
| assert.equal(sanitizeMemoryLimit("2048"), 2048); |
| assert.equal(sanitizeMemoryLimit("4096"), 4096); |
| assert.equal(sanitizeMemoryLimit("8192"), 8192); |
| }); |
|
|
| it("should accept boundary values", () => { |
| assert.equal(sanitizeMemoryLimit("64"), 64); |
| assert.equal(sanitizeMemoryLimit("16384"), 16384); |
| }); |
|
|
| it("should reject values below minimum (64MB)", () => { |
| assert.equal(sanitizeMemoryLimit("0"), 512); |
| assert.equal(sanitizeMemoryLimit("1"), 512); |
| assert.equal(sanitizeMemoryLimit("32"), 512); |
| assert.equal(sanitizeMemoryLimit("63"), 512); |
| assert.equal(sanitizeMemoryLimit("-1"), 512); |
| assert.equal(sanitizeMemoryLimit("-9999"), 512); |
| }); |
|
|
| it("should reject values above maximum (16384MB)", () => { |
| assert.equal(sanitizeMemoryLimit("16385"), 512); |
| assert.equal(sanitizeMemoryLimit("99999"), 512); |
| assert.equal(sanitizeMemoryLimit("1000000"), 512); |
| }); |
|
|
| |
|
|
| it("should prevent command injection via shell metacharacters", () => { |
| |
| |
| const r1 = sanitizeMemoryLimit("256; rm -rf /"); |
| assert.equal(typeof r1, "number"); |
| assert.ok(r1 >= 64 && r1 <= 16384); |
|
|
| |
| assert.equal(sanitizeMemoryLimit("`id`"), 512); |
| assert.equal(sanitizeMemoryLimit("$(whoami)"), 512); |
| }); |
|
|
| it("should prevent injection via Node.js spawn args", () => { |
| |
| assert.equal(sanitizeMemoryLimit("--require=/tmp/malware.js"), 512); |
| assert.equal(sanitizeMemoryLimit("--experimental-modules"), 512); |
| assert.equal(sanitizeMemoryLimit("-e 'process.exit()'"), 512); |
| }); |
|
|
| it("should handle non-numeric strings gracefully", () => { |
| assert.equal(sanitizeMemoryLimit("abc"), 512); |
| assert.equal(sanitizeMemoryLimit("twelve"), 512); |
| assert.equal(sanitizeMemoryLimit("NaN"), 512); |
| assert.equal(sanitizeMemoryLimit("Infinity"), 512); |
| assert.equal(sanitizeMemoryLimit("undefined"), 512); |
| }); |
|
|
| it("should handle special numeric formats", () => { |
| |
| assert.equal(sanitizeMemoryLimit("0x100"), 512); |
| |
| assert.equal(sanitizeMemoryLimit("1e3"), 512); |
| assert.equal(sanitizeMemoryLimit("512.7"), 512); |
| assert.equal(sanitizeMemoryLimit(" 256 "), 256); |
| }); |
| }); |
|
|
| |
|
|
| describe("CLI .env File Loading", () => { |
| |
| |
| |
| function parseEnvLine(line) { |
| const trimmed = line.trim(); |
| if (!trimmed || trimmed.startsWith("#")) return null; |
| const eqIdx = trimmed.indexOf("="); |
| if (eqIdx === -1) return null; |
| const key = trimmed.substring(0, eqIdx).trim(); |
| let value = trimmed.substring(eqIdx + 1).trim(); |
| |
| value = value.replace(/^["']|["']$/g, ""); |
| return { key, value }; |
| } |
|
|
| it("should parse KEY=VALUE lines", () => { |
| const result = parseEnvLine("PORT=3000"); |
| assert.deepEqual(result, { key: "PORT", value: "3000" }); |
| }); |
|
|
| it("should strip surrounding quotes", () => { |
| const dq = parseEnvLine('JWT_SECRET="my-secret"'); |
| assert.deepEqual(dq, { key: "JWT_SECRET", value: "my-secret" }); |
|
|
| const sq = parseEnvLine("JWT_SECRET='my-secret'"); |
| assert.deepEqual(sq, { key: "JWT_SECRET", value: "my-secret" }); |
| }); |
|
|
| it("should skip comments", () => { |
| assert.equal(parseEnvLine("# This is a comment"), null); |
| assert.equal(parseEnvLine(" # Indented comment"), null); |
| }); |
|
|
| it("should skip empty lines", () => { |
| assert.equal(parseEnvLine(""), null); |
| assert.equal(parseEnvLine(" "), null); |
| }); |
|
|
| it("should skip lines without =", () => { |
| assert.equal(parseEnvLine("MALFORMED_LINE"), null); |
| }); |
|
|
| it("should handle values with equals signs", () => { |
| const result = parseEnvLine("DATABASE_URL=postgres://user:pass@host:5432/db?sslmode=require"); |
| assert.equal(result.key, "DATABASE_URL"); |
| assert.equal(result.value, "postgres://user:pass@host:5432/db?sslmode=require"); |
| }); |
|
|
| it("should handle empty values", () => { |
| const result = parseEnvLine("EMPTY_VAR="); |
| assert.deepEqual(result, { key: "EMPTY_VAR", value: "" }); |
| }); |
| }); |
|
|