diff --git a/scripts/dependency-changes-report.mjs b/scripts/dependency-changes-report.mjs index fe3aae0f5c2..db09e43500d 100644 --- a/scripts/dependency-changes-report.mjs +++ b/scripts/dependency-changes-report.mjs @@ -345,7 +345,7 @@ if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(import.met process.exitCode = exitCode; }, /** @param {unknown} error */ (error) => { - process.stderr.write(`${error.stack ?? error.message ?? String(error)}\n`); + process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); process.exitCode = 1; }, ); diff --git a/scripts/dependency-vulnerability-gate.mjs b/scripts/dependency-vulnerability-gate.mjs index 633eb7ba6d4..a4edadec90b 100644 --- a/scripts/dependency-vulnerability-gate.mjs +++ b/scripts/dependency-vulnerability-gate.mjs @@ -303,7 +303,7 @@ if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(import.met process.exitCode = exitCode; }, /** @param {unknown} error */ (error) => { - process.stderr.write(`${error.stack ?? error.message ?? String(error)}\n`); + process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); process.exitCode = 1; }, ); diff --git a/scripts/transitive-manifest-risk-report.mjs b/scripts/transitive-manifest-risk-report.mjs index c78b65d3451..e3c0f6d26fb 100644 --- a/scripts/transitive-manifest-risk-report.mjs +++ b/scripts/transitive-manifest-risk-report.mjs @@ -656,7 +656,7 @@ if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(import.met process.exitCode = exitCode; }, /** @param {unknown} error */ (error) => { - process.stderr.write(`${error.stack ?? error.message ?? String(error)}\n`); + process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); process.exitCode = 1; }, ); diff --git a/test/scripts/dependency-changes-report.test.ts b/test/scripts/dependency-changes-report.test.ts index aff28aa4663..906b4489623 100644 --- a/test/scripts/dependency-changes-report.test.ts +++ b/test/scripts/dependency-changes-report.test.ts @@ -1,4 +1,6 @@ // Dependency Changes Report tests cover dependency changes report script behavior. +import { spawnSync } from "node:child_process"; +import path from "node:path"; import { describe, expect, it } from "vitest"; import { createDependencyChangesReport, @@ -7,6 +9,18 @@ import { parseArgs, } from "../../scripts/dependency-changes-report.mjs"; +function runCli(...args: string[]) { + return spawnSync(process.execPath, ["scripts/dependency-changes-report.mjs", ...args], { + cwd: path.resolve("."), + encoding: "utf8", + }); +} + +function expectNoNodeStack(stderr: string) { + expect(stderr).not.toContain("Node.js"); + expect(stderr).not.toContain("\n at "); +} + describe("dependency-changes-report", () => { it("reports added, removed, and changed packages", () => { const report = createDependencyChangesReport({ @@ -72,4 +86,20 @@ describe("dependency-changes-report", () => { expect(() => parseArgs([flag, "--json"])).toThrow(`${flag} requires a value`); } }); + + it("reports CLI argument errors without a Node stack trace", () => { + const missingBase = runCli(); + expect(missingBase.status).toBe(1); + expect(missingBase.stdout).toBe(""); + expect(missingBase.stderr.trim()).toBe( + "Expected --base-ref or --base-lockfile .", + ); + expectNoNodeStack(missingBase.stderr); + + const unknownArg = runCli("--wat"); + expect(unknownArg.status).toBe(1); + expect(unknownArg.stdout).toBe(""); + expect(unknownArg.stderr.trim()).toBe("Unsupported argument: --wat"); + expectNoNodeStack(unknownArg.stderr); + }); }); diff --git a/test/scripts/dependency-vulnerability-gate.test.ts b/test/scripts/dependency-vulnerability-gate.test.ts index a42128ea174..1c75f72d221 100644 --- a/test/scripts/dependency-vulnerability-gate.test.ts +++ b/test/scripts/dependency-vulnerability-gate.test.ts @@ -1,4 +1,5 @@ // Dependency Vulnerability Gate tests cover dependency vulnerability gate script behavior. +import { spawnSync } from "node:child_process"; import { mkdtemp, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; @@ -9,6 +10,18 @@ import { runDependencyVulnerabilityGate, } from "../../scripts/dependency-vulnerability-gate.mjs"; +function runCli(...args: string[]) { + return spawnSync(process.execPath, ["scripts/dependency-vulnerability-gate.mjs", ...args], { + cwd: path.resolve("."), + encoding: "utf8", + }); +} + +function expectNoNodeStack(stderr: string) { + expect(stderr).not.toContain("Node.js"); + expect(stderr).not.toContain("\n at "); +} + function advisory({ id, severity, @@ -53,6 +66,14 @@ snapshots: } describe("dependency-vulnerability-gate", () => { + it("reports CLI argument errors without a Node stack trace", () => { + const unknownArg = runCli("--wat"); + expect(unknownArg.status).toBe(1); + expect(unknownArg.stdout).toBe(""); + expect(unknownArg.stderr.trim()).toBe("Unsupported argument: --wat"); + expectNoNodeStack(unknownArg.stderr); + }); + it("blocks critical advisories anywhere and high advisories in the production graph", () => { const result = classifyVulnerabilityFindings({ allAdvisories: { diff --git a/test/scripts/transitive-manifest-risk-report.test.ts b/test/scripts/transitive-manifest-risk-report.test.ts index 208fb03f0c8..f93886c53e2 100644 --- a/test/scripts/transitive-manifest-risk-report.test.ts +++ b/test/scripts/transitive-manifest-risk-report.test.ts @@ -1,4 +1,6 @@ // Transitive Manifest Risk Report tests cover transitive manifest risk report script behavior. +import { spawnSync } from "node:child_process"; +import path from "node:path"; import { describe, expect, it } from "vitest"; import { createTransitiveManifestRiskReport, @@ -7,7 +9,27 @@ import { renderTransitiveManifestRiskMarkdownReport, } from "../../scripts/transitive-manifest-risk-report.mjs"; +function runCli(...args: string[]) { + return spawnSync(process.execPath, ["scripts/transitive-manifest-risk-report.mjs", ...args], { + cwd: path.resolve("."), + encoding: "utf8", + }); +} + +function expectNoNodeStack(stderr: string) { + expect(stderr).not.toContain("Node.js"); + expect(stderr).not.toContain("\n at "); +} + describe("transitive-manifest-risk-report", () => { + it("reports CLI argument errors without a Node stack trace", () => { + const unknownArg = runCli("--wat"); + expect(unknownArg.status).toBe(1); + expect(unknownArg.stdout).toBe(""); + expect(unknownArg.stderr.trim()).toBe("Unsupported argument: --wat"); + expectNoNodeStack(unknownArg.stderr); + }); + it("reports floating transitive specs, lifecycle scripts, exotic sources, and recently published versions", async () => { const report = await createTransitiveManifestRiskReport({ packageVersions: [