From 0f7fd33c53e7fd20b07ae37be1fb3b26c152d2c3 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 17 Mar 2017 17:49:00 +0000 Subject: [PATCH] Issue #174: Add new program GRoot and change version option for JuNest! This replaces jchroot because GRoot can be also used in a user namespace environment. --- README.md | 4 +- bin/groot | 180 ++++++++++++++++++ bin/jchroot | 98 ---------- bin/junest | 20 +- lib/core/build.sh | 4 +- lib/core/common.sh | 9 +- lib/core/namespace.sh | 14 +- lib/utils/utils.sh | 14 ++ tests/unit-tests/test-common.sh | 20 +- tests/unit-tests/test-groot.sh | 137 +++++++++++++ .../{test-cli.sh => test-junest.sh} | 115 +++++------ tests/unit-tests/test-utils.sh | 22 +++ tests/utils/utils.sh | 5 +- 13 files changed, 458 insertions(+), 184 deletions(-) create mode 100755 bin/groot delete mode 100755 bin/jchroot create mode 100755 tests/unit-tests/test-groot.sh rename tests/unit-tests/{test-cli.sh => test-junest.sh} (66%) diff --git a/README.md b/README.md index 98f0c9e..e747c4e 100644 --- a/README.md +++ b/README.md @@ -169,14 +169,14 @@ Internals There are two main chroot jail used in JuNest. The main one is [proot](https://wiki.archlinux.org/index.php/Proot) which allows unprivileged users to execute programs inside a sandbox and -jchroot, a small and portable version of +GRoot, a small and portable version of [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) which is an enhanced chroot for privileged users that mounts the primary directories (i.e. /proc, /sys, /dev and /run) before executing any programs inside the sandbox. ## Automatic fallback to classic chroot ## -If jchroot fails for some reasons in the host system (i.e. it is not able to +If GRoot fails for some reasons in the host system (i.e. it is not able to mount one of the directories), JuNest automatically tries to fallback to the classic chroot. diff --git a/bin/groot b/bin/groot new file mode 100755 index 0000000..1d6e26b --- /dev/null +++ b/bin/groot @@ -0,0 +1,180 @@ +#!/bin/bash +# +# This script is the simplified and portable version of arch-chroot +# (https://wiki.archlinux.org/index.php/Change_root#Using_arch-chroot) +# + +set -e + +# JUNEST_BASE can be overridden for testing purposes. +# There is no need for doing it for normal usage. +JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/..)}" +NAME='GRoot' +CMD='groot' +DESCRIPTION="I am $NAME!" +CHROOTCMD=${CHROOTCMD:-chroot} +SHELL="/bin/sh" +MOUNT=mount +UMOUNT=umount +MOUNTPOINT=mountpoint +MKDIR=mkdir +TOUCH=touch + +NOT_EXISTING_FILE=103 +NOT_ABSOLUTE_PATH=111 +NO_ROOT_PRIVILEGES=110 + +source "${JUNEST_BASE}/lib/utils/utils.sh" + + +################################ MAIN FUNCTIONS ########################### + +function chroot_add_mount() { + $MOUNT "$@" && CHROOT_ACTIVE_MOUNTS=("${@: -1}" "${CHROOT_ACTIVE_MOUNTS[@]}") +} + +function chroot_teardown() { + $UMOUNT "${CHROOT_ACTIVE_MOUNTS[@]}" + unset CHROOT_ACTIVE_MOUNTS +} + +function chroot_maybe_add_mount() { + local cond=$1 + shift + if eval "$cond"; then + chroot_add_mount "$@" + return + fi + return 1 +} + +function chroot_setup() { + CHROOT_ACTIVE_MOUNTS=() + check_and_trap 'chroot_teardown' EXIT + + if ! chroot_maybe_add_mount "! $MOUNTPOINT -q '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR" + then + warn "Failed mount of directories. $CHROOTDIR is already a mountpoint. Skipping it..." + return 0 + fi + + local re='(.*):(.*)' + for binds in ${BINDINGS[@]} + do + local host_path="" + local guest_path="" + if [[ $binds =~ $re ]] + then + local host_path="${BASH_REMATCH[1]}" + local guest_path="${BASH_REMATCH[2]}" + else + local host_path="$binds" + local guest_path="$binds" + fi + + create_node "${host_path}" "${CHROOTDIR}${guest_path}" + chroot_add_mount --rbind "${host_path}" "${CHROOTDIR}${guest_path}" + done +} + +function create_node() { + local src="$1" + local dst="$2" + if [[ ! -e $src ]] + then + die_on_status $NOT_EXISTING_FILE "${src} does not exist." + elif [[ $src != /* ]] + then + die_on_status $NOT_ABSOLUTE_PATH "${src} is not an absolute path." + elif [[ -f $src ]] + then + $TOUCH "$dst" + elif [[ -d $src ]] + then + $MKDIR -p "$dst" + fi +} + +function usage() { + cat < [command]] + +Options: + -b, --bind + Make the content of accessible in the guest rootfs. + + This option makes any file or directory of the host rootfs + accessible in the confined environment just as if it were part of + the guest rootfs. By default the host path is bound to the same + path in the guest rootfs but users can specify any other location + with the syntax: -b :. This option can + be invoked multiple times and the paths specified must be absolutes. + + -h, --help Print this help message + + -V, --version Show the $NAME version + +If 'command' is unspecified, $CMD will launch $SHELL. + +EOF +} + +version() { + echo -e "$NAME $(cat $JUNEST_BASE/VERSION)" +} + +function parse_arguments() { + OPT_BIND=false + BINDINGS=() + OPT_HELP=false + OPT_VERSION=false + for opt in "$@" + do + case "$1" in + -b|--bind) OPT_BIND=true ; shift ; BINDINGS+=("$1") ; shift ;; + -h|--help) OPT_HELP=true ; shift ;; + -V|--version) OPT_VERSION=true ; shift ;; + -*) die "Invalid option $1" ;; + *) break ;; + esac + done + + if [[ ! -z $1 ]] + then + CHROOTDIR="$1" + shift + fi + ARGS=() + for arg in "$@" + do + ARGS+=("$arg") + done +} + +function is_user_root() { + (( EUID == 0 )) +} + +function execute_operation() { + $OPT_HELP && usage && return + $OPT_VERSION && version && return + + is_user_root || die_on_status $NO_ROOT_PRIVILEGES 'This script must be run with root privileges' + + [[ -d $CHROOTDIR ]] || die_on_status $NOT_EXISTING_FILE "Can't create chroot on non-directory $CHROOTDIR" + + chroot_setup "$CHROOTDIR" || die "Failed to setup chroot $CHROOTDIR" + + $CHROOTCMD "$CHROOTDIR" "${ARGS[@]}" +} + + +function main() { + parse_arguments "$@" + execute_operation +} + +main "$@" diff --git a/bin/jchroot b/bin/jchroot deleted file mode 100755 index fe43661..0000000 --- a/bin/jchroot +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash -# -# This script is the simplified and portable version of arch-chroot -# (https://wiki.archlinux.org/index.php/Change_root#Using_arch-chroot) -# - -set -e - -JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)" - -source "${JUNEST_BASE}/lib/utils/utils.sh" - -################################ MAIN FUNCTIONS ########################### - -chroot_add_mount() { - mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}") -} - -chroot_maybe_add_mount() { - local cond=$1; shift - if eval "$cond"; then - chroot_add_mount "$@" - fi -} - -chroot_setup() { - CHROOT_ACTIVE_MOUNTS=() - [[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap' - trap 'chroot_teardown' EXIT - - chroot_maybe_add_mount "! mountpoint -q '$1'" "$1" "$1" --bind && - chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev && - chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro && - chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid && - chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec && - chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev && - chroot_add_mount run "$1/run" -t tmpfs -o nosuid,nodev,mode=0755 && - chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,atime,nodev,nosuid && - mkdir -p "$1/$HOME" && - chroot_add_mount $HOME "$1/$HOME" --bind - - mkdir -p "$1/run/lock" -} - -chroot_teardown() { - umount "${CHROOT_ACTIVE_MOUNTS[@]}" - unset CHROOT_ACTIVE_MOUNTS -} - -usage() { - cat < Arguments for backend program (PRoot or jchroot)" + echo -e "-r, --root Run $NAME with root privileges via GRoot" + echo -e "-p, --backend-args Arguments for backend program (PRoot or GRoot)" echo -e " ($CMD -p \"--help\" to check out the PRoot options" - echo -e " $CMD -u -p \"--help\" to check out the jchroot options)" + echo -e " $CMD -u -p \"--help\" to check out the GRoot options)" echo -e "-u, --user-namespace Use Linux User Namespace instead of PRoot" echo echo -e "Building options:" @@ -47,7 +51,7 @@ usage() { echo echo -e "General options:" echo -e "-h, --help Show this help message" - echo -e "-v, --version Show the $NAME version" + echo -e "-V, --version Show the $NAME version" } version() { @@ -169,7 +173,7 @@ function parse_arguments(){ -s|--skip-root-tests) OPT_SKIP_ROOT_TEST=true ; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; -h|--help) OPT_HELP=true ; shift ;; - -v|--version) OPT_VERSION=true ; shift ;; + -V|--version) OPT_VERSION=true ; shift ;; --) shift ; break ;; -*) die "Invalid option $1" ;; *) break ;; @@ -231,11 +235,11 @@ function execute_operation(){ } -function cli() { +function main() { parse_arguments "$@" check_cli execute_operation } -cli "$@" +main "$@" # vim: set ts=4 sw=4 noet: diff --git a/lib/core/build.sh b/lib/core/build.sh index 017ccad..fd87d86 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -69,11 +69,11 @@ function build_image_env(){ # sed command is required for locale-gen sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" - sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root locale-gen + sudo ${maindir}/root/opt/junest/bin/groot ${maindir}/root locale-gen sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" info "Setting up the pacman keyring (this might take a while!)..." - sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root bash -c \ + sudo ${maindir}/root/opt/junest/bin/groot ${maindir}/root bash -c \ "pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" sudo rm ${maindir}/root/var/cache/pacman/pkg/* diff --git a/lib/core/common.sh b/lib/core/common.sh index 87b5812..d7e050c 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -7,8 +7,6 @@ # # vim: ft=sh -set -e - NAME='JuNest' CMD='junest' DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' @@ -79,7 +77,7 @@ SH=("/bin/sh" "--login") # List of executables that are run in the host OS: PROOT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" -JCHROOT=${JUNEST_BASE}/bin/jchroot +GROOT=${JUNEST_BASE}/bin/groot CLASSIC_CHROOT=chroot WGET="wget --no-check-certificate" CURL="curl -L -J -O -k" @@ -125,7 +123,8 @@ function mkdir_cmd(){ } function zgrep_cmd(){ - $ZGREP $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$ZGREP $@ + # No need for LD_EXEC as zgrep is a POSIX shell script + $ZGREP $@ || ${JUNEST_HOME}/usr/bin/$ZGREP $@ } function unshare_cmd(){ @@ -151,7 +150,7 @@ function download_cmd(){ } function chroot_cmd(){ - $JCHROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CLASSIC_CHROOT "$@" + $GROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CLASSIC_CHROOT "$@" } ############## COMMON FUNCTIONS ############### diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index dddf521..7c3da65 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -59,7 +59,7 @@ function run_env_as_user_with_namespace() { local bindings=${RESULT} unset RESULT - unshare_cmd --mount --user --map-root-user $JCHROOT $bindings $backend_args "$JUNEST_HOME" + unshare_cmd --mount --user --map-root-user $GROOT $bindings $backend_args "$JUNEST_HOME" } function run_env_as_fakeroot_with_namespace() { @@ -69,9 +69,19 @@ function run_env_as_fakeroot_with_namespace() { copy_common_files + #mkdir -p "$chrootdir/$HOME" + #mkdir -p "$chrootdir/run/lock" + #chroot_add_mount --rbind /proc "$chrootdir/proc/" + #chroot_add_mount --rbind /dev "$chrootdir/dev/" + #chroot_add_mount --rbind /sys "$chrootdir/sys/" + #chroot_add_mount --rbind /tmp "$chrootdir/tmp/" + ## alternately create a new tmp istead of binding it: + ##chroot_add_mount -t tmpfs tmp "$chrootdir/tmp/" + #chroot_add_mount --rbind $HOME "$chrootdir/$HOME" provide_common_bindings local bindings=${RESULT} unset RESULT - JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $JCHROOT $bindings $backend_args "$JUNEST_HOME" + JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT $bindings $backend_args "$JUNEST_HOME" + } diff --git a/lib/utils/utils.sh b/lib/utils/utils.sh index 840fbe9..00e2cb6 100644 --- a/lib/utils/utils.sh +++ b/lib/utils/utils.sh @@ -170,6 +170,20 @@ function ask(){ [ "$res" == "Y" ] } +function check_and_trap() { + local sigs="${@:2:${#@}}" + local traps="$(trap -p $sigs)" + [[ $traps ]] && die "Attempting to overwrite existing $sigs trap: $traps" + trap $@ +} + +function check_and_force_trap() { + local sigs="${@:2:${#@}}" + local traps="$(trap -p $sigs)" + [[ $traps ]] && warn "Attempting to overwrite existing $sigs trap: $traps" + trap $@ +} + function insert_quotes_on_spaces(){ # It inserts quotes between arguments. # Useful to preserve quotes on command diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index 33beefa..a95c32a 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -104,10 +104,16 @@ function test_zgrep(){ ZGREP=echo assertCommandSuccess zgrep_cmd new_file assertEquals "new_file" "$(cat $STDOUTF)" - ZGREP=false assertCommandSuccess zgrep_cmd new_file - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false new_file" "$(cat $STDOUTF)" + mkdir -p ${JUNEST_HOME}/usr/bin + touch ${JUNEST_HOME}/usr/bin/false + chmod +x ${JUNEST_HOME}/usr/bin/false - ZGREP=false LD_EXEC=false assertCommandFail zgrep_cmd new_file + echo -e "#!/bin/bash\necho zgrep" > ${JUNEST_HOME}/usr/bin/false + ZGREP=false assertCommandSuccess zgrep_cmd new_file + assertEquals "zgrep" "$(cat $STDOUTF)" + + echo -e "#!/bin/bash\nexit 1" > ${JUNEST_HOME}/usr/bin/false + ZGREP=false assertCommandFail zgrep_cmd new_file } function test_unshare(){ @@ -121,16 +127,16 @@ function test_unshare(){ } function test_chroot(){ - JCHROOT=echo assertCommandSuccess chroot_cmd root + GROOT=echo assertCommandSuccess chroot_cmd root assertEquals "root" "$(cat $STDOUTF)" - JCHROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root + GROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root assertEquals "root" "$(cat $STDOUTF)" - JCHROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root + GROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root assertEquals "ld_exec $JUNEST_HOME/usr/bin/false root" "$(cat $STDOUTF)" - JCHROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root + GROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root } function test_proot_cmd_compat(){ diff --git a/tests/unit-tests/test-groot.sh b/tests/unit-tests/test-groot.sh new file mode 100755 index 0000000..02f05ec --- /dev/null +++ b/tests/unit-tests/test-groot.sh @@ -0,0 +1,137 @@ +#!/bin/bash +source "$(dirname $0)/../utils/utils.sh" + +JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/../..)" + +# Disable the exiterr +set +e + +function oneTimeSetUp(){ + setUpUnitTests +} + +function setUp(){ + # Attempt to source the files under test to revert variable overrides + source $JUNEST_BASE/bin/groot -h &> /dev/null + set +e + + cwdSetUp + mkdir -p chrootdir + + init_mocks +} + +function tearDown(){ + cwdTearDown +} + +## Mock functions ## +function init_mocks() { + function usage(){ + echo "usage" + } + function is_user_root() { + return 0 + } + function chroot() { + echo "chroot($@)" + } + function mountpoint() { + echo "mountpoint($@)" + # As default suppose the mountpoint does not exist + return 1 + } + function mount() { + echo "mount($@)" + } + function umount() { + echo "umount($@)" + } + function check_and_trap() { + echo "check_and_trap($@)" + } +} + +function test_help(){ + assertCommandSuccess main -h + assertEquals "usage" "$(cat $STDOUTF)" + assertCommandSuccess main --help + assertEquals "usage" "$(cat $STDOUTF)" +} +function test_version(){ + assertCommandSuccess main -V + assertEquals "$NAME $(cat $JUNEST_BASE/VERSION)" "$(cat $STDOUTF)" + assertCommandSuccess main --version + assertEquals "$NAME $(cat $JUNEST_BASE/VERSION)" "$(cat $STDOUTF)" +} +function test_groot_no_root(){ + is_user_root() { + return 1 + } + assertCommandFailOnStatus $NO_ROOT_PRIVILEGES main +} +function test_groot_no_directory(){ + assertCommandFailOnStatus $NOT_EXISTING_FILE main no-directory +} +function test_groot_mountpoint_exist(){ + mountpoint_mock() { + echo "mountpoint($@)" + } + MOUNTPOINT=mountpoint_mock + assertCommandSuccess main chrootdir + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_mountpoint_does_not_exist(){ + assertCommandSuccess main chrootdir + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind(){ + assertCommandSuccess main -b /tmp chrootdir + [[ -d chrootdir/tmp ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind_file(){ + touch file_src + assertCommandSuccess main -b ${PWD}/file_src:/file_src chrootdir + [[ -f chrootdir/file_src ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind_not_existing_node(){ + assertCommandFailOnStatus $NOT_EXISTING_FILE main -b ${PWD}/file_src:/file_src chrootdir + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind_not_absolute_path_node(){ + touch file_src + assertCommandFailOnStatus $NOT_ABSOLUTE_PATH main -b file_src:/file_src chrootdir + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind_guest_host(){ + assertCommandSuccess main -b /tmp:/home/tmp chrootdir + [[ -d chrootdir/home/tmp ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_multiple_bind(){ + assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir + [[ -d chrootdir/home/tmp ]] + assertEquals 0 $? + [[ -d chrootdir/dev ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_command(){ + assertCommandSuccess main chrootdir ls -la -h + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind_and_command(){ + assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir ls -la -h + [[ -d chrootdir/home/tmp ]] + assertEquals 0 $? + [[ -d chrootdir/dev ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" +} + +source $(dirname $0)/../utils/shunit2 diff --git a/tests/unit-tests/test-cli.sh b/tests/unit-tests/test-junest.sh similarity index 66% rename from tests/unit-tests/test-cli.sh rename to tests/unit-tests/test-junest.sh index efe55b5..c9f2d4a 100755 --- a/tests/unit-tests/test-cli.sh +++ b/tests/unit-tests/test-junest.sh @@ -1,7 +1,8 @@ #!/bin/bash source "$(dirname $0)/../utils/utils.sh" -source $(dirname $0)/../../bin/junest -h &> /dev/null +JUNEST_BASE="$(dirname $0)/../.." +source $JUNEST_BASE/bin/junest -h &> /dev/null # Disable the exiterr set +e @@ -68,149 +69,149 @@ function run_env_as_user_with_namespace(){ } function test_help(){ - assertCommandSuccess cli -h + assertCommandSuccess main -h assertEquals "usage" "$(cat $STDOUTF)" - assertCommandSuccess cli --help + assertCommandSuccess main --help assertEquals "usage" "$(cat $STDOUTF)" } function test_version(){ - assertCommandSuccess cli -v + assertCommandSuccess main -V assertEquals "version" "$(cat $STDOUTF)" - assertCommandSuccess cli --version + assertCommandSuccess main --version assertEquals "version" "$(cat $STDOUTF)" } function test_build_image_env(){ - assertCommandSuccess cli -b + assertCommandSuccess main -b assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" - assertCommandSuccess cli --build-image + assertCommandSuccess main --build-image assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" - assertCommandSuccess cli -b -s + assertCommandSuccess main -b -s assertEquals "build_image_env(false,true)" "$(cat $STDOUTF)" - assertCommandSuccess cli -b -n + assertCommandSuccess main -b -n assertEquals "build_image_env(true,false)" "$(cat $STDOUTF)" - assertCommandSuccess cli -b -n -s + assertCommandSuccess main -b -n -s assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" - assertCommandSuccess cli --build-image --disable-validation --skip-root-tests + assertCommandSuccess main --build-image --disable-validation --skip-root-tests assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" } function test_check_env(){ - assertCommandSuccess cli -c myscript + assertCommandSuccess main -c myscript assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" - assertCommandSuccess cli --check myscript + assertCommandSuccess main --check myscript assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" - assertCommandSuccess cli -c myscript -s + assertCommandSuccess main -c myscript -s assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" - assertCommandSuccess cli --check myscript --skip-root-tests + assertCommandSuccess main --check myscript --skip-root-tests assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" } function test_delete_env(){ - assertCommandSuccess cli -d + assertCommandSuccess main -d assertEquals "delete_env" "$(cat $STDOUTF)" - assertCommandSuccess cli --delete + assertCommandSuccess main --delete assertEquals "delete_env" "$(cat $STDOUTF)" } function test_setup_env_from_file(){ is_env_installed(){ return 1 } - assertCommandSuccess cli -i myimage + assertCommandSuccess main -i myimage assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" - assertCommandSuccess cli --setup-from-file myimage + assertCommandSuccess main --setup-from-file myimage assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" is_env_installed(){ return 0 } - assertCommandFail cli -i myimage + assertCommandFail main -i myimage } function test_setup_env(){ is_env_installed(){ return 1 } - assertCommandSuccess cli -a arm + assertCommandSuccess main -a arm assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" - assertCommandSuccess cli --arch arm + assertCommandSuccess main --arch arm assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" - assertCommandSuccess cli + assertCommandSuccess main assertEquals "$(echo -e "setup_env()\nrun_env_as_user(,)")" "$(cat $STDOUTF)" is_env_installed(){ return 0 } - assertCommandFail cli -a arm + assertCommandFail main -a arm } function test_run_env_as_fakeroot(){ - assertCommandSuccess cli -f + assertCommandSuccess main -f assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli --fakeroot + assertCommandSuccess main --fakeroot assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -f -p "-b arg" + assertCommandSuccess main -f -p "-b arg" assertEquals "run_env_as_fakeroot(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -f -p "-b arg" -- command -kv + assertCommandSuccess main -f -p "-b arg" -- command -kv assertEquals "run_env_as_fakeroot(-b arg,command -kv)" "$(cat $STDOUTF)" - assertCommandSuccess cli -f command --as + assertCommandSuccess main -f command --as assertEquals "run_env_as_fakeroot(,command --as)" "$(cat $STDOUTF)" - assertCommandFail cli -a "myarch" -f command --as + assertCommandFail main -a "myarch" -f command --as } function test_run_env_as_user(){ - assertCommandSuccess cli + assertCommandSuccess main assertEquals "run_env_as_user(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -p "-b arg" + assertCommandSuccess main -p "-b arg" assertEquals "run_env_as_user(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -p "-b arg" -- command -ll + assertCommandSuccess main -p "-b arg" -- command -ll assertEquals "run_env_as_user(-b arg,command -ll)" "$(cat $STDOUTF)" - assertCommandSuccess cli command -ls + assertCommandSuccess main command -ls assertEquals "run_env_as_user(,command -ls)" "$(cat $STDOUTF)" - assertCommandFail cli -a "myarch" -- command -ls + assertCommandFail main -a "myarch" -- command -ls } function test_run_env_as_root(){ - assertCommandSuccess cli -r + assertCommandSuccess main -r assertEquals "run_env_as_root " "$(cat $STDOUTF)" - assertCommandSuccess cli -r command + assertCommandSuccess main -r command assertEquals "run_env_as_root command" "$(cat $STDOUTF)" } function test_run_env_as_fakeroot_with_namespace(){ - assertCommandSuccess cli -u -f + assertCommandSuccess main -u -f assertEquals "run_env_as_fakeroot_with_namespace(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli --user-namespace --fakeroot + assertCommandSuccess main --user-namespace --fakeroot assertEquals "run_env_as_fakeroot_with_namespace(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u -f -p "-b arg" + assertCommandSuccess main -u -f -p "-b arg" assertEquals "run_env_as_fakeroot_with_namespace(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u -f -p "-b arg" -- command -kv + assertCommandSuccess main -u -f -p "-b arg" -- command -kv assertEquals "run_env_as_fakeroot_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u -f command --as + assertCommandSuccess main -u -f command --as assertEquals "run_env_as_fakeroot_with_namespace(,command --as)" "$(cat $STDOUTF)" } function test_run_env_as_user_with_namespace(){ - assertCommandSuccess cli -u + assertCommandSuccess main -u assertEquals "run_env_as_user_with_namespace(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u -p "-b arg" + assertCommandSuccess main -u -p "-b arg" assertEquals "run_env_as_user_with_namespace(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u -p "-b arg" -- command -ll + assertCommandSuccess main -u -p "-b arg" -- command -ll assertEquals "run_env_as_user_with_namespace(-b arg,command -ll)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u command -ls + assertCommandSuccess main -u command -ls assertEquals "run_env_as_user_with_namespace(,command -ls)" "$(cat $STDOUTF)" } function test_check_cli(){ - assertCommandFail cli -b -h - assertCommandFail cli -b -c - assertCommandFail cli -d -s - assertCommandFail cli -n -v - assertCommandFail cli -d -r - assertCommandFail cli -h -f - assertCommandFail cli -v -i fsd - assertCommandFail cli -f -r - assertCommandFail cli -p args -v - assertCommandFail cli -a arch -v - assertCommandFail cli -d args + assertCommandFail main -b -h + assertCommandFail main -b -c + assertCommandFail main -d -s + assertCommandFail main -n -v + assertCommandFail main -d -r + assertCommandFail main -h -f + assertCommandFail main -v -i fsd + assertCommandFail main -f -r + assertCommandFail main -p args -v + assertCommandFail main -a arch -v + assertCommandFail main -d args } source $(dirname $0)/../utils/shunit2 diff --git a/tests/unit-tests/test-utils.sh b/tests/unit-tests/test-utils.sh index 8a5a127..c0b1ebf 100755 --- a/tests/unit-tests/test-utils.sh +++ b/tests/unit-tests/test-utils.sh @@ -79,6 +79,28 @@ function test_ask_wrong_default_answer() { assertEquals 33 $? } +function test_check_and_trap_fail() { + trap echo EXIT + trap ls QUIT + assertCommandFailOnStatus 1 check_and_trap 'pwd' EXIT QUIT +} + +function test_check_and_trap() { + trap - EXIT QUIT + assertCommandSuccess check_and_trap 'echo' EXIT QUIT +} + +function test_check_and_force_trap_fail() { + trap echo EXIT + trap ls QUIT + assertCommandSuccess check_and_force_trap 'echo' EXIT QUIT +} + +function test_check_and_force_trap() { + trap - EXIT QUIT + assertCommandSuccess check_and_force_trap 'echo' EXIT QUIT +} + function test_insert_quotes_on_spaces(){ assertCommandSuccess insert_quotes_on_spaces this is "a test" assertEquals "this is \"a test\"" "$(cat $STDOUTF)" diff --git a/tests/utils/utils.sh b/tests/utils/utils.sh index b96000c..ed7cb8c 100644 --- a/tests/utils/utils.sh +++ b/tests/utils/utils.sh @@ -1,3 +1,4 @@ +OLD_CWD=${PWD} function cwdSetUp(){ ORIGIN_CWD=$(TMPDIR=/tmp mktemp -d -t junest-cwd.XXXXXXXXXX) cd $ORIGIN_CWD @@ -5,6 +6,7 @@ function cwdSetUp(){ function cwdTearDown(){ rm -rf $ORIGIN_CWD + cd $OLD_CWD } function junestSetUp(){ @@ -12,15 +14,12 @@ function junestSetUp(){ mkdir -p ${JUNEST_HOME}/etc/junest echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info mkdir -p ${JUNEST_HOME}/etc/ca-certificates - trap - QUIT EXIT ABRT KILL TERM INT - trap "rm -rf ${JUNEST_HOME}" EXIT QUIT ABRT KILL TERM INT } function junestTearDown(){ # the CA directories are read only and can be deleted only by changing the mod [ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates rm -rf $JUNEST_HOME - trap - QUIT EXIT ABRT KILL TERM INT unset JUNEST_HOME }