0
0
Fork 0
mirror of https://github.com/atmoz/sftp.git synced 2024-11-17 12:51:33 -05:00

Support running tests with podman

This commit is contained in:
Adrian Dvergsdal 2024-07-12 23:25:23 +02:00
parent 57ad432230
commit c3c949d277
No known key found for this signature in database
GPG key ID: C1E9E2D9552A42D2

162
tests/run
View file

@ -1,58 +1,78 @@
#!/bin/bash #!/bin/bash
# See: https://github.com/kward/shunit2 # See: https://github.com/kward/shunit2
# Usage: tests/run [OPTION]... IMAGE_NAME
# Options: --verbose --no-cleanup
# Example: tests/run atmoz/sftp:alpine
# Booleans
OPTION_TRUE=0
OPTION_FALSE=1
# Options
OPTION_VERBOSE="${OPTION_VERBOSE:-"$OPTION_FALSE"}"
OPTION_CLEANUP="${OPTION_CLEANUP:-"$OPTION_TRUE"}"
# ARGUMENTS:
while [ "$#" -ge 1 ]; do
case "$1" in
--verbose) OPTION_VERBOSE="$OPTION_TRUE"; shift ;;
--no-cleanup) OPTION_VERBOSE="$OPTION_FALSE"; shift ;;
--) break ;; # rest of arguments goes to shunit2
--*) echo "Unknown argument: $1"; exit 2 ;;
*) imageName="$1"; shift ;;
esac
done
argImage=$1
argOutput=${2:-"quiet"}
argCleanup=${3:-"cleanup"}
testDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" testDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
imageName="$argImage"
tmpDir="$(mktemp -d /tmp/atmoz_sftp_XXXX)" tmpDir="$(mktemp -d /tmp/atmoz_sftp_XXXX)"
sshKeyPri="$tmpDir/rsa" sshKeyPri="$tmpDir/rsa"
sshKeyPub="$tmpDir/rsa.pub" sshKeyPub="$tmpDir/rsa.pub"
sshHostEd25519Key="$tmpDir/ssh_host_ed25519_key" sshHostEd25519Key="$tmpDir/ssh_host_ed25519_key"
sshHostKeyMountArg="--volume=$sshHostEd25519Key:/etc/ssh/ssh_host_ed25519_key" sshHostKeyMountArg="--volume=$sshHostEd25519Key:/etc/ssh/ssh_host_ed25519_key"
sshKnownHosts="$tmpDir/known_hosts" sshKnownHosts="$tmpDir/known_hosts"
runArgs=("-P" "--network=private" "$sshHostKeyMountArg")
if [ $UID != 0 ] && ! groups | grep -qw docker; then # podman or docker
echo "Run with sudo/root or add user $USER to group 'docker'" if [ -z "$CONTAINER_ENGINE" ]; then
exit 1 if type podman &>/dev/null; then
CONTAINER_ENGINE="podman"
else
CONTAINER_ENGINE="docker"
fi
fi fi
if [ ! -f "$testDir/shunit2/shunit2" ]; then if [ ! -f "$testDir/shunit2/shunit2" ]; then
echo "Could not find shunit2 in $testDir/shunit2." echo "Could not find shunit2 in $testDir/shunit2"
echo "Run 'git submodule update --init'" echo "Run 'git submodule update --init'"
exit 2 exit 2
fi fi
if [ -z "$argImage" ]; then if [ -z "$imageName" ]; then
echo "Missing image name" echo "Missing name of image you want to run tests against"
exit 3 exit 3
fi fi
if [ "$argOutput" == "quiet" ]; then if [ "$OPTION_VERBOSE" == "$OPTION_TRUE" ]; then
redirect="/dev/null"
else
redirect="/dev/stdout" redirect="/dev/stdout"
else
redirect="/dev/null"
fi fi
# clear argument list (or shunit2 will try to use them)
set --
############################################################################## ##############################################################################
## Helper functions ## Setup: shunit2 functions
############################################################################## ##############################################################################
function oneTimeSetUp() { function oneTimeSetUp() {
# Generate temporary ssh keys for testing # Generate temporary ssh keys for testing
if [ ! -f "$sshKeyPri" ]; then if [ ! -f "$sshKeyPri" ]; then
ssh-keygen -t rsa -f "$sshKeyPri" -N '' > "$redirect" 2>&1 ssh-keygen -t rsa -f "$sshKeyPri" -N '' < /dev/null > "$redirect" 2>&1
fi fi
# Private key can not be read by others (sshd will complain) # Private key can not be read by others (sshd will complain)
chmod go-rw "$sshKeyPri" chmod go-rw "$sshKeyPri"
# Generate host key # Generate host key
ssh-keygen -t ed25519 -f "$sshHostEd25519Key" < /dev/null ssh-keygen -t ed25519 -f "$sshHostEd25519Key" -N '' < /dev/null
} }
function setUp() { function setUp() {
@ -67,34 +87,41 @@ function setUp() {
function tearDown() { function tearDown() {
retireContainer "$containerName" retireContainer "$containerName"
if [ "$argCleanup" == "cleanup" ] && [ -d "$containerTmpDir" ]; then if [ "$OPTION_CLEANUP" == "$OPTION_TRUE" ] && [ -d "$containerTmpDir" ]; then
rm -rf "$containerTmpDir" || true # Can fail on GitHub Actions rm -rf "$containerTmpDir" || true # Can fail on GitHub Actions
fi fi
} }
##############################################################################
## Helper functions
##############################################################################
function container() {
"$CONTAINER_ENGINE" "$@"
}
function retireContainer() { function retireContainer() {
if [ "$(docker ps -qaf name="$1")" ]; then if [ "$(container ps -qaf name="$1")" ]; then
if [ "$argOutput" != "quiet" ]; then if [ "$OPTION_VERBOSE" == "$OPTION_TRUE" ]; then
echo "Docker log for $1:" echo "container log for $1:"
docker logs "$1" container logs "$1"
fi fi
if [ "$argCleanup" == "cleanup" ]; then if [ "$OPTION_CLEANUP" == "$OPTION_TRUE" ]; then
docker rm -fv "$1" > "$redirect" 2>&1 container rm -fv "$1" > "$redirect" 2>&1
fi fi
fi fi
} }
function getSftpIp() { function getSftpPort() {
docker inspect -f "{{.NetworkSettings.IPAddress}}" "$1" container container port "$1" | cut -d: -f2 | head -1
} }
function runSftpCommands() { function runSftpCommands() {
ip="$(getSftpIp "$1")" port="$(getSftpPort "$1")"
user="$2" user="$2"
shift 2 shift 2
echo "$ip $(cat "$sshHostEd25519Key.pub")" >> "$sshKnownHosts" echo "127.0.0.1 $(cat "$sshHostEd25519Key.pub")" >> "$sshKnownHosts"
commands="" commands=""
for cmd in "$@"; do for cmd in "$@"; do
@ -104,7 +131,7 @@ function runSftpCommands() {
echo "$commands" | sftp \ echo "$commands" | sftp \
-i "$sshKeyPri" \ -i "$sshKeyPri" \
-oUserKnownHostsFile="$sshKnownHosts" \ -oUserKnownHostsFile="$sshKnownHosts" \
-b - "$user@$ip" \ -b - -P "$port" "$user@127.0.0.1" \
> "$redirect" 2>&1 > "$redirect" 2>&1
status=$? status=$?
@ -113,17 +140,19 @@ function runSftpCommands() {
} }
function waitForServer() { function waitForServer() {
containerName="$1" local containerName="$1"
echo -n "Waiting for $containerName to open port 22 ..." local port
echo -n "Waiting for $containerName to open a port ..."
for _ in {1..30}; do for _ in {1..30}; do
sleep 1
ip="$(getSftpIp "$containerName")"
echo -n "." echo -n "."
if [ -n "$ip" ] && nc -z "$ip" 22; then port="$(getSftpPort "$containerName")"
echo " OPEN" if [ -n "$port" ] && ssh-keyscan -4 -T 1 -p "$port" "127.0.0.1" &>/dev/null; then
echo " PORT $port OPEN"
return 0; return 0;
fi fi
sleep 0.5
done done
echo " TIMEOUT" echo " TIMEOUT"
@ -135,7 +164,7 @@ function waitForServer() {
############################################################################## ##############################################################################
function testSmallestUserConfig() { function testSmallestUserConfig() {
docker run --name "$containerName" "$sshHostKeyMountArg" \ container run --name "$containerName" "${runArgs[@]}" \
--entrypoint="/bin/sh" \ --entrypoint="/bin/sh" \
"$imageName" \ "$imageName" \
-c "create-sftp-user u: && id u" \ -c "create-sftp-user u: && id u" \
@ -144,7 +173,7 @@ function testSmallestUserConfig() {
} }
function testCreateUserWithDot() { function testCreateUserWithDot() {
docker run --name "$containerName" "$sshHostKeyMountArg" \ container run --name "$containerName" "${runArgs[@]}" \
--entrypoint="/bin/sh" \ --entrypoint="/bin/sh" \
"$imageName" \ "$imageName" \
-c "create-sftp-user user.with.dot: && id user.with.dot" \ -c "create-sftp-user user.with.dot: && id user.with.dot" \
@ -153,7 +182,7 @@ function testCreateUserWithDot() {
} }
function testUserCustomUidAndGid() { function testUserCustomUidAndGid() {
id="$(docker run --name "$containerName" "$sshHostKeyMountArg" \ id="$(container run --name "$containerName" "${runArgs[@]}" \
--entrypoint="/bin/sh" \ --entrypoint="/bin/sh" \
"$imageName" \ "$imageName" \
-c "create-sftp-user u::1234:4321: > /dev/null && id u" )" -c "create-sftp-user u::1234:4321: > /dev/null && id u" )"
@ -169,14 +198,14 @@ function testUserCustomUidAndGid() {
} }
function testCommandPassthrough() { function testCommandPassthrough() {
docker run --name "$containerName" "$sshHostKeyMountArg" \ container run --name "$containerName" "${runArgs[@]}" \
"$imageName" test 1 -eq 1 \ "$imageName" test 1 -eq 1 \
> "$redirect" 2>&1 > "$redirect" 2>&1
assertTrue "command passthrough" $? assertTrue "command passthrough" $?
} }
function testUsersConf() { function testUsersConf() {
docker run --name "$containerName" "$sshHostKeyMountArg" -d \ container run --name "$containerName" "${runArgs[@]}" -d \
-v "$testDir/files/users.conf:/etc/sftp/users.conf:ro" \ -v "$testDir/files/users.conf:/etc/sftp/users.conf:ro" \
"$imageName" \ "$imageName" \
> "$redirect" 2>&1 > "$redirect" 2>&1
@ -184,21 +213,21 @@ function testUsersConf() {
waitForServer "$containerName" waitForServer "$containerName"
assertTrue "waitForServer" $? assertTrue "waitForServer" $?
docker exec "$containerName" id user-from-conf > /dev/null container exec "$containerName" id user-from-conf > /dev/null
assertTrue "user-from-conf" $? assertTrue "user-from-conf" $?
docker exec "$containerName" id test > /dev/null container exec "$containerName" id test > /dev/null
assertTrue "test" $? assertTrue "test" $?
docker exec "$containerName" id user.with.dot > /dev/null container exec "$containerName" id user.with.dot > /dev/null
assertTrue "user.with.dot" $? assertTrue "user.with.dot" $?
docker exec "$containerName" test -d /home/test/dir1 -a -d /home/test/dir2 container exec "$containerName" test -d /home/test/dir1 -a -d /home/test/dir2
assertTrue "dirs exists" $? assertTrue "dirs exists" $?
} }
function testLegacyUsersConf() { function testLegacyUsersConf() {
docker run --name "$containerName" "$sshHostKeyMountArg" -d \ container run --name "$containerName" "${runArgs[@]}" -d \
-v "$testDir/files/users.conf:/etc/sftp-users.conf:ro" \ -v "$testDir/files/users.conf:/etc/sftp-users.conf:ro" \
"$imageName" \ "$imageName" \
> "$redirect" 2>&1 > "$redirect" 2>&1
@ -206,12 +235,12 @@ function testLegacyUsersConf() {
waitForServer "$containerName" waitForServer "$containerName"
assertTrue "waitForServer" $? assertTrue "waitForServer" $?
docker exec "$containerName" id user-from-conf > /dev/null container exec "$containerName" id user-from-conf > /dev/null
assertTrue "user-from-conf" $? assertTrue "user-from-conf" $?
} }
function testCreateUsersUsingEnv() { function testCreateUsersUsingEnv() {
docker run --name "$containerName" "$sshHostKeyMountArg" -d \ container run --name "$containerName" "${runArgs[@]}" -d \
-e "SFTP_USERS=user-from-env: user-from-env-2:" \ -e "SFTP_USERS=user-from-env: user-from-env-2:" \
"$imageName" \ "$imageName" \
> "$redirect" 2>&1 > "$redirect" 2>&1
@ -219,15 +248,15 @@ function testCreateUsersUsingEnv() {
waitForServer "$containerName" waitForServer "$containerName"
assertTrue "waitForServer" $? assertTrue "waitForServer" $?
docker exec "$containerName" id user-from-env > /dev/null container exec "$containerName" id user-from-env > /dev/null
assertTrue "user-from-env" $? assertTrue "user-from-env" $?
docker exec "$containerName" id user-from-env-2 > /dev/null container exec "$containerName" id user-from-env-2 > /dev/null
assertTrue "user-from-env-2" $? assertTrue "user-from-env-2" $?
} }
function testCreateUsersUsingCombo() { function testCreateUsersUsingCombo() {
docker run --name "$containerName" "$sshHostKeyMountArg" -d \ container run --name "$containerName" "${runArgs[@]}" -d \
-v "$testDir/files/users.conf:/etc/sftp-users.conf:ro" \ -v "$testDir/files/users.conf:/etc/sftp-users.conf:ro" \
-e "SFTP_USERS=user-from-env:" \ -e "SFTP_USERS=user-from-env:" \
"$imageName" \ "$imageName" \
@ -237,18 +266,18 @@ function testCreateUsersUsingCombo() {
waitForServer "$containerName" waitForServer "$containerName"
assertTrue "waitForServer" $? assertTrue "waitForServer" $?
docker exec "$containerName" id user-from-conf > /dev/null container exec "$containerName" id user-from-conf > /dev/null
assertTrue "user-from-conf" $? assertTrue "user-from-conf" $?
docker exec "$containerName" id user-from-env > /dev/null container exec "$containerName" id user-from-env > /dev/null
assertTrue "user-from-env" $? assertTrue "user-from-env" $?
docker exec "$containerName" id user-from-cmd > /dev/null container exec "$containerName" id user-from-cmd > /dev/null
assertTrue "user-from-cmd" $? assertTrue "user-from-cmd" $?
} }
function testWriteAccessToAutocreatedDirs() { function testWriteAccessToAutocreatedDirs() {
docker run --name "$containerName" "$sshHostKeyMountArg" -d \ container run --name "$containerName" "${runArgs[@]}" -d \
-v "$sshKeyPub":/home/test/.ssh/keys/id_rsa.pub:ro \ -v "$sshKeyPub":/home/test/.ssh/keys/id_rsa.pub:ro \
"$imageName" "test::::testdir,dir with spaces" \ "$imageName" "test::::testdir,dir with spaces" \
> "$redirect" 2>&1 > "$redirect" 2>&1
@ -264,18 +293,19 @@ function testWriteAccessToAutocreatedDirs() {
"exit" "exit"
assertTrue "runSftpCommands" $? assertTrue "runSftpCommands" $?
docker exec "$containerName" test -d /home/test/testdir/test container exec "$containerName" test -d /home/test/testdir/test
assertTrue "testdir write access" $? assertTrue "testdir write access" $?
docker exec "$containerName" test -d "/home/test/dir with spaces/test" container exec "$containerName" test -d "/home/test/dir with spaces/test"
assertTrue "dir with spaces write access" $? assertTrue "dir with spaces write access" $?
} }
function testWriteAccessToLimitedChroot() { function testWriteAccessToLimitedChroot() {
# Modified sshd_config with chrooted home subdir # Modified sshd_config with chrooted home subdir
tmpConfig="$(mktemp)" tmpConfig="$(mktemp)"
sed 's/^ChrootDirectory.*/ChrootDirectory %h\/sftp/' \ container run --rm --entrypoint=bash "$imageName" -c "cat /etc/ssh/sshd_config" |
< "$testDir/../files/sshd_config" > "$tmpConfig" sed 's/^ChrootDirectory.*/ChrootDirectory %h\/sftp/' \
> "$tmpConfig"
# Set correct permissions on chroot # Set correct permissions on chroot
tmpScript="$(mktemp)" tmpScript="$(mktemp)"
@ -286,7 +316,7 @@ chmod 755 /home/*/sftp
EOF EOF
chmod +x "$tmpScript" chmod +x "$tmpScript"
docker run --name "$containerName" "$sshHostKeyMountArg" -d \ container run --name "$containerName" "${runArgs[@]}" -d \
-v "$sshKeyPub":/home/test/.ssh/keys/id_rsa.pub:ro \ -v "$sshKeyPub":/home/test/.ssh/keys/id_rsa.pub:ro \
-v "$tmpConfig:/etc/ssh/sshd_config" \ -v "$tmpConfig:/etc/ssh/sshd_config" \
-v "$tmpScript:/etc/sftp.d/limited_home_dir" \ -v "$tmpScript:/etc/sftp.d/limited_home_dir" \
@ -302,7 +332,7 @@ EOF
"exit" "exit"
assertTrue "runSftpCommands" $? assertTrue "runSftpCommands" $?
docker exec "$containerName" test -d /home/test/sftp/upload/test container exec "$containerName" test -d /home/test/sftp/upload/test
assertTrue "limited chroot write access" $? assertTrue "limited chroot write access" $?
} }
@ -314,7 +344,7 @@ function testBindmountDirScript() {
> "$containerTmpDir/mount.sh" > "$containerTmpDir/mount.sh"
chmod +x "$containerTmpDir/mount.sh" chmod +x "$containerTmpDir/mount.sh"
docker run --name "$containerName" "$sshHostKeyMountArg" -d \ container run --name "$containerName" "${runArgs[@]}" -d \
--privileged=true \ --privileged=true \
-v "$sshKeyPub":/home/custom/.ssh/keys/id_rsa.pub:ro \ -v "$sshKeyPub":/home/custom/.ssh/keys/id_rsa.pub:ro \
-v "$containerTmpDir/custom/bindmount":/custom \ -v "$containerTmpDir/custom/bindmount":/custom \
@ -331,12 +361,12 @@ function testBindmountDirScript() {
"exit" "exit"
assertTrue "runSftpCommands" $? assertTrue "runSftpCommands" $?
docker exec "$containerName" test -d /home/custom/bindmount/test container exec "$containerName" test -d /home/custom/bindmount/test
assertTrue "directory exist" $? assertTrue "directory exist" $?
} }
function testDuplicateSshKeys() { function testDuplicateSshKeys() {
docker run --name "$containerName" "$sshHostKeyMountArg" -d \ container run --name "$containerName" "${runArgs[@]}" -d \
-v "$sshKeyPub":/home/user/.ssh/keys/key1.pub:ro \ -v "$sshKeyPub":/home/user/.ssh/keys/key1.pub:ro \
-v "$sshKeyPub":/home/user/.ssh/keys/key2.pub:ro \ -v "$sshKeyPub":/home/user/.ssh/keys/key2.pub:ro \
"$imageName" "user:" \ "$imageName" "user:" \
@ -345,7 +375,7 @@ function testDuplicateSshKeys() {
waitForServer "$containerName" waitForServer "$containerName"
assertTrue "waitForServer" $? assertTrue "waitForServer" $?
lines="$(docker exec "$containerName" sh -c \ lines="$(container exec "$containerName" sh -c \
"wc -l < /home/user/.ssh/authorized_keys")" "wc -l < /home/user/.ssh/authorized_keys")"
assertEquals "1" "$lines" assertEquals "1" "$lines"
} }