Repository: borgbackup/borg

Issue:
test_fuse fails if SELinux is enabled
borgbackup 1.1.10 (Fedora rawhide) on x86_64


    python3 setup.py build
    export PYTHONPATH=$(pwd)/build/$(ls build/ | grep 'lib.')
    py.test-3 -vk "not benchmark" $PYTHONPATH/borg/testsuite/*.py

    ================================== FAILURES ==================================
    __________________________________ ArchiverTestCase.test_fuse __________________________________

    self = <borg.testsuite.archiver.ArchiverTestCase testMethod=test_fuse>

        @unittest.skipUnless(has_llfuse, 'llfuse not installed')
        def test_fuse(self):
            def has_noatime(some_file):
                atime_before = os.stat(some_file).st_atime_ns
                try:
                    os.close(os.open(some_file, flags_noatime))
                except PermissionError:
                    return False
                else:
                    atime_after = os.stat(some_file).st_atime_ns
                    noatime_used = flags_noatime != flags_normal
                    return noatime_used and atime_before == atime_after
        
            self.cmd('init', '--encryption=repokey', self.repository_location)
            self.create_test_files()
            have_noatime = has_noatime('input/file1')
            self.cmd('create', '--exclude-nodump', self.repository_location + '::archive', 'input')
            self.cmd('create', '--exclude-nodump', self.repository_location + '::archive2', 'input')
            if has_lchflags:
                # remove the file we did not backup, so input and output become equal
                os.remove(os.path.join('input', 'flagfile'))
            mountpoint = os.path.join(self.tmpdir, 'mountpoint')
            # mount the whole repository, archive contents shall show up in archivename subdirs of mountpoint:
            with self.fuse_mount(self.repository_location, mountpoint):
                # bsdflags are not supported by the FUSE mount
                # we also ignore xattrs here, they are tested separately
                self.assert_dirs_equal(self.input_path, os.path.join(mountpoint, 'archive', 'input'),
                                       ignore_bsdflags=True, ignore_xattrs=True)
                self.assert_dirs_equal(self.input_path, os.path.join(mountpoint, 'archive2', 'input'),
                                       ignore_bsdflags=True, ignore_xattrs=True)
            # mount only 1 archive, its contents shall show up directly in mountpoint:
            with self.fuse_mount(self.repository_location + '::archive', mountpoint):
                self.assert_dirs_equal(self.input_path, os.path.join(mountpoint, 'input'),
                                       ignore_bsdflags=True, ignore_xattrs=True)
                # regular file
                in_fn = 'input/file1'
                out_fn = os.path.join(mountpoint, 'input', 'file1')
                # stat
                sti1 = os.stat(in_fn)
                sto1 = os.stat(out_fn)
                assert sti1.st_mode == sto1.st_mode
                assert sti1.st_uid == sto1.st_uid
                assert sti1.st_gid == sto1.st_gid
                assert sti1.st_size == sto1.st_size
                if have_noatime:
                    assert sti1.st_atime == sto1.st_atime
                assert sti1.st_ctime == sto1.st_ctime
                assert sti1.st_mtime == sto1.st_mtime
                # note: there is another hardlink to this, see below
                assert sti1.st_nlink == sto1.st_nlink == 2
                # read
                with open(in_fn, 'rb') as in_f, open(out_fn, 'rb') as out_f:
                    assert in_f.read() == out_f.read()
                # hardlink (to 'input/file1')
                if are_hardlinks_supported():
                    in_fn = 'input/hardlink'
                    out_fn = os.path.join(mountpoint, 'input', 'hardlink')
                    sti2 = os.stat(in_fn)
                    sto2 = os.stat(out_fn)
                    assert sti2.st_nlink == sto2.st_nlink == 2
                    assert sto1.st_ino == sto2.st_ino
                # symlink
                if are_symlinks_supported():
                    in_fn = 'input/link1'
                    out_fn = os.path.join(mountpoint, 'input', 'link1')
                    sti = os.stat(in_fn, follow_symlinks=False)
                    sto = os.stat(out_fn, follow_symlinks=False)
                    assert sti.st_size == len('somewhere')
                    assert sto.st_size == len('somewhere')
                    assert stat.S_ISLNK(sti.st_mode)
                    assert stat.S_ISLNK(sto.st_mode)
                    assert os.readlink(in_fn) == os.readlink(out_fn)
                # FIFO
                if are_fifos_supported():
                    out_fn = os.path.join(mountpoint, 'input', 'fifo1')
                    sto = os.stat(out_fn)
                    assert stat.S_ISFIFO(sto.st_mode)
                # list/read xattrs
                try:
                    in_fn = 'input/fusexattr'
                    out_fn = os.path.join(mountpoint, 'input', 'fusexattr')
                    if not xattr.XATTR_FAKEROOT and xattr.is_enabled(self.input_path):
                        assert sorted(no_selinux(xattr.listxattr(out_fn))) == ['user.empty', 'user.foo', ]
                        assert xattr.getxattr(out_fn, 'user.foo') == b'bar'
                        # Special case: getxattr returns None (not b'') when reading an empty xattr.
                        assert xattr.getxattr(out_fn, 'user.empty') is None
                    else:
    >                   assert xattr.listxattr(out_fn) == []
    E                   AssertionError: assert ['security.selinux'] == []
    E                     Left contains more items, first extra item: 'security.selinux'
    E                     Full diff:
    E                     - ['security.selinux']
    E                     + []

    build/lib.linux-x86_64-3.7/borg/testsuite/archiver.py:2222: AssertionError
    __________________________________ RemoteArchiverTestCase.test_fuse __________________________________

Fedora's builder do not run "test_fuse" (as it does not working within mock) but I'm seeing this when running the test suite manually on a rawhide machine.



Discussion:
at other places, the borg tests already use some filter to remove the selinux xattr, needs to be added here also.

Resolving patch:
diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py
--- a/src/borg/testsuite/archiver.py
+++ b/src/borg/testsuite/archiver.py
@@ -2219,7 +2219,7 @@ def has_noatime(some_file):
                     # Special case: getxattr returns None (not b'') when reading an empty xattr.
                     assert xattr.getxattr(out_fn, 'user.empty') is None
                 else:
-                    assert xattr.listxattr(out_fn) == []
+                    assert no_selinux(xattr.listxattr(out_fn)) == []
                     try:
                         xattr.getxattr(out_fn, 'user.foo')
                     except OSError as e:


Test patch: