Unverified Commit c1df45b1 authored by Prabhakar Kumar's avatar Prabhakar Kumar Committed by GitHub

Adds /home/USER/.local/bin/ to PATH in /etc/sudoers.d/vscode, (#887)

* Adds /home/USER/.local/bin/ to PATH in /etc/sudoers.d/vscode,  fixes devcontainers/features#870

* Bumping up version to 1.4.2

* Adds to sudoers file if already present

* Tests to ensure Default secure_path is not overwritten

* Bump to version 1.4.4

* Fix version as 1.4.3
Co-authored-by: 's avatarSamruddhi Khandale <samruddhikhandale@github.com>

* Update src/python/install.sh
Co-authored-by: 's avatarPrabhakar Kumar <64955767+prabhakk-mw@users.noreply.github.com>

* Update src/python/devcontainer-feature.json

---------
Co-authored-by: 's avatarSamruddhi Khandale <samruddhikhandale@github.com>
Co-authored-by: 's avatarSamruddhi Khandale <skhandale@microsoft.com>
parent 32797f4f
{
"id": "python",
"version": "1.5.0",
"version": "1.6.0",
"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.",
......
......@@ -130,7 +130,7 @@ updaterc() {
fi
}
# Import the specified key in a variable name passed in as
# Import the specified key in a variable name passed in as
receive_gpg_keys() {
local keys=${!1}
local keyring_args=""
......@@ -152,7 +152,7 @@ receive_gpg_keys() {
local retry_count=0
local gpg_ok="false"
set +e
until [ "${gpg_ok}" = "true" ] || [ "${retry_count}" -eq "5" ];
until [ "${gpg_ok}" = "true" ] || [ "${retry_count}" -eq "5" ];
do
echo "(*) Downloading GPG key..."
( echo "${keys}" | xargs -n 1 gpg -q ${keyring_args} --recv-keys) 2>&1 && gpg_ok="true"
......@@ -222,7 +222,7 @@ find_version_from_git_tags() {
local repository=$2
local prefix=${3:-"tags/v"}
local separator=${4:-"."}
local last_part_optional=${5:-"false"}
local last_part_optional=${5:-"false"}
if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then
local escaped_separator=${separator//./\\.}
local last_part
......@@ -282,7 +282,7 @@ find_prev_version_from_git_tags() {
((breakfix=breakfix-1))
if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then
declare -g ${variable_name}="${major}.${minor}"
else
else
declare -g ${variable_name}="${major}.${minor}.${breakfix}"
fi
fi
......@@ -378,13 +378,13 @@ check_packages() {
add_symlink() {
if [[ ! -d "${CURRENT_PATH}" ]]; then
ln -s -r "${INSTALL_PATH}" "${CURRENT_PATH}"
ln -s -r "${INSTALL_PATH}" "${CURRENT_PATH}"
fi
if [ "${OVERRIDE_DEFAULT_VERSION}" = "true" ]; then
if [[ $(ls -l ${CURRENT_PATH}) != *"-> ${INSTALL_PATH}"* ]] ; then
rm "${CURRENT_PATH}"
ln -s -r "${INSTALL_PATH}" "${CURRENT_PATH}"
ln -s -r "${INSTALL_PATH}" "${CURRENT_PATH}"
fi
fi
}
......@@ -397,7 +397,7 @@ install_openssl3() {
openssl3_version="3.0"
# Find version using soft match
find_version_from_git_tags openssl3_version "https://github.com/openssl/openssl" "openssl-"
local tgz_filename="openssl-${openssl3_version}.tar.gz"
local tgz_filename="openssl-${openssl3_version}.tar.gz"
local tgz_url="https://github.com/openssl/openssl/releases/download/openssl-${openssl3_version}/${tgz_filename}"
echo "Downloading ${tgz_filename}..."
curl -sSL -o "/tmp/openssl3/${tgz_filename}" "${tgz_url}"
......@@ -434,7 +434,7 @@ install_cpython() {
}
install_from_source() {
VERSION=$1
VERSION=$1
echo "(*) Building Python ${VERSION} from source..."
if ! type git > /dev/null 2>&1; then
check_packages git
......@@ -444,7 +444,7 @@ install_from_source() {
find_version_from_git_tags VERSION "https://github.com/python/cpython"
# Some platforms/os versions need modern versions of openssl installed
# via common package repositories, for now rhel-7 family, use case statement to
# via common package repositories, for now rhel-7 family, use case statement to
# make it easy to expand
case ${VERSION_CODENAME} in
centos7|rhel7)
......@@ -455,7 +455,7 @@ install_from_source() {
esac
install_cpython "${VERSION}"
if [ -f "/tmp/python-src/${cpython_tgz_filename}" ]; then
if [ -f "/tmp/python-src/${cpython_tgz_filename}" ]; then
if grep -q "404 Not Found" "/tmp/python-src/${cpython_tgz_filename}"; then
install_prev_vers_cpython "${VERSION}"
fi
......@@ -512,9 +512,9 @@ install_from_source() {
}
install_using_oryx() {
VERSION=$1
VERSION=$1
INSTALL_PATH="${PYTHON_INSTALL_PATH}/${VERSION}"
if [ -d "${INSTALL_PATH}" ]; then
echo "(!) Python version ${VERSION} already exists."
exit 1
......@@ -727,7 +727,7 @@ if [ "${PYTHON_VERSION}" != "none" ]; then
usermod -a -G python "${USERNAME}"
CURRENT_PATH="${PYTHON_INSTALL_PATH}/current"
install_python ${PYTHON_VERSION}
# Additional python versions to be installed but not be set as default.
......@@ -748,7 +748,7 @@ if [ "${PYTHON_VERSION}" != "none" ]; then
updaterc "if [[ \"\${PATH}\" != *\"${CURRENT_PATH}/bin\"* ]]; then export PATH=${CURRENT_PATH}/bin:\${PATH}; fi"
PATH="${INSTALL_PATH}/bin:${PATH}"
fi
# Updates the symlinks for os-provided, or the installed python version in other cases
chown -R "${USERNAME}:python" "${PYTHON_INSTALL_PATH}"
chmod -R g+r+w "${PYTHON_INSTALL_PATH}"
......@@ -776,7 +776,7 @@ if [[ "${INSTALL_PYTHON_TOOLS}" = "true" ]] && [[ -n "${PYTHON_SRC}" ]]; then
umask 0002
mkdir -p ${PIPX_BIN_DIR}
chown -R "${USERNAME}:pipx" ${PIPX_HOME}
chmod -R g+r+w "${PIPX_HOME}"
chmod -R g+r+w "${PIPX_HOME}"
find "${PIPX_HOME}" -type d -print0 | xargs -0 -n 1 chmod g+s
# Update pip if not using os provided python
......@@ -805,21 +805,21 @@ if [[ "${INSTALL_PYTHON_TOOLS}" = "true" ]] && [[ -n "${PYTHON_SRC}" ]]; then
echo "${util} already installed. Skipping."
fi
done
# Temporary: Removes “setup tools” metadata directory due to https://github.com/advisories/GHSA-r9hx-vwmv-q579
if [[ $SKIP_VULNERABILITY_PATCHING = "false" ]]; then
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
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
# 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)
......@@ -833,7 +833,7 @@ if [[ "${INSTALL_PYTHON_TOOLS}" = "true" ]] && [[ -n "${PYTHON_SRC}" ]]; then
python setup.py bdist_wheel
# move inside the dist directory in pwd
cd dist
# copy this file to the ensurepip/_bundled directory
# 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
......@@ -865,6 +865,23 @@ if [ "${INSTALL_JUPYTERLAB}" = "true" ]; then
install_user_package $INSTALL_UNDER_ROOT jupyterlab
install_user_package $INSTALL_UNDER_ROOT jupyterlab-git
if [ "$INSTALL_UNDER_ROOT" = false ]; then
# JupyterLab would have installed into /home/${USERNAME}/.local/bin
# Adding it to default path for Codespaces which use non-login shells
SUDOERS_FILE="/etc/sudoers.d/$USERNAME"
SEARCH_STR="Defaults secure_path="
REPLACE_STR="Defaults secure_path=/home/${USERNAME}/.local/bin"
if grep -qs ${SEARCH_STR} ${SUDOERS_FILE}; then
# string found and file is present
sed -i "s|${SEARCH_STR}|${REPLACE_STR}:|g" "${SUDOERS_FILE}"
else
# either string is not found, or file is not present
# In either case take same action, note >> places at end of file
echo "${REPLACE_STR}:${PATH}" >> ${SUDOERS_FILE}
fi
fi
# Configure JupyterLab if needed
if [ -n "${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN}" ]; then
# Resolve config directory
......
......@@ -22,5 +22,8 @@ check "jupyterlab_git" grep jupyterlab_git <<< "$packages"
# Check for correct JupyterLab configuration
check "config" grep ".*.allow_origin = '*'" /home/vscode/.jupyter/jupyter_server_config.py
# Check for PATH modification
check "default path has jupyterlab" sudo grep "/home/${user}/.local/bin" /etc/sudoers.d/$user
# Report result
reportResults
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
# Always run these checks as the non-root user
user="$(whoami)"
check "user" grep vscode <<< "$user"
# Check for an installation of JupyterLab
check "version" jupyter lab --version
# Check location of JupyterLab installation
packages="$(python3 -m pip list)"
check "location" grep jupyter <<< "$packages"
# Check for git extension
check "jupyterlab_git" grep jupyterlab_git <<< "$packages"
# Check for correct JupyterLab configuration
check "config" grep ".*.allow_origin = '*'" /home/vscode/.jupyter/jupyter_server_config.py
# Check for PATH modification
check "default path has jupyterlab" grep "Defaults secure_path=/home/${user}/.local/bin" /etc/sudoers.d/$user
# Check if previous PATH exists
check "existing default path is preserved" grep "Defaults secure_path=.*original_content_of_sudoers_file" /etc/sudoers.d/$user
# Check if PATH modification includes original and new paths
check "existing path included with jupyterlab" grep "Defaults secure_path.*/home/${user}/.local/bin.*original_content_of_sudoers_file" /etc/sudoers.d/$user
# Report result
reportResults
# Builds an image with a preconfigured SUDOERS file
# Used to test the install script for JupyterLab which modifies this file
FROM mcr.microsoft.com/devcontainers/base:focal
COPY --chown=root sudoers.test /etc/sudoers.d/vscode
# Sudoers File for testing, after install script runs the Defaults secure_path should be appended to
Defaults secure_path=/original_content_of_sudoers_file
\ No newline at end of file
......@@ -68,6 +68,19 @@
}
}
},
"install_jupyterlab_existing_sudoers_file": {
"build": {
"dockerfile": "Dockerfile"
},
"remoteUser": "vscode",
"features": {
"python": {
"version": "latest",
"installJupyterlab": true,
"configureJupyterlabAllowOrigin": "*"
}
}
},
"install_jupyterlab_rhel_family": {
"image": "almalinux:8",
"remoteUser": "vscode",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment