Commit 6f274446 authored by Julien Muchembled's avatar Julien Muchembled

fix_shebang: don't touch symlinks

Symlinks can point anywhere outside the parts. Also symlinks can be
broken.

By using lstat instead of stat, the symlink is not considered as a
regular file.

See merge request !14
parent 02a086dd
Pipeline #13863 passed with stage
in 0 seconds
...@@ -463,7 +463,7 @@ echo %s ...@@ -463,7 +463,7 @@ echo %s
continue continue
for f in os.listdir(dir_abspath): for f in os.listdir(dir_abspath):
f_abspath = os.path.join(dir_abspath, f) f_abspath = os.path.join(dir_abspath, f)
st_mode = os.stat(f_abspath).st_mode st_mode = os.lstat(f_abspath).st_mode
if not stat.S_ISREG(st_mode): if not stat.S_ISREG(st_mode):
continue continue
with open(f_abspath, 'rb') as f: with open(f_abspath, 'rb') as f:
......
...@@ -8,8 +8,10 @@ import shutil ...@@ -8,8 +8,10 @@ import shutil
import stat import stat
import tarfile import tarfile
import tempfile import tempfile
import pkg_resources from contextlib import contextmanager
from io import BytesIO
from time import sleep from time import sleep
import pkg_resources
import zc.buildout import zc.buildout
import zc.buildout.testing import zc.buildout.testing
import zc.buildout.tests import zc.buildout.tests
...@@ -30,6 +32,25 @@ def setUp(test): ...@@ -30,6 +32,25 @@ def setUp(test):
zc.buildout.testing.install('slapos.recipe.build', test) zc.buildout.testing.install('slapos.recipe.build', test)
zc.buildout.testing.install_develop('slapos.recipe.cmmi', test) zc.buildout.testing.install_develop('slapos.recipe.cmmi', test)
def tarfile_addfileobj(tarobj, name, dataobj, **kw):
tarinfo = tarfile.TarInfo(name)
dataobj.seek(0, 2)
tarinfo.size = dataobj.tell()
dataobj.seek(0)
for x in kw.items():
setattr(tarinfo, *x)
tarobj.addfile(tarinfo, dataobj)
@contextmanager
def fake_package(**kw):
with tempfile.NamedTemporaryFile(suffix=".tar") as tmp:
with tarfile.open(mode='w', fileobj=tmp) as tar:
for k, v in kw.items():
tarfile_addfileobj(tar, k, BytesIO(v.encode()),
**{'mode':stat.S_IRWXU} if v.startswith('#!') else {})
tmp.flush()
yield tmp.name
class NonInformativeTests(unittest.TestCase): class NonInformativeTests(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -103,25 +124,13 @@ class NonInformativeTests(unittest.TestCase): ...@@ -103,25 +124,13 @@ class NonInformativeTests(unittest.TestCase):
recipe.install() recipe.install()
def test_restart_after_failure(self): def test_restart_after_failure(self):
temp_directory = tempfile.mkdtemp(dir=self.dir, prefix="fake_package") with fake_package(
configure='#!/bin/sh\n',
configure_path = os.path.join(temp_directory, 'configure') Makefile='all:\n\texit -1',
self.write_file(configure_path, 'exit 0', mode=stat.S_IRWXU) ) as tarfile_path:
makefile_path = os.path.join(temp_directory, 'Makefile') recipe = self.make_recipe({}, 'test', {'url': tarfile_path})
self.write_file(makefile_path, 'all:\n\texit -1') os.chdir(self.dir)
os.chdir(temp_directory)
ignore, tarfile_path = tempfile.mkstemp(suffix=".tar")
tar = tarfile.open(tarfile_path, 'w')
tar.add('configure')
tar.add('Makefile')
tar.close()
recipe = self.make_recipe({}, 'test', {'url': tarfile_path})
os.chdir(self.dir)
try:
# expected failure # expected failure
with self.assertRaises(zc.buildout.UserError): with self.assertRaises(zc.buildout.UserError):
recipe.install() recipe.install()
...@@ -129,12 +138,6 @@ class NonInformativeTests(unittest.TestCase): ...@@ -129,12 +138,6 @@ class NonInformativeTests(unittest.TestCase):
# the install should still fail, and _not_ raise an OSError # the install should still fail, and _not_ raise an OSError
with self.assertRaises(zc.buildout.UserError): with self.assertRaises(zc.buildout.UserError):
recipe.install() recipe.install()
finally:
try:
shutil.rmtree(temp_directory)
os.remove(tarfile_path)
except:
pass
def test_environment_restored_after_building_a_part(self): def test_environment_restored_after_building_a_part(self):
# Make sure the test variables do not exist beforehand # Make sure the test variables do not exist beforehand
...@@ -345,6 +348,22 @@ class NonInformativeTests(unittest.TestCase): ...@@ -345,6 +348,22 @@ class NonInformativeTests(unittest.TestCase):
build_directory = os.path.join(self.dir, 'test_parts/test__compile__') build_directory = os.path.join(self.dir, 'test_parts/test__compile__')
self.assertTrue(os.path.exists(build_directory)) self.assertTrue(os.path.exists(build_directory))
def test_bad_symlink_in_bin(self):
with fake_package(
configure="""#!/bin/sh
echo prefix = ${@##--prefix=} > Makefile.in
""",
Makefile="""include Makefile.in
install:
\tmkdir -p $(prefix)/bin
\tln -sf /DUMMYFILENOTEXISTING $(prefix)/bin/badlink
""",
) as tarfile_path:
recipe = self.make_recipe({}, 'test', {'url': tarfile_path})
os.chdir(self.dir)
recipe.install()
self.assertTrue(os.path.islink('test_parts/test/bin/badlink'))
def test_suite(): def test_suite():
sums = [] sums = []
def md5sum(m): def md5sum(m):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment