From 71419a0b8b996e6c894f00326e34dfea1b64c217 Mon Sep 17 00:00:00 2001 From: jdalton Date: Tue, 1 Jul 2025 10:55:35 -0400 Subject: [PATCH] Add support for proxy env var aliases --- src/commands/fix/npm-fix.mts | 2 +- src/constants.mts | 16 ++++++++++++++- src/utils/sdk.mts | 40 ++++++++++++++++++++++++++++-------- test/socket-npm.test.mts | 1 + 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/commands/fix/npm-fix.mts b/src/commands/fix/npm-fix.mts index 32e1d28f0..ab4265839 100644 --- a/src/commands/fix/npm-fix.mts +++ b/src/commands/fix/npm-fix.mts @@ -82,7 +82,7 @@ export async function npmFix( definitions: npmConfigDefinitions, // Lazily access constants.execPath. execPath: constants.execPath, - env: process.env, + env: { ...process.env }, flatten: npmConfigFlatten, npmPath, platform: process.platform, diff --git a/src/constants.mts b/src/constants.mts index 086a3c659..63886f488 100644 --- a/src/constants.mts +++ b/src/constants.mts @@ -62,6 +62,7 @@ type ENV = Remap< INLINED_SYNP_VERSION: string LOCALAPPDATA: string NODE_COMPILE_CACHE: string + NODE_EXTRA_CA_CERTS: string PATH: string SOCKET_CLI_ACCEPT_RISKS: boolean SOCKET_CLI_API_BASE_URL: string @@ -308,6 +309,15 @@ const LAZY_ENV = () => { ? // Lazily access constants.socketCachePath. constants.socketCachePath : '', + // When set, the well known "root" CAs (like VeriSign) will be extended with + // the extra certificates in file. The file should consist of one or more + // trusted certificates in PEM format. + // https://nodejs.org/api/cli.html#node_extra_ca_certsfile + NODE_EXTRA_CA_CERTS: + envAsString(env['NODE_EXTRA_CA_CERTS']) || + // Commonly used environment variable to specify the path to a single + // PEM-encoded certificate file. + envAsString(env['SSL_CERT_FILE']), // PATH is an environment variable that lists directories where executable // programs are located. When a command is run, the system searches these // directories to find the executable. @@ -323,7 +333,11 @@ const LAZY_ENV = () => { // https://github.com/SocketDev/socket-cli?tab=readme-ov-file#environment-variables-for-development SOCKET_CLI_API_PROXY: envAsString(env['SOCKET_CLI_API_PROXY']) || - envAsString(env['SOCKET_SECURITY_API_PROXY']), + envAsString(env['SOCKET_SECURITY_API_PROXY']) || + // Commonly used environment variables to specify routing requests through + // a proxy server. + envAsString(env['HTTPS_PROXY']) || + envAsString(env['https_proxy']), // Flag to set the API token. // https://github.com/SocketDev/socket-cli?tab=readme-ov-file#environment-variables SOCKET_CLI_API_TOKEN: diff --git a/src/utils/sdk.mts b/src/utils/sdk.mts index 8ff2bde7c..f3e2487e9 100644 --- a/src/utils/sdk.mts +++ b/src/utils/sdk.mts @@ -1,4 +1,4 @@ -import { HttpsProxyAgent } from 'hpagent' +import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent' import isInteractive from '@socketregistry/is-interactive/index.cjs' import { password } from '@socketsecurity/registry/lib/prompts' @@ -10,8 +10,6 @@ import constants from '../constants.mts' import type { CResult } from '../types.mts' -const { SOCKET_PUBLIC_API_TOKEN } = constants - const TOKEN_PREFIX = 'sktsec_' const { length: TOKEN_PREFIX_LENGTH } = TOKEN_PREFIX @@ -21,15 +19,26 @@ function getDefaultApiBaseUrl(): string | undefined { const baseUrl = // Lazily access constants.ENV.SOCKET_CLI_API_BASE_URL. constants.ENV.SOCKET_CLI_API_BASE_URL || getConfigValueOrUndef('apiBaseUrl') - return isNonEmptyString(baseUrl) ? baseUrl : undefined + return isUrl(baseUrl) ? baseUrl : undefined } // The API server that should be used for operations. -function getDefaultHttpProxy(): string | undefined { +function getDefaultProxyUrl(): string | undefined { const apiProxy = // Lazily access constants.ENV.SOCKET_CLI_API_PROXY. constants.ENV.SOCKET_CLI_API_PROXY || getConfigValueOrUndef('apiProxy') - return isNonEmptyString(apiProxy) ? apiProxy : undefined + return isUrl(apiProxy) ? apiProxy : undefined +} + +function isUrl(value: any): value is string { + if (isNonEmptyString(value)) { + try { + // eslint-disable-next-line no-new + new URL(value) + return true + } catch {} + } + return false } // This API key should be stored globally for the duration of the CLI execution. @@ -64,14 +73,15 @@ export function getPublicToken(): string { return ( // Lazily access constants.ENV.SOCKET_CLI_API_TOKEN. (constants.ENV.SOCKET_CLI_API_TOKEN || getDefaultToken()) ?? - SOCKET_PUBLIC_API_TOKEN + // Lazily access constants.SOCKET_PUBLIC_API_TOKEN. + constants.SOCKET_PUBLIC_API_TOKEN ) } export async function setupSdk( apiToken: string | undefined = getDefaultToken(), apiBaseUrl: string | undefined = getDefaultApiBaseUrl(), - proxy: string | undefined = getDefaultHttpProxy(), + proxy: string | undefined, ): Promise> { if (typeof apiToken !== 'string' && isInteractive()) { apiToken = await password({ @@ -87,10 +97,22 @@ export async function setupSdk( cause: 'You need to provide an API Token. Run `socket login` first.', } } + if (!isUrl(proxy)) { + proxy = getDefaultProxyUrl() + } + + const ProxyAgent = proxy?.startsWith('http:') + ? HttpProxyAgent + : HttpsProxyAgent + return { ok: true, data: new SocketSdk(apiToken, { - agent: proxy ? new HttpsProxyAgent({ proxy }) : undefined, + agent: proxy + ? new ProxyAgent({ + proxy, + }) + : undefined, baseUrl: apiBaseUrl, userAgent: createUserAgentFromPkgJson({ // Lazily access constants.ENV.INLINED_SOCKET_CLI_NAME. diff --git a/test/socket-npm.test.mts b/test/socket-npm.test.mts index 5c46c9800..6d50639bb 100644 --- a/test/socket-npm.test.mts +++ b/test/socket-npm.test.mts @@ -56,6 +56,7 @@ for (const npmDir of ['npm9', 'npm10', 'npm11']) { { cwd: path.join(npmFixturesPath, 'lacking-typosquat'), env: { + ...process.env, // Lazily access constants.ENV.PATH. PATH: `${npmBinPath}:${constants.ENV.PATH}`, },