mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 20:20:49 +00:00
Fix python command returning -1 by selective wrapper interception and explicit bypass
This commit is contained in:
parent
14bb6899d8
commit
9417be1ac5
8 changed files with 354 additions and 44 deletions
|
|
@ -2,31 +2,13 @@ import { ui } from "../../environment/userInteraction.js";
|
|||
import { safeSpawn } from "../../utils/safeSpawn.js";
|
||||
import { mergeSafeChainProxyEnvironmentVariables } from "../../registryProxy/registryProxy.js";
|
||||
import { getCombinedCaBundlePath } from "../../registryProxy/certBundle.js";
|
||||
import { PIP_COMMAND, PIP3_COMMAND, PYTHON_COMMAND, PYTHON3_COMMAND } from "./pipSettings.js";
|
||||
import { PIP_COMMAND, PIP3_COMMAND } from "./pipSettings.js";
|
||||
import fs from "node:fs/promises";
|
||||
import fsSync from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import ini from "ini";
|
||||
|
||||
/**
|
||||
* Checks if this pip invocation should bypass safe-chain and spawn directly.
|
||||
* Returns true if the tool is python/python3 but NOT being run with -m pip/pip3.
|
||||
* @param {string} command - The command executable
|
||||
* @param {string[]} args - The arguments
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function shouldBypassSafeChain(command, args) {
|
||||
if (command === PYTHON_COMMAND || command === PYTHON3_COMMAND) {
|
||||
// Check if args start with -m pip
|
||||
if (args.length >= 2 && args[0] === "-m" && (args[1] === PIP_COMMAND || args[1] === PIP3_COMMAND)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets fallback CA bundle environment variables used by Python libraries.
|
||||
* These are applied in addition to the PIP_CONFIG_FILE to ensure all Python
|
||||
|
|
@ -73,23 +55,6 @@ function setFallbackCaBundleEnvironmentVariables(env, combinedCaPath) {
|
|||
* @returns {Promise<{status: number}>} Exit status of the pip command
|
||||
*/
|
||||
export async function runPip(command, args) {
|
||||
// Check if we should bypass safe-chain (python/python3 without -m pip)
|
||||
if (shouldBypassSafeChain(command, args)) {
|
||||
ui.writeVerbose(`Safe-chain: Bypassing safe-chain for non-pip invocation: ${command} ${args.join(" ")}`);
|
||||
// Spawn the ORIGINAL command with ORIGINAL args
|
||||
const { spawn } = await import("child_process");
|
||||
return new Promise((_resolve) => {
|
||||
const proc = spawn(command, args, { stdio: "inherit" });
|
||||
proc.on("exit", (/** @type {number | null} */ code) => {
|
||||
process.exit(code ?? 0);
|
||||
});
|
||||
proc.on("error", (/** @type {Error} */ err) => {
|
||||
ui.writeError(`Error executing command: ${err.message}`);
|
||||
process.exit(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const env = mergeSafeChainProxyEnvironmentVariables(process.env);
|
||||
|
||||
|
|
|
|||
|
|
@ -58,12 +58,22 @@ end
|
|||
|
||||
# `python -m pip`, `python -m pip3`.
|
||||
function python
|
||||
wrapSafeChainCommand "python" $argv
|
||||
# Intercept only `python -m pip|pip3`; otherwise call real python
|
||||
if test (count $argv) -ge 2; and test $argv[1] = "-m"; and (test $argv[2] = "pip" -o test $argv[2] = "pip3")
|
||||
wrapSafeChainCommand "python" $argv
|
||||
else
|
||||
command python $argv
|
||||
end
|
||||
end
|
||||
|
||||
# `python3 -m pip`, `python3 -m pip3'.
|
||||
function python3
|
||||
wrapSafeChainCommand "python3" $argv
|
||||
# Intercept only `python3 -m pip|pip3`; otherwise call real python3
|
||||
if test (count $argv) -ge 2; and test $argv[1] = "-m"; and (test $argv[2] = "pip" -o test $argv[2] = "pip3")
|
||||
wrapSafeChainCommand "python3" $argv
|
||||
else
|
||||
command python3 $argv
|
||||
end
|
||||
end
|
||||
|
||||
function printSafeChainWarning
|
||||
|
|
|
|||
|
|
@ -54,12 +54,22 @@ function poetry() {
|
|||
|
||||
# `python -m pip`, `python -m pip3`.
|
||||
function python() {
|
||||
wrapSafeChainCommand "python" "$@"
|
||||
# Intercept only `python -m pip|pip3`; otherwise run the real python to avoid loops/shadowing
|
||||
if [[ "$1" == "-m" && ( "$2" == "pip" || "$2" == "pip3" ) ]]; then
|
||||
wrapSafeChainCommand "python" "$@"
|
||||
else
|
||||
command python "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# `python3 -m pip`, `python3 -m pip3'.
|
||||
function python3() {
|
||||
wrapSafeChainCommand "python3" "$@"
|
||||
# Intercept only `python3 -m pip|pip3`; otherwise run the real python3
|
||||
if [[ "$1" == "-m" && ( "$2" == "pip" || "$2" == "pip3" ) ]]; then
|
||||
wrapSafeChainCommand "python3" "$@"
|
||||
else
|
||||
command python3 "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
function printSafeChainWarning() {
|
||||
|
|
|
|||
|
|
@ -56,12 +56,22 @@ function poetry {
|
|||
|
||||
# `python -m pip`, `python -m pip3`.
|
||||
function python {
|
||||
Invoke-WrappedCommand 'python' $args
|
||||
# Intercept only `python -m pip|pip3`; otherwise invoke real python
|
||||
if (($args.Length -ge 2) -and ($args[0] -eq '-m') -and (($args[1] -eq 'pip') -or ($args[1] -eq 'pip3'))) {
|
||||
Invoke-WrappedCommand 'python' $args
|
||||
} else {
|
||||
Invoke-RealCommand 'python' $args
|
||||
}
|
||||
}
|
||||
|
||||
# `python3 -m pip`, `python3 -m pip3'.
|
||||
function python3 {
|
||||
Invoke-WrappedCommand 'python3' $args
|
||||
# Intercept only `python3 -m pip|pip3`; otherwise invoke real python3
|
||||
if (($args.Length -ge 2) -and ($args[0] -eq '-m') -and (($args[1] -eq 'pip') -or ($args[1] -eq 'pip3'))) {
|
||||
Invoke-WrappedCommand 'python3' $args
|
||||
} else {
|
||||
Invoke-RealCommand 'python3' $args
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue