Another iteration

This commit is contained in:
Reinier Criel 2025-11-06 10:26:26 -08:00
parent f400c5576a
commit 28d24bb6ea
12 changed files with 134 additions and 107 deletions

View file

@ -1,19 +1,19 @@
#!/usr/bin/env node
import { main } from "../src/main.js";
import { initializePackageManager } from "../src/packagemanager/currentPackageManager.js";
import { setEcoSystem, ECOSYSTEM_PY } from "../src/config/settings.js";
// Defaults
let packageManagerName = "pip";
// Pass through user args as-is
const argv = process.argv.slice(2);
import { setCurrentPipInvocation, PIP_INVOCATIONS, PIP_PACKAGE_MANAGER } from "../src/packagemanager/pip/pipSettings.js";
// Set eco system
// This can be used in other parts of the code to determine which eco system we are working with
setEcoSystem(ECOSYSTEM_PY);
initializePackageManager(packageManagerName);
var exitCode = await main(argv);
// Set current invocation
setCurrentPipInvocation(PIP_INVOCATIONS.PIP);
initializePackageManager(PIP_PACKAGE_MANAGER);
// Pass through only user-supplied pip args
var exitCode = await main(process.argv.slice(2));
process.exit(exitCode);

View file

@ -3,17 +3,17 @@
import { main } from "../src/main.js";
import { initializePackageManager } from "../src/packagemanager/currentPackageManager.js";
import { setEcoSystem, ECOSYSTEM_PY } from "../src/config/settings.js";
import { setCurrentPipInvocation, PIP_INVOCATIONS, PIP_PACKAGE_MANAGER } from "../src/packagemanager/pip/pipSettings.js";
// Explicit pip3 entrypoint
const packageManagerName = "pip3";
// Copy argv as-is
const argv = process.argv.slice(2);
// Set ecosystem to Python
// Set eco system
setEcoSystem(ECOSYSTEM_PY);
initializePackageManager(packageManagerName);
var exitCode = await main(argv);
// Set current invocation
setCurrentPipInvocation(PIP_INVOCATIONS.PIP3);
// Create package manager
initializePackageManager(PIP_PACKAGE_MANAGER);
// Pass through only user-supplied pip args
var exitCode = await main(process.argv.slice(2));
process.exit(exitCode);

View file

@ -1,22 +1,25 @@
#!/usr/bin/env node
import { initializePackageManager } from "../src/packagemanager/currentPackageManager.js";
import { setCurrentPipInvocation, PIP_INVOCATIONS, PIP_PACKAGE_MANAGER } from "../src/packagemanager/pip/pipSettings.js";
import { setEcoSystem, ECOSYSTEM_PY } from "../src/config/settings.js";
import { main } from "../src/main.js";
const argv = process.argv.slice(2);
// Set eco system
setEcoSystem(ECOSYSTEM_PY);
const supportedArgs = ["pip", "pip3"];
if (argv[0] === "-m" && argv[1] && supportedArgs.includes(argv[1])) {
// Strip '-m pip' or '-m pip3' from args if present
let argv = process.argv.slice(2);
if (argv[0] === '-m' && argv[1] === 'pip') {
setEcoSystem(ECOSYSTEM_PY);
initializePackageManager(argv[1]);
var exitCode = await main(argv.slice(2));
process.exit(exitCode);
setCurrentPipInvocation(PIP_INVOCATIONS.PY_PIP);
initializePackageManager(PIP_PACKAGE_MANAGER);
argv = argv.slice(2);
var exitCode = await main(argv);
process.exit(exitCode);
} else {
// Fallback: run the real python
const { spawn } = await import("child_process");
spawn("python", argv, { stdio: "inherit" });
// Forward to real python binary for non-pip flows
const { spawn } = await import('child_process');
spawn('python', argv, { stdio: 'inherit' });
}

View file

@ -1,22 +1,25 @@
#!/usr/bin/env node
import { initializePackageManager } from "../src/packagemanager/currentPackageManager.js";
import { setCurrentPipInvocation, PIP_INVOCATIONS, PIP_PACKAGE_MANAGER } from "../src/packagemanager/pip/pipSettings.js";
import { setEcoSystem, ECOSYSTEM_PY } from "../src/config/settings.js";
import { main } from "../src/main.js";
const argv = process.argv.slice(2);
// Set eco system
setEcoSystem(ECOSYSTEM_PY);
const supportedArgs = ["pip", "pip3"];
if (argv[0] === "-m" && argv[1] && supportedArgs.includes(argv[1])) {
// Strip nodejs and wrapper script from args
let argv = process.argv.slice(2);
if (argv[0] === '-m' && argv[1] === 'pip') {
setEcoSystem(ECOSYSTEM_PY);
// python3 -m pip or python3 -m pip3: always use pip3 package manager
initializePackageManager("pip3");
var exitCode = await main(argv.slice(2));
process.exit(exitCode);
setCurrentPipInvocation(PIP_INVOCATIONS.PY3_PIP);
initializePackageManager(PIP_PACKAGE_MANAGER);
// Strip '-m pip' or '-m pip3' from args if present
argv = argv.slice(2);
var exitCode = await main(argv);
process.exit(exitCode);
} else {
// Fallback: run the real python3
const { spawn } = await import("child_process");
spawn("python3", argv, { stdio: "inherit" });
// Forward to real python3 binary for non-pip flows
const { spawn } = await import('child_process');
spawn('python3', argv, { stdio: 'inherit' });
}

View file

@ -52,8 +52,8 @@ export function initializePackageManager(packageManagerName) {
state.packageManagerName = createBunPackageManager();
} else if (packageManagerName === "bunx") {
state.packageManagerName = createBunxPackageManager();
} else if (packageManagerName === "pip" || packageManagerName === "pip3") {
state.packageManagerName = createPipPackageManager(packageManagerName);
} else if (packageManagerName === "pip") {
state.packageManagerName = createPipPackageManager();
} else {
throw new Error("Unsupported package manager: " + packageManagerName);
}

View file

@ -1,12 +1,19 @@
import { runPip } from "./runPipCommand.js";
import { getCurrentPipInvocation } from "./pipSettings.js";
/**
* @param {string} [command]
* @returns {import("../currentPackageManager.js").PackageManager}
*/
export function createPipPackageManager(command = "pip") {
export function createPipPackageManager() {
return {
runCommand: /** @param {string[]} args */ (args) => runPip(command, args),
/**
* @param {string[]} args
*/
runCommand: (args) => {
const invocation = getCurrentPipInvocation();
const fullArgs = [...invocation.args, ...args];
console.debug('[safe-chain debug] runCommand:', invocation.command, fullArgs);
return runPip(invocation.command, fullArgs);
},
// For pip, rely solely on MITM proxy to detect/deny downloads from known registries.
isSupportedCommand: () => false,
getDependencyUpdatesForCommand: () => [],

View file

@ -0,0 +1,31 @@
// Constant for pip package manager name
export const PIP_PACKAGE_MANAGER = "pip";
// Enum of possible Python/pip invocations for Safe Chain interception
export const PIP_INVOCATIONS = {
PIP: { command: "pip", args: [] },
PIP3: { command: "pip3", args: [] },
PY_PIP: { command: "python", args: ["-m", "pip"] },
PY3_PIP: { command: "python3", args: ["-m", "pip"] }
};
/**
* @type {{ command: string, args: string[] }}
*/
let currentInvocation = PIP_INVOCATIONS.PY3_PIP; // Default to python3 -m pip
/**
* @param {{ command: string, args: string[] }} invocation
*/
export function setCurrentPipInvocation(invocation) {
console.debug('[safe-chain debug] setCurrentPipInvocation:', invocation);
currentInvocation = invocation;
}
/**
* @returns {{ command: string, args: string[] }}
*/
export function getCurrentPipInvocation() {
console.debug('[safe-chain debug] getCurrentPipInvocation:', currentInvocation);
return currentInvocation;
}

View file

@ -26,10 +26,10 @@ export async function runPip(command, args) {
});
return { status: result.status };
} catch (/** @type any */ error) {
ui.writeError("Error executing command:", error.message);
if (error.status) {
return { status: error.status };
} else {
ui.writeError("Error executing command:", error.message);
return { status: 1 };
}
}

View file

@ -142,10 +142,12 @@ function handleConnect(req, clientSocket, head) {
isKnownRegistry = knownPipRegistries.some((reg) => url.includes(reg));
}
// Debug: log CONNECT request URL and MITM/tunnel decision
ui.writeVerbose(`[Safe-chain debug] CONNECT request: url=${url}, ecosystem=${ecosystem}, isKnownRegistry=${isKnownRegistry}`);
if (isKnownRegistry) {
mitmConnect(req, clientSocket, isAllowedUrl);
} else {
// For other hosts, just tunnel the request to the destination tcp socket
ui.writeVerbose(`Safe-chain: Tunneling request to ${req.url}`);
tunnelRequest(req, clientSocket, head);
}