Skip to content

Commit

Permalink
[python]-setuptools-GHSA-r9hx-vwmv-q579-remove setuptools-65.5.0-py3-…
Browse files Browse the repository at this point in the history
…none-any.whl (#866)

* [python]-setuptools-GHSA-r9hx-vwmv-q579-remove setuptools-65.5.0-py3-none-any.whl

* changes based on comments on pr #866

* Tried to answer acc. to last comment

* Added tests to validate when skipVulnerabilityPatching=true
  • Loading branch information
gauravsaini04 authored Feb 22, 2024
1 parent 7d807c2 commit 01aad64
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 31 deletions.
2 changes: 1 addition & 1 deletion src/python/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "python",
"version": "1.4.0",
"version": "1.4.1",
"name": "Python",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/python",
"description": "Installs the provided version of Python, as well as PIPX, and other common Python utilities. JupyterLab is conditionally installed with the python feature. Note: May require source code compilation.",
Expand Down
41 changes: 35 additions & 6 deletions src/python/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

PYTHON_VERSION="${VERSION:-"latest"}" # 'system' or 'os-provided' checks the base image first, else installs 'latest'
INSTALL_PYTHON_TOOLS="${INSTALLTOOLS:-"true"}"
SKIP_VULNERABILITY_PATCHING="${SKIPVULNERABILITYPATCHING:-"false"}"
OPTIMIZE_BUILD_FROM_SOURCE="${OPTIMIZE:-"false"}"
ENABLE_SHARED_FROM_SOURCE="${ENABLESHARED:-"false"}"
PYTHON_INSTALL_PATH="${INSTALLPATH:-"/usr/local/python"}"
Expand Down Expand Up @@ -750,12 +751,40 @@ if [[ "${INSTALL_PYTHON_TOOLS}" = "true" ]] && [[ -n "${PYTHON_SRC}" ]]; then
done

# Temporary: Removes “setup tools” metadata directory due to https://github.com/advisories/GHSA-r9hx-vwmv-q579

VULNERABLE_VERSIONS=("3.10" "3.11")
RUN_TIME_PY_VER_DETECT=$(${PYTHON_SRC} --version 2>&1)
PY_MAJOR_MINOR_VER=${RUN_TIME_PY_VER_DETECT:7:4};
if [[ ${VULNERABLE_VERSIONS[*]} =~ $PY_MAJOR_MINOR_VER ]]; then
rm -rf ${PIPX_HOME}/shared/lib/"python${PY_MAJOR_MINOR_VER}"/site-packages/setuptools-65.5.0.dist-info
if [[ $SKIP_VULNERABILITY_PATCHING = "false" ]]; then
VULNERABLE_VERSIONS=("3.10" "3.11")
RUN_TIME_PY_VER_DETECT=$(${PYTHON_SRC} --version 2>&1)
PY_MAJOR_MINOR_VER=${RUN_TIME_PY_VER_DETECT:7:4};
if [[ ${VULNERABLE_VERSIONS[*]} =~ $PY_MAJOR_MINOR_VER ]]; then
rm -rf ${PIPX_HOME}/shared/lib/"python${PY_MAJOR_MINOR_VER}"/site-packages/setuptools-65.5.0.dist-info
if [[ -e "/usr/local/lib/python${PY_MAJOR_MINOR_VER}/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl" ]]; then
# remove the vulnerable setuptools-65.5.0-py3-none-any.whl file
rm /usr/local/lib/python${PY_MAJOR_MINOR_VER}/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl
# create and change to the setuptools_downloaded directory
mkdir -p /tmp/setuptools_downloaded
cd /tmp/setuptools_downloaded
# download the source distribution for setuptools using pip
pip download setuptools==65.5.1 --no-binary :all:
# extract the filename of the setuptools-*.tar.gz file
filename=$(find . -maxdepth 1 -type f)
# create a directory to store unpacked contents of the source distribution
mkdir -p /tmp/setuptools_src_dist
# extract the contents inside the new directory
tar -xzf $filename -C /tmp/setuptools_src_dist
# move to the setuptools-* directory inside /setuptools_src_dist
cd /tmp/setuptools_src_dist/setuptools-65.5.1/
# look for setup.py file in the current directory and create a wheel file
python setup.py bdist_wheel
# move inside the dist directory in pwd
cd dist
# copy this file to the ensurepip/_bundled directory
cp setuptools-65.5.1-py3-none-any.whl /usr/local/lib/python${PY_MAJOR_MINOR_VER}/ensurepip/_bundled/
# replace the version in __init__.py file with the installed version
sed -i 's/_SETUPTOOLS_VERSION = \"65\.5\.0\"/_SETUPTOOLS_VERSION = "65.5.1"/g' /usr/local/lib/"python${PY_MAJOR_MINOR_VER}"/ensurepip/__init__.py
# cleanup created dir's
rm -rf /tmp/setuptools_downloaded /tmp/setuptools_src_dist
fi
fi
fi

rm -rf /tmp/pip-tmp
Expand Down
51 changes: 40 additions & 11 deletions test/python/install_python310_setuptools_vulnerability.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,51 @@ check "which pydocstyle" bash -c "which pydocstyle | grep /usr/local/py-utils/bi
check "which pylint" bash -c "which pylint | grep /usr/local/py-utils/bin/pylint"
check "which pytest" bash -c "which pytest | grep /usr/local/py-utils/bin/pytest"
checkVulnerableDir()
checkVulnerableFile_OR_DIR()
{
DIRECTORY=$1
VERSION=$2
if [[ -d $DIRECTORY ]] ; then
echoStderr "❌ check for vulnerable setuptools version failed for python ${VERSION}."
return 1
for arg in "$@"; do
if [[ -e $arg ]]; then
echo -e "\n✅ Vulnerable:- ${arg} - exists in v3.10 as Vulnerability Patching has been skipped."
else
echo -e "\n❌ Vulnerable:- ${arg} - don't exist in v3.10 as Vulnerability Patching has not been skipped."
fi
done
}
# print setuptools
check "Show All Files/Folders which include setuptools" bash -c 'find / -name "*setuptools*"'
# only for 3.10
checkVulnerableFile_OR_DIR "/usr/local/py-utils/shared/lib/python3.10/site-packages/setuptools-65.5.0.dist-info" "/usr/local/lib/python3.10/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl"
# Function to check if a package is installed
checkPackageInstalled() {
if python -c "import $1" &>/dev/null; then
echo -e "\n✅ Passed! \n$1 is installed"
else
echo "✅ Passed! Either the container does not have vulnerable version or vulnerable version specific directory got removed."
return 0
echo -e "$1 is NOT installed\n"
echoStderr "❌ check failed."
fi
}
# only for 3.10
checkVulnerableDir "/usr/local/py-utils/shared/lib/python3.10/site-packages/setuptools-65.5.0.dist-info" "3.10"
# Function to install a package using pip
installPackage() {
python3 -m pip install "$1"
}
checkPipWorkingCorrectly() {
echo -e "\n🧪 Testing whether pip install works fine \n"
# List of packages to install via pip
packages=("numpy" "requests" "matplotlib")
# Install packages and check if installation was successful
for package in "${packages[@]}"; do
echo -e "\n🧪 Testing pip install $package\n"
installPackage "$package"
checkPackageInstalled "$package"
done
}
checkPipWorkingCorrectly
# Report result
reportResults
117 changes: 117 additions & 0 deletions test/python/install_python310_skipVulnerabilityPatching_true.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/bin/bash
set -e

# Optional: Import test library
source dev-container-features-test-lib

FAILED=()

echoStderr()
{
echo "$@" 1>&2
}

check-version-ge() {
LABEL=$1
CURRENT_VERSION=$2
REQUIRED_VERSION=$3
shift
echo -e "\n🧪 Testing $LABEL: '$CURRENT_VERSION' is >= '$REQUIRED_VERSION'"
local GREATER_VERSION=$((echo ${CURRENT_VERSION}; echo ${REQUIRED_VERSION}) | sort -V | tail -1)
if [ "${CURRENT_VERSION}" == "${GREATER_VERSION}" ]; then
echo "✅ Passed!"
return 0
else
echoStderr "❌ $LABEL check failed."
FAILED+=("$LABEL")
return 1
fi
}
checkPythonPackageVersion()
{
PACKAGE=$1
REQUIRED_VERSION=$2
current_version=$(python -c "import importlib.metadata; print(importlib.metadata.version('${PACKAGE}'))")
check-version-ge "${PACKAGE}-requirement" "${current_version}" "${REQUIRED_VERSION}"
}
checkPythonPackageVersion "setuptools" "65.5.1"
# Check that tools can execute - make sure something didn't get messed up in this scenario
check "autopep8" autopep8 --version
check "black" black --version
check "yapf" yapf --version
check "bandit" bandit --version
check "flake8" flake8 --version
check "mypy" mypy --version
check "pycodestyle" pycodestyle --version
check "pydocstyle" pydocstyle --version
check "pylint" pylint --version
check "pytest" pytest --version
check "setuptools" pip list | grep setuptools
# Check paths in settings
check "which autopep8" bash -c "which autopep8 | grep /usr/local/py-utils/bin/autopep8"
check "which black" bash -c "which black | grep /usr/local/py-utils/bin/black"
check "which yapf" bash -c "which yapf | grep /usr/local/py-utils/bin/yapf"
check "which bandit" bash -c "which bandit | grep /usr/local/py-utils/bin/bandit"
check "which flake8" bash -c "which flake8 | grep /usr/local/py-utils/bin/flake8"
check "which mypy" bash -c "which mypy | grep /usr/local/py-utils/bin/mypy"
check "which pycodestyle" bash -c "which pycodestyle | grep /usr/local/py-utils/bin/pycodestyle"
check "which pydocstyle" bash -c "which pydocstyle | grep /usr/local/py-utils/bin/pydocstyle"
check "which pylint" bash -c "which pylint | grep /usr/local/py-utils/bin/pylint"
check "which pytest" bash -c "which pytest | grep /usr/local/py-utils/bin/pytest"
HL="\033[1;33m"
N="\033[0;37m"
checkVulnerableFile_OR_DIR()
{
for arg in "$@"; do
if [[ -e $arg ]]; then
echo -e "\n${HL} Vulnerable:- ${N}${arg} - ${HL}EXISTS ${N}in v3.10 as skipVulnerabilityPatching=true"
else
echo -e "\n${HL} Vulnerable:- ${arg} - ${N}don't ${HL}EXISTS ${N}in v3.10 as skipVulnerabilityPatching=false"
fi
done
}
# print setuptools
check "Show All Files/Folders which include setuptools" bash -c 'find / -name "*setuptools*"'
# only for 3.10
checkVulnerableFile_OR_DIR "/usr/local/py-utils/shared/lib/python3.10/site-packages/setuptools-65.5.0.dist-info" "/usr/local/lib/python3.10/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl"
# Function to check if a package is installed
checkPackageInstalled() {
if python -c "import $1" &>/dev/null; then
echo -e "\n✅ Passed! \n$1 is installed"
else
echo -e "$1 is NOT installed\n"
echoStderr "❌ check failed."
fi
}
# Function to install a package using pip
installPackage() {
python3 -m pip install "$1"
}
checkPipWorkingCorrectly() {
echo -e "\n🧪 Testing whether pip install works fine \n"
# List of packages to install via pip
packages=("numpy" "requests" "matplotlib")
# Install packages and check if installation was successful
for package in "${packages[@]}"; do
echo -e "\n🧪 Testing pip install $package\n"
installPackage "$package"
checkPackageInstalled "$package"
done
}
checkPipWorkingCorrectly
# Report result
reportResults
51 changes: 40 additions & 11 deletions test/python/install_python311_setuptools_vulnerability.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,51 @@ check "which pydocstyle" bash -c "which pydocstyle | grep /usr/local/py-utils/bi
check "which pylint" bash -c "which pylint | grep /usr/local/py-utils/bin/pylint"
check "which pytest" bash -c "which pytest | grep /usr/local/py-utils/bin/pytest"
checkVulnerableDir()
checkVulnerableFile_OR_DIR()
{
DIRECTORY=$1
VERSION=$2
if [[ -d $DIRECTORY ]] ; then
echoStderr "❌ check for vulnerable setuptools version failed for python ${VERSION}."
return 1
for arg in "$@"; do
if [[ -e $arg ]]; then
echo -e "\n✅ Vulnerable:- ${arg} - exists in v3.11 as Vulnerability Patching has been skipped."
else
echo -e "\n❌ Vulnerable:- ${arg} - don't exist in v3.11 as Vulnerability Patching has not been skipped."
fi
done
}
# print setuptools
check "Show All Files/Folders which include setuptools" bash -c 'find / -name "*setuptools*"'
# only for 3.11
checkVulnerableFile_OR_DIR "/usr/local/py-utils/shared/lib/python3.11/site-packages/setuptools-65.5.0.dist-info" "/usr/local/lib/python3.11/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl"
# Function to check if a package is installed
checkPackageInstalled() {
if python -c "import $1" &>/dev/null; then
echo -e "\n✅ Passed! \n$1 is installed"
else
echo "✅ Passed! Either the container does not have vulnerable version or vulnerable version specific directory got removed."
return 0
echo -e "$1 is NOT installed\n"
echoStderr "❌ check failed."
fi
}
# only for 3.11
checkVulnerableDir "/usr/local/py-utils/shared/lib/python3.11/site-packages/setuptools-65.5.0.dist-info" "3.11"
# Function to install a package using pip
installPackage() {
python3 -m pip install "$1"
}
checkPipWorkingCorrectly() {
echo -e "\n🧪 Testing whether pip install works fine \n"
# List of packages to install via pip
packages=("numpy" "requests" "matplotlib")
# Install packages and check if installation was successful
for package in "${packages[@]}"; do
echo -e "\n🧪 Testing pip install $package\n"
installPackage "$package"
checkPackageInstalled "$package"
done
}
checkPipWorkingCorrectly
# Report result
reportResults
16 changes: 14 additions & 2 deletions test/python/scenarios.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
{
"install_python310_skipVulnerabilityPatching_true": {
"image": "python:3.10",
"features": {
"python": {
"version": "none",
"installTools": true,
"skipVulnerabilityPatching": true
}
}
},
"install_python310_setuptools_vulnerability": {
"image": "python:3.10",
"features": {
"python": {
"version": "none",
"installTools": true
"installTools": true,
"skipVulnerabilityPatching": false
}
}
},
Expand All @@ -13,7 +24,8 @@
"features": {
"python": {
"version": "none",
"installTools": true
"installTools": true,
"skipVulnerabilityPatching": false
}
}
},
Expand Down

0 comments on commit 01aad64

Please sign in to comment.