From afc161a0b1ce74cdcbc9be84d1dca58b10f0daf1 Mon Sep 17 00:00:00 2001 From: Hiroshi Ioka Date: Fri, 7 Dec 2018 17:12:40 +0900 Subject: [PATCH] reject environment variable that contains white spaces Signed-off-by: Hiroshi Ioka --- compose/config/environment.py | 29 ++++++++++++++++++++------- compose/config/errors.py | 4 ++++ tests/unit/config/environment_test.py | 10 +++++++++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/compose/config/environment.py b/compose/config/environment.py index 0087b6128..675ab10eb 100644 --- a/compose/config/environment.py +++ b/compose/config/environment.py @@ -5,22 +5,33 @@ import codecs import contextlib import logging import os +import string import six from ..const import IS_WINDOWS_PLATFORM from .errors import ConfigurationError +from .errors import EnvFileNotFound log = logging.getLogger(__name__) +whitespace = set(string.whitespace) + def split_env(env): if isinstance(env, six.binary_type): env = env.decode('utf-8', 'replace') + key = value = None if '=' in env: - return env.split('=', 1) + key, value = env.split('=', 1) else: - return env, None + key = env + for k in key: + if k in whitespace: + raise ConfigurationError( + "environment variable name '%s' may not contains white spaces." % key + ) + return key, value def env_vars_from_file(filename): @@ -28,16 +39,19 @@ def env_vars_from_file(filename): Read in a line delimited file of environment variables. """ if not os.path.exists(filename): - raise ConfigurationError("Couldn't find env file: %s" % filename) + raise EnvFileNotFound("Couldn't find env file: %s" % filename) elif not os.path.isfile(filename): - raise ConfigurationError("%s is not a file." % (filename)) + raise EnvFileNotFound("%s is not a file." % (filename)) env = {} with contextlib.closing(codecs.open(filename, 'r', 'utf-8-sig')) as fileobj: for line in fileobj: line = line.strip() if line and not line.startswith('#'): - k, v = split_env(line) - env[k] = v + try: + k, v = split_env(line) + env[k] = v + except ConfigurationError as e: + raise ConfigurationError('In file {}: {}'.format(filename, e.msg)) return env @@ -55,9 +69,10 @@ class Environment(dict): env_file_path = os.path.join(base_dir, '.env') try: return cls(env_vars_from_file(env_file_path)) - except ConfigurationError: + except EnvFileNotFound: pass return result + instance = _initialize() instance.update(os.environ) return instance diff --git a/compose/config/errors.py b/compose/config/errors.py index f5c038088..9b2078f2c 100644 --- a/compose/config/errors.py +++ b/compose/config/errors.py @@ -19,6 +19,10 @@ class ConfigurationError(Exception): return self.msg +class EnvFileNotFound(ConfigurationError): + pass + + class DependencyError(ConfigurationError): pass diff --git a/tests/unit/config/environment_test.py b/tests/unit/config/environment_test.py index 854aee5a3..88eb0d6e1 100644 --- a/tests/unit/config/environment_test.py +++ b/tests/unit/config/environment_test.py @@ -9,6 +9,7 @@ import pytest from compose.config.environment import env_vars_from_file from compose.config.environment import Environment +from compose.config.errors import ConfigurationError from tests import unittest @@ -52,3 +53,12 @@ class EnvironmentTest(unittest.TestCase): assert env_vars_from_file(str(tmpdir.join('bom.env'))) == { 'PARK_BOM': '박봄' } + + def test_env_vars_from_file_whitespace(self): + tmpdir = pytest.ensuretemp('env_file') + self.addCleanup(tmpdir.remove) + with codecs.open('{}/whitespace.env'.format(str(tmpdir)), 'w', encoding='utf-8') as f: + f.write('WHITESPACE =yes\n') + with pytest.raises(ConfigurationError) as exc: + env_vars_from_file(str(tmpdir.join('whitespace.env'))) + assert 'environment variable' in exc.exconly()