Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Comment thread
samruddhikhandale marked this conversation as resolved.
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
Comment thread
samruddhikhandale marked this conversation as resolved.
}
}
},
Expand Down