add config.yml as default config file format

None of the config options in config.py require Python code.  YAML is a
common config data format, and it is also used for build metadata.  It is
also much safer to use since it can be pure data, without anything
executable in it.  This also reduces the attack surface of the fdroid
process by eliminating a guaranteed place to write to get code executed.
With config.py, any exploit that can get local write access can turn that
into execute access by writing to the config.py, then cleaning up after
itself once it has what it needs.  Switching to YAML removes that vector
entirely.

Also, this removes the config_file argument.  It is not used in either
fdroidserver or repomaker.  Also, it probably wouldn't work since so
much of the code assumes that the current working dir is the root of the
repo.
This commit is contained in:
Hans-Christoph Steiner 2018-09-04 11:03:05 +02:00
parent fd41b70e27
commit d3d48dba5e
2 changed files with 93 additions and 8 deletions

View file

@ -47,6 +47,7 @@ class CommonTest(unittest.TestCase):
if not os.path.exists(self.tmpdir):
os.makedirs(self.tmpdir)
os.chdir(self.basedir)
fdroidserver.common.config = None
def test_parse_human_readable_size(self):
for k, v in ((9827, 9827), (123.456, 123), ('123b', 123), ('1.2', 1),
@ -1409,6 +1410,70 @@ class CommonTest(unittest.TestCase):
self.assertIsNotNone(result)
self.assertNotEqual(result, '')
def test_with_no_config(self):
"""It should set defaults if no config file is found"""
testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
os.chdir(testdir)
self.assertFalse(os.path.exists('config.yml'))
self.assertFalse(os.path.exists('config.py'))
config = fdroidserver.common.read_config(fdroidserver.common.options)
self.assertEqual(None, config.get('apksigner'))
self.assertIsNotNone(config.get('char_limits'))
def test_with_config_yml(self):
"""Make sure it is possible to use config.yml alone."""
testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
os.chdir(testdir)
with open('config.yml', 'w') as fp:
fp.write('apksigner: yml')
self.assertTrue(os.path.exists('config.yml'))
self.assertFalse(os.path.exists('config.py'))
config = fdroidserver.common.read_config(fdroidserver.common.options)
self.assertEqual('yml', config.get('apksigner'))
def test_with_config_py(self):
"""Make sure it is still possible to use config.py alone."""
testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
os.chdir(testdir)
with open('config.py', 'w') as fp:
fp.write('apksigner = "py"')
self.assertFalse(os.path.exists('config.yml'))
self.assertTrue(os.path.exists('config.py'))
config = fdroidserver.common.read_config(fdroidserver.common.options)
self.assertEqual("py", config.get('apksigner'))
def test_config_perm_warning(self):
"""Exercise the code path that issues a warning about unsafe permissions."""
testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
os.chdir(testdir)
with open('config.yml', 'w') as fp:
fp.write('keystore: foo.jks')
self.assertTrue(os.path.exists(fp.name))
os.chmod(fp.name, 0o666)
fdroidserver.common.read_config(fdroidserver.common.options)
os.remove(fp.name)
fdroidserver.common.config = None
with open('config.py', 'w') as fp:
fp.write('keystore = "foo.jks"')
self.assertTrue(os.path.exists(fp.name))
os.chmod(fp.name, 0o666)
fdroidserver.common.read_config(fdroidserver.common.options)
def test_with_both_config_yml_py(self):
"""If config.yml and config.py are present, config.py should be ignored."""
testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
os.chdir(testdir)
with open('config.yml', 'w') as fp:
fp.write('apksigner: yml')
with open('config.py', 'w') as fp:
fp.write('apksigner = "py"')
self.assertTrue(os.path.exists('config.yml'))
self.assertTrue(os.path.exists('config.py'))
config = fdroidserver.common.read_config(fdroidserver.common.options)
self.assertEqual('yml', config.get('apksigner'))
if __name__ == "__main__":
os.chdir(os.path.dirname(__file__))