refactor: centralize node startup tls planning

This commit is contained in:
Peter Steinberger
2026-03-21 15:57:44 -07:00
parent 5b31b3400e
commit 29b165e456
9 changed files with 179 additions and 49 deletions

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import {
isNvmNode,
isNodeVersionManagerRuntime,
LINUX_CA_BUNDLE_PATHS,
resolveAutoNodeExtraCaCerts,
resolveLinuxSystemCaBundle,
@@ -34,17 +34,19 @@ describe("resolveLinuxSystemCaBundle", () => {
});
});
describe("isNvmNode", () => {
describe("isNodeVersionManagerRuntime", () => {
it("detects nvm via NVM_DIR", () => {
expect(isNvmNode({ NVM_DIR: "/home/test/.nvm" }, "/usr/bin/node")).toBe(true);
expect(isNodeVersionManagerRuntime({ NVM_DIR: "/home/test/.nvm" }, "/usr/bin/node")).toBe(true);
});
it("detects nvm via execPath", () => {
expect(isNvmNode({}, "/home/test/.nvm/versions/node/v22/bin/node")).toBe(true);
expect(isNodeVersionManagerRuntime({}, "/home/test/.nvm/versions/node/v22/bin/node")).toBe(
true,
);
});
it("returns false for non-nvm node paths", () => {
expect(isNvmNode({}, "/usr/bin/node")).toBe(false);
expect(isNodeVersionManagerRuntime({}, "/usr/bin/node")).toBe(false);
});
});

View File

@@ -6,7 +6,7 @@ export const LINUX_CA_BUNDLE_PATHS = [
"/etc/ssl/ca-bundle.pem",
] as const;
type EnvMap = Record<string, string | undefined>;
export type EnvMap = Record<string, string | undefined>;
type AccessSyncFn = (path: string, mode?: number) => void;
export function resolveLinuxSystemCaBundle(
@@ -32,7 +32,7 @@ export function resolveLinuxSystemCaBundle(
return undefined;
}
export function isNvmNode(
export function isNodeVersionManagerRuntime(
env: EnvMap = process.env as EnvMap,
execPath: string = process.execPath,
): boolean {
@@ -57,7 +57,7 @@ export function resolveAutoNodeExtraCaCerts(
const platform = params.platform ?? process.platform;
const execPath = params.execPath ?? process.execPath;
if (platform !== "linux" || !isNvmNode(env, execPath)) {
if (platform !== "linux" || !isNodeVersionManagerRuntime(env, execPath)) {
return undefined;
}

View File

@@ -0,0 +1,79 @@
import { describe, expect, it } from "vitest";
import { LINUX_CA_BUNDLE_PATHS } from "./node-extra-ca-certs.js";
import { resolveNodeStartupTlsEnvironment } from "./node-startup-env.js";
function allowOnly(path: string) {
return (candidate: string) => {
if (candidate !== path) {
throw new Error("ENOENT");
}
};
}
describe("resolveNodeStartupTlsEnvironment", () => {
it("defaults macOS launch env values", () => {
expect(
resolveNodeStartupTlsEnvironment({
env: {},
platform: "darwin",
}),
).toEqual({
NODE_EXTRA_CA_CERTS: "/etc/ssl/cert.pem",
NODE_USE_SYSTEM_CA: "1",
});
});
it("keeps user-provided env values", () => {
expect(
resolveNodeStartupTlsEnvironment({
env: {
NODE_EXTRA_CA_CERTS: "/custom/ca.pem",
NODE_USE_SYSTEM_CA: "0",
},
platform: "darwin",
}),
).toEqual({
NODE_EXTRA_CA_CERTS: "/custom/ca.pem",
NODE_USE_SYSTEM_CA: "0",
});
});
it("resolves Linux CA env for version-manager Node runtimes", () => {
expect(
resolveNodeStartupTlsEnvironment({
env: { NVM_DIR: "/home/test/.nvm" },
platform: "linux",
execPath: "/usr/bin/node",
accessSync: allowOnly(LINUX_CA_BUNDLE_PATHS[1]),
}),
).toEqual({
NODE_EXTRA_CA_CERTS: LINUX_CA_BUNDLE_PATHS[1],
NODE_USE_SYSTEM_CA: undefined,
});
});
it("can skip macOS defaults for CLI-only pre-start planning", () => {
expect(
resolveNodeStartupTlsEnvironment({
env: {},
platform: "darwin",
includeDarwinDefaults: false,
}),
).toEqual({
NODE_EXTRA_CA_CERTS: undefined,
NODE_USE_SYSTEM_CA: undefined,
});
});
it("uses the Linux CA bundle heuristic when available", () => {
const value = resolveNodeStartupTlsEnvironment({
env: { NVM_DIR: "/home/test/.nvm" },
platform: "linux",
execPath: "/usr/bin/node",
accessSync: allowOnly(LINUX_CA_BUNDLE_PATHS[2]),
}).NODE_EXTRA_CA_CERTS;
if (value !== undefined) {
expect(LINUX_CA_BUNDLE_PATHS).toContain(value);
}
});
});

View File

@@ -0,0 +1,38 @@
import { type EnvMap, resolveAutoNodeExtraCaCerts } from "./node-extra-ca-certs.js";
export type NodeStartupTlsEnvironment = {
NODE_EXTRA_CA_CERTS?: string;
NODE_USE_SYSTEM_CA?: string;
};
export function resolveNodeStartupTlsEnvironment(
params: {
env?: EnvMap;
platform?: NodeJS.Platform;
execPath?: string;
includeDarwinDefaults?: boolean;
accessSync?: (path: string, mode?: number) => void;
} = {},
): NodeStartupTlsEnvironment {
const env = params.env ?? (process.env as EnvMap);
const platform = params.platform ?? process.platform;
const includeDarwinDefaults = params.includeDarwinDefaults ?? true;
const nodeExtraCaCerts =
env.NODE_EXTRA_CA_CERTS ??
(platform === "darwin" && includeDarwinDefaults
? "/etc/ssl/cert.pem"
: resolveAutoNodeExtraCaCerts({
env,
platform,
execPath: params.execPath,
accessSync: params.accessSync,
}));
const nodeUseSystemCa =
env.NODE_USE_SYSTEM_CA ?? (platform === "darwin" && includeDarwinDefaults ? "1" : undefined);
return {
NODE_EXTRA_CA_CERTS: nodeExtraCaCerts,
NODE_USE_SYSTEM_CA: nodeUseSystemCa,
};
}