test_extract.py (4221B)
1 #!/usr/bin/env python 2 3 import os 4 import tarfile 5 import tempfile 6 import zipfile 7 8 import mozfile 9 import mozunit 10 import pytest 11 import stubs 12 13 14 @pytest.fixture 15 def ensure_directory_contents(): 16 """ensure the directory contents match""" 17 18 def inner(directory): 19 for f in stubs.files: 20 path = os.path.join(directory, *f) 21 exists = os.path.exists(path) 22 if not exists: 23 print("%s does not exist" % (os.path.join(f))) 24 assert exists 25 if exists: 26 contents = open(path).read().strip() 27 assert contents == f[-1] 28 29 return inner 30 31 32 @pytest.fixture(scope="module") 33 def tarpath(tmpdir_factory): 34 """create a stub tarball for testing""" 35 tmpdir = tmpdir_factory.mktemp("test_extract") 36 37 tempdir = tmpdir.join("stubs").strpath 38 stubs.create_stub(tempdir) 39 filename = tmpdir.join("bundle.tar").strpath 40 archive = tarfile.TarFile(filename, mode="w") 41 for path in stubs.files: 42 archive.add(os.path.join(tempdir, *path), arcname=os.path.join(*path)) 43 archive.close() 44 45 assert os.path.exists(filename) 46 return filename 47 48 49 @pytest.fixture(scope="module") 50 def zippath(tmpdir_factory): 51 """create a stub zipfile for testing""" 52 tmpdir = tmpdir_factory.mktemp("test_extract") 53 54 tempdir = tmpdir.join("stubs").strpath 55 stubs.create_stub(tempdir) 56 filename = tmpdir.join("bundle.zip").strpath 57 archive = zipfile.ZipFile(filename, mode="w") 58 for path in stubs.files: 59 archive.write(os.path.join(tempdir, *path), arcname=os.path.join(*path)) 60 archive.close() 61 62 assert os.path.exists(filename) 63 return filename 64 65 66 @pytest.fixture(scope="module", params=["tar", "zip"]) 67 def bundlepath(request, tarpath, zippath): 68 if request.param == "tar": 69 return tarpath 70 else: 71 return zippath 72 73 74 def test_extract(tmpdir, bundlepath, ensure_directory_contents): 75 """test extracting a zipfile""" 76 dest = tmpdir.mkdir("dest").strpath 77 mozfile.extract(bundlepath, dest) 78 ensure_directory_contents(dest) 79 80 81 def test_extract_zipfile_missing_file_attributes(tmpdir): 82 """if files do not have attributes set the default permissions have to be inherited.""" 83 _zipfile = os.path.join( 84 os.path.dirname(__file__), "files", "missing_file_attributes.zip" 85 ) 86 assert os.path.exists(_zipfile) 87 dest = tmpdir.mkdir("dest").strpath 88 89 # Get the default file permissions for the user 90 fname = os.path.join(dest, "foo") 91 with open(fname, "w"): 92 pass 93 default_stmode = os.stat(fname).st_mode 94 95 files = mozfile.extract_zip(_zipfile, dest) 96 for filename in files: 97 assert os.stat(os.path.join(dest, filename)).st_mode == default_stmode 98 99 100 def test_extract_non_archive(tarpath, zippath): 101 """test the generalized extract function""" 102 # test extracting some non-archive; this should fail 103 fd, filename = tempfile.mkstemp() 104 os.write(fd, b"This is not a zipfile or tarball") 105 os.close(fd) 106 exception = None 107 108 try: 109 dest = tempfile.mkdtemp() 110 mozfile.extract(filename, dest) 111 except Exception as exc: 112 exception = exc 113 finally: 114 os.remove(filename) 115 os.rmdir(dest) 116 117 assert isinstance(exception, Exception) 118 119 120 def test_extract_ignore(tmpdir, bundlepath): 121 dest = tmpdir.mkdir("dest").strpath 122 ignore = ("foo", "**/fleem.txt", "read*.txt") 123 mozfile.extract(bundlepath, dest, ignore=ignore) 124 125 assert sorted(os.listdir(dest)) == ["bar.txt", "foo.txt"] 126 127 128 def test_tarball_escape(tmpdir): 129 """Ensures that extracting a tarball can't write outside of the intended 130 destination directory. 131 """ 132 workdir = tmpdir.mkdir("workdir") 133 os.chdir(workdir) 134 135 # Generate a "malicious" bundle. 136 with open("bad.txt", "w") as fh: 137 fh.write("pwned!") 138 139 def change_name(tarinfo): 140 tarinfo.name = "../" + tarinfo.name 141 return tarinfo 142 143 with tarfile.open("evil.tar", "w:xz") as tar: 144 tar.add("bad.txt", filter=change_name) 145 146 with pytest.raises(RuntimeError): 147 mozfile.extract_tarball("evil.tar", workdir) 148 assert not os.path.exists(tmpdir.join("bad.txt")) 149 150 151 if __name__ == "__main__": 152 mozunit.main()