From 63a4962c0802a4b6f761f544d5075e78e2eb66d4 Mon Sep 17 00:00:00 2001 From: jdalton Date: Mon, 13 Apr 2026 16:28:00 -0400 Subject: [PATCH 1/2] fix: add pip3 shim support and MSYS path normalization in index.mts - Add pip3 to ecosystem lists in external-tools.json (free + enterprise) - Add pip3 to SHIM_CMDS in setup action.yml (free + enterprise) - Add msysToWinPath normalization in index.mts for Windows MSYS paths (/c/Users/... -> C:\Users\...) matching the existing fix in action.yml --- .../setup-security-tools/external-tools.json | 4 ++-- .claude/hooks/setup-security-tools/index.mts | 19 +++++++++++++++---- .github/actions/setup/action.yml | 4 ++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/.claude/hooks/setup-security-tools/external-tools.json b/.claude/hooks/setup-security-tools/external-tools.json index f8f6d2a2..fc18b17c 100644 --- a/.claude/hooks/setup-security-tools/external-tools.json +++ b/.claude/hooks/setup-security-tools/external-tools.json @@ -56,7 +56,7 @@ "sha256": "c953e62ad7928d4d8f2302f5737884ea1a757babc26bed6a42b9b6b68a5d54af" } }, - "ecosystems": ["npm", "yarn", "pnpm", "pip", "uv", "cargo"] + "ecosystems": ["npm", "yarn", "pnpm", "pip", "pip3", "uv", "cargo"] }, "sfw-enterprise": { "description": "Socket Firewall (enterprise tier)", @@ -85,7 +85,7 @@ "sha256": "9a50e1ddaf038138c3f85418dc5df0113bbe6fc884f5abe158beaa9aea18d70a" } }, - "ecosystems": ["npm", "yarn", "pnpm", "pip", "uv", "cargo", "gem", "bundler", "nuget"] + "ecosystems": ["npm", "yarn", "pnpm", "pip", "pip3", "uv", "cargo", "gem", "bundler", "nuget"] } } } diff --git a/.claude/hooks/setup-security-tools/index.mts b/.claude/hooks/setup-security-tools/index.mts index eb82e518..4aae6ae6 100644 --- a/.claude/hooks/setup-security-tools/index.mts +++ b/.claude/hooks/setup-security-tools/index.mts @@ -194,6 +194,15 @@ async function setupSfw(apiKey: string | undefined): Promise { // Create shims. const isWindows = process.platform === 'win32' + + // On Windows, MSYS paths like /c/Users/... need to be converted to + // native format (C:\Users\...) so sfw and PowerShell can resolve them. + const msysToWinPath = (p: string): string => { + const match = p.match(/^\/([a-zA-Z])\/(.*)/) + return match ? `${match[1].toUpperCase()}:\\${match[2].replace(/\//g, '\\')}` : p + } + const normalizePath = isWindows ? msysToWinPath : (p: string) => p + const shimDir = path.join(getSocketHomePath(), 'sfw', 'shims') await fs.mkdir(shimDir, { recursive: true }) const ecosystems = [...(sfwConfig.ecosystems ?? [])] @@ -202,12 +211,14 @@ async function setupSfw(apiKey: string | undefined): Promise { } const cleanPath = (process.env['PATH'] ?? '').split(path.delimiter) .filter(p => p !== shimDir).join(path.delimiter) + const sfwBin = normalizePath(binaryPath) const created: string[] = [] for (const cmd of ecosystems) { - const realBin = whichSync(cmd, { nothrow: true, path: cleanPath }) + let realBin = whichSync(cmd, { nothrow: true, path: cleanPath }) if (!realBin || typeof realBin !== 'string') continue + realBin = normalizePath(realBin) - // Bash shim (macOS/Linux). + // Bash shim (macOS/Linux/Windows Git Bash). const bashLines = [ '#!/bin/bash', `export PATH="$(echo "$PATH" | tr ':' '\\n' | grep -vxF '${shimDir}' | paste -sd: -)"`, @@ -226,7 +237,7 @@ async function setupSfw(apiKey: string | undefined): Promise { 'fi', ) } - bashLines.push(`exec "${binaryPath}" "${realBin}" "$@"`) + bashLines.push(`exec "${sfwBin}" "${realBin}" "$@"`) const bashContent = bashLines.join('\n') + '\n' const bashPath = path.join(shimDir, cmd) if (!existsSync(bashPath) || await fs.readFile(bashPath, 'utf8').catch(() => '') !== bashContent) { @@ -256,7 +267,7 @@ async function setupSfw(apiKey: string | undefined): Promise { + `set "PATH=%PATH:;${shimDir};=%"\r\n` + `set "PATH=%PATH:~1,-1%"\r\n` + cmdApiKeyBlock - + `"${binaryPath}" "${realBin}" %*\r\n` + + `"${sfwBin}" "${realBin}" %*\r\n` const cmdPath = path.join(shimDir, `${cmd}.cmd`) if (!existsSync(cmdPath) || await fs.readFile(cmdPath, 'utf8').catch(() => '') !== cmdContent) { await fs.writeFile(cmdPath, cmdContent) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 18fa8969..4b67609d 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -172,9 +172,9 @@ runs: strip_shim_dir() { echo "$PATH" | tr ':' '\n' | grep -vxF "$SHIM_DIR" | paste -sd: -; } CLEAN_PATH="$(strip_shim_dir)" SSL_WORKAROUND="" - SHIM_CMDS="npm yarn pnpm pip uv cargo" + SHIM_CMDS="npm yarn pnpm pip pip3 uv cargo" if [ "$SFW_IS_ENTERPRISE" = "true" ]; then - SHIM_CMDS="npm yarn pnpm pip uv cargo gem bundler nuget" + SHIM_CMDS="npm yarn pnpm pip pip3 uv cargo gem bundler nuget" # Go wrapper mode is only supported on Linux. [[ "$OSTYPE" == linux* ]] && SHIM_CMDS="$SHIM_CMDS go" else From 4ee2b6f6433227d925c34dd3617f0d13d7c39d24 Mon Sep 17 00:00:00 2001 From: jdalton Date: Tue, 14 Apr 2026 12:09:12 -0400 Subject: [PATCH 2/2] refactor(sfw): use fromUnixPath from @socketsecurity/lib for MSYS path conversion --- .claude/hooks/setup-security-tools/index.mts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.claude/hooks/setup-security-tools/index.mts b/.claude/hooks/setup-security-tools/index.mts index 4aae6ae6..0c8c2086 100644 --- a/.claude/hooks/setup-security-tools/index.mts +++ b/.claude/hooks/setup-security-tools/index.mts @@ -19,6 +19,7 @@ import { fileURLToPath } from 'node:url' import { whichSync } from '@socketsecurity/lib/bin' import { downloadBinary } from '@socketsecurity/lib/dlx/binary' import { getDefaultLogger } from '@socketsecurity/lib/logger' +import { normalizePath } from '@socketsecurity/lib/paths/normalize' import { getSocketHomePath } from '@socketsecurity/lib/paths/socket' import { spawn, spawnSync } from '@socketsecurity/lib/spawn' import { z } from 'zod' @@ -195,14 +196,6 @@ async function setupSfw(apiKey: string | undefined): Promise { // Create shims. const isWindows = process.platform === 'win32' - // On Windows, MSYS paths like /c/Users/... need to be converted to - // native format (C:\Users\...) so sfw and PowerShell can resolve them. - const msysToWinPath = (p: string): string => { - const match = p.match(/^\/([a-zA-Z])\/(.*)/) - return match ? `${match[1].toUpperCase()}:\\${match[2].replace(/\//g, '\\')}` : p - } - const normalizePath = isWindows ? msysToWinPath : (p: string) => p - const shimDir = path.join(getSocketHomePath(), 'sfw', 'shims') await fs.mkdir(shimDir, { recursive: true }) const ecosystems = [...(sfwConfig.ecosystems ?? [])]