diff --git a/tests/bud/namespaces/Containerfile b/tests/bud/namespaces/Containerfile new file mode 100644 index 00000000000..e27e69610d7 --- /dev/null +++ b/tests/bud/namespaces/Containerfile @@ -0,0 +1,9 @@ +FROM alpine +RUN echo "ReadlinkResult" && readlink /proc/self/ns/user +RUN echo "UidMapResult" && cat /proc/self/uid_map +RUN echo "GidMapResult" && cat /proc/self/gid_map +COPY --chown=1:1 somefile / +RUN echo "StatSomefileResult" && stat -c '%u:%g' /somefile +COPY somedir /somedir +RUN echo "StatSomedirResult" && stat -c '%u:%g' /somedir +RUN echo "StatSomeotherfileResult" && stat -c '%u:%g %a' /somedir/someotherfile diff --git a/tests/namespaces.bats b/tests/namespaces.bats index c79a6f42a14..ce35885c973 100644 --- a/tests/namespaces.bats +++ b/tests/namespaces.bats @@ -72,6 +72,51 @@ load helpers fi } +idmapping_check_namespace() { + local _uidmapargs=$1 + local _gidmapargs=$2 + local _mynamespace=$3 + local _output=$4 + + [ "$_output" != "" ] + if [ -z "${_uidmapargs}${_gidmapargs}" ]; then + if test "$BUILDAH_ISOLATION" != "chroot" -a "$BUILDAH_ISOLATION" != "rootless" ; then + expect_output --from="$_output" "$_mynamespace" + fi + else + [ "$_output" != "$_mynamespace" ] + fi +} + +idmapping_check_map() { + local _output_uidmap=$1 + local _output_gidmap=$2 + local _expect_uidmap=$3 + local _expect_gidmap=$4 + + [ -n "$_output_uidmap" ] + local uidmap=$(sed -E -e 's, +, ,g' -e 's,^ +,,g' <<< "${_output_uidmap}") + [ -n "$_output_gidmap" ] + local gidmap=$(sed -E -e 's, +, ,g' -e 's,^ +,,g' <<< "${_output_gidmap}") + echo expected UID map "${_expect_uidmap}", got UID map "${uidmap}", expected GID map "${_expect_gid_map}", got GID map "${gidmap}". + expect_output --from="$uidmap" "${_expect_uidmap}" + expect_output --from="$gidmap" "${_expect_gidmap}" + # these vars are global + rootuid=$(sed -E -e 's,^([^ ]*) (.*) ([^ ]*),\2,' <<< "$uidmap") + rootgid=$(sed -E -e 's,^([^ ]*) (.*) ([^ ]*),\2,' <<< "$gidmap") +} + +idmapping_check_permission() { + local _output_file_stat=$1 + local _output_dir_stat=$2 + local _output_otherfile_stat=$3 + local _expect_otherfile_stat=$4 + + expect_output --from="${_output_file_stat}" "1:1" "Check if a copied file gets the right permissions" + expect_output --from="${_output_dir_stat}" "0:0" "Check if a copied directory gets the right permissions" + expect_output --from="${_output_otherfile_stat}" "${_expect_otherfile_stat}" "Check if another copied file gets the right permissions" +} + @test "idmapping" { mkdir -p $TESTDIR/no-cni-configs RUNOPTS="--cni-config-dir=${TESTDIR}/no-cni-configs ${RUNC_BINARY:+--runtime $RUNC_BINARY}" @@ -163,55 +208,65 @@ load helpers # If we specified mappings, expect to be in a different namespace by default. run_buildah run $RUNOPTS "$ctr" readlink /proc/self/ns/user - [ "$output" != "" ] - case x"${uidmapargs[$i]}""${gidmapargs[$i]}" in - x) - if test "$BUILDAH_ISOLATION" != "chroot" -a "$BUILDAH_ISOLATION" != "rootless" ; then - expect_output "$mynamespace" - fi - ;; - *) - [ "$output" != "$mynamespace" ] - ;; - esac + idmapping_check_namespace "${uidmapargs[$i]}" "${gidmapargs[$i]}" "$mynamespace" "$output" # Check that we got the mappings that we expected. run_buildah run $RUNOPTS "$ctr" cat /proc/self/uid_map - [ "$output" != "" ] - uidmap=$(sed -E -e 's, +, ,g' -e 's,^ +,,g' <<< "$output") + output_uidmap="$output" run_buildah run $RUNOPTS "$ctr" cat /proc/self/gid_map - [ "$output" != "" ] - gidmap=$(sed -E -e 's, +, ,g' -e 's,^ +,,g' <<< "$output") - echo With settings "$map", expected UID map "${uidmaps[$i]}", got UID map "${uidmap}", expected GID map "${gidmaps[$i]}", got GID map "${gidmap}". - expect_output --from="$uidmap" "${uidmaps[$i]}" - expect_output --from="$gidmap" "${gidmaps[$i]}" - rootuid=$(sed -E -e 's,^([^ ]*) (.*) ([^ ]*),\2,' <<< "$uidmap") - rootgid=$(sed -E -e 's,^([^ ]*) (.*) ([^ ]*),\2,' <<< "$gidmap") + output_gidmap="$output" + idmapping_check_map "$output_uidmap" "$output_gidmap" "${uidmaps[$i]}" "${gidmaps[$i]}" # Check that if we copy a file into the container, it gets the right permissions. run_buildah copy --chown 1:1 "$ctr" ${TESTDIR}/somefile / run_buildah run $RUNOPTS "$ctr" stat -c '%u:%g' /somefile - expect_output "1:1" - + output_file_stat="$output" # Check that if we copy a directory into the container, its contents get the right permissions. run_buildah copy "$ctr" ${TESTDIR}/somedir /somedir run_buildah run $RUNOPTS "$ctr" stat -c '%u:%g' /somedir - expect_output "0:0" + output_dir_stat="$output" + run_buildah run $RUNOPTS "$ctr" stat -c '%u:%g %a' /somedir/someotherfile + output_otherfile_stat="$output" + idmapping_check_permission "$output_file_stat" "$output_dir_stat" "$output_otherfile_stat" "0:0 4700" + + # Check that the copied file has the right permissions on host. run_buildah mount "$ctr" mnt="$output" run stat -c '%u:%g %a' "$mnt"/somedir/someotherfile [ $status -eq 0 ] expect_output "$rootuid:$rootgid 4700" - run_buildah run $RUNOPTS "$ctr" stat -c '%u:%g %a' /somedir/someotherfile - expect_output "0:0 4700" # Check that a container with mapped-layer can be committed. run_buildah commit "$ctr" localhost/alpine-working:$i + + + # Also test bud command + # Build an image using these mappings. + echo "Building image with ${uidmapargs[$i]} ${gidmapargs[$i]}" + run_buildah bud ${uidmapargs[$i]} ${gidmapargs[$i]} $RUNOPTS --signature-policy ${TESTSDIR}/policy.json \ + -t localhost/alpine-bud:$i -f ${TESTSDIR}/bud/namespaces/Containerfile $TESTDIR + # If we specified mappings, expect to be in a different namespace by default. + output_namespace="$(grep -A1 'ReadlinkResult' <<< "$output" | tail -n1)" + idmapping_check_namespace "${uidmapargs[$i]}" "${gidmapargs[$i]}" "$mynamespace" "$output_namespace" + # Check that we got the mappings that we expected. + output_uidmap="$(grep -A1 'UidMapResult' <<< "$output" | tail -n1)" + output_gidmap="$(grep -A1 'GidMapResult' <<< "$output" | tail -n1)" + idmapping_check_map "$output_uidmap" "$output_gidmap" "${uidmaps[$i]}" "${gidmaps[$i]}" + + # Check that if we copy a file into the container, it gets the right permissions. + output_file_stat="$(grep -A1 'StatSomefileResult' <<< "$output" | tail -n1)" + # Check that if we copy a directory into the container, its contents get the right permissions. + output_dir_stat="$(grep -A1 'StatSomedirResult' <<< "$output" | tail -n1)" + output_otherfile_stat="$(grep -A1 'StatSomeotherfileResult' <<< "$output" | tail -n1)" + # bud strips suid. + idmapping_check_permission "$output_file_stat" "$output_dir_stat" "$output_otherfile_stat" "0:0 700" done } general_namespace() { mkdir -p $TESTDIR/no-cni-configs RUNOPTS="--cni-config-dir=${TESTDIR}/no-cni-configs ${RUNC_BINARY:+--runtime $RUNC_BINARY}" + mytmpdir=$TESTDIR/my-dir + mkdir -p ${mytmpdir} # The name of the /proc/self/ns/$link. nstype="$1" @@ -254,27 +309,44 @@ general_namespace() { ;; esac - if [ "$nsflag" = "userns" ]; then - # "run" doesn't have --userns option. - continue + # "run" doesn't have --userns option. + if [ "$nsflag" != "userns" ]; then + for different in ${types[@]} ; do + # Check that, if we override it, we get what we specify for "run". + run_buildah run $RUNOPTS --"$nsflag"=$different "$ctr" readlink /proc/self/ns/"$nstype" + [ "$output" != "" ] + case "$different" in + ""|container|private) + [ "$output" != "$mynamespace" ] + ;; + host) + expect_output "$mynamespace" + ;; + /*) + expect_output "$(readlink $different)" + ;; + esac + done fi - for different in ${types[@]} ; do - # Check that, if we override it, we get what we specify for "run". - run_buildah run $RUNOPTS --"$nsflag"=$different "$ctr" readlink /proc/self/ns/"$nstype" - [ "$output" != "" ] - case "$different" in - ""|container|private) - [ "$output" != "$mynamespace" ] - ;; - host) - expect_output "$mynamespace" - ;; - /*) - expect_output "$(readlink $different)" - ;; - esac - done + # Also check "from" command + cat > $mytmpdir/Containerfile << _EOF +FROM alpine +RUN echo "TargetOutput" && readlink /proc/self/ns/$nstype +_EOF + run_buildah bud --"$nsflag"=$namespace $RUNOPTS --signature-policy ${TESTSDIR}/policy.json --file ${mytmpdir} . + result=$(grep -A1 "TargetOutput" <<< "$output" | tail -n1) + case "$namespace" in + ""|container|private) + [ "$result" != "$mynamespace" ] + ;; + host) + expect_output --from="$result" "$mynamespace" + ;; + /*) + expect_output --from="$result" "$(readlink $namespace)" + ;; + esac done }