diff --git a/Makefile b/Makefile index d896678..a9df465 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,14 @@ ROOT := $(shell git rev-parse --show-toplevel) GO_SRC_DIRS := $(shell find . -name "*.go" | xargs -n1 dirname | sort -u) GO_SRC := $(shell find . -name "*.go") VERSION_LDFLAGS=-X main.Version=$(MAIN_VERSION) +BATS = $(TOOLS_D)/bin/bats +BATS_VERSION := v1.10.0 +STACKER = $(TOOLS_D)/bin/stacker +STACKER_VERSION := v1.0.0 +TOOLS_D := $(ROOT)/tools + +export PATH := $(TOOLS_D)/bin:$(PATH) + .PHONY: gofmt gofmt: .made-gofmt @@ -23,6 +31,36 @@ atomfs: .made-gofmt $(GO_SRC) gotest: $(GO_SRC) go test -coverprofile=coverage.txt -ldflags "$(VERSION_LDFLAGS)" ./... -clean: - rm -f $(ROOT)/bin - rm .made-* +$(STACKER): + mkdir -p $(TOOLS_D)/bin + wget --progress=dot:giga https://github.com/project-stacker/stacker/releases/download/$(STACKER_VERSION)/stacker + chmod +x stacker + cp stacker $(TOOLS_D)/bin/ + +$(BATS): + mkdir -p $(TOOLS_D)/bin + git clone -b $(BATS_VERSION) https://github.com/bats-core/bats-core.git + cd bats-core; ./install.sh $(TOOLS_D) + mkdir -p $(ROOT)/test/test_helper + git clone --depth 1 https://github.com/bats-core/bats-support $(ROOT)/test/test_helper/bats-support + git clone --depth 1 https://github.com/bats-core/bats-assert $(ROOT)/test/test_helper/bats-assert + git clone --depth 1 https://github.com/bats-core/bats-file $(ROOT)/test/test_helper/bats-file + +batstest: $(BATS) $(STACKER) atomfs test/random.txt + cd $(ROOT)/test; sudo $(BATS) --tap --timing priv-*.bats + cd $(ROOT)/test; $(BATS) --tap --timing unpriv-*.bats + +test/random.txt: + dd if=/dev/random of=/dev/stdout count=2048 | base64 > test/random.txt + +.PHONY: test toolsclean +test: gotest batstest + +toolsclean: + rm -rf $(TOOLS_D) + rm -rf $(ROOT)/test/test_helper + rm -rf $(ROOT)/bats-core + +clean: toolsclean + rm -rf $(ROOT)/bin + rm -f .made-* diff --git a/test/1.README.md b/test/1.README.md new file mode 100644 index 0000000..32fc2ca --- /dev/null +++ b/test/1.README.md @@ -0,0 +1,2 @@ +# Just a file to import into a scratch stacker image + diff --git a/test/1.stacker.yaml b/test/1.stacker.yaml new file mode 100644 index 0000000..5f03389 --- /dev/null +++ b/test/1.stacker.yaml @@ -0,0 +1,14 @@ +test_base: + from: + type: scratch + imports: + - path: 1.README.md + dest: / + +test: + from: + type: built + tag: test_base + imports: + - path: random.txt + dest: / diff --git a/test/helpers.bash b/test/helpers.bash new file mode 100644 index 0000000..44a9252 --- /dev/null +++ b/test/helpers.bash @@ -0,0 +1,17 @@ + +check_root(){ + if [ "$(id -u)" != "0" ]; then + echo "you should be root to run this suite" + exit 1 + fi +} + +ROOT_D=$(dirname $BATS_TEST_FILENAME)/.. +TOOLS_D=$ROOT_D/tools +export PATH="$TOOLS_D/bin:$ROOT_D/bin:$PATH" + +build_image_at() { + cd $1 + stacker --oci-dir $1/oci --debug build -f $(dirname $BATS_TEST_FILENAME)/1.stacker.yaml --layer-type squashfs + stacker --oci-dir $1/oci-no-verity --debug build -f $(dirname $BATS_TEST_FILENAME)/1.stacker.yaml --layer-type squashfs --no-squashfs-verity +} diff --git a/test/priv-mount.bats b/test/priv-mount.bats new file mode 100644 index 0000000..6b7743e --- /dev/null +++ b/test/priv-mount.bats @@ -0,0 +1,122 @@ +load helpers +load 'test_helper/bats-support/load' +load 'test_helper/bats-assert/load' +load 'test_helper/bats-file/load' + +function setup_file() { + check_root + build_image_at $BATS_SUITE_TMPDIR + export ATOMFS_TEST_RUN_DIR=${BATS_SUITE_TMPDIR}/run/atomfs + mkdir -p $ATOMFS_TEST_RUN_DIR + export MY_MNTNSNAME=$(readlink /proc/self/ns/mnt | cut -c 6-15) +} + +function setup() { + export MP=${BATS_TEST_TMPDIR}/testmountpoint + mkdir -p $MP +} + +@test "RO mount/umount and verify of good image works" { + run atomfs --debug mount ${BATS_SUITE_TMPDIR}/oci:test-squashfs $MP + assert_success + assert_file_exists $MP/1.README.md + assert_file_exists $MP/random.txt + assert_dir_exists $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/ + + run touch $MP/do-not-let-me + assert_failure + + run atomfs verify $MP + assert_success + + run atomfs --debug umount $MP + assert_success + + # mount point and meta dir should exist but be empty: + assert_dir_exists $MP + assert [ -z $( ls -A $MP) ] + assert_dir_exists $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/ + assert [ -z $( ls -A $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/ ) ] + +} + +@test "mount with missing verity data fails" { + run atomfs --debug mount ${BATS_SUITE_TMPDIR}/oci-no-verity:test-squashfs $MP + assert_failure + assert_line --partial "is missing verity data" + + # mount point and meta dir should exist but be empty: + assert_dir_exists $MP + assert [ -z $( ls -A $MP) ] + assert_dir_exists $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/ + assert [ -z $( ls -A $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/ ) ] + +} + +@test "mount with missing verity data passes if you ignore it" { + run atomfs --debug mount --allow-missing-verity ${BATS_SUITE_TMPDIR}/oci-no-verity:test-squashfs $MP + assert_success + + run atomfs --debug umount $MP + assert_success + + # mount point and meta dir should exist but be empty: + assert_dir_exists $MP + assert [ -z $( ls -A $MP) ] + assert_dir_exists $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/ + assert [ -z $( ls -A $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/ ) ] + +} + +@test "mount/umount with writeable overlay" { + run atomfs --debug mount --writeable ${BATS_SUITE_TMPDIR}/oci:test-squashfs $MP + assert_success + assert_file_exists $MP/1.README.md + assert_file_exists $MP/random.txt + assert_dir_exists $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/ + + run touch $MP/this-time-let-me + assert_success + + run cp $MP/1.README.md $MP/3.README.md + assert_success + + run atomfs --debug umount $MP + assert_success + + # mount point and meta dir should exist but be empty: + assert_dir_exists $MP + assert [ -z $( ls -A $MP) ] + assert_dir_exists $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/ + assert [ -z $( ls -A $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/ ) ] +} + +@test "mount with writeable overlay in separate dir" { + export PERSIST_DIR=${BATS_TEST_TMPDIR}/upperdir + mkdir -p $PERSIST_DIR + run atomfs --debug mount --persist=${PERSIST_DIR} ${BATS_SUITE_TMPDIR}/oci:test-squashfs $MP + assert_success + assert_file_exists $MP/1.README.md + assert_file_exists $MP/random.txt + + run touch $MP/this-time-let-me + assert_success + run cp $MP/1.README.md $MP/3.README.md + assert_success + + assert_file_exists $PERSIST_DIR/this-time-let-me + assert_file_exists $PERSIST_DIR/3.README.md + assert_file_not_exists $PERSIST_DIR/1.README.md + + run atomfs --debug umount $MP + assert_success + # mount point and meta dir should exist but be empty: + assert_dir_exists $MP + assert [ -z $( ls -A $MP) ] + assert_dir_exists $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/ + assert [ -z $( ls -A $ATOMFS_TEST_RUN_DIR/meta/$MY_MNTNSNAME/) ] + + # but persist dir should still be there: + assert_file_exists $PERSIST_DIR/this-time-let-me + assert_file_exists $PERSIST_DIR/3.README.md +} diff --git a/test/priv-verify.bats b/test/priv-verify.bats new file mode 100644 index 0000000..5ab78e5 --- /dev/null +++ b/test/priv-verify.bats @@ -0,0 +1,36 @@ +load helpers +load 'test_helper/bats-support/load' +load 'test_helper/bats-assert/load' +load 'test_helper/bats-file/load' + +function setup_file() { + export ATOMFS_TEST_RUN_DIR=${BATS_SUITE_TMPDIR}/run/atomfs + mkdir -p $ATOMFS_TEST_RUN_DIR +} + +@test "mounting tampered small images fails immediately" { + build_image_at $BATS_TEST_TMPDIR + + sha256sum $BATS_TEST_TMPDIR/oci/blobs/sha256/* > initialsums + + # write some bad data onto the squash blobs to make them invalid + for blob in $BATS_TEST_TMPDIR/oci/blobs/sha256/* ; do + file $blob | grep "Squashfs filesystem" || continue + dd if=/dev/random of=$blob conv=notrunc seek=100 count=100 + done + + sha256sum $BATS_TEST_TMPDIR/oci/blobs/sha256/* > finalsums + + # the sums should be different, so assert that diff finds diffs: + run diff initialsums finalsums + assert_failure + + mkdir -p mountpoint + run atomfs --debug mount ${BATS_TEST_TMPDIR}/oci:test-squashfs mountpoint + assert_failure + +} + +@test "TODO: check atomfs verify on a mounted image that isn't detected immediately" { + echo TODO +} diff --git a/test/unpriv-guestmount.bats b/test/unpriv-guestmount.bats new file mode 100644 index 0000000..20b40c7 --- /dev/null +++ b/test/unpriv-guestmount.bats @@ -0,0 +1,102 @@ +load helpers +load test_helper/bats-support/load +load test_helper/bats-assert/load +load test_helper/bats-file/load + +function setup_file() { + build_image_at $BATS_SUITE_TMPDIR + export ATOMFS_TEST_RUN_DIR=${BATS_SUITE_TMPDIR}/run/atomfs + mkdir -p $ATOMFS_TEST_RUN_DIR + export MY_MNTNSNAME=$(readlink /proc/self/ns/mnt | cut -c 6-15) +} + +function setup() { + export MP=${BATS_TEST_TMPDIR}/testmountpoint + mkdir -p $MP +} + +@test "guestmount works ignoring verity" { + + lxc-usernsexec -s <