diff options
Diffstat (limited to 'tests')
117 files changed, 3254 insertions, 0 deletions
diff --git a/tests/apt-patterns b/tests/apt-patterns new file mode 100644 index 0000000..c87e932 --- /dev/null +++ b/tests/apt-patterns @@ -0,0 +1,8 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=essential \ + --include '?or(?exact-name(dummy-does-not-exist),?exact-name(apt))' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | grep -v ./var/lib/apt/extended_states | diff -u tar1.txt - diff --git a/tests/apt-patterns-custom b/tests/apt-patterns-custom new file mode 100644 index 0000000..2348a76 --- /dev/null +++ b/tests/apt-patterns-custom @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=custom \ + --include '?narrow(?archive(^{{ DIST }}$),?essential)' \ + --include apt \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/aptopt b/tests/aptopt new file mode 100644 index 0000000..c757c30 --- /dev/null +++ b/tests/aptopt @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/config" EXIT INT TERM +echo 'Acquire::Languages "none";' > /tmp/config +{{ CMD }} --mode=root --variant=apt --aptopt='Acquire::Check-Valid-Until "false"' --aptopt=/tmp/config {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf 'Acquire::Check-Valid-Until "false";\nAcquire::Languages "none";\n' | cmp /tmp/debian-chroot/etc/apt/apt.conf.d/99mmdebstrap - +rm /tmp/debian-chroot/etc/apt/apt.conf.d/99mmdebstrap +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/arm64-without-qemu-support b/tests/arm64-without-qemu-support new file mode 100644 index 0000000..98b4724 --- /dev/null +++ b/tests/arm64-without-qemu-support @@ -0,0 +1,18 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +apt-get remove --yes qemu-user-static binfmt-support qemu-user +# the following is not necessary anymore since systemd-binfmt +# successfully disables support upon removal of qemu-user with +# the upload of src:systemd 251.2-4: https://bugs.debian.org/1012163 +#echo 0 > /proc/sys/fs/binfmt_misc/qemu-aarch64 +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt --architectures=arm64 {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/as-debootstrap-unshare-wrapper b/tests/as-debootstrap-unshare-wrapper new file mode 100644 index 0000000..b3f7a44 --- /dev/null +++ b/tests/as-debootstrap-unshare-wrapper @@ -0,0 +1,133 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +# debootstrap uses apt-config to figure out whether the system running it has +# any proxies configured and then runs the binary to set the http_proxy +# environment variable. This will fail if debootstrap is run in a linux user +# namespace because auto-apt-proxy will see /tmp/.auto-apt-proxy-0 as being +# owned by the user "nobody" and group "nogroup" and fail with: +# insecure cache dir /tmp/.auto-apt-proxy-0. Must be owned by UID 0 and have permissions 700 +# We cannot overwrite a configuration item using the APT_CONFIG environment +# variable, so instead we use it to set the Dir configuration option +# to /dev/null to force all apt settings to their defaults. +# There is currently no better way to disable this behavior. See also: +# https://bugs.debian.org/1031105 +# https://salsa.debian.org/installer-team/debootstrap/-/merge_requests/90 +AUTOPROXY= +eval "$(apt-config shell AUTOPROXY Acquire::http::Proxy-Auto-Detect)" +if [ -n "$AUTOPROXY" ] && [ -x "$AUTOPROXY" ] && [ -e /tmp/.auto-apt-proxy-0 ]; then + TMP_APT_CONFIG=$(mktemp) + echo "Dir \"/dev/null\";" > "$TMP_APT_CONFIG" + chmod 644 "$TMP_APT_CONFIG" +fi + +$prefix {{ CMD }} --variant=custom --mode={{ MODE }} \ + --setup-hook='env '"${AUTOPROXY:+APT_CONFIG='$TMP_APT_CONFIG'}"' debootstrap --variant={{ VARIANT }} unstable "$1" {{ MIRROR }}' \ + - /tmp/debian-mm.tar {{ MIRROR }} +if [ -n "$AUTOPROXY" ] && [ -x "$AUTOPROXY" ] && [ -e /tmp/.auto-apt-proxy-0 ]; then + rm "$TMP_APT_CONFIG" +fi + +mkdir /tmp/debian-mm +tar --xattrs --xattrs-include='*' -C /tmp/debian-mm -xf /tmp/debian-mm.tar + +mkdir /tmp/debian-debootstrap +tar --xattrs --xattrs-include='*' -C /tmp/debian-debootstrap -xf "cache/debian-unstable-{{ VARIANT }}.tar" + +# diff cannot compare device nodes, so we use tar to do that for us and then +# delete the directory +tar -C /tmp/debian-debootstrap -cf dev1.tar ./dev +tar -C /tmp/debian-mm -cf dev2.tar ./dev +cmp dev1.tar dev2.tar >&2 +rm dev1.tar dev2.tar +rm -r /tmp/debian-debootstrap/dev /tmp/debian-mm/dev + +# remove downloaded deb packages +rm /tmp/debian-debootstrap/var/cache/apt/archives/*.deb +# remove aux-cache +rm /tmp/debian-debootstrap/var/cache/ldconfig/aux-cache +# remove logs +rm /tmp/debian-debootstrap/var/log/dpkg.log \ + /tmp/debian-debootstrap/var/log/bootstrap.log \ + /tmp/debian-debootstrap/var/log/alternatives.log \ + /tmp/debian-mm/var/log/bootstrap.log + +# clear out /run except for /run/lock +find /tmp/debian-debootstrap/run/ -mindepth 1 -maxdepth 1 ! -name lock -print0 | xargs --no-run-if-empty -0 rm -r + +# debootstrap doesn't clean apt +rm /tmp/debian-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_unstable_main_binary-{{ HOSTARCH }}_Packages \ + /tmp/debian-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_unstable_InRelease \ + /tmp/debian-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_unstable_Release \ + /tmp/debian-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_unstable_Release.gpg + +if [ -e /tmp/debian-debootstrap/etc/machine-id ]; then + rm /tmp/debian-debootstrap/etc/machine-id /tmp/debian-mm/etc/machine-id +fi +rm /tmp/debian-mm/var/cache/apt/archives/lock +rm /tmp/debian-mm/var/lib/apt/lists/lock +rm /tmp/debian-mm/var/lib/dpkg/arch + +# also needed for users that are created by systemd-sysusers before systemd 252 +# https://github.com/systemd/systemd/pull/24534 +for f in shadow shadow-; do + if [ ! -e /tmp/debian-debootstrap/etc/$f ]; then + continue + fi + if ! cmp /tmp/debian-debootstrap/etc/$f /tmp/debian-mm/etc/$f >&2; then + echo patching /etc/$f >&2 + awk -v FS=: -v OFS=: -v SDE={{ SOURCE_DATE_EPOCH }} '{ print $1,$2,int(SDE/60/60/24),$4,$5,$6,$7,$8,$9 }' < /tmp/debian-mm/etc/$f > /tmp/debian-mm/etc/$f.bak + cat /tmp/debian-mm/etc/$f.bak > /tmp/debian-mm/etc/$f + rm /tmp/debian-mm/etc/$f.bak + else + echo no difference for /etc/$f >&2 + fi +done + +# isc-dhcp-client postinst doesn't create this file in debootstrap run with +# unshared wrapper. The responsible postinst snippet was automatically added +# by dh_apparmor since isc-dhcp-client 4.4.3-P1-1.1 +if [ -e /tmp/debian-debootstrap/etc/apparmor.d/local/sbin.dhclient ] && [ ! -s /tmp/debian-debootstrap/etc/apparmor.d/local/sbin.dhclient ]; then + echo /sbin/setcap > /tmp/debian-debootstrap/etc/apparmor.d/local/sbin.dhclient +fi + +# check if the file content differs +diff --unified --no-dereference --recursive /tmp/debian-debootstrap /tmp/debian-mm >&2 + +# check permissions, ownership, symlink targets, modification times using tar +# mtimes of directories created by mmdebstrap will differ, thus we equalize them first +for d in etc/apt/preferences.d/ etc/apt/sources.list.d/ etc/dpkg/dpkg.cfg.d/ var/log/apt/; do + touch --date="@{{ SOURCE_DATE_EPOCH }}" /tmp/debian-debootstrap/$d /tmp/debian-mm/$d +done +# debootstrap never ran apt -- fixing permissions +for d in ./var/lib/apt/lists/partial ./var/cache/apt/archives/partial; do + chroot /tmp/debian-debootstrap chmod 0700 $d + chroot /tmp/debian-debootstrap chown _apt:root $d +done +tar -C /tmp/debian-debootstrap --numeric-owner --xattrs --xattrs-include='*' --sort=name --clamp-mtime --mtime="$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds)" -cf /tmp/root1.tar . +tar -C /tmp/debian-mm --numeric-owner --xattrs --xattrs-include='*' --sort=name --clamp-mtime --mtime="$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds)" -cf /tmp/root2.tar . +tar --full-time --verbose -tf /tmp/root1.tar > /tmp/root1.tar.list +tar --full-time --verbose -tf /tmp/root2.tar > /tmp/root2.tar.list +# despite SOURCE_DATE_EPOCH and --clamp-mtime, the timestamps in the tarball +# will slightly differ from each other in the sub-second precision (last +# decimals) so the tarballs will not be identical, so we use diff to compare +# content and tar to compare attributes +diff -u /tmp/root1.tar.list /tmp/root2.tar.list >&2 +rm /tmp/root1.tar /tmp/root2.tar /tmp/root1.tar.list /tmp/root2.tar.list + +rm /tmp/debian-mm.tar +rm -r /tmp/debian-debootstrap /tmp/debian-mm diff --git a/tests/ascii-armored-keys b/tests/ascii-armored-keys new file mode 100644 index 0000000..518991c --- /dev/null +++ b/tests/ascii-armored-keys @@ -0,0 +1,21 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +for f in /etc/apt/trusted.gpg.d/*.gpg /etc/apt/trusted.gpg.d/*.asc; do + [ -e "$f" ] || continue + rm "$f" +done +rmdir /etc/apt/trusted.gpg.d +mkdir /etc/apt/trusted.gpg.d +for f in /usr/share/keyrings/*.gpg; do + name=$(basename "$f" .gpg) + gpg --no-default-keyring --keyring="/usr/share/keyrings/$name.gpg" --armor --output="/etc/apt/trusted.gpg.d/$name.asc" --export + rm "/usr/share/keyrings/$name.gpg" +done +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot.tar diff --git a/tests/aspcud-apt-solver b/tests/aspcud-apt-solver new file mode 100644 index 0000000..bc0fbc3 --- /dev/null +++ b/tests/aspcud-apt-solver @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=custom \ + --include "$(tr '\n' ',' < pkglist.txt)" \ + --aptopt='APT::Solver "aspcud"' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort \ + | grep -v '^./etc/apt/apt.conf.d/99mmdebstrap$' \ + | diff -u tar1.txt - diff --git a/tests/auto-mode-as-normal-user b/tests/auto-mode-as-normal-user new file mode 100644 index 0000000..e8ab828 --- /dev/null +++ b/tests/auto-mode-as-normal-user @@ -0,0 +1,22 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +trap "rm -f /tmp/debian-chroot.tar.gz" EXIT INT TERM + +[ {{ MODE }} = "auto" ] + +prefix= +if [ "$(id -u)" -eq 0 ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar.gz {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar.gz | sort | diff -u tar1.txt - diff --git a/tests/auto-mode-without-unshare-capabilities b/tests/auto-mode-without-unshare-capabilities new file mode 100644 index 0000000..17244b8 --- /dev/null +++ b/tests/auto-mode-without-unshare-capabilities @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +useradd --home-dir /home/user --create-home user +if [ -e /proc/sys/kernel/unprivileged_userns_clone ] && [ "$(sysctl -n kernel.unprivileged_userns_clone)" = "1" ]; then + sysctl -w kernel.unprivileged_userns_clone=0 +fi +runuser -u user -- {{ CMD }} --mode=auto --variant=apt {{ DIST }} /tmp/debian-chroot.tar.gz {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar.gz | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar.gz diff --git a/tests/automatic-mirror-from-suite b/tests/automatic-mirror-from-suite new file mode 100644 index 0000000..7cff5a6 --- /dev/null +++ b/tests/automatic-mirror-from-suite @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +cat << HOSTS >> /etc/hosts +127.0.0.1 deb.debian.org +127.0.0.1 security.debian.org +HOSTS +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/check-against-debootstrap-dist b/tests/check-against-debootstrap-dist new file mode 100644 index 0000000..b5706c6 --- /dev/null +++ b/tests/check-against-debootstrap-dist @@ -0,0 +1,228 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH" + +# we create the apt user ourselves or otherwise its uid/gid will differ +# compared to the one chosen in debootstrap because of different installation +# order in comparison to the systemd users +# https://bugs.debian.org/969631 +# we cannot use useradd because passwd is not Essential:yes +{{ CMD }} --variant={{ VARIANT }} --mode={{ MODE }} \ + --essential-hook='[ {{ DIST }} = oldstable ] && [ {{ VARIANT }} = - ] && echo _apt:*:100:65534::/nonexistent:/usr/sbin/nologin >> "$1"/etc/passwd || :' \ + "$(if [ {{ DIST }} = oldstable ]; then echo --merged-usr; else echo --hook-dir=./hooks/merged-usr; fi)" \ + "$(case {{ DIST }} in oldstable) echo --include=e2fsprogs,mount,tzdata,gcc-9-base;; stable) echo --include=e2fsprogs,mount,tzdata;; *) echo --include=base-files ;; esac )" \ + {{ DIST }} /tmp/debian-{{ DIST }}-mm.tar {{ MIRROR }} + +mkdir /tmp/debian-{{ DIST }}-mm +tar --xattrs --xattrs-include='*' -C /tmp/debian-{{ DIST }}-mm -xf /tmp/debian-{{ DIST }}-mm.tar +rm /tmp/debian-{{ DIST }}-mm.tar + +mkdir /tmp/debian-{{ DIST }}-debootstrap +tar --xattrs --xattrs-include='*' -C /tmp/debian-{{ DIST }}-debootstrap -xf "cache/debian-{{ DIST }}-{{ VARIANT }}.tar" + +# diff cannot compare device nodes, so we use tar to do that for us and then +# delete the directory +tar -C /tmp/debian-{{ DIST }}-debootstrap -cf /tmp/dev1.tar ./dev +tar -C /tmp/debian-{{ DIST }}-mm -cf /tmp/dev2.tar ./dev +ret=0 +cmp /tmp/dev1.tar /tmp/dev2.tar >&2 || ret=$? +if [ "$ret" -ne 0 ]; then + if type diffoscope >/dev/null; then + diffoscope /tmp/dev1.tar /tmp/dev2.tar + exit 1 + else + echo "no diffoscope installed" >&2 + fi + if type base64 >/dev/null; then + base64 /tmp/dev1.tar + base64 /tmp/dev2.tar + exit 1 + else + echo "no base64 installed" >&2 + fi + if type xxd >/dev/null; then + xxd /tmp/dev1.tar + xxd /tmp/dev2.tar + exit 1 + else + echo "no xxd installed" >&2 + fi + exit 1 +fi +rm /tmp/dev1.tar /tmp/dev2.tar +rm -r /tmp/debian-{{ DIST }}-debootstrap/dev /tmp/debian-{{ DIST }}-mm/dev + +# remove downloaded deb packages +rm /tmp/debian-{{ DIST }}-debootstrap/var/cache/apt/archives/*.deb +# remove aux-cache +rm /tmp/debian-{{ DIST }}-debootstrap/var/cache/ldconfig/aux-cache +# remove logs +rm /tmp/debian-{{ DIST }}-debootstrap/var/log/dpkg.log \ + /tmp/debian-{{ DIST }}-debootstrap/var/log/bootstrap.log \ + /tmp/debian-{{ DIST }}-debootstrap/var/log/alternatives.log +# remove *-old files +rm /tmp/debian-{{ DIST }}-debootstrap/var/cache/debconf/config.dat-old \ + /tmp/debian-{{ DIST }}-mm/var/cache/debconf/config.dat-old +rm /tmp/debian-{{ DIST }}-debootstrap/var/cache/debconf/templates.dat-old \ + /tmp/debian-{{ DIST }}-mm/var/cache/debconf/templates.dat-old +rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/dpkg/status-old \ + /tmp/debian-{{ DIST }}-mm/var/lib/dpkg/status-old +# remove dpkg files +rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/dpkg/available +rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/dpkg/cmethopt +# remove /var/lib/dpkg/arch +rm /tmp/debian-{{ DIST }}-mm/var/lib/dpkg/arch +# since we installed packages directly from the .deb files, Priorities differ +# thus we first check for equality and then remove the files +chroot /tmp/debian-{{ DIST }}-debootstrap dpkg --list > /tmp/dpkg1 +chroot /tmp/debian-{{ DIST }}-mm dpkg --list > /tmp/dpkg2 +diff -u /tmp/dpkg1 /tmp/dpkg2 >&2 +rm /tmp/dpkg1 /tmp/dpkg2 +grep -v '^Priority: ' /tmp/debian-{{ DIST }}-debootstrap/var/lib/dpkg/status > /tmp/status1 +grep -v '^Priority: ' /tmp/debian-{{ DIST }}-mm/var/lib/dpkg/status > /tmp/status2 +diff -u /tmp/status1 /tmp/status2 >&2 +rm /tmp/status1 /tmp/status2 +rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/dpkg/status /tmp/debian-{{ DIST }}-mm/var/lib/dpkg/status +# debootstrap exposes the hosts's kernel version +if [ -e /tmp/debian-{{ DIST }}-debootstrap/etc/apt/apt.conf.d/01autoremove-kernels ]; then + rm /tmp/debian-{{ DIST }}-debootstrap/etc/apt/apt.conf.d/01autoremove-kernels +fi +if [ -e /tmp/debian-{{ DIST }}-mm/etc/apt/apt.conf.d/01autoremove-kernels ]; then + rm /tmp/debian-{{ DIST }}-mm/etc/apt/apt.conf.d/01autoremove-kernels +fi +# clear out /run except for /run/lock +find /tmp/debian-{{ DIST }}-debootstrap/run/ -mindepth 1 -maxdepth 1 ! -name lock -print0 | xargs --no-run-if-empty -0 rm -r +# debootstrap doesn't clean apt +rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_{{ DIST }}_main_binary-{{ HOSTARCH }}_Packages \ + /tmp/debian-{{ DIST }}-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_{{ DIST }}_InRelease \ + /tmp/debian-{{ DIST }}-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_{{ DIST }}_Release \ + /tmp/debian-{{ DIST }}-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_{{ DIST }}_Release.gpg + +if [ "{{ VARIANT }}" = "-" ]; then + rm /tmp/debian-{{ DIST }}-debootstrap/etc/machine-id + rm /tmp/debian-{{ DIST }}-mm/etc/machine-id + rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/systemd/catalog/database + rm /tmp/debian-{{ DIST }}-mm/var/lib/systemd/catalog/database + + cap=$(chroot /tmp/debian-{{ DIST }}-debootstrap /sbin/getcap /bin/ping) + expected="/bin/ping cap_net_raw=ep" + if [ "$cap" != "$expected" ]; then + echo "expected bin/ping to have capabilities $expected" >&2 + echo "but debootstrap produced: $cap" >&2 + exit 1 + fi + cap=$(chroot /tmp/debian-{{ DIST }}-mm /sbin/getcap /bin/ping) + if [ "$cap" != "$expected" ]; then + echo "expected bin/ping to have capabilities $expected" >&2 + echo "but mmdebstrap produced: $cap" >&2 + exit 1 + fi +fi +rm /tmp/debian-{{ DIST }}-mm/var/cache/apt/archives/lock +rm /tmp/debian-{{ DIST }}-mm/var/lib/apt/extended_states +rm /tmp/debian-{{ DIST }}-mm/var/lib/apt/lists/lock + +# the list of shells might be sorted wrongly +# /var/lib/dpkg/triggers/File might be sorted wrongly +for f in "/var/lib/dpkg/triggers/File" "/etc/shells"; do + f1="/tmp/debian-{{ DIST }}-debootstrap/$f" + f2="/tmp/debian-{{ DIST }}-mm/$f" + # both chroots must have the file + if [ ! -e "$f1" ] || [ ! -e "$f2" ]; then + continue + fi + # the file must be different + if cmp "$f1" "$f2" >&2; then + continue + fi + # then sort both + sort -o "$f1" "$f1" + sort -o "$f2" "$f2" +done + +# Because of unreproducible uids (#969631) we created the _apt user ourselves +# and because passwd is not Essential:yes we didn't use useradd. But newer +# versions of adduser and shadow will create a different /etc/shadow +if [ "{{ VARIANT }}" = "-" ] && [ "{{ DIST}}" = oldstable ]; then + for f in shadow shadow-; do + if grep -q '^_apt:!:' /tmp/debian-{{ DIST }}-debootstrap/etc/$f; then + sed -i 's/^_apt:\*:\([^:]\+\):0:99999:7:::$/_apt:!:\1::::::/' /tmp/debian-{{ DIST }}-mm/etc/$f + fi + done +fi + +for log in faillog lastlog; do + if ! cmp /tmp/debian-{{ DIST }}-debootstrap/var/log/$log /tmp/debian-{{ DIST }}-mm/var/log/$log >&2;then + # if the files differ, make sure they are all zeroes + cmp -n "$(stat -c %s "/tmp/debian-{{ DIST }}-debootstrap/var/log/$log")" "/tmp/debian-{{ DIST }}-debootstrap/var/log/$log" /dev/zero >&2 + cmp -n "$(stat -c %s "/tmp/debian-{{ DIST }}-mm/var/log/$log")" "/tmp/debian-{{ DIST }}-mm/var/log/$log" /dev/zero >&2 + # then delete them + rm /tmp/debian-{{ DIST }}-debootstrap/var/log/$log /tmp/debian-{{ DIST }}-mm/var/log/$log + fi +done + +# the order in which systemd and cron get installed differ and thus the order +# of lines in /etc/group and /etc/gshadow differs +if [ "{{ VARIANT }}" = "-" ]; then + for f in group group- gshadow gshadow-; do + for d in mm debootstrap; do + sort /tmp/debian-{{ DIST }}-$d/etc/$f > /tmp/debian-{{ DIST }}-$d/etc/$f.bak + mv /tmp/debian-{{ DIST }}-$d/etc/$f.bak /tmp/debian-{{ DIST }}-$d/etc/$f + done + done +fi + +# since debootstrap 1.0.133 there is no tzdata in the buildd variant and thus +# debootstrap creates its own /etc/localtime +if [ "{{ VARIANT }}" = "buildd" ] && [ "{{ DIST }}" != "stable" ] && [ "{{ DIST }}" != "oldstable" ]; then + [ "$(readlink /tmp/debian-{{ DIST }}-debootstrap/etc/localtime)" = /usr/share/zoneinfo/UTC ] + rm /tmp/debian-{{ DIST }}-debootstrap/etc/localtime +fi + +# starting with systemd 255 upstream dropped splitusr support and depending on +# the installation order, symlink targets are prefixed with /usr or not +# See #1060000 and #1054137 +case {{ DIST }} in testing|unstable) + for f in multi-user.target.wants/e2scrub_reap.service timers.target.wants/apt-daily-upgrade.timer timers.target.wants/apt-daily.timer timers.target.wants/e2scrub_all.timer; do + for d in mm debootstrap; do + [ -L "/tmp/debian-{{ DIST }}-$d/etc/systemd/system/$f" ] || continue + oldlink="$(readlink "/tmp/debian-{{ DIST }}-$d/etc/systemd/system/$f")" + case $oldlink in + /usr/*) : ;; + /*) oldlink="/usr$oldlink" ;; + *) echo unexpected >&2; exit 1 ;; + esac + ln -sf "$oldlink" "/tmp/debian-{{ DIST }}-$d/etc/systemd/system/$f" + done + done + ;; +esac + +# check if the file content differs +diff --unified --no-dereference --recursive /tmp/debian-{{ DIST }}-debootstrap /tmp/debian-{{ DIST }}-mm >&2 + +# check permissions, ownership, symlink targets, modification times using tar +# directory mtimes will differ, thus we equalize them first +find /tmp/debian-{{ DIST }}-debootstrap /tmp/debian-{{ DIST }}-mm -type d -print0 | xargs -0 touch --date="@{{ SOURCE_DATE_EPOCH }}" +# debootstrap never ran apt -- fixing permissions +for d in ./var/lib/apt/lists/partial ./var/cache/apt/archives/partial; do + unmergedPATH="$PATH$(if [ "{{ DIST }}" = oldstable ]; then echo :/bin:/sbin; fi)" + PATH="$unmergedPATH" chroot /tmp/debian-{{ DIST }}-debootstrap chmod 0700 $d + PATH="$unmergedPATH" chroot /tmp/debian-{{ DIST }}-debootstrap chown "$(id -u _apt):root" $d +done +tar -C /tmp/debian-{{ DIST }}-debootstrap --numeric-owner --sort=name --clamp-mtime --mtime="$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds)" -cf /tmp/root1.tar . +tar -C /tmp/debian-{{ DIST }}-mm --numeric-owner --sort=name --clamp-mtime --mtime="$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds)" -cf /tmp/root2.tar . +tar --full-time --verbose -tf /tmp/root1.tar > /tmp/root1.tar.list +tar --full-time --verbose -tf /tmp/root2.tar > /tmp/root2.tar.list +diff -u /tmp/root1.tar.list /tmp/root2.tar.list >&2 +rm /tmp/root1.tar /tmp/root2.tar /tmp/root1.tar.list /tmp/root2.tar.list + +# check if file properties (permissions, ownership, symlink names, modification time) differ +# +# we cannot use this (yet) because it cannot cope with paths that have [ or @ in them +#fmtree -c -p /tmp/debian-{{ DIST }}-debootstrap -k flags,gid,link,mode,size,time,uid | sudo fmtree -p /tmp/debian-{{ DIST }}-mm + +rm -r /tmp/debian-{{ DIST }}-debootstrap /tmp/debian-{{ DIST }}-mm diff --git a/tests/check-for-bit-by-bit-identical-format-output b/tests/check-for-bit-by-bit-identical-format-output new file mode 100644 index 0000000..6cbab90 --- /dev/null +++ b/tests/check-for-bit-by-bit-identical-format-output @@ -0,0 +1,28 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +trap "rm -f /tmp/debian-chroot-{{ MODE }}.{{ FORMAT }}" EXIT INT TERM + +case {{ MODE }} in unshare|fakechroot) : ;; *) exit 1;; esac + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +$prefix {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} {{ DIST }} /tmp/debian-chroot-{{ MODE }}.{{ FORMAT }} {{ MIRROR }} +cmp ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.{{ FORMAT }} /tmp/debian-chroot-{{ MODE }}.{{ FORMAT }} \ + || diffoscope ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.{{ FORMAT }} /tmp/debian-chroot-{{ MODE }}.{{ FORMAT }} + +# we cannot test chrootless mode here, because mmdebstrap relies on the +# usrmerge package to set up merged-/usr and that doesn't work in chrootless +# mode diff --git a/tests/chroot-directory-not-accessible-by-apt-user b/tests/chroot-directory-not-accessible-by-apt-user new file mode 100644 index 0000000..eb2d343 --- /dev/null +++ b/tests/chroot-directory-not-accessible-by-apt-user @@ -0,0 +1,8 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +mkdir /tmp/debian-chroot +chmod 700 /tmp/debian-chroot +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/chrootless b/tests/chrootless new file mode 100644 index 0000000..77490c3 --- /dev/null +++ b/tests/chrootless @@ -0,0 +1,16 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} +trap "rm -f /tmp/chrootless.tar /tmp/root.tar" EXIT INT TERM +# we need --hook-dir=./hooks/merged-usr because usrmerge does not understand +# DPKG_ROOT +for INCLUDE in '' 'apt' 'apt,build-essential' 'systemd-sysv'; do + for MODE in root chrootless; do + {{ CMD }} --mode=$MODE --variant={{ VARIANT }} --hook-dir=./hooks/merged-usr \ + ${INCLUDE:+--include="$INCLUDE"} --skip=check/chrootless \ + {{ DIST }} "/tmp/$MODE.tar" {{ MIRROR }} + done + cmp /tmp/root.tar /tmp/chrootless.tar || diffoscope /tmp/root.tar /tmp/chrootless.tar + rm /tmp/chrootless.tar /tmp/root.tar +done diff --git a/tests/chrootless-fakeroot b/tests/chrootless-fakeroot new file mode 100644 index 0000000..8821fa6 --- /dev/null +++ b/tests/chrootless-fakeroot @@ -0,0 +1,43 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} +trap "rm -f /tmp/chrootless.tar /tmp/root.tar" EXIT INT TERM + +[ {{ MODE }} = chrootless ] + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +MMTARFILTER= +[ -x /usr/bin/mmtarfilter ] && MMTARFILTER=/usr/bin/mmtarfilter +[ -x ./tarfilter ] && MMTARFILTER=./tarfilter + +# we need --hook-dir=./hooks/merged-usr because usrmerge does not understand +# DPKG_ROOT +# permissions drwxr-sr-x and extended attributes of ./var/log/journal/ cannot +# be preserved under fakeroot +# this applies to 'z' lines in files in /usr/lib/tmpfiles.d/ +for INCLUDE in '' 'apt' 'apt,build-essential' 'systemd-sysv'; do + {{ CMD }} --variant={{ VARIANT }} --hook-dir=./hooks/merged-usr \ + ${INCLUDE:+--include="$INCLUDE"} \ + {{ DIST }} - {{ MIRROR }} \ + | "$MMTARFILTER" --path-exclude="/var/log/journal" --path-exclude="/etc/credstore*" \ + >/tmp/root.tar + $prefix fakeroot {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} --hook-dir=./hooks/merged-usr \ + ${INCLUDE:+--include="$INCLUDE"} \ + {{ DIST }} - {{ MIRROR }} \ + | "$MMTARFILTER" --path-exclude="/var/log/journal" --path-exclude="/etc/credstore*" \ + > /tmp/chrootless.tar + cmp /tmp/root.tar /tmp/chrootless.tar || diffoscope /tmp/root.tar /tmp/chrootless.tar + rm /tmp/chrootless.tar /tmp/root.tar +done diff --git a/tests/chrootless-foreign b/tests/chrootless-foreign new file mode 100644 index 0000000..03203d0 --- /dev/null +++ b/tests/chrootless-foreign @@ -0,0 +1,68 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} +trap "rm -f /tmp/chrootless.tar /tmp/root.tar" EXIT INT TERM +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi + +deb2qemu() { + case "$1" in + amd64) echo x86_64;; + arm64) echo aarch64;; + armel|armhf) echo arm;; + ppc64el) echo ppc64le;; + *) echo "$1";; + esac +} +if [ "$(dpkg --print-architecture)" = "arm64" ]; then + arch=amd64 +else + arch=arm64 +fi + +[ "$(id -u)" -eq 0 ] +[ -e "/proc/sys/fs/binfmt_misc/qemu-$(deb2qemu "$arch")" ] + + +# we need --hook-dir=./hooks/merged-usr because usrmerge does not understand +# DPKG_ROOT +# +# dpkg is unable to install architecture arch:all packages with a +# dependency on an arch:any package (perl-modules-5.34 in this case) +# inside foreign architecture chrootless chroots, because dpkg will use +# its own architecture as the native architecture, see #825385 and #1020533 +# So we are not testing the installation of apt,build-essential here. +for INCLUDE in '' 'apt' 'systemd-sysv'; do + echo 1 > "/proc/sys/fs/binfmt_misc/qemu-$(deb2qemu "$arch")" + arch-test "$arch" + {{ CMD }} --mode=root --architecture="$arch" --variant={{ VARIANT }} \ + --hook-dir=./hooks/merged-usr ${INCLUDE:+--include="$INCLUDE"} \ + {{ DIST }} "/tmp/root.tar" {{ MIRROR }} + echo 0 > "/proc/sys/fs/binfmt_misc/qemu-$(deb2qemu "$arch")" + arch-test "$arch" && exit 1 + {{ CMD }} --mode=chrootless --architecture="$arch" --variant={{ VARIANT }} \ + --hook-dir=./hooks/merged-usr ${INCLUDE:+--include="$INCLUDE"} \ + --skip=check/chrootless {{ DIST }} "/tmp/chrootless.tar" {{ MIRROR }} + # when creating a foreign architecture chroot, the tarballs are not + # bit-by-bit identical but contain a few remaining differences: + # + # * /etc/ld.so.cache -- hard problem, must be solved in glibc upstream + # * /var/lib/dpkg/triggers -- #990712 + # * /var/cache/debconf/*.dat-old -- needs investigation + for tar in root chrootless; do + <"/tmp/$tar.tar" \ + ./tarfilter \ + --path-exclude=/var/cache/debconf/config.dat-old \ + --path-exclude=/var/cache/debconf/templates.dat-old \ + --path-exclude=/etc/ld.so.cache \ + --path-exclude=/var/lib/dpkg/triggers/File \ + --path-exclude=/var/lib/dpkg/triggers/ldconfig \ + > "/tmp/$tar.tar.tmp" + mv "/tmp/$tar.tar.tmp" "/tmp/$tar.tar" + done + cmp /tmp/root.tar /tmp/chrootless.tar || diffoscope /tmp/root.tar /tmp/chrootless.tar + rm /tmp/chrootless.tar /tmp/root.tar +done diff --git a/tests/compare-output-with-pre-seeded-var-cache-apt-archives b/tests/compare-output-with-pre-seeded-var-cache-apt-archives new file mode 100644 index 0000000..f0e132c --- /dev/null +++ b/tests/compare-output-with-pre-seeded-var-cache-apt-archives @@ -0,0 +1,44 @@ +#!/bin/sh +# +# test that the user can drop archives into /var/cache/apt/archives as well as +# into /var/cache/apt/archives/partial + +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 + exit 1 +fi +tmpdir=$(mktemp -d) +trap 'rm -f "$tmpdir"/*.deb /tmp/orig.tar /tmp/test1.tar /tmp/test2.tar; rmdir "$tmpdir"' EXIT INT TERM + +include="--include=doc-debian" +if [ "{{ VARIANT }}" = "custom" ]; then + include="$include,base-files,base-passwd,coreutils,dash,diffutils,dpkg,libc-bin,sed" +fi +{{ CMD }} $include --mode={{ MODE }} --variant={{ VARIANT }} \ + --setup-hook='mkdir -p "$1"/var/cache/apt/archives/partial' \ + --setup-hook='touch "$1"/var/cache/apt/archives/lock' \ + --setup-hook='chmod 0640 "$1"/var/cache/apt/archives/lock' \ + {{ DIST }} - {{ MIRROR }} > /tmp/orig.tar +# somehow, when trying to create a tarball from the 9p mount, tar throws the +# following error: tar: ./doc-debian_6.4_all.deb: File shrank by 132942 bytes; padding with zeros +# to reproduce, try: tar --directory /mnt/cache/debian/pool/main/d/doc-debian/ --create --file - . | tar --directory /tmp/ --extract --file - +# this will be different: +# md5sum /mnt/cache/debian/pool/main/d/doc-debian/*.deb /tmp/*.deb +# another reason to copy the files into a new directory is, that we can use shell globs +cp /mnt/cache/debian/pool/main/b/busybox/busybox_*"_{{ HOSTARCH }}.deb" /mnt/cache/debian/pool/main/a/apt/apt_*"_{{ HOSTARCH }}.deb" "$tmpdir" +{{ CMD }} $include --mode={{ MODE }} --variant={{ VARIANT }} \ + --setup-hook='mkdir -p "$1"/var/cache/apt/archives/partial' \ + --setup-hook='sync-in "'"$tmpdir"'" /var/cache/apt/archives/partial' \ + {{ DIST }} - {{ MIRROR }} > /tmp/test1.tar +cmp /tmp/orig.tar /tmp/test1.tar +{{ CMD }} $include --mode={{ MODE }} --variant={{ VARIANT }} \ + --customize-hook='touch "$1"/var/cache/apt/archives/partial' \ + --setup-hook='mkdir -p "$1"/var/cache/apt/archives/' \ + --setup-hook='sync-in "'"$tmpdir"'" /var/cache/apt/archives/' \ + --setup-hook='chmod 0755 "$1"/var/cache/apt/archives/' \ + --customize-hook='find "'"$tmpdir"'" -type f -exec md5sum "{}" \; | sed "s|"'"$tmpdir"'"|$1/var/cache/apt/archives|" | md5sum --check' \ + {{ DIST }} - {{ MIRROR }} > /tmp/test2.tar +cmp /tmp/orig.tar /tmp/test2.tar diff --git a/tests/copy-mirror b/tests/copy-mirror new file mode 100644 index 0000000..1903925 --- /dev/null +++ b/tests/copy-mirror @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 + exit 1 +fi +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar "deb copy:///mnt/cache/debian {{ DIST }} main" +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/create-directory b/tests/create-directory new file mode 100644 index 0000000..2d5461b --- /dev/null +++ b/tests/create-directory @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM + +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +chroot /tmp/debian-chroot dpkg-query --showformat '${binary:Package}\n' --show > pkglist.txt +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort > tar1.txt diff --git a/tests/create-directory-dry-run b/tests/create-directory-dry-run new file mode 100644 index 0000000..03226e4 --- /dev/null +++ b/tests/create-directory-dry-run @@ -0,0 +1,29 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode={{ MODE }} --dry-run --variant=apt \ + --setup-hook="exit 1" \ + --essential-hook="exit 1" \ + --customize-hook="exit 1" \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +rm /tmp/debian-chroot/dev/console +rm /tmp/debian-chroot/dev/fd +rm /tmp/debian-chroot/dev/full +rm /tmp/debian-chroot/dev/null +rm /tmp/debian-chroot/dev/ptmx +rm /tmp/debian-chroot/dev/random +rm /tmp/debian-chroot/dev/stderr +rm /tmp/debian-chroot/dev/stdin +rm /tmp/debian-chroot/dev/stdout +rm /tmp/debian-chroot/dev/tty +rm /tmp/debian-chroot/dev/urandom +rm /tmp/debian-chroot/dev/zero +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/apt/lists/lock +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/lib/dpkg/arch +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir diff --git a/tests/create-foreign-tarball b/tests/create-foreign-tarball new file mode 100644 index 0000000..bf8f13a --- /dev/null +++ b/tests/create-foreign-tarball @@ -0,0 +1,77 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +case "$(dpkg --print-architecture)" in + arm64) + native_arch=arm64 + native_gnu=aarch64-linux-gnu + foreign_arch=amd64 + foreign_gnu=x86_64-linux-gnu + ;; + amd64) + native_arch=amd64 + native_gnu=x86_64-linux-gnu + foreign_arch=arm64 + foreign_gnu=aarch64-linux-gnu + ;; + *) + echo "unsupported native architecture" >&2 + exit 1 + ;; +esac + +[ "{{ MODE }}" = "fakechroot" ] && prefix="$prefix fakechroot fakeroot" +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --architectures="$foreign_arch" \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +# we ignore differences between architectures by ignoring some files +# and renaming others +{ tar -tf /tmp/debian-chroot.tar \ + | grep -v '^\./usr/bin/i386$' \ + | grep -v '^\./usr/bin/x86_64$' \ + | grep -v '^\./lib64$' \ + | grep -v '^\./usr/lib64/$' \ + | grep -v '^\./usr/lib64/ld-linux-x86-64\.so\.2$' \ + | grep -v '^\./usr/lib/ld-linux-aarch64\.so\.1$' \ + | grep -v "^\\./usr/lib/$foreign_gnu/ld-linux-aarch64\\.so\\.1$" \ + | grep -v "^\\./usr/lib/$foreign_gnu/ld-linux-x86-64\\.so\\.2$" \ + | grep -v "^\\./usr/lib/$foreign_gnu/perl/5\\.[0-9][.0-9]\\+/.*\\.ph$" \ + | grep -v "^\\./usr/lib/$foreign_gnu/libmvec\\.so\\.1$" \ + | grep -v "^\\./usr/share/doc/[^/]\\+/changelog\\(\\.Debian\\)\\?\\.$foreign_arch\\.gz$" \ + | grep -v '^\./usr/share/man/man8/i386\.8\.gz$' \ + | grep -v '^\./usr/share/man/man8/x86_64\.8\.gz$' \ + | sed "s/$foreign_gnu/$native_gnu/" \ + | sed "s/$foreign_arch/$native_arch/"; +} | sort > /tmp/tar2.txt +{ < tar1.txt \ + grep -v '^\./usr/bin/i386$' \ + | grep -v '^\./usr/bin/x86_64$' \ + | grep -v '^\./lib32$' \ + | grep -v '^\./lib64$' \ + | grep -v '^\./libx32$' \ + | grep -v '^\./usr/lib32/$' \ + | grep -v '^\./usr/libx32/$' \ + | grep -v '^\./usr/lib64/$' \ + | grep -v '^\./usr/lib64/ld-linux-x86-64\.so\.2$' \ + | grep -v '^\./usr/lib/ld-linux-aarch64\.so\.1$' \ + | grep -v "^\\./usr/lib/$native_gnu/ld-linux-x86-64\\.so\\.2$" \ + | grep -v "^\\./usr/lib/$native_gnu/ld-linux-aarch64\\.so\\.1$" \ + | grep -v "^\\./usr/lib/$native_gnu/libmvec\\.so\\.1$" \ + | grep -v "^\\./usr/lib/$native_gnu/perl/5\\.[0-9][.0-9]\\+/.*\\.ph$" \ + | grep -v "^\\./usr/share/doc/[^/]\\+/changelog\\(\\.Debian\\)\\?\\.$native_arch\\.gz$" \ + | grep -v '^\./usr/share/man/man8/i386\.8\.gz$' \ + | grep -v '^\./usr/share/man/man8/x86_64\.8\.gz$'; +} | sort | diff -u - /tmp/tar2.txt >&2 +rm /tmp/debian-chroot.tar /tmp/tar2.txt diff --git a/tests/create-gzip-compressed-tarball b/tests/create-gzip-compressed-tarball new file mode 100644 index 0000000..1492df2 --- /dev/null +++ b/tests/create-gzip-compressed-tarball @@ -0,0 +1,20 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar.gz {{ MIRROR }} +printf '\037\213\010' | cmp --bytes=3 /tmp/debian-chroot.tar.gz - +tar -tf /tmp/debian-chroot.tar.gz | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar.gz diff --git a/tests/create-tarball-dry-run b/tests/create-tarball-dry-run new file mode 100644 index 0000000..f4c5fe2 --- /dev/null +++ b/tests/create-tarball-dry-run @@ -0,0 +1,27 @@ +#!/bin/sh +# +# we are testing all variants here because with 0.7.5 we had a bug: +# mmdebstrap sid /dev/null --simulate ==> E: cannot read /var/cache/apt/archives/ + +set -eu +export LC_ALL=C.UTF-8 +prefix= +include=, +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != root ] && [ "{{ MODE }}" != auto ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" + if [ "{{ VARIANT }}" = extract ] || [ "{{ VARIANT }}" = custom ]; then + include="$(tr '\n' ',' < pkglist.txt)" + fi +fi +$prefix {{ CMD }} --mode={{ MODE }} --include="$include" --dry-run --variant={{ VARIANT }} {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +if [ -e /tmp/debian-chroot.tar ]; then + echo "/tmp/debian-chroot.tar must not be created with --dry-run" >&2 + exit 1 +fi diff --git a/tests/create-tarball-with-tmp-mounted-nodev b/tests/create-tarball-with-tmp-mounted-nodev new file mode 100644 index 0000000..61ff320 --- /dev/null +++ b/tests/create-tarball-with-tmp-mounted-nodev @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +mount -t tmpfs -o nodev,nosuid,size=400M tmpfs /tmp +# use --customize-hook to exercise the mounting/unmounting code of block devices in root mode +{{ CMD }} --mode=root --variant=apt --customize-hook='mount | grep /dev/full' --customize-hook='test "$(echo foo | tee /dev/full 2>&1 1>/dev/null)" = "tee: /dev/full: No space left on device"' {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/custom-tmpdir b/tests/custom-tmpdir new file mode 100644 index 0000000..bfd3651 --- /dev/null +++ b/tests/custom-tmpdir @@ -0,0 +1,33 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +[ "$(id -u)" -eq 0 ] +[ {{ MODE }} = "unshare" ] + +if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" +fi +prefix="runuser -u ${SUDO_USER:-user} --" + +# https://www.etalabs.net/sh_tricks.html +quote () { printf %s\\n "$1" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/" ; } +homedir=$($prefix sh -c 'cd && pwd') +# apt:test/integration/test-apt-key +TMPDIR_ADD="This is fü\$\$ing crà zy, \$(apt -v)\$!" +$prefix mkdir "$homedir/$TMPDIR_ADD" +# make sure the unshared user can traverse into the TMPDIR +chmod 711 "$homedir" +# set permissions and sticky bit like the real /tmp +chmod 1777 "$homedir/$TMPDIR_ADD" +$prefix env TMPDIR="$homedir/$TMPDIR_ADD" {{ CMD }} --mode={{ MODE }} --variant=apt \ + --setup-hook='case "$1" in '"$(quote "$homedir/$TMPDIR_ADD/mmdebstrap.")"'??????????) exit 0;; *) echo "$1"; exit 1;; esac' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +# use rmdir as a quick check that nothing is remaining in TMPDIR +$prefix rmdir "$homedir/$TMPDIR_ADD" +rm /tmp/debian-chroot.tar diff --git a/tests/customize-hook b/tests/customize-hook new file mode 100644 index 0000000..6437eac --- /dev/null +++ b/tests/customize-hook @@ -0,0 +1,16 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/customize.sh" EXIT INT TERM +cat << 'SCRIPT' > /tmp/customize.sh +#!/bin/sh +chroot "$1" whoami > "$1/output2" +chroot "$1" pwd >> "$1/output2" +SCRIPT +chmod +x /tmp/customize.sh +{{ CMD }} --mode=root --variant=apt --customize-hook='chroot "$1" sh -c "whoami; pwd" > "$1/output1"' --customize-hook=/tmp/customize.sh {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf "root\n/\n" | cmp /tmp/debian-chroot/output1 +printf "root\n/\n" | cmp /tmp/debian-chroot/output2 +rm /tmp/debian-chroot/output1 +rm /tmp/debian-chroot/output2 +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/cwd-directory-not-accessible-by-unshared-user b/tests/cwd-directory-not-accessible-by-unshared-user new file mode 100644 index 0000000..859cf6b --- /dev/null +++ b/tests/cwd-directory-not-accessible-by-unshared-user @@ -0,0 +1,30 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +[ "$(id -u)" -eq 0 ] +[ {{ MODE }} = "unshare" ] + +if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" +fi +prefix="runuser -u ${SUDO_USER:-user} --" + +mkdir /tmp/debian-chroot +chmod 700 /tmp/debian-chroot +chown "${SUDO_USER:-user}:${SUDO_USER:-user}" /tmp/debian-chroot +set -- env --chdir=/tmp/debian-chroot +if [ "{{ CMD }}" = "./mmdebstrap" ]; then + set -- "$@" "$(realpath --canonicalize-existing ./mmdebstrap)" +elif [ "{{ CMD }}" = "perl -MDevel::Cover=-silent,-nogcov ./mmdebstrap" ]; then + set -- "$@" perl -MDevel::Cover=-silent,-nogcov "$(realpath --canonicalize-existing ./mmdebstrap)" +else + set -- "$@" {{ CMD }} +fi +$prefix "$@" --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/deb822-1-2 b/tests/deb822-1-2 new file mode 100644 index 0000000..1459117 --- /dev/null +++ b/tests/deb822-1-2 @@ -0,0 +1,45 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/sources.list /tmp/deb822.sources" EXIT INT TERM +cat << SOURCES > /tmp/deb822.sources +Types: deb +URIs: {{ MIRROR }}1 +Suites: {{ DIST }} +Components: main +SOURCES +echo "deb {{ MIRROR }}2 {{ DIST }} main" > /tmp/sources.list +echo "deb {{ MIRROR }}3 {{ DIST }} main" \ + | {{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} \ + /tmp/debian-chroot \ + /tmp/deb822.sources \ + {{ MIRROR }}4 \ + - \ + "deb {{ MIRROR }}5 {{ DIST }} main" \ + {{ MIRROR }}6 \ + /tmp/sources.list +test ! -e /tmp/debian-chroot/etc/apt/sources.list +cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0000deb822.sources - +Types: deb +URIs: {{ MIRROR }}1 +Suites: {{ DIST }} +Components: main +SOURCES +cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0001main.list - +deb {{ MIRROR }}4 {{ DIST }} main + +deb {{ MIRROR }}3 {{ DIST }} main + +deb {{ MIRROR }}5 {{ DIST }} main + +deb {{ MIRROR }}6 {{ DIST }} main +SOURCES +echo "deb {{ MIRROR }}2 {{ DIST }} main" | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0002sources.list - +tar -C /tmp/debian-chroot --one-file-system -c . \ + | { + tar -t \ + | grep -v "^./etc/apt/sources.list.d/0000deb822.sources$" \ + | grep -v "^./etc/apt/sources.list.d/0001main.list$" \ + | grep -v "^./etc/apt/sources.list.d/0002sources.list"; + printf "./etc/apt/sources.list\n"; + } | sort | diff -u tar1.txt - diff --git a/tests/deb822-2-2 b/tests/deb822-2-2 new file mode 100644 index 0000000..c533264 --- /dev/null +++ b/tests/deb822-2-2 @@ -0,0 +1,44 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/sources /tmp/deb822" EXIT INT TERM +cat << SOURCES > /tmp/deb822 +Types: deb +URIs: {{ MIRROR }}1 +Suites: {{ DIST }} +Components: main +SOURCES +echo "deb {{ MIRROR }}2 {{ DIST }} main" > /tmp/sources +cat << SOURCES | {{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} \ + /tmp/debian-chroot \ + /tmp/deb822 \ + - \ + /tmp/sources +Types: deb +URIs: {{ MIRROR }}3 +Suites: {{ DIST }} +Components: main +SOURCES +test ! -e /tmp/debian-chroot/etc/apt/sources.list +ls -lha /tmp/debian-chroot/etc/apt/sources.list.d/ +cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0000deb822.sources - +Types: deb +URIs: {{ MIRROR }}1 +Suites: {{ DIST }} +Components: main +SOURCES +cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0001main.sources - +Types: deb +URIs: {{ MIRROR }}3 +Suites: {{ DIST }} +Components: main +SOURCES +echo "deb {{ MIRROR }}2 {{ DIST }} main" | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0002sources.list - +tar -C /tmp/debian-chroot --one-file-system -c . \ + | { + tar -t \ + | grep -v "^./etc/apt/sources.list.d/0000deb822.sources$" \ + | grep -v "^./etc/apt/sources.list.d/0001main.sources$" \ + | grep -v "^./etc/apt/sources.list.d/0002sources.list$"; + printf "./etc/apt/sources.list\n"; + } | sort | diff -u tar1.txt - diff --git a/tests/debootstrap b/tests/debootstrap new file mode 100644 index 0000000..63c217d --- /dev/null +++ b/tests/debootstrap @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +tmpdir="$(mktemp -d)" +chmod 755 "$tmpdir" +debootstrap "$([ "{{ DIST }}" = oldstable ] && echo --no-merged-usr || echo --merged-usr)" --variant={{ VARIANT }} {{ DIST }} "$tmpdir" {{ MIRROR }} +tar --sort=name --mtime=@$SOURCE_DATE_EPOCH --clamp-mtime --numeric-owner --one-file-system --xattrs -C "$tmpdir" -c . > "./cache/debian-{{ DIST }}-{{ VARIANT }}.tar" +rm -r "$tmpdir" diff --git a/tests/debootstrap-no-op-options b/tests/debootstrap-no-op-options new file mode 100644 index 0000000..cd41681 --- /dev/null +++ b/tests/debootstrap-no-op-options @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode=root --variant=apt --resolve-deps --merged-usr --no-merged-usr --force-check-gpg {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/debug b/tests/debug new file mode 100644 index 0000000..5612115 --- /dev/null +++ b/tests/debug @@ -0,0 +1,17 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM + +# we use variant standard in verbose mode to see the maximum number of packages +# that was chosen in case of USE_HOST_APT_CONFIG=yes +# we use variant important on arches where variant standard is not bit-by-bit +# reproducible due to #1031276 +case {{ VARIANT }} in standard|-) : ;; *) exit 1;; esac + +{{ CMD }} --variant={{ VARIANT }} --debug {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} + +cmp ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.tar /tmp/debian-chroot.tar \ + || diffoscope ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.tar /tmp/debian-chroot.tar diff --git a/tests/debug-output-on-fake-tty b/tests/debug-output-on-fake-tty new file mode 100644 index 0000000..c8c8a87 --- /dev/null +++ b/tests/debug-output-on-fake-tty @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +script -qfc "{{ CMD }} --mode={{ MODE }} --debug --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}" /dev/null +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/dev-ptmx b/tests/dev-ptmx new file mode 100644 index 0000000..5eb7bd0 --- /dev/null +++ b/tests/dev-ptmx @@ -0,0 +1,149 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +if [ {{ MODE }} != unshare ] && [ {{ MODE }} != root ]; then + echo "test requires root or unshare mode" >&2 + exit 1 +fi + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +# this mimics what apt does in apt-pkg/deb/dpkgpm.cc/pkgDPkgPM::StartPtyMagic() +cat > /tmp/test.c << 'END' +#define _GNU_SOURCE + +#include <stdlib.h> +#include <fcntl.h> +#include <termios.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <signal.h> + +int main() { + int ret; + int fd = posix_openpt(O_RDWR | O_NOCTTY); + if (fd < 0) { + perror("posix_openpt"); + return 1; + } + char buf[64]; // 64 is used by apt + ret = ptsname_r(fd, buf, sizeof(buf)); + if (ret != 0) { + perror("ptsname_r"); + return 1; + } + ret = grantpt(fd); + if (ret == -1) { + perror("grantpt"); + return 1; + } + struct termios origtt; + ret = tcgetattr(STDIN_FILENO, &origtt); + if (ret != 0) { + perror("tcgetattr1"); + return 1; + } + struct termios tt; + ret = tcgetattr(STDOUT_FILENO, &tt); + if (ret != 0) { + perror("tcgetattr2"); + return 1; + } + struct winsize win; + ret = ioctl(STDOUT_FILENO, TIOCGWINSZ, &win); + if (ret < 0) { + perror("ioctl stdout TIOCGWINSZ"); + return 1; + } + ret = ioctl(fd, TIOCSWINSZ, &win); + if (ret < 0) { + perror("ioctl fd TIOCGWINSZ"); + return 1; + } + ret = tcsetattr(fd, TCSANOW, &tt); + if (ret != 0) { + perror("tcsetattr1"); + return 1; + } + cfmakeraw(&tt); + tt.c_lflag &= ~ECHO; + tt.c_lflag |= ISIG; + sigset_t sigmask; + sigset_t sigmask_old; + ret = sigemptyset(&sigmask); + if (ret != 0) { + perror("sigemptyset"); + return 1; + } + ret = sigaddset(&sigmask, SIGTTOU); + if (ret != 0) { + perror("sigaddset"); + return 1; + } + ret = sigprocmask(SIG_BLOCK,&sigmask, &sigmask_old); + if (ret != 0) { + perror("sigprocmask1"); + return 1; + } + ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt); + if (ret != 0) { + perror("tcsetattr2"); + return 1; + } + ret = sigprocmask(SIG_BLOCK,&sigmask_old, NULL); + if (ret != 0) { + perror("sigprocmask2"); + return 1; + } + ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, &origtt); + if (ret != 0) { + perror("tcsetattr3"); + return 1; + } + return 0; +} +END + +# use script to create a fake tty +# run all tests as root and as a normal user (the latter requires ptmxmode=666) +script -qfec "$prefix {{ CMD }} --mode={{ MODE }} --variant=apt \ + --include=gcc,libc6-dev,python3,passwd \ + --customize-hook='chroot \"\$1\" useradd --home-dir /home/user --create-home user' \ + --customize-hook='chroot \"\$1\" python3 -c \"import pty; print(pty.openpty())\"' \ + --customize-hook='chroot \"\$1\" runuser -u user -- python3 -c \"import pty; print(pty.openpty())\"' \ + --customize-hook='chroot \"\$1\" script -c \"echo foobar\"' \ + --customize-hook='chroot \"\$1\" runuser -u user -- env --chdir=/home/user script -c \"echo foobar\"' \ + --customize-hook='chroot \"\$1\" apt-get install --yes doc-debian 2>&1 | tee \"\$1\"/tmp/log' \ + --customize-hook=\"copy-in /tmp/test.c /tmp\" \ + --customize-hook='chroot \"\$1\" gcc /tmp/test.c -o /tmp/test' \ + --customize-hook='chroot \"\$1\" /tmp/test' \ + --customize-hook='chroot \"\$1\" runuser -u user -- /tmp/test' \ + --customize-hook='rm \"\$1\"/tmp/test \"\$1\"/tmp/test.c' \ + --customize-hook=\"copy-out /tmp/log /tmp\" \ + {{ DIST }} /dev/null {{ MIRROR }}" /dev/null + +fail=0 +[ -r /tmp/log ] || fail=1 +grep '^E:' /tmp/log && fail=1 +grep 'Can not write log' /tmp/log && fail=1 +grep 'posix_openpt' /tmp/log && fail=1 +grep 'No such file or directory' /tmp/log && fail=1 +if [ $fail -eq 1 ]; then + echo "apt failed to write log:" >&2 + cat /tmp/log >&2 + exit 1 +fi + +rm /tmp/test.c /tmp/log diff --git a/tests/directory-ending-in-tar b/tests/directory-ending-in-tar new file mode 100644 index 0000000..b44e35a --- /dev/null +++ b/tests/directory-ending-in-tar @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +[ "$(whoami)" = "root" ] +trap "rm -rf /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=apt --format=directory {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +ftype=$(stat -c %F /tmp/debian-chroot.tar) +if [ "$ftype" != directory ]; then + echo "expected directory but got: $ftype" >&2 + exit 1 +fi +tar -C /tmp/debian-chroot.tar --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/dist-using-codename b/tests/dist-using-codename new file mode 100644 index 0000000..96d8929 --- /dev/null +++ b/tests/dist-using-codename @@ -0,0 +1,13 @@ +#!/bin/sh +# +# make sure that using codenames works https://bugs.debian.org/1003191 + +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f InRelease; rm -rf /tmp/debian-chroot.tar /tmp/expected" EXIT INT TERM +/usr/lib/apt/apt-helper download-file "{{ MIRROR }}/dists/{{ DIST }}/InRelease" InRelease +codename=$(awk '/^Codename: / { print $2; }' InRelease) +{{ CMD }} --mode={{ MODE }} --variant=apt "$codename" /tmp/debian-chroot.tar {{ MIRROR }} +echo "deb {{ MIRROR }} $codename main" > /tmp/expected +tar --to-stdout --extract --file /tmp/debian-chroot.tar ./etc/apt/sources.list \ + | diff -u /tmp/expected - diff --git a/tests/dpkgopt b/tests/dpkgopt new file mode 100644 index 0000000..1a41da4 --- /dev/null +++ b/tests/dpkgopt @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/config" EXIT INT TERM +echo no-pager > /tmp/config +{{ CMD }} --mode=root --variant=apt --dpkgopt="path-exclude=/usr/share/doc/*" --dpkgopt=/tmp/config --dpkgopt="path-include=/usr/share/doc/dpkg/copyright" {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf 'path-exclude=/usr/share/doc/*\nno-pager\npath-include=/usr/share/doc/dpkg/copyright\n' | cmp /tmp/debian-chroot/etc/dpkg/dpkg.cfg.d/99mmdebstrap - +rm /tmp/debian-chroot/etc/dpkg/dpkg.cfg.d/99mmdebstrap +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort > tar2.txt +{ grep -v '^./usr/share/doc/.' tar1.txt; echo ./usr/share/doc/dpkg/; echo ./usr/share/doc/dpkg/copyright; } | sort | diff -u - tar2.txt diff --git a/tests/eatmydata-via-hook-dir b/tests/eatmydata-via-hook-dir new file mode 100644 index 0000000..0df72df --- /dev/null +++ b/tests/eatmydata-via-hook-dir @@ -0,0 +1,43 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +cat << SCRIPT > /tmp/checkeatmydata.sh +#!/bin/sh +set -exu +cat << EOF | diff - "\$1"/usr/bin/dpkg +#!/bin/sh +exec /usr/bin/eatmydata /usr/bin/dpkg.distrib "\\\$@" +EOF +[ -e "\$1"/usr/bin/eatmydata ] +SCRIPT +chmod +x /tmp/checkeatmydata.sh +# first four bytes: magic +elfheader="\\177ELF" +# fifth byte: bits +case "$(dpkg-architecture -qDEB_HOST_ARCH_BITS)" in + 32) elfheader="$elfheader\\001";; + 64) elfheader="$elfheader\\002";; + *) echo "bits not supported"; exit 1;; +esac +# sixth byte: endian +case "$(dpkg-architecture -qDEB_HOST_ARCH_ENDIAN)" in + little) elfheader="$elfheader\\001";; + big) elfheader="$elfheader\\002";; + *) echo "endian not supported"; exit 1;; +esac +# seventh and eigth byte: elf version (1) and abi (unset) +elfheader="$elfheader\\001\\000" +{{ CMD }} --mode=root --variant=apt \ + --customize-hook=/tmp/checkeatmydata.sh \ + --essential-hook=/tmp/checkeatmydata.sh \ + --extract-hook='printf "'"$elfheader"'" | cmp --bytes=8 - "$1"/usr/bin/dpkg' \ + --hook-dir=./hooks/eatmydata \ + --customize-hook='printf "'"$elfheader"'" | cmp --bytes=8 - "$1"/usr/bin/dpkg' \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} + tar -C /tmp/debian-chroot --one-file-system -c . \ + | tar -t \ + | sort \ + | grep -v '^\./var/lib/dpkg/diversions\(-old\)\?$' \ + | diff -u tar1.txt - +rm /tmp/checkeatmydata.sh +rm -r /tmp/debian-chroot diff --git a/tests/empty-sources.list b/tests/empty-sources.list new file mode 100644 index 0000000..bf384f3 --- /dev/null +++ b/tests/empty-sources.list @@ -0,0 +1,8 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +printf '' | {{ CMD }} --mode={{ MODE }} --variant=apt \ + --setup-hook='echo "deb {{ MIRROR }} {{ DIST }} main" > "$1"/etc/apt/sources.list' \ + {{ DIST }} /tmp/debian-chroot.tar - +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/error-if-stdout-is-tty b/tests/error-if-stdout-is-tty new file mode 100644 index 0000000..b4f6923 --- /dev/null +++ b/tests/error-if-stdout-is-tty @@ -0,0 +1,12 @@ +#!/bin/sh + +set -eu + +export LC_ALL=C.UTF-8 + +ret=0 +script -qfec "{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} - {{ MIRROR }}" /dev/null || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/essential-hook b/tests/essential-hook new file mode 100644 index 0000000..dc2b01f --- /dev/null +++ b/tests/essential-hook @@ -0,0 +1,21 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/essential.sh" EXIT INT TERM +cat << 'SCRIPT' > /tmp/essential.sh +#!/bin/sh +echo tzdata tzdata/Zones/Europe select Berlin | chroot "$1" debconf-set-selections +SCRIPT +chmod +x /tmp/essential.sh +{{ CMD }} --mode=root --variant=apt --include=tzdata --essential-hook='echo tzdata tzdata/Areas select Europe | chroot "$1" debconf-set-selections' --essential-hook=/tmp/essential.sh {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +[ "$(readlink /tmp/debian-chroot/etc/localtime)" = "/usr/share/zoneinfo/Europe/Berlin" ] +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort \ + | grep -v '^./etc/localtime' \ + | grep -v '^./etc/timezone' \ + | grep -v '^./usr/sbin/tzconfig' \ + | grep -v '^./usr/share/doc/tzdata' \ + | grep -v '^./usr/share/lintian/overrides/tzdata' \ + | grep -v '^./usr/share/zoneinfo' \ + | grep -v '^./var/lib/dpkg/info/tzdata.' \ + | grep -v '^./var/lib/apt/extended_states$' \ + | diff -u tar1.txt - diff --git a/tests/existing-directory-with-lost-found b/tests/existing-directory-with-lost-found new file mode 100644 index 0000000..9757d06 --- /dev/null +++ b/tests/existing-directory-with-lost-found @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +mkdir /tmp/debian-chroot +mkdir /tmp/debian-chroot/lost+found +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +rmdir /tmp/debian-chroot/lost+found +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/existing-empty-directory b/tests/existing-empty-directory new file mode 100644 index 0000000..23efeea --- /dev/null +++ b/tests/existing-empty-directory @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +mkdir /tmp/debian-chroot +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/fail-installing-to-existing-file b/tests/fail-installing-to-existing-file new file mode 100644 index 0000000..916c98c --- /dev/null +++ b/tests/fail-installing-to-existing-file @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +trap "rm -f /tmp/exists" EXIT INT TERM + +touch /tmp/exists +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/exists {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-installing-to-non-empty-lost-found b/tests/fail-installing-to-non-empty-lost-found new file mode 100644 index 0000000..4130bf5 --- /dev/null +++ b/tests/fail-installing-to-non-empty-lost-found @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm /tmp/debian-chroot/lost+found/exists; rmdir /tmp/debian-chroot/lost+found /tmp/debian-chroot" EXIT INT TERM +mkdir /tmp/debian-chroot +mkdir /tmp/debian-chroot/lost+found +touch /tmp/debian-chroot/lost+found/exists +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-installing-to-non-empty-target-directory b/tests/fail-installing-to-non-empty-target-directory new file mode 100644 index 0000000..2606b7f --- /dev/null +++ b/tests/fail-installing-to-non-empty-target-directory @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rmdir /tmp/debian-chroot/lost+found; rm /tmp/debian-chroot/exists; rmdir /tmp/debian-chroot" EXIT INT TERM +mkdir /tmp/debian-chroot +mkdir /tmp/debian-chroot/lost+found +touch /tmp/debian-chroot/exists +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-installing-to-root b/tests/fail-installing-to-root new file mode 100644 index 0000000..ded6b5d --- /dev/null +++ b/tests/fail-installing-to-root @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} / {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-with-missing-lz4 b/tests/fail-with-missing-lz4 new file mode 100644 index 0000000..71c6d60 --- /dev/null +++ b/tests/fail-with-missing-lz4 @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar.lz4 {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-with-path-with-quotes b/tests/fail-with-path-with-quotes new file mode 100644 index 0000000..5483ff1 --- /dev/null +++ b/tests/fail-with-path-with-quotes @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +trap 'rm -rf /tmp/quoted\"path' EXIT INT TERM + +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/quoted\"path {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-without-etc-subuid b/tests/fail-without-etc-subuid new file mode 100644 index 0000000..7a0b146 --- /dev/null +++ b/tests/fail-without-etc-subuid @@ -0,0 +1,16 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +useradd --home-dir /home/user --create-home user +rm /etc/subuid +ret=0 +runuser -u user -- {{ CMD }} --mode=unshare --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi +[ ! -e /tmp/debian-chroot ] diff --git a/tests/fail-without-username-in-etc-subuid b/tests/fail-without-username-in-etc-subuid new file mode 100644 index 0000000..319eadf --- /dev/null +++ b/tests/fail-without-username-in-etc-subuid @@ -0,0 +1,17 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +useradd --home-dir /home/user --create-home user +awk -F: '$1!="user"' /etc/subuid > /etc/subuid.tmp +mv /etc/subuid.tmp /etc/subuid +ret=0 +runuser -u user -- {{ CMD }} --mode=unshare --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi +[ ! -e /tmp/debian-chroot ] diff --git a/tests/failing-customize-hook b/tests/failing-customize-hook new file mode 100644 index 0000000..8ecc065 --- /dev/null +++ b/tests/failing-customize-hook @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +ret=0 +{{ CMD }} --mode=root --variant=apt --customize-hook='chroot "$1" sh -c "exit 1"' {{ DIST }} /tmp/debian-chroot {{ MIRROR }} || ret=$? +rm -r /tmp/debian-chroot +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/file-mirror b/tests/file-mirror new file mode 100644 index 0000000..b0388bb --- /dev/null +++ b/tests/file-mirror @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 + exit 1 +fi +{{ CMD }} --mode={{ MODE }} --variant=apt \ + --setup-hook='mkdir -p "$1"/mnt/cache/debian; mount -o ro,bind /mnt/cache/debian "$1"/mnt/cache/debian' \ + --customize-hook='umount "$1"/mnt/cache/debian; rmdir "$1"/mnt/cache/debian "$1"/mnt/cache' \ + {{ DIST }} /tmp/debian-chroot.tar "deb file:///mnt/cache/debian {{ DIST }} main" +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/file-mirror-automount-hook b/tests/file-mirror-automount-hook new file mode 100644 index 0000000..11ab330 --- /dev/null +++ b/tests/file-mirror-automount-hook @@ -0,0 +1,20 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 + exit 1 +fi +if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then + useradd --home-dir /home/user --create-home user +fi +prefix= +[ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && prefix="runuser -u user --" +[ "{{ MODE }}" = "fakechroot" ] && prefix="$prefix fakechroot fakeroot" +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt \ + --hook-dir=./hooks/file-mirror-automount \ + --customize-hook='[ ! -e "$1"/mnt/cache/debian/ ] || rmdir "$1"/mnt/cache/debian/' \ + --customize-hook='rmdir "$1"/mnt/cache' \ + {{ DIST }} /tmp/debian-chroot.tar "deb file:///mnt/cache/debian {{ DIST }} main" +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/help b/tests/help new file mode 100644 index 0000000..535eeba --- /dev/null +++ b/tests/help @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +# we redirect to /dev/null instead of using --quiet to not cause a broken pipe +# when grep exits before mmdebstrap was able to write all its output +{{ CMD }} --help | grep --fixed-strings 'mmdebstrap [OPTION...] [SUITE [TARGET [MIRROR...]]]' >/dev/null diff --git a/tests/hook-directory b/tests/hook-directory new file mode 100644 index 0000000..c9b22f9 --- /dev/null +++ b/tests/hook-directory @@ -0,0 +1,49 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +for h in hookA hookB; do + mkdir /tmp/$h + for s in setup extract essential customize; do + cat << SCRIPT > /tmp/$h/${s}00.sh +#!/bin/sh +echo $h/${s}00 >> "\$1/$s" +SCRIPT + chmod +x /tmp/$h/${s}00.sh + cat << SCRIPT > /tmp/$h/${s}01.sh +echo $h/${s}01 >> "\$1/$s" +SCRIPT + chmod +x /tmp/$h/${s}01.sh + done +done +{{ CMD }} --mode=root --variant=apt \ + --setup-hook='echo cliA/setup >> "$1"/setup' \ + --extract-hook='echo cliA/extract >> "$1"/extract' \ + --essential-hook='echo cliA/essential >> "$1"/essential' \ + --customize-hook='echo cliA/customize >> "$1"/customize' \ + --hook-dir=/tmp/hookA \ + --setup-hook='echo cliB/setup >> "$1"/setup' \ + --extract-hook='echo cliB/extract >> "$1"/extract' \ + --essential-hook='echo cliB/essential >> "$1"/essential' \ + --customize-hook='echo cliB/customize >> "$1"/customize' \ + --hook-dir=/tmp/hookB \ + --setup-hook='echo cliC/setup >> "$1"/setup' \ + --extract-hook='echo cliC/extract >> "$1"/extract' \ + --essential-hook='echo cliC/essential >> "$1"/essential' \ + --customize-hook='echo cliC/customize >> "$1"/customize' \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf "cliA/setup\nhookA/setup00\nhookA/setup01\ncliB/setup\nhookB/setup00\nhookB/setup01\ncliC/setup\n" | diff -u - /tmp/debian-chroot/setup +printf "cliA/extract\nhookA/extract00\nhookA/extract01\ncliB/extract\nhookB/extract00\nhookB/extract01\ncliC/extract\n" | diff -u - /tmp/debian-chroot/extract +printf "cliA/essential\nhookA/essential00\nhookA/essential01\ncliB/essential\nhookB/essential00\nhookB/essential01\ncliC/essential\n" | diff -u - /tmp/debian-chroot/essential +printf "cliA/customize\nhookA/customize00\nhookA/customize01\ncliB/customize\nhookB/customize00\nhookB/customize01\ncliC/customize\n" | diff -u - /tmp/debian-chroot/customize +for s in setup extract essential customize; do + rm /tmp/debian-chroot/$s +done +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +for h in hookA hookB; do + for s in setup extract essential customize; do + rm /tmp/$h/${s}00.sh + rm /tmp/$h/${s}01.sh + done + rmdir /tmp/$h +done +rm -r /tmp/debian-chroot diff --git a/tests/i386-which-can-be-executed-without-qemu b/tests/i386-which-can-be-executed-without-qemu new file mode 100644 index 0000000..91c53df --- /dev/null +++ b/tests/i386-which-can-be-executed-without-qemu @@ -0,0 +1,41 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +# remove qemu just to be sure +apt-get remove --yes qemu-user-static binfmt-support qemu-user +{{ CMD }} --mode={{ MODE }} --variant=apt --architectures=i386 {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +# we ignore differences between architectures by ignoring some files +# and renaming others +{ tar -tf /tmp/debian-chroot.tar \ + | grep -v '^\./usr/bin/i386$' \ + | grep -v '^\./usr/lib/ld-linux\.so\.2$' \ + | grep -v '^\./usr/lib/i386-linux-gnu/ld-linux\.so\.2$' \ + | grep -v '^\./usr/lib/gcc/i686-linux-gnu/$' \ + | grep -v '^\./usr/lib/gcc/i686-linux-gnu/[0-9]\+/$' \ + | grep -v '^\./usr/share/man/man8/i386\.8\.gz$' \ + | grep -v '^\./usr/share/doc/[^/]\+/changelog\(\.Debian\)\?\.i386\.gz$' \ + | sed 's/i386-linux-gnu/x86_64-linux-gnu/' \ + | sed 's/i386/amd64/' \ + | sed 's/\/stubs-32.ph$/\/stubs-64.ph/'; +} | sort > tar2.txt +{ < tar1.txt \ + grep -v '^\./usr/bin/i386$' \ + | grep -v '^\./usr/bin/x86_64$' \ + | grep -v '^\./usr/lib32/$' \ + | grep -v '^\./lib32$' \ + | grep -v '^\./lib64$' \ + | grep -v '^\./usr/lib64/$' \ + | grep -v '^\./usr/lib64/ld-linux-x86-64\.so\.2$' \ + | grep -v '^\./usr/lib/gcc/x86_64-linux-gnu/$' \ + | grep -v '^\./usr/lib/gcc/x86_64-linux-gnu/[0-9]\+/$' \ + | grep -v '^\./usr/lib/x86_64-linux-gnu/ld-linux-x86-64\.so\.2$' \ + | grep -v '^\./usr/lib/x86_64-linux-gnu/libmvec\.so\.1$' \ + | grep -v '^\./usr/share/doc/[^/]\+/changelog\(\.Debian\)\?\.amd64\.gz$' \ + | grep -v '^\./usr/share/man/man8/i386\.8\.gz$' \ + | grep -v '^\./usr/share/man/man8/x86_64\.8\.gz$'; +} | sort | diff -u - tar2.txt >&2 +rm /tmp/debian-chroot.tar diff --git a/tests/include b/tests/include new file mode 100644 index 0000000..e284b7d --- /dev/null +++ b/tests/include @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +{{ CMD }} --mode=root --variant=apt --include=doc-debian {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +rm /tmp/debian-chroot/usr/share/doc-base/doc-debian.debian-* +rm -r /tmp/debian-chroot/usr/share/doc/debian +rm -r /tmp/debian-chroot/usr/share/doc/doc-debian +rm /tmp/debian-chroot/var/lib/apt/extended_states +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/include-deb-file b/tests/include-deb-file new file mode 100644 index 0000000..ad31de2 --- /dev/null +++ b/tests/include-deb-file @@ -0,0 +1,40 @@ +#!/bin/sh + +set -eu +export LC_ALL=C.UTF-8 + +trap "rm -rf /tmp/dummypkg.deb /tmp/dummypkg" EXIT INT TERM + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +# instead of obtaining a .deb from our cache, we create a new package because +# otherwise apt might decide to download the package with the same name and +# version from the cache instead of using the local .deb +mkdir -p /tmp/dummypkg/DEBIAN +cat << END > "/tmp/dummypkg/DEBIAN/control" +Package: dummypkg +Priority: optional +Section: oldlibs +Maintainer: Johannes Schauer Marin Rodrigues <josch@debian.org> +Architecture: all +Multi-Arch: foreign +Source: dummypkg +Version: 1 +Description: dummypkg +END +dpkg-deb --build "/tmp/dummypkg" "/tmp/dummypkg.deb" + +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --include="/tmp/dummypkg.deb" \ + --hook-dir=./hooks/file-mirror-automount \ + --customize-hook='chroot "$1" dpkg-query -W -f="\${Status}\n" dummypkg | grep "^install ok installed$"' \ + {{ DIST }} /dev/null {{ MIRROR }} diff --git a/tests/include-foreign-libmagic-mgc b/tests/include-foreign-libmagic-mgc new file mode 100644 index 0000000..127a84e --- /dev/null +++ b/tests/include-foreign-libmagic-mgc @@ -0,0 +1,47 @@ +#!/bin/sh +# +# to test foreign architecture package installation we choose a package which +# - is not part of the native installation set +# - does not have any dependencies +# - installs only few files +# - doesn't change its name regularly (like gcc-*-base) + +case "$(dpkg --print-architecture)" in + arm64) + native_arch=arm64 + foreign_arch=amd64 + ;; + amd64) + native_arch=amd64 + foreign_arch=arm64 + ;; + *) + echo "unsupported native architecture" >&2 + exit 1 + ;; +esac + +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode=root --variant=apt \ + --architectures="$native_arch,$foreign_arch" \ + --include="libmagic-mgc:$foreign_arch" \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +{ echo "$native_arch"; echo "$foreign_arch"; } | cmp /tmp/debian-chroot/var/lib/dpkg/arch - +rm /tmp/debian-chroot/usr/lib/file/magic.mgc +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/README.Debian +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/"changelog.Debian.$foreign_arch.gz" +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.Debian.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/copyright +rm /tmp/debian-chroot/usr/share/file/magic.mgc +rm /tmp/debian-chroot/usr/share/misc/magic.mgc +rm /tmp/debian-chroot/var/lib/apt/extended_states +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.list +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.md5sums +rmdir /tmp/debian-chroot/usr/share/doc/libmagic-mgc/ +rmdir /tmp/debian-chroot/usr/share/file/magic/ +rmdir /tmp/debian-chroot/usr/share/file/ +rmdir /tmp/debian-chroot/usr/lib/file/ +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/include-foreign-libmagic-mgc-with-multiple-arch-options b/tests/include-foreign-libmagic-mgc-with-multiple-arch-options new file mode 100644 index 0000000..3108134 --- /dev/null +++ b/tests/include-foreign-libmagic-mgc-with-multiple-arch-options @@ -0,0 +1,48 @@ +#!/bin/sh +# +# to test foreign architecture package installation we choose a package which +# - is not part of the native installation set +# - does not have any dependencies +# - installs only few files +# - doesn't change its name regularly (like gcc-*-base) + +case "$(dpkg --print-architecture)" in + arm64) + native_arch=arm64 + foreign_arch=amd64 + ;; + amd64) + native_arch=amd64 + foreign_arch=arm64 + ;; + *) + echo "unsupported native architecture" >&2 + exit 1 + ;; +esac + +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode=root --variant=apt \ + --architectures="$native_arch" \ + --architectures="$foreign_arch" \ + --include="libmagic-mgc:$foreign_arch" \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +{ echo "$native_arch"; echo "$foreign_arch"; } | cmp /tmp/debian-chroot/var/lib/dpkg/arch - +rm /tmp/debian-chroot/usr/lib/file/magic.mgc +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/README.Debian +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/"changelog.Debian.$foreign_arch.gz" +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.Debian.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/copyright +rm /tmp/debian-chroot/usr/share/file/magic.mgc +rm /tmp/debian-chroot/usr/share/misc/magic.mgc +rm /tmp/debian-chroot/var/lib/apt/extended_states +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.list +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.md5sums +rmdir /tmp/debian-chroot/usr/share/doc/libmagic-mgc/ +rmdir /tmp/debian-chroot/usr/share/file/magic/ +rmdir /tmp/debian-chroot/usr/share/file/ +rmdir /tmp/debian-chroot/usr/lib/file/ +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/include-with-multiple-apt-sources b/tests/include-with-multiple-apt-sources new file mode 100644 index 0000000..1d335d4 --- /dev/null +++ b/tests/include-with-multiple-apt-sources @@ -0,0 +1,10 @@ +#!/bin/sh +# +# This checks for https://bugs.debian.org/976166 +# Since $DEFAULT_DIST varies, we hardcode stable and unstable. + +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +{{ CMD }} --mode=root --variant=minbase --include=doc-debian unstable /tmp/debian-chroot "deb {{ MIRROR }} unstable main" "deb {{ MIRROR }} stable main" +chroot /tmp/debian-chroot dpkg-query --show doc-debian diff --git a/tests/install-busybox-based-sub-essential-system b/tests/install-busybox-based-sub-essential-system new file mode 100644 index 0000000..7854f0e --- /dev/null +++ b/tests/install-busybox-based-sub-essential-system @@ -0,0 +1,41 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM + +pkgs=base-files,base-passwd,busybox,debianutils,dpkg,libc-bin,mawk,tar +# busybox --install -s will install symbolic links into the rootfs, leaving +# existing files untouched. It has to run after extraction (otherwise there is +# no busybox binary) and before first configuration +{{ CMD }} --mode=root --variant=custom \ + --include=$pkgs \ + --setup-hook='mkdir -p "$1/bin"' \ + --setup-hook='echo root:x:0:0:root:/root:/bin/sh > "$1/etc/passwd"' \ + --setup-hook='printf "root:x:0:\nmail:x:8:\nutmp:x:43:\n" > "$1/etc/group"' \ + --extract-hook='chroot "$1" busybox --install -s' \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +echo "$pkgs" | tr ',' '\n' > /tmp/expected +chroot /tmp/debian-chroot dpkg-query -f '${binary:Package}\n' -W \ + | comm -12 - /tmp/expected \ + | diff -u - /tmp/expected +rm /tmp/expected +for cmd in echo cat sed grep; do + test -L /tmp/debian-chroot/bin/$cmd + test "$(readlink /tmp/debian-chroot/bin/$cmd)" = "/usr/bin/busybox" +done +for cmd in sort tee; do + test -L /tmp/debian-chroot/usr/bin/$cmd + test "$(readlink /tmp/debian-chroot/usr/bin/$cmd)" = "/usr/bin/busybox" +done + +# if /bin or /sbin are not symlinks, add /bin and /sbin to PATH +if [ ! -L /tmp/debian-chroot/bin ] || [ ! -L /tmp/debian-chroot/sbin ]; then + export PATH="$PATH:/sbin:/bin" +fi +chroot /tmp/debian-chroot echo foobar \ + | chroot /tmp/debian-chroot cat \ + | chroot /tmp/debian-chroot sort \ + | chroot /tmp/debian-chroot tee /dev/null \ + | chroot /tmp/debian-chroot sed 's/foobar/blubber/' \ + | chroot /tmp/debian-chroot grep blubber >/dev/null diff --git a/tests/install-doc-debian b/tests/install-doc-debian new file mode 100644 index 0000000..27d7f3e --- /dev/null +++ b/tests/install-doc-debian @@ -0,0 +1,56 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +[ {{ VARIANT }} = "custom" ] +[ {{ MODE }} = "chrootless" ] + +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +$prefix {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} --include=doc-debian {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --owner=0 --group=0 --numeric-owner --sort=name --clamp-mtime --mtime="$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds)" -cf /tmp/debian-chroot.tar . +tar tvf /tmp/debian-chroot.tar > doc-debian.tar.list +rm /tmp/debian-chroot.tar +# delete contents of doc-debian +rm /tmp/debian-chroot/usr/share/doc-base/doc-debian.debian-* +rm -r /tmp/debian-chroot/usr/share/doc/debian +rm -r /tmp/debian-chroot/usr/share/doc/doc-debian +# delete real files +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/lib/dpkg/arch +rm /tmp/debian-chroot/var/cache/apt/archives/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend +rm /tmp/debian-chroot/var/lib/apt/lists/lock +## delete merged usr symlinks +#rm /tmp/debian-chroot/libx32 +#rm /tmp/debian-chroot/lib64 +#rm /tmp/debian-chroot/lib32 +#rm /tmp/debian-chroot/sbin +#rm /tmp/debian-chroot/bin +#rm /tmp/debian-chroot/lib +# in chrootless mode, there is more to remove +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Lock +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Unincorp +rm /tmp/debian-chroot/var/lib/dpkg/status-old +rm /tmp/debian-chroot/var/lib/dpkg/info/format +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir diff --git a/tests/install-doc-debian-and-output-tarball b/tests/install-doc-debian-and-output-tarball new file mode 100644 index 0000000..118ae89 --- /dev/null +++ b/tests/install-doc-debian-and-output-tarball @@ -0,0 +1,23 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +[ {{ VARIANT }} = "custom" ] +[ {{ MODE }} = "chrootless" ] + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +$prefix {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} --include=doc-debian {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar tvf /tmp/debian-chroot.tar | grep -v ' ./dev' | diff -u doc-debian.tar.list - +rm /tmp/debian-chroot.tar diff --git a/tests/install-doc-debian-and-test-hooks b/tests/install-doc-debian-and-test-hooks new file mode 100644 index 0000000..e69066c --- /dev/null +++ b/tests/install-doc-debian-and-test-hooks @@ -0,0 +1,59 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +[ {{ VARIANT }} = "custom" ] +[ {{ MODE }} = "chrootless" ] + +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +$prefix {{ CMD }} --mode={{ MODE }} --skip=cleanup/tmp --variant={{ VARIANT }} --include=doc-debian --setup-hook='touch "$1/tmp/setup"' --customize-hook='touch "$1/tmp/customize"' {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +rm /tmp/debian-chroot/tmp/setup +rm /tmp/debian-chroot/tmp/customize +tar -C /tmp/debian-chroot --owner=0 --group=0 --numeric-owner --sort=name --clamp-mtime --mtime="$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds)" -cf /tmp/debian-chroot.tar . +tar tvf /tmp/debian-chroot.tar | grep -v ' ./dev' | diff -u doc-debian.tar.list - +rm /tmp/debian-chroot.tar +# delete contents of doc-debian +rm /tmp/debian-chroot/usr/share/doc-base/doc-debian.debian-* +rm -r /tmp/debian-chroot/usr/share/doc/debian +rm -r /tmp/debian-chroot/usr/share/doc/doc-debian +# delete real files +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/lib/dpkg/arch +rm /tmp/debian-chroot/var/cache/apt/archives/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend +rm /tmp/debian-chroot/var/lib/apt/lists/lock +## delete merged usr symlinks +#rm /tmp/debian-chroot/libx32 +#rm /tmp/debian-chroot/lib64 +#rm /tmp/debian-chroot/lib32 +#rm /tmp/debian-chroot/sbin +#rm /tmp/debian-chroot/bin +#rm /tmp/debian-chroot/lib +# in chrootless mode, there is more to remove +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Lock +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Unincorp +rm /tmp/debian-chroot/var/lib/dpkg/status-old +rm /tmp/debian-chroot/var/lib/dpkg/info/format +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir diff --git a/tests/install-libmagic-mgc-on-foreign b/tests/install-libmagic-mgc-on-foreign new file mode 100644 index 0000000..918224b --- /dev/null +++ b/tests/install-libmagic-mgc-on-foreign @@ -0,0 +1,69 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +[ {{ VARIANT }} = "custom" ] +[ {{ MODE }} = "chrootless" ] + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +case "$(dpkg --print-architecture)" in + arm64) + foreign_arch=amd64 + ;; + amd64) + foreign_arch=arm64 + ;; + *) + echo "unsupported native architecture" >&2 + exit 1 + ;; +esac + +$prefix {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} --architectures="$foreign_arch" --include=libmagic-mgc {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +# delete contents of libmagic-mgc +rm /tmp/debian-chroot/usr/lib/file/magic.mgc +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/README.Debian +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.Debian.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/copyright +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/"changelog.Debian.$foreign_arch.gz" +rm /tmp/debian-chroot/usr/share/file/magic.mgc +rm /tmp/debian-chroot/usr/share/misc/magic.mgc +# delete real files +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/cache/apt/archives/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend +rm /tmp/debian-chroot/var/lib/apt/lists/lock +## delete merged usr symlinks +#rm /tmp/debian-chroot/libx32 +#rm /tmp/debian-chroot/lib64 +#rm /tmp/debian-chroot/lib32 +#rm /tmp/debian-chroot/sbin +#rm /tmp/debian-chroot/bin +#rm /tmp/debian-chroot/lib +# in chrootless mode, there is more to remove +rm /tmp/debian-chroot/var/lib/dpkg/arch +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Lock +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Unincorp +rm /tmp/debian-chroot/var/lib/dpkg/status-old +rm /tmp/debian-chroot/var/lib/dpkg/info/format +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.md5sums +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.list +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir diff --git a/tests/invalid-mirror b/tests/invalid-mirror new file mode 100644 index 0000000..97cde05 --- /dev/null +++ b/tests/invalid-mirror @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}/invalid || ret=$? +rm /tmp/debian-chroot.tar +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/jessie-or-older b/tests/jessie-or-older new file mode 100644 index 0000000..a3a2ace --- /dev/null +++ b/tests/jessie-or-older @@ -0,0 +1,42 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +trap "rm -f /tmp/debian-chroot-{{ MODE }}.tar /tmp/debian-chroot-root-normal.tar" EXIT INT TERM + +[ "$(id -u)" -eq 0 ] + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +MMTARFILTER= +[ -x /usr/bin/mmtarfilter ] && MMTARFILTER=/usr/bin/mmtarfilter +[ -x ./tarfilter ] && MMTARFILTER=./tarfilter + +filter() { + "$MMTARFILTER" \ + --path-exclude=/usr/bin/uncompress \ + --path-exclude=/var/cache/debconf/config.dat-old \ + --path-exclude=/var/cache/debconf/templates.dat-old \ + --path-exclude=/var/lib/dpkg/available \ + --path-exclude=/var/lib/dpkg/diversions \ + --path-exclude=/var/lib/dpkg/cmethopt \ + --path-exclude=/var/lib/dpkg/status-old \ + --path-exclude=/var/lib/shells.state +} + +# base for comparison without jessie-or-older hook +{{ CMD }} --mode=root --variant={{ VARIANT }} {{ DIST }} - {{ MIRROR }} > /tmp/debian-chroot-root-normal.tar + +$prefix {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} --hook-dir=./hooks/jessie-or-older {{ DIST }} - {{ MIRROR }} | filter > /tmp/debian-chroot-{{ MODE }}.tar +filter < /tmp/debian-chroot-root-normal.tar | cmp - /tmp/debian-chroot-{{ MODE }}.tar diff --git a/tests/keyring b/tests/keyring new file mode 100644 index 0000000..7308f0d --- /dev/null +++ b/tests/keyring @@ -0,0 +1,18 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +for f in /etc/apt/trusted.gpg.d/*.gpg /etc/apt/trusted.gpg.d/*.asc; do + [ -e "$f" ] || continue + rm "$f" +done +rmdir /etc/apt/trusted.gpg.d +mkdir /etc/apt/trusted.gpg.d +{{ CMD }} --mode=root --variant=apt --keyring=/usr/share/keyrings/debian-archive-keyring.gpg --keyring=/usr/share/keyrings/ {{ DIST }} /tmp/debian-chroot "deb {{ MIRROR }} {{ DIST }} main" +# make sure that no [signedby=...] managed to make it into the sources.list +echo "deb {{ MIRROR }} {{ DIST }} main" | cmp /tmp/debian-chroot/etc/apt/sources.list - +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/keyring-overwrites b/tests/keyring-overwrites new file mode 100644 index 0000000..f070654 --- /dev/null +++ b/tests/keyring-overwrites @@ -0,0 +1,15 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rmdir /tmp/emptydir; rm -f /tmp/emptyfile" EXIT INT TERM +mkdir -p /tmp/emptydir +touch /tmp/emptyfile +# this overwrites the apt keyring options and should fail +ret=0 +{{ CMD }} --mode=root --variant=apt --keyring=/tmp/emptydir --keyring=/tmp/emptyfile {{ DIST }} /tmp/debian-chroot "deb {{ MIRROR }} {{ DIST }} main" || ret=$? +# make sure that no [signedby=...] managed to make it into the sources.list +echo "deb {{ MIRROR }} {{ DIST }} main" | cmp /tmp/debian-chroot/etc/apt/sources.list - +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/logfile b/tests/logfile new file mode 100644 index 0000000..5e2dbeb --- /dev/null +++ b/tests/logfile @@ -0,0 +1,22 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +trap "rm -rf /tmp/debian-chroot /tmp/log /tmp/trimmed" EXIT INT TERM + +# we check the full log to also prevent debug printfs to accidentally make it into a commit +{{ CMD }} --mode=root --variant=apt --logfile=/tmp/log {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +# omit the last line which should contain the runtime +head --lines=-1 /tmp/log > /tmp/trimmed +cat << LOG | diff -u - /tmp/trimmed +I: chroot architecture {{ HOSTARCH }} is equal to the host's architecture +I: finding correct signed-by value... +I: automatically chosen format: directory +I: running apt-get update... +I: downloading packages with apt... +I: extracting archives... +I: installing essential packages... +I: cleaning package lists and apt cache... +LOG +tail --lines=1 /tmp/log | grep '^I: success in .* seconds$' +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/man b/tests/man new file mode 100644 index 0000000..b5c38b9 --- /dev/null +++ b/tests/man @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +# we redirect to /dev/null instead of using --quiet to not cause a broken pipe +# when grep exits before mmdebstrap was able to write all its output +{{ CMD }} --man | grep --fixed-strings 'mmdebstrap [OPTION...] [*SUITE* [*TARGET* [*MIRROR*...]]]' >/dev/null diff --git a/tests/merged-fakechroot-inside-unmerged-chroot b/tests/merged-fakechroot-inside-unmerged-chroot new file mode 100644 index 0000000..c05ada1 --- /dev/null +++ b/tests/merged-fakechroot-inside-unmerged-chroot @@ -0,0 +1,49 @@ +#!/bin/sh +# +# make sure that the $FAKECHROOT_CMD_SUBST environment variable is set up +# such that one can create a merged-/usr chroot from an unmerged-/usr system + +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} +trap "rm -f /tmp/chroot-fakechroot.tar /tmp/chroot-root.tar" EXIT INT TERM +[ "$(whoami)" = "root" ] +{{ CMD }} --mode=root --variant=apt --hook-dir=./hooks/merged-usr {{ DIST }} /tmp/chroot-root.tar {{ MIRROR }} +cat << 'SCRIPT' > script.sh +#!/bin/sh +set -exu +rootfs="$1" +mkdir -p "$rootfs/mnt/hooks" +[ -e /usr/libexec/mmdebstrap/ldconfig.fakechroot ] && cp -a /usr/libexec/mmdebstrap/ldconfig.fakechroot "$rootfs/mnt" +[ -e ./ldconfig.fakechroot ] && cp -a ./ldconfig.fakechroot "$rootfs/mnt" +[ -e /usr/share/mmdebstrap/hooks/merged-usr ] && cp -a /usr/share/mmdebstrap/hooks/merged-usr "$rootfs/mnt/hooks" +[ -e ./hooks/merged-usr ] && cp -a ./hooks/merged-usr "$rootfs/mnt/hooks" +[ -e /usr/bin/mmdebstrap ] && cp -aT /usr/bin/mmdebstrap "$rootfs/usr/bin/mmdebstrap" +[ -e ./mmdebstrap ] && cp -aT ./mmdebstrap "$rootfs/mnt/mmdebstrap" +chroot "$rootfs" env --chdir=/mnt \ + runuser -u user -- \ + {{ CMD }} --mode=fakechroot --variant=apt \ + --hook-dir=./hooks/merged-usr \ + --customize-hook='chroot "$1" echo "$FAKECHROOT_CMD_SUBST" | tr ":" "\n" | sort' \ + --customize-hook='chroot "$1" sh -c "exec test \"\$(readlink /bin)\" = usr/bin"' \ + --customize-hook='chroot "$1" sh -c "exec test \"\$(realpath -e /bin/ldd)\" = /usr/bin/ldd"' \ + --customize-hook='chroot "$1" echo ":$FAKECHROOT_CMD_SUBST" | grep --quiet :/usr/bin/ldd=' \ + --customize-hook='chroot "$1" echo ":$FAKECHROOT_CMD_SUBST" | grep --quiet :/bin/ldd=' \ + --customize-hook='chroot "$1" env PATH=/bin ldd /bin/true 2>&1 | grep --quiet "fakeldd: objdump: command not found: install binutils package"' \ + --customize-hook='chroot "$1" sh -c "exec test \"\$(readlink /sbin)\" = usr/sbin"' \ + --customize-hook='chroot "$1" sh -c "exec test \"\$(realpath -e /sbin/ldconfig)\" = /usr/sbin/ldconfig"' \ + --customize-hook='chroot "$1" echo ":$FAKECHROOT_CMD_SUBST" | grep --quiet :/usr/sbin/ldconfig=' \ + --customize-hook='chroot "$1" echo ":$FAKECHROOT_CMD_SUBST" | grep --quiet :/sbin/ldconfig=' \ + --customize-hook='chroot "$1" env PATH=/sbin ldconfig 2>&1 | grep --quiet "/usr/bin/env: ‘python3’: No such file or directory"' \ + {{ DIST }} /tmp/chroot-fakechroot.tar {{ MIRROR }} +SCRIPT +chmod +x script.sh +{{ CMD }} --mode=root --variant=apt --include=perl,python3,passwd,fakeroot,fakechroot \ + --hook-dir=./hooks/no-merged-usr \ + --customize-hook='chroot "$1" useradd --home-dir /home/user --create-home user' \ + --customize-hook='chroot "$1" sh -c "exec test \"\$(realpath -e /usr/bin/ldd)\" = /usr/bin/ldd"' \ + --customize-hook='chroot "$1" sh -c "exec test ! -e /usr/sbin/ldconfig"' \ + --customize-hook=./script.sh \ + --customize-hook="copy-out /tmp/chroot-fakechroot.tar /tmp" \ + {{ DIST }} /dev/null {{ MIRROR }} +cmp /tmp/chroot-fakechroot.tar /tmp/chroot-root.tar || diffoscope /tmp/chroot-fakechroot.tar /tmp/chroot-root.tar diff --git a/tests/mirror-is-deb b/tests/mirror-is-deb new file mode 100644 index 0000000..c751aad --- /dev/null +++ b/tests/mirror-is-deb @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar "deb {{ MIRROR }} {{ DIST }} main" +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/mirror-is-real-file b/tests/mirror-is-real-file new file mode 100644 index 0000000..76f9efc --- /dev/null +++ b/tests/mirror-is-real-file @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar /tmp/sources.list" EXIT INT TERM +echo "deb {{ MIRROR }} {{ DIST }} main" > /tmp/sources.list +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar /tmp/sources.list +tar -tf /tmp/debian-chroot.tar \ + | sed 's#^./etc/apt/sources.list.d/0000sources.list$#./etc/apt/sources.list#' \ + | sort | diff -u tar1.txt - diff --git a/tests/mirror-is-stdin b/tests/mirror-is-stdin new file mode 100644 index 0000000..ba0e376 --- /dev/null +++ b/tests/mirror-is-stdin @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +echo "deb {{ MIRROR }} {{ DIST }} main" | {{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar - +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/missing-dev-sys-proc-inside-the-chroot b/tests/missing-dev-sys-proc-inside-the-chroot new file mode 100644 index 0000000..d127911 --- /dev/null +++ b/tests/missing-dev-sys-proc-inside-the-chroot @@ -0,0 +1,20 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +[ {{ MODE }} = "unshare" ] +[ {{ VARIANT }} = "custom" ] + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +$prefix {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} --include=dpkg,dash,diffutils,coreutils,libc-bin,sed {{ DIST }} /dev/null {{ MIRROR }} diff --git a/tests/missing-device-nodes-outside-the-chroot b/tests/missing-device-nodes-outside-the-chroot new file mode 100644 index 0000000..7f2fa27 --- /dev/null +++ b/tests/missing-device-nodes-outside-the-chroot @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +rm /dev/console +useradd --home-dir /home/user --create-home user +runuser -u user -- {{ CMD }} --mode=unshare --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/mmdebstrap b/tests/mmdebstrap new file mode 100644 index 0000000..3327fc6 --- /dev/null +++ b/tests/mmdebstrap @@ -0,0 +1,20 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +[ "$(id -u)" -eq 0 ] +[ {{ MODE }} = "root" ] +case {{ FORMAT }} in tar|squashfs|ext2) : ;; *) exit 1;; esac + +{{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} {{ DIST }} ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.{{ FORMAT }} {{ MIRROR }} +if [ "{{ FORMAT }}" = tar ]; then + printf 'ustar ' | cmp --bytes=6 --ignore-initial=257:0 ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.tar - +elif [ "{{ FORMAT }}" = squashfs ]; then + printf 'hsqs' | cmp --bytes=4 ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.squashfs - +elif [ "{{ FORMAT }}" = ext2 ]; then + printf '\123\357' | cmp --bytes=2 --ignore-initial=1080:0 ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.ext2 - +else + echo "unknown format: {{ FORMAT }}" >&2 + exit 1 +fi diff --git a/tests/mount-is-missing b/tests/mount-is-missing new file mode 100644 index 0000000..2e0c4b0 --- /dev/null +++ b/tests/mount-is-missing @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +for p in /bin /usr/bin /sbin /usr/sbin; do + rm -f "$p/mount" +done +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/multiple-include b/tests/multiple-include new file mode 100644 index 0000000..36f53ec --- /dev/null +++ b/tests/multiple-include @@ -0,0 +1,21 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +{{ CMD }} --mode=root --variant=apt --include=doc-debian --include=tzdata {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +rm /tmp/debian-chroot/usr/share/doc-base/doc-debian.debian-* +rm -r /tmp/debian-chroot/usr/share/doc/debian +rm -r /tmp/debian-chroot/usr/share/doc/doc-debian +rm /tmp/debian-chroot/usr/share/lintian/overrides/tzdata +rm /tmp/debian-chroot/etc/localtime +rm /tmp/debian-chroot/etc/timezone +rm -r /tmp/debian-chroot/usr/share/doc/tzdata +rm -r /tmp/debian-chroot/usr/share/zoneinfo +rm /tmp/debian-chroot/var/lib/apt/extended_states +for p in doc-debian tzdata; do + for f in list md5sums config postinst postrm templates preinst prerm; do + [ -e "/tmp/debian-chroot/var/lib/dpkg/info/$p.$f" ] || continue + rm "/tmp/debian-chroot/var/lib/dpkg/info/$p.$f" + done +done +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/no-sbin-in-path b/tests/no-sbin-in-path new file mode 100644 index 0000000..0cedc0b --- /dev/null +++ b/tests/no-sbin-in-path @@ -0,0 +1,28 @@ +#!/bin/sh +# +# If FAKECHROOT_CMD_SUBST sets up wrong substitutions, then binaries cannot be +# found. For example if /usr/bin/chroot is listed in FAKECHROOT_CMD_SUBST but +# /usr/sbin (the actual location of the chroot binary) is not in PATH, the +# command fails + +set -eu +export LC_ALL=C.UTF-8 + +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM + +[ "{{ MODE }}" = "fakechroot" ] + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +$prefix env PATH=/usr/bin:/bin fakechroot fakeroot {{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/not-having-to-install-apt-in-include-because-a-hook-did-it-before b/tests/not-having-to-install-apt-in-include-because-a-hook-did-it-before new file mode 100644 index 0000000..9a36307 --- /dev/null +++ b/tests/not-having-to-install-apt-in-include-because-a-hook-did-it-before @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=essential --include=apt \ + --essential-hook='APT_CONFIG=$MMDEBSTRAP_APT_CONFIG apt-get update' \ + --essential-hook='APT_CONFIG=$MMDEBSTRAP_APT_CONFIG apt-get --yes install apt' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | grep -v ./var/lib/apt/extended_states | diff -u tar1.txt - diff --git a/tests/pass-distribution-but-implicitly-write-to-stdout b/tests/pass-distribution-but-implicitly-write-to-stdout new file mode 100644 index 0000000..16d2243 --- /dev/null +++ b/tests/pass-distribution-but-implicitly-write-to-stdout @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +cat << HOSTS >> /etc/hosts +127.0.0.1 deb.debian.org +127.0.0.1 security.debian.org +HOSTS +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} > /tmp/debian-chroot.tar +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/pivot_root b/tests/pivot_root new file mode 100644 index 0000000..860c41b --- /dev/null +++ b/tests/pivot_root @@ -0,0 +1,54 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} +trap "rm -f /tmp/chroot1.tar /tmp/chroot2.tar /tmp/chroot3.tar /tmp/mmdebstrap" EXIT INT TERM + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" 2>/dev/null; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt \ + --include=mount \ + {{ DIST }} /tmp/chroot1.tar {{ MIRROR }} + +if [ {{ MODE }} = "unshare" ]; then + # calling pivot_root in root mode does not work for mysterious reasons: + # pivot_root: failed to change root from `.' to `mnt': Invalid argument + $prefix {{ CMD }} --mode={{ MODE }} --variant=apt --include=mount \ + --customize-hook='mkdir -p "$1/mnt" "$1/oldroot"' \ + --customize-hook='[ ! -e /usr/bin/mmdebstrap ] || cp -aT /usr/bin/mmdebstrap "$1/usr/bin/mmdebstrap"' \ + --customize-hook='[ ! -e ./mmdebstrap ] || cp -aT ./mmdebstrap "$1/mnt/mmdebstrap"' \ + --customize-hook='mount -o rbind "$1" /mnt && cd /mnt && /sbin/pivot_root . oldroot' \ + --customize-hook='unshare -U echo nested unprivileged unshare' \ + --customize-hook='env --chdir=/mnt {{ CMD }} --mode=unshare --variant=apt --include=mount {{ DIST }} /tmp/chroot3.tar {{ MIRROR }}' \ + --customize-hook='copy-out /tmp/chroot3.tar /tmp' \ + --customize-hook='rm -f "/usr/bin/mmdebstrap" "/mnt/mmdebstrap"' \ + --customize-hook='umount -l oldroot sys' \ + --customize-hook='rmdir /oldroot' \ + {{ DIST }} /tmp/chroot2.tar {{ MIRROR }} + + cmp /tmp/chroot1.tar /tmp/chroot2.tar || diffoscope /tmp/chroot1.tar /tmp/chroot2.tar + cmp /tmp/chroot1.tar /tmp/chroot3.tar || diffoscope /tmp/chroot1.tar /tmp/chroot3.tar + rm /tmp/chroot2.tar /tmp/chroot3.tar +fi + +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --include=mount \ + --customize-hook='mkdir -p "$1/mnt"' \ + --customize-hook='[ ! -e /usr/bin/mmdebstrap ] || cp -aT /usr/bin/mmdebstrap "$1/usr/bin/mmdebstrap"' \ + --customize-hook='[ ! -e ./mmdebstrap ] || cp -aT ./mmdebstrap "$1/mnt/mmdebstrap"' \ + --chrooted-customize-hook='env --chdir=/mnt {{ CMD }} --mode=unshare --variant=apt --include=mount {{ DIST }} /tmp/chroot3.tar {{ MIRROR }}' \ + --customize-hook='copy-out /tmp/chroot3.tar /tmp' \ + --customize-hook='rm -f "$1/usr/bin/mmdebstrap" "$1/mnt/mmdebstrap"' \ + {{ DIST }} /tmp/chroot2.tar {{ MIRROR }} + +cmp /tmp/chroot1.tar /tmp/chroot2.tar || diffoscope /tmp/chroot1.tar /tmp/chroot2.tar +cmp /tmp/chroot1.tar /tmp/chroot3.tar || diffoscope /tmp/chroot1.tar /tmp/chroot3.tar diff --git a/tests/preserve-mode-of-etc-resolv-conf-and-etc-hostname b/tests/preserve-mode-of-etc-resolv-conf-and-etc-hostname new file mode 100644 index 0000000..5e5f835 --- /dev/null +++ b/tests/preserve-mode-of-etc-resolv-conf-and-etc-hostname @@ -0,0 +1,102 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +for f in /etc/resolv.conf /etc/hostname; do + # preserve original content + cat "$f" > "$f.bak" + # in case $f is a symlink, we replace it by a real file + if [ -L "$f" ]; then + rm "$f" + cp "$f.bak" "$f" + fi + chmod 644 "$f" + [ "$(stat --format=%A "$f")" = "-rw-r--r--" ] +done +{{ CMD }} --variant=custom --mode={{ MODE }} {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +for f in /etc/resolv.conf /etc/hostname; do + [ "$(stat --format=%A "/tmp/debian-chroot/$f")" = "-rw-r--r--" ] +done +rm /tmp/debian-chroot/dev/console +rm /tmp/debian-chroot/dev/fd +rm /tmp/debian-chroot/dev/full +rm /tmp/debian-chroot/dev/null +rm /tmp/debian-chroot/dev/ptmx +rm /tmp/debian-chroot/dev/random +rm /tmp/debian-chroot/dev/stderr +rm /tmp/debian-chroot/dev/stdin +rm /tmp/debian-chroot/dev/stdout +rm /tmp/debian-chroot/dev/tty +rm /tmp/debian-chroot/dev/urandom +rm /tmp/debian-chroot/dev/zero +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/apt/lists/lock +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/lib/dpkg/arch +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir +for f in /etc/resolv.conf /etc/hostname; do + chmod 755 "$f" + [ "$(stat --format=%A "$f")" = "-rwxr-xr-x" ] +done +{{ CMD }} --variant=custom --mode={{ MODE }} {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +for f in /etc/resolv.conf /etc/hostname; do + [ "$(stat --format=%A "/tmp/debian-chroot/$f")" = "-rwxr-xr-x" ] +done +rm /tmp/debian-chroot/dev/console +rm /tmp/debian-chroot/dev/fd +rm /tmp/debian-chroot/dev/full +rm /tmp/debian-chroot/dev/null +rm /tmp/debian-chroot/dev/ptmx +rm /tmp/debian-chroot/dev/random +rm /tmp/debian-chroot/dev/stderr +rm /tmp/debian-chroot/dev/stdin +rm /tmp/debian-chroot/dev/stdout +rm /tmp/debian-chroot/dev/tty +rm /tmp/debian-chroot/dev/urandom +rm /tmp/debian-chroot/dev/zero +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/apt/lists/lock +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/lib/dpkg/arch +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir +for f in /etc/resolv.conf /etc/hostname; do + rm "$f" + ln -s "$f.bak" "$f" + [ "$(stat --format=%A "$f")" = "lrwxrwxrwx" ] +done +{{ CMD }} --variant=custom --mode={{ MODE }} {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +for f in /etc/resolv.conf /etc/hostname; do + [ "$(stat --format=%A "/tmp/debian-chroot/$f")" = "-rw-r--r--" ] +done +rm /tmp/debian-chroot/dev/console +rm /tmp/debian-chroot/dev/fd +rm /tmp/debian-chroot/dev/full +rm /tmp/debian-chroot/dev/null +rm /tmp/debian-chroot/dev/ptmx +rm /tmp/debian-chroot/dev/random +rm /tmp/debian-chroot/dev/stderr +rm /tmp/debian-chroot/dev/stdin +rm /tmp/debian-chroot/dev/stdout +rm /tmp/debian-chroot/dev/tty +rm /tmp/debian-chroot/dev/urandom +rm /tmp/debian-chroot/dev/zero +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/apt/lists/lock +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/lib/dpkg/arch +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir diff --git a/tests/progress-bars-on-fake-tty b/tests/progress-bars-on-fake-tty new file mode 100644 index 0000000..e403111 --- /dev/null +++ b/tests/progress-bars-on-fake-tty @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +script -qfec "{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}" /dev/null +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/quiet b/tests/quiet new file mode 100644 index 0000000..d1cbb22 --- /dev/null +++ b/tests/quiet @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode=root --variant=apt --quiet {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/read-from-stdin-write-to-stdout b/tests/read-from-stdin-write-to-stdout new file mode 100644 index 0000000..960cd3a --- /dev/null +++ b/tests/read-from-stdin-write-to-stdout @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm /tmp/debian-chroot.tar" EXIT INT TERM +echo "deb {{ MIRROR }} {{ DIST }} main" | {{ CMD }} --mode={{ MODE }} --variant=apt > /tmp/debian-chroot.tar +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/remove-start-stop-daemon-and-policy-rc-d-in-hook b/tests/remove-start-stop-daemon-and-policy-rc-d-in-hook new file mode 100644 index 0000000..d9c4be6 --- /dev/null +++ b/tests/remove-start-stop-daemon-and-policy-rc-d-in-hook @@ -0,0 +1,8 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=apt \ + --customize-hook='rm "$1/usr/sbin/policy-rc.d"; rm "$1/usr/sbin/start-stop-daemon"' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/root-mode-inside-chroot b/tests/root-mode-inside-chroot new file mode 100644 index 0000000..0049c6b --- /dev/null +++ b/tests/root-mode-inside-chroot @@ -0,0 +1,28 @@ +#!/bin/sh +# +# Same as unshare-as-root-user-inside-chroot but this time we run mmdebstrap in +# root mode from inside a chroot + +set -eu +export LC_ALL=C.UTF-8 +[ "$(whoami)" = "root" ] + +trap "rm -f /tmp/debian-chroot.tar script.sh" EXIT INT TERM + +cat << 'SCRIPT' > script.sh +#!/bin/sh +set -exu +rootfs="$1" +mkdir -p "$rootfs/mnt" +[ -e /usr/bin/mmdebstrap ] && cp -aT /usr/bin/mmdebstrap "$rootfs/usr/bin/mmdebstrap" +[ -e ./mmdebstrap ] && cp -aT ./mmdebstrap "$rootfs/mnt/mmdebstrap" +chroot "$rootfs" env --chdir=/mnt \ + {{ CMD }} --mode=root --variant=apt \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +SCRIPT +chmod +x script.sh +{{ CMD }} --mode=root --variant=apt --include=perl,mount \ + --customize-hook=./script.sh \ + --customize-hook="download /tmp/debian-chroot.tar /tmp/debian-chroot.tar" \ + {{ DIST }} /dev/null {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/root-mode-inside-unshare-chroot b/tests/root-mode-inside-unshare-chroot new file mode 100644 index 0000000..e953c65 --- /dev/null +++ b/tests/root-mode-inside-unshare-chroot @@ -0,0 +1,40 @@ +#!/bin/sh +# +# Same as root-mode-inside-chroot but this time we run mmdebstrap in root mode +# from inside an unshare chroot. + +set -eu +export LC_ALL=C.UTF-8 + +[ {{ MODE }} = "unshare" ] + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +cat << 'SCRIPT' > /tmp/script.sh +#!/bin/sh +set -eu +rootfs="$1" +mkdir -p "$rootfs/mnt" +[ -e /usr/bin/mmdebstrap ] && cp -aT /usr/bin/mmdebstrap "$rootfs/usr/bin/mmdebstrap" +[ -e ./mmdebstrap ] && cp -aT ./mmdebstrap "$rootfs/mnt/mmdebstrap" +chroot "$rootfs" env --chdir=/mnt \ + {{ CMD }} --mode=root --variant=apt \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +SCRIPT +chmod +x /tmp/script.sh +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --include=perl,mount \ + --customize-hook=/tmp/script.sh \ + --customize-hook="download /tmp/debian-chroot.tar /tmp/debian-chroot.tar" \ + {{ DIST }} /dev/null {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar /tmp/script.sh diff --git a/tests/root-without-cap-sys-admin b/tests/root-without-cap-sys-admin new file mode 100644 index 0000000..419f7b3 --- /dev/null +++ b/tests/root-without-cap-sys-admin @@ -0,0 +1,17 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +[ "$(whoami)" = "root" ] + +if grep --null-data --quiet --no-messages '^container=lxc$' /proc/1/environ; then + # see https://stackoverflow.com/questions/65748254/ + echo "cannot run under lxc -- Skipping test..." >&2 + exit 0 +fi + +capsh --drop=cap_sys_admin -- -c 'exec "$@"' exec \ + {{ CMD }} --mode=root --variant=apt \ + --customize-hook='chroot "$1" sh -c "test ! -e /proc/self/fd"' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/sigint-during-customize-hook b/tests/sigint-during-customize-hook new file mode 100644 index 0000000..c8a4c94 --- /dev/null +++ b/tests/sigint-during-customize-hook @@ -0,0 +1,22 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +setsid --wait {{ CMD }} --mode=root --variant=apt --customize-hook='touch hookstarted && sleep 10 && touch fail' {{ DIST }} /tmp/debian-chroot {{ MIRROR }} & +pid=$! +while sleep 1; do [ -e hookstarted ] && break; done +rm hookstarted +# negative PID values choose the whole process group +pgid=$((-1*$(ps -p "$pid" -o pgid=))) +/bin/kill --signal INT -- "$pgid" +ret=0 +wait $pid || ret=$? +rm -r /tmp/debian-chroot +if [ -e fail ]; then + echo customize hook was not interrupted >&2 + rm fail + exit 1 +fi +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/signed-by-with-host-keys b/tests/signed-by-with-host-keys new file mode 100644 index 0000000..ef0d8c7 --- /dev/null +++ b/tests/signed-by-with-host-keys @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf 'deb {{ MIRROR }} {{ DIST }} main\n' | cmp /tmp/debian-chroot/etc/apt/sources.list - +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/signed-by-without-host-keys b/tests/signed-by-without-host-keys new file mode 100644 index 0000000..470a9de --- /dev/null +++ b/tests/signed-by-without-host-keys @@ -0,0 +1,17 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +for f in /etc/apt/trusted.gpg.d/*.gpg /etc/apt/trusted.gpg.d/*.asc; do + [ -e "$f" ] || continue + rm "$f" +done +rmdir /etc/apt/trusted.gpg.d +mkdir /etc/apt/trusted.gpg.d +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf 'deb [signed-by="/usr/share/keyrings/debian-archive-keyring.gpg"] {{ MIRROR }} {{ DIST }} main\n' | cmp /tmp/debian-chroot/etc/apt/sources.list - +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/skip-mount b/tests/skip-mount new file mode 100644 index 0000000..e210d5c --- /dev/null +++ b/tests/skip-mount @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +[ "{{ MODE }}" = "unshare" ] +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode=unshare --variant=apt \ + --skip=chroot/mount/proc,chroot/mount/sys \ + --customize-hook='mountpoint "$1"/dev/null' \ + --customize-hook='if mountpoint "$1"/sys; then exit 1; fi' \ + --customize-hook='if mountpoint "$1"/proc; then exit 1; fi' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/skip-output-dev b/tests/skip-output-dev new file mode 100644 index 0000000..0766a66 --- /dev/null +++ b/tests/skip-output-dev @@ -0,0 +1,35 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +# test this for both unshare and root mode because the code paths creating +# entries in /dev are different depending on whether mknod is available or not +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --skip=output/dev {{ DIST }} - {{ MIRROR }} | { + tar -t; + echo ./dev/console; + echo ./dev/fd; + echo ./dev/full; + echo ./dev/null; + echo ./dev/ptmx; + echo ./dev/pts/; + echo ./dev/random; + echo ./dev/shm/; + echo ./dev/stderr; + echo ./dev/stdin; + echo ./dev/stdout; + echo ./dev/tty; + echo ./dev/urandom; + echo ./dev/zero; +} | sort | diff -u tar1.txt - diff --git a/tests/skip-output-mknod b/tests/skip-output-mknod new file mode 100644 index 0000000..8ccbfdf --- /dev/null +++ b/tests/skip-output-mknod @@ -0,0 +1,30 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +# test this for both unshare and root mode because the code paths creating +# entries in /dev are different depending on whether mknod is available or not +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --skip=output/mknod \ + {{ DIST }} - {{ MIRROR }} | { + tar -t; + echo ./dev/console; + echo ./dev/full; + echo ./dev/null; + echo ./dev/ptmx; + echo ./dev/random; + echo ./dev/tty; + echo ./dev/urandom; + echo ./dev/zero; +} | sort | diff -u tar1.txt - diff --git a/tests/skip-start-stop-daemon-policy-rc b/tests/skip-start-stop-daemon-policy-rc new file mode 100644 index 0000000..bdf5469 --- /dev/null +++ b/tests/skip-start-stop-daemon-policy-rc @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=apt \ + --skip=chroot/start-stop-daemon,chroot/policy-rc.d \ + --customize-hook='test ! -e "$1/sbin/start-stop-daemon.REAL"' \ + --customize-hook='test ! -e "$1/usr/sbin/policy-rc.d"' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/skip-tar-in-mknod b/tests/skip-tar-in-mknod new file mode 100644 index 0000000..eb3027a --- /dev/null +++ b/tests/skip-tar-in-mknod @@ -0,0 +1,28 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +[ {{ MODE }} = "unshare" ] + +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +$prefix {{ CMD }} --mode={{ MODE }} --variant=custom \ + --skip=update,setup,cleanup,tar-in/mknod \ + --setup-hook='tar-in ./cache/mmdebstrap-{{ DIST }}-apt.tar /' \ + '' /tmp/debian-chroot.tar + +cmp ./cache/mmdebstrap-{{ DIST }}-apt.tar /tmp/debian-chroot.tar \ + || diffoscope ./cache/mmdebstrap-{{ DIST }}-apt.tar /tmp/debian-chroot.tar diff --git a/tests/special-hooks-using-helpers b/tests/special-hooks-using-helpers new file mode 100644 index 0000000..a211746 --- /dev/null +++ b/tests/special-hooks-using-helpers @@ -0,0 +1,28 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +mkfifo /tmp/myfifo +mkdir /tmp/root +ln -s /real /tmp/root/link +mkdir /tmp/root/real +run_testA() { + echo content > /tmp/foo + # shellcheck disable=SC2094 + { { { {{ CMD }} --hook-helper /tmp/root root setup '' 1 upload /tmp/foo "$1" < /tmp/myfifo 3>&-; echo $? >&3; printf "\\000\\000adios"; + } | {{ CMD }} --hook-listener 1 3>&- >/tmp/myfifo; echo $?; } 3>&1; + } | { read -r xs1; [ "$xs1" -eq 0 ]; read -r xs2; [ "$xs2" -eq 0 ]; } + echo content | diff -u - /tmp/root/real/foo + rm /tmp/foo + rm /tmp/root/real/foo +} +run_testA link/foo +run_testA /link/foo +run_testA ///link///foo/// +run_testA /././link/././foo/././ +run_testA /link/../link/foo +run_testA /link/../../link/foo +run_testA /../../link/foo +rmdir /tmp/root/real +rm /tmp/root/link +rmdir /tmp/root +rm /tmp/myfifo diff --git a/tests/special-hooks-using-helpers-and-env-vars b/tests/special-hooks-using-helpers-and-env-vars new file mode 100644 index 0000000..7a1ffeb --- /dev/null +++ b/tests/special-hooks-using-helpers-and-env-vars @@ -0,0 +1,31 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +cat << 'SCRIPT' > /tmp/script.sh +#!/bin/sh +set -eu +echo "MMDEBSTRAP_APT_CONFIG $MMDEBSTRAP_APT_CONFIG" +echo "$MMDEBSTRAP_HOOK" >> /tmp/hooks +[ "$MMDEBSTRAP_MODE" = "root" ] +echo test-content $MMDEBSTRAP_HOOK > test +{{ CMD }} --hook-helper "$1" "$MMDEBSTRAP_MODE" "$MMDEBSTRAP_HOOK" '' 1 upload test /test <&$MMDEBSTRAP_HOOKSOCK >&$MMDEBSTRAP_HOOKSOCK +rm test +echo "content inside chroot:" +cat "$1/test" +[ "test-content $MMDEBSTRAP_HOOK" = "$(cat "$1/test")" ] +{{ CMD }} --hook-helper "$1" "$MMDEBSTRAP_MODE" "$MMDEBSTRAP_HOOK" '' 1 download /test test <&$MMDEBSTRAP_HOOKSOCK >&$MMDEBSTRAP_HOOKSOCK +echo "content outside chroot:" +cat test +[ "test-content $MMDEBSTRAP_HOOK" = "$(cat test)" ] +rm test +SCRIPT +chmod +x /tmp/script.sh +{{ CMD }} --mode=root --variant=apt \ + --setup-hook=/tmp/script.sh \ + --extract-hook=/tmp/script.sh \ + --essential-hook=/tmp/script.sh \ + --customize-hook=/tmp/script.sh \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf "setup\nextract\nessential\ncustomize\n" | diff -u - /tmp/hooks +rm /tmp/script.sh /tmp/hooks +rm -r /tmp/debian-chroot diff --git a/tests/special-hooks-with-mode-mode b/tests/special-hooks-with-mode-mode new file mode 100644 index 0000000..99e2a47 --- /dev/null +++ b/tests/special-hooks-with-mode-mode @@ -0,0 +1,148 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +[ "{{ MODE }}" = "fakechroot" ] && prefix="$prefix fakechroot fakeroot" +symlinktarget=/real +[ "{{ MODE }}" = "fakechroot" ] && symlinktarget='$1/real' +echo copy-in-setup > /tmp/copy-in-setup +echo copy-in-essential > /tmp/copy-in-essential +echo copy-in-customize > /tmp/copy-in-customize +echo tar-in-setup > /tmp/tar-in-setup +echo tar-in-essential > /tmp/tar-in-essential +echo tar-in-customize > /tmp/tar-in-customize +tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-setup.tar tar-in-setup +tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-essential.tar tar-in-essential +tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-customize.tar tar-in-customize +rm /tmp/tar-in-setup +rm /tmp/tar-in-essential +rm /tmp/tar-in-customize +echo upload-setup > /tmp/upload-setup +echo upload-essential > /tmp/upload-essential +echo upload-customize > /tmp/upload-customize +mkdir /tmp/sync-in-setup +mkdir /tmp/sync-in-essential +mkdir /tmp/sync-in-customize +echo sync-in-setup > /tmp/sync-in-setup/file +echo sync-in-essential > /tmp/sync-in-essential/file +echo sync-in-customize > /tmp/sync-in-customize/file +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt \ + --setup-hook='mkdir "$1/real"' \ + --setup-hook='copy-in /tmp/copy-in-setup /real' \ + --setup-hook='echo copy-in-setup | cmp "$1/real/copy-in-setup" -' \ + --setup-hook='rm "$1/real/copy-in-setup"' \ + --setup-hook='echo copy-out-setup > "$1/real/copy-out-setup"' \ + --setup-hook='copy-out /real/copy-out-setup /tmp' \ + --setup-hook='rm "$1/real/copy-out-setup"' \ + --setup-hook='tar-in /tmp/tar-in-setup.tar /real' \ + --setup-hook='echo tar-in-setup | cmp "$1/real/tar-in-setup" -' \ + --setup-hook='tar-out /real/tar-in-setup /tmp/tar-out-setup.tar' \ + --setup-hook='rm "$1"/real/tar-in-setup' \ + --setup-hook='upload /tmp/upload-setup /real/upload' \ + --setup-hook='echo upload-setup | cmp "$1/real/upload" -' \ + --setup-hook='download /real/upload /tmp/download-setup' \ + --setup-hook='rm "$1/real/upload"' \ + --setup-hook='sync-in /tmp/sync-in-setup /real' \ + --setup-hook='echo sync-in-setup | cmp "$1/real/file" -' \ + --setup-hook='sync-out /real /tmp/sync-out-setup' \ + --setup-hook='rm "$1/real/file"' \ + --essential-hook='ln -s "'"$symlinktarget"'" "$1/symlink"' \ + --essential-hook='copy-in /tmp/copy-in-essential /symlink' \ + --essential-hook='echo copy-in-essential | cmp "$1/real/copy-in-essential" -' \ + --essential-hook='rm "$1/real/copy-in-essential"' \ + --essential-hook='echo copy-out-essential > "$1/real/copy-out-essential"' \ + --essential-hook='copy-out /symlink/copy-out-essential /tmp' \ + --essential-hook='rm "$1/real/copy-out-essential"' \ + --essential-hook='tar-in /tmp/tar-in-essential.tar /symlink' \ + --essential-hook='echo tar-in-essential | cmp "$1/real/tar-in-essential" -' \ + --essential-hook='tar-out /symlink/tar-in-essential /tmp/tar-out-essential.tar' \ + --essential-hook='rm "$1"/real/tar-in-essential' \ + --essential-hook='upload /tmp/upload-essential /symlink/upload' \ + --essential-hook='echo upload-essential | cmp "$1/real/upload" -' \ + --essential-hook='download /symlink/upload /tmp/download-essential' \ + --essential-hook='rm "$1/real/upload"' \ + --essential-hook='sync-in /tmp/sync-in-essential /symlink' \ + --essential-hook='echo sync-in-essential | cmp "$1/real/file" -' \ + --essential-hook='sync-out /real /tmp/sync-out-essential' \ + --essential-hook='rm "$1/real/file"' \ + --customize-hook='copy-in /tmp/copy-in-customize /symlink' \ + --customize-hook='echo copy-in-customize | cmp "$1/real/copy-in-customize" -' \ + --customize-hook='rm "$1/real/copy-in-customize"' \ + --customize-hook='echo copy-out-customize > "$1/real/copy-out-customize"' \ + --customize-hook='copy-out /symlink/copy-out-customize /tmp' \ + --customize-hook='rm "$1/real/copy-out-customize"' \ + --customize-hook='tar-in /tmp/tar-in-customize.tar /symlink' \ + --customize-hook='echo tar-in-customize | cmp "$1/real/tar-in-customize" -' \ + --customize-hook='tar-out /symlink/tar-in-customize /tmp/tar-out-customize.tar' \ + --customize-hook='rm "$1"/real/tar-in-customize' \ + --customize-hook='upload /tmp/upload-customize /symlink/upload' \ + --customize-hook='echo upload-customize | cmp "$1/real/upload" -' \ + --customize-hook='download /symlink/upload /tmp/download-customize' \ + --customize-hook='rm "$1/real/upload"' \ + --customize-hook='sync-in /tmp/sync-in-customize /symlink' \ + --customize-hook='echo sync-in-customize | cmp "$1/real/file" -' \ + --customize-hook='sync-out /real /tmp/sync-out-customize' \ + --customize-hook='rm "$1/real/file"' \ + --customize-hook='rmdir "$1/real"' \ + --customize-hook='rm "$1/symlink"' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +for n in setup essential customize; do + ret=0 + cmp /tmp/tar-in-$n.tar /tmp/tar-out-$n.tar || ret=$? + if [ "$ret" -ne 0 ]; then + if type diffoscope >/dev/null; then + diffoscope /tmp/tar-in-$n.tar /tmp/tar-out-$n.tar + exit 1 + else + echo "no diffoscope installed" >&2 + fi + if type base64 >/dev/null; then + base64 /tmp/tar-in-$n.tar + base64 /tmp/tar-out-$n.tar + exit 1 + else + echo "no base64 installed" >&2 + fi + if type xxd >/dev/null; then + xxd /tmp/tar-in-$n.tar + xxd /tmp/tar-out-$n.tar + exit 1 + else + echo "no xxd installed" >&2 + fi + exit 1 + fi +done +echo copy-out-setup | cmp /tmp/copy-out-setup - +echo copy-out-essential | cmp /tmp/copy-out-essential - +echo copy-out-customize | cmp /tmp/copy-out-customize - +echo upload-setup | cmp /tmp/download-setup - +echo upload-essential | cmp /tmp/download-essential - +echo upload-customize | cmp /tmp/download-customize - +echo sync-in-setup | cmp /tmp/sync-out-setup/file - +echo sync-in-essential | cmp /tmp/sync-out-essential/file - +echo sync-in-customize | cmp /tmp/sync-out-customize/file - +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar \ + /tmp/copy-in-setup /tmp/copy-in-essential /tmp/copy-in-customize \ + /tmp/copy-out-setup /tmp/copy-out-essential /tmp/copy-out-customize \ + /tmp/tar-in-setup.tar /tmp/tar-in-essential.tar /tmp/tar-in-customize.tar \ + /tmp/tar-out-setup.tar /tmp/tar-out-essential.tar /tmp/tar-out-customize.tar \ + /tmp/upload-setup /tmp/upload-essential /tmp/upload-customize \ + /tmp/download-setup /tmp/download-essential /tmp/download-customize \ + /tmp/sync-in-setup/file /tmp/sync-in-essential/file /tmp/sync-in-customize/file \ + /tmp/sync-out-setup/file /tmp/sync-out-essential/file /tmp/sync-out-customize/file +rmdir /tmp/sync-in-setup /tmp/sync-in-essential /tmp/sync-in-customize \ + /tmp/sync-out-setup /tmp/sync-out-essential /tmp/sync-out-customize diff --git a/tests/stable-default-mirror b/tests/stable-default-mirror new file mode 100644 index 0000000..c79f9d6 --- /dev/null +++ b/tests/stable-default-mirror @@ -0,0 +1,20 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +cat << HOSTS >> /etc/hosts +127.0.0.1 deb.debian.org +127.0.0.1 security.debian.org +HOSTS +apt-cache policy +cat /etc/apt/sources.list +{{ CMD }} --mode=root --variant=apt stable /tmp/debian-chroot +cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list +deb http://deb.debian.org/debian stable main +deb http://deb.debian.org/debian stable-updates main +deb http://security.debian.org/debian-security stable-security main +SOURCES +rm -r /tmp/debian-chroot diff --git a/tests/supply-components-manually b/tests/supply-components-manually new file mode 100644 index 0000000..038b5dc --- /dev/null +++ b/tests/supply-components-manually @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=apt --components="main main" --comp="main,main" {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +echo "deb {{ MIRROR }} {{ DIST }} main" | cmp /tmp/debian-chroot/etc/apt/sources.list +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/tarfilter-idshift b/tests/tarfilter-idshift new file mode 100644 index 0000000..731d40f --- /dev/null +++ b/tests/tarfilter-idshift @@ -0,0 +1,58 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +trap "rm -f /tmp/debian-chroot.tar /tmp/debian-chroot-shifted.tar /tmp/debian-chroot.txt /tmp/debian-chroot-shiftedback.tar /tmp/expected; rm -rf /tmp/debian-chroot" EXIT INT TERM +useradd --home-dir /home/user --create-home user +echo user:100000:65536 | cmp /etc/subuid - +echo user:100000:65536 | cmp /etc/subgid - +# include iputils-ping so that we can verify that tarfilter does not remove +# extended attributes +# run through tarshift no-op to create a tarball that should be bit-by-bit +# identical to a round trip through "tarfilter --idshift X" and "tarfilter --idshift -X" +runuser -u user -- {{ CMD }} --mode=unshare --variant=apt --include=iputils-ping {{ DIST }} - {{ MIRROR }} \ + | ./tarfilter --idshift 0 > /tmp/debian-chroot.tar +# make sure that xattrs are set in the original tarball +mkdir /tmp/debian-chroot +tar --xattrs --xattrs-include='*' --directory /tmp/debian-chroot -xf /tmp/debian-chroot.tar ./usr/bin/ping +echo "/tmp/debian-chroot/usr/bin/ping cap_net_raw=ep" > /tmp/expected +getcap /tmp/debian-chroot/usr/bin/ping | diff -u /tmp/expected - >&2 +rm /tmp/debian-chroot/usr/bin/ping +rmdir /tmp/debian-chroot/usr/bin +rmdir /tmp/debian-chroot/usr +rmdir /tmp/debian-chroot +# shift the uid/gid forward by 100000 and backward by 100000 +./tarfilter --idshift 100000 < /tmp/debian-chroot.tar > /tmp/debian-chroot-shifted.tar +./tarfilter --idshift -100000 < /tmp/debian-chroot-shifted.tar > /tmp/debian-chroot-shiftedback.tar +# the tarball before and after the roundtrip through tarfilter should be bit +# by bit identical +cmp /tmp/debian-chroot.tar /tmp/debian-chroot-shiftedback.tar +# manually adjust uid/gid and compare "tar -t" output +tar --numeric-owner -tvf /tmp/debian-chroot.tar \ + | sed 's# 42/0 # 100042/100000 #' \ + | sed 's# 0/0 # 100000/100000 #' \ + | sed 's# 0/5 # 100000/100005 #' \ + | sed 's# 0/8 # 100000/100008 #' \ + | sed 's# 0/42 # 100000/100042 #' \ + | sed 's# 0/43 # 100000/100043 #' \ + | sed 's# 0/50 # 100000/100050 #' \ + | sed 's/ \+/ /g' \ + > /tmp/debian-chroot.txt +tar --numeric-owner -tvf /tmp/debian-chroot-shifted.tar \ + | sed 's/ \+/ /g' \ + | diff -u /tmp/debian-chroot.txt - >&2 +mkdir /tmp/debian-chroot +tar --xattrs --xattrs-include='*' --directory /tmp/debian-chroot -xf /tmp/debian-chroot-shifted.tar +echo "100000 100000" > /tmp/expected +stat --format="%u %g" /tmp/debian-chroot/usr/bin/ping | diff -u /tmp/expected - >&2 +echo "/tmp/debian-chroot/usr/bin/ping cap_net_raw=ep" > /tmp/expected +getcap /tmp/debian-chroot/usr/bin/ping | diff -u /tmp/expected - >&2 +echo "0 0" > /tmp/expected +runuser -u user -- {{ CMD }} --unshare-helper /usr/sbin/chroot /tmp/debian-chroot stat --format="%u %g" /usr/bin/ping \ + | diff -u /tmp/expected - >&2 +echo "/usr/bin/ping cap_net_raw=ep" > /tmp/expected +runuser -u user -- {{ CMD }} --unshare-helper /usr/sbin/chroot /tmp/debian-chroot getcap /usr/bin/ping \ + | diff -u /tmp/expected - >&2 diff --git a/tests/unpack-doc-debian b/tests/unpack-doc-debian new file mode 100644 index 0000000..fe87d13 --- /dev/null +++ b/tests/unpack-doc-debian @@ -0,0 +1,57 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM + +[ {{ VARIANT }} = extract ] + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +[ "{{ MODE }}" = "fakechroot" ] && prefix="$prefix fakechroot fakeroot" +$prefix {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} --include=doc-debian {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +# delete contents of doc-debian +rm /tmp/debian-chroot/usr/share/doc-base/doc-debian.debian-* +rm -r /tmp/debian-chroot/usr/share/doc/debian +rm -r /tmp/debian-chroot/usr/share/doc/doc-debian +# delete real files +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/lib/dpkg/arch +rm /tmp/debian-chroot/var/cache/apt/archives/lock +rm /tmp/debian-chroot/var/lib/apt/lists/lock +## delete merged usr symlinks +#rm /tmp/debian-chroot/libx32 +#rm /tmp/debian-chroot/lib64 +#rm /tmp/debian-chroot/lib32 +#rm /tmp/debian-chroot/sbin +#rm /tmp/debian-chroot/bin +#rm /tmp/debian-chroot/lib +# delete ./dev (files might exist or not depending on the mode) +rm -f /tmp/debian-chroot/dev/console +rm -f /tmp/debian-chroot/dev/fd +rm -f /tmp/debian-chroot/dev/full +rm -f /tmp/debian-chroot/dev/null +rm -f /tmp/debian-chroot/dev/ptmx +rm -f /tmp/debian-chroot/dev/random +rm -f /tmp/debian-chroot/dev/stderr +rm -f /tmp/debian-chroot/dev/stdin +rm -f /tmp/debian-chroot/dev/stdout +rm -f /tmp/debian-chroot/dev/tty +rm -f /tmp/debian-chroot/dev/urandom +rm -f /tmp/debian-chroot/dev/zero +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir diff --git a/tests/unshare-as-root-user b/tests/unshare-as-root-user new file mode 100644 index 0000000..e1ba4d6 --- /dev/null +++ b/tests/unshare-as-root-user @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +[ "$(whoami)" = "root" ] +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode=unshare --variant=apt \ + --customize-hook='chroot "$1" sh -c "test -e /proc/self/fd"' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/unshare-as-root-user-inside-chroot b/tests/unshare-as-root-user-inside-chroot new file mode 100644 index 0000000..9c0eb0d --- /dev/null +++ b/tests/unshare-as-root-user-inside-chroot @@ -0,0 +1,28 @@ +#!/bin/sh +# +# Before running unshare mode as root, we run "unshare --mount" but that fails +# if mmdebstrap itself is executed from within a chroot: +# unshare: cannot change root filesystem propagation: Invalid argument +# This test tests the workaround in mmdebstrap using --propagation unchanged + +set -eu +export LC_ALL=C.UTF-8 +[ "$(whoami)" = "root" ] +trap "rm -f /tmp/debian-chroot.tar script.sh" EXIT INT TERM +cat << 'SCRIPT' > script.sh +#!/bin/sh +set -eu +rootfs="$1" +mkdir -p "$rootfs/mnt" +[ -e /usr/bin/mmdebstrap ] && cp -aT /usr/bin/mmdebstrap "$rootfs/usr/bin/mmdebstrap" +[ -e ./mmdebstrap ] && cp -aT ./mmdebstrap "$rootfs/mnt/mmdebstrap" +chroot "$rootfs" env --chdir=/mnt \ + {{ CMD }} --mode=unshare --variant=apt \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +SCRIPT +chmod +x script.sh +{{ CMD }} --mode=root --variant=apt --include=perl,mount \ + --customize-hook=./script.sh \ + --customize-hook="download /tmp/debian-chroot.tar /tmp/debian-chroot.tar" \ + {{ DIST }} /dev/null {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/unshare-include-deb b/tests/unshare-include-deb new file mode 100644 index 0000000..2b9c54b --- /dev/null +++ b/tests/unshare-include-deb @@ -0,0 +1,49 @@ +#!/bin/sh + +set -eu +export LC_ALL=C.UTF-8 + +[ "{{ MODE }}" = unshare ] + +trap "rm -rf /tmp/dummypkg.deb /tmp/dummypkg" EXIT INT TERM + +prefix= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then + if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}" + fi + prefix="runuser -u ${SUDO_USER:-user} --" +fi + +# instead of obtaining a .deb from our cache, we create a new package because +# otherwise apt might decide to download the package with the same name and +# version from the cache instead of using the local .deb +mkdir -p /tmp/dummypkg/DEBIAN +cat << END > "/tmp/dummypkg/DEBIAN/control" +Package: dummypkg +Priority: optional +Section: oldlibs +Maintainer: Johannes Schauer Marin Rodrigues <josch@debian.org> +Architecture: all +Multi-Arch: foreign +Source: dummypkg +Version: 1 +Description: dummypkg +END +dpkg-deb --build "/tmp/dummypkg" "/tmp/dummypkg.deb" + +# make the .deb only redable by its owner which will exclude the unshared user +chmod 600 /tmp/dummypkg.deb + +ret=0 +$prefix {{ CMD }} --variant=apt --mode={{ MODE }} --include="/tmp/dummypkg.deb" \ + {{ DIST }} /dev/null {{ MIRROR }} || ret=$? + +if [ "$ret" -eq 0 ]; then + echo "expected failure but got exit $ret" >&2 + exit 1 +fi diff --git a/tests/variant-custom-timeout b/tests/variant-custom-timeout new file mode 100644 index 0000000..06f0b42 --- /dev/null +++ b/tests/variant-custom-timeout @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +# mmdebstrap used to hang forever if apt in custom mode failed to resolve +# dependencies because a process died without cleaning up its children. +# https://bugs.debian.org/1017795 +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=custom \ + --include=this-package-does-not-exist {{ DIST }} /dev/null {{ MIRROR }} || ret=1 +[ $ret -eq 1 ] diff --git a/tests/verbose b/tests/verbose new file mode 100644 index 0000000..b0b0fb9 --- /dev/null +++ b/tests/verbose @@ -0,0 +1,17 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM + +# we use variant standard in verbose mode to see the maximum number of packages +# that was chosen in case of USE_HOST_APT_CONFIG=yes +# we use variant important on arches where variant standard is not bit-by-bit +# reproducible due to #1031276 +case {{ VARIANT }} in standard|-) : ;; *) exit 1;; esac + +{{ CMD }} --variant={{ VARIANT }} --verbose {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} + +cmp ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.tar /tmp/debian-chroot.tar \ + || diffoscope ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.tar /tmp/debian-chroot.tar diff --git a/tests/version b/tests/version new file mode 100644 index 0000000..cae04a6 --- /dev/null +++ b/tests/version @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +# we redirect to /dev/null instead of using --quiet to not cause a broken pipe +# when grep exits before mmdebstrap was able to write all its output +{{ CMD }} --version | grep -E '^mmdebstrap [0-9](\.[0-9])+$' >/dev/null diff --git a/tests/without-etc-resolv-conf-and-etc-hostname b/tests/without-etc-resolv-conf-and-etc-hostname new file mode 100644 index 0000000..1d3dfef --- /dev/null +++ b/tests/without-etc-resolv-conf-and-etc-hostname @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +rm /etc/resolv.conf /etc/hostname +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +{ tar -tf /tmp/debian-chroot.tar; + printf "./etc/hostname\n"; + printf "./etc/resolv.conf\n"; +} | sort | diff -u tar1.txt - diff --git a/tests/xz-compressed-tarball b/tests/xz-compressed-tarball new file mode 100644 index 0000000..6dc6a37 --- /dev/null +++ b/tests/xz-compressed-tarball @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar.xz" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar.xz {{ MIRROR }} +printf '\3757zXZ\0' | cmp --bytes=6 /tmp/debian-chroot.tar.xz - +tar -tf /tmp/debian-chroot.tar.xz | sort | diff -u tar1.txt - |