Skip to content

Commit

Permalink
test: add bats tests for mount
Browse files Browse the repository at this point in the history
Add a bats tests suite for mounting and for failing to mount when the
images are bad.

Uses the ATOMFS_TEST_RUN_DIR env var to avoid polluting your host's
/run/atomfs/meta dir.

copies the guestmount test from the github yaml into bats and expands it
a bit.

I apologize for the bash quoting situation in the heredoc in the
guestmount tests, forgive me

Missing cases:
- testing `atomfs verify` on bad images:
  requires manufacturing a verity image that will mount OK but has a bad
  block that won't get read until later. I have tested verify with
  mounted bad images that I mounted with a purposely broken atomfs, but
  there should be a better way for CI.

Signed-off-by: Michael McCracken <[email protected]>
  • Loading branch information
mikemccracken committed Oct 21, 2024
1 parent faf1e15 commit 83e497f
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 3 deletions.
44 changes: 41 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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-*
2 changes: 2 additions & 0 deletions test/1.README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Just a file to import into a scratch stacker image

14 changes: 14 additions & 0 deletions test/1.stacker.yaml
Original file line number Diff line number Diff line change
@@ -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: /
17 changes: 17 additions & 0 deletions test/helpers.bash
Original file line number Diff line number Diff line change
@@ -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
}
122 changes: 122 additions & 0 deletions test/priv-mount.bats
Original file line number Diff line number Diff line change
@@ -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
}
36 changes: 36 additions & 0 deletions test/priv-verify.bats
Original file line number Diff line number Diff line change
@@ -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
}
102 changes: 102 additions & 0 deletions test/unpriv-guestmount.bats
Original file line number Diff line number Diff line change
@@ -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 <<EOF
set -x
export ATOMFS_TEST_RUN_DIR=$ATOMFS_TEST_RUN_DIR
export PERSIST_DIR=${BATS_TEST_TMPDIR}/upperdir
mkdir -p \$PERSIST_DIR
export INNER_MNTNSNAME=\$(readlink /proc/self/ns/mnt | cut -c 6-15)
set +e
atomfs --debug mount --persist=\$PERSIST_DIR ${BATS_SUITE_TMPDIR}/oci:test-squashfs $MP
[ \$? -eq 0 ] && {
echo guestmount without allow-missing should fail, because we do not have verity
exit 1
}
set -e
atomfs --debug mount --allow-missing-verity --persist=\$PERSIST_DIR ${BATS_SUITE_TMPDIR}/oci:test-squashfs $MP
[ -f $MP/1.README.md ]
[ -f $MP/random.txt ]
touch $MP/let-me-write
set +e
atomfs --debug verify $MP
[ \$? -eq 0 ] && {
echo mount with squashfuse ignores verity, so verify should have failed, output should include warning
exit 1
}
set -e
find $ATOMFS_TEST_RUN_DIR/meta/\$INNER_MNTNSNAME/ -name config.json|xargs cat
find $ATOMFS_TEST_RUN_DIR/meta/\$INNER_MNTNSNAME/
atomfs --debug umount $MP
[ -f \$PERSIST_DIR/let-me-write ]
# mount point and meta dir should be empty
[ -d $MP ]
[ -z \$( ls -A $MP) ]
[ -d $ATOMFS_TEST_RUN_DIR/meta/\$INNER_MNTNSNAME/ ]
[ -z \$( ls -A $ATOMFS_TEST_RUN_DIR/meta/\$INNER_MNTNSNAME/) ]
rm -rf \$PERSIST_DIR
rm -rf $ATOMFS_TEST_RUN_DIR/meta
EOF

}


@test "guestmount works on images without verity" {

lxc-usernsexec -s <<EOF
set -x
export ATOMFS_TEST_RUN_DIR=$ATOMFS_TEST_RUN_DIR
export PERSIST_DIR=${BATS_TEST_TMPDIR}/upperdir
mkdir -p \$PERSIST_DIR
export INNER_MNTNSNAME=\$(readlink /proc/self/ns/mnt | cut -c 6-15)
atomfs --debug mount --allow-missing-verity --persist=\$PERSIST_DIR ${BATS_SUITE_TMPDIR}/oci-no-verity:test-squashfs $MP
[ -f $MP/1.README.md ]
[ -f $MP/random.txt ]
touch $MP/let-me-write
set +e
atomfs --debug verify $MP
[ \$? -eq 0 ] && {
echo mount with squashfuse ignores verity, so verify should have failed, output should include warning
exit 1
}
set -e
atomfs --debug umount $MP
[ -f \$PERSIST_DIR/let-me-write ]
[ -d $MP ]
[ -z \$( ls -A $MP) ]
[ -d $ATOMFS_TEST_RUN_DIR/meta/\$INNER_MNTNSNAME/ ]
find $ATOMFS_TEST_RUN_DIR/meta/\$INNER_MNTNSNAME/
[ -z \$( ls -A $ATOMFS_TEST_RUN_DIR/meta/\$INNER_MNTNSNAME/) ]
rm -rf \$PERSIST_DIR
rm -rf $ATOMFS_TEST_RUN_DIR/meta
EOF
}

0 comments on commit 83e497f

Please sign in to comment.