Przeglądaj źródła

Properly escape values coming from env_files, fixes #6871

Signed-off-by: Florian Apolloner <[email protected]>
Florian Apolloner 6 lat temu
rodzic
commit
f17e7268b0

+ 9 - 7
compose/config/config.py

@@ -408,7 +408,7 @@ def load(config_details, compatibility=False, interpolate=True):
     configs = load_mapping(
         config_details.config_files, 'get_configs', 'Config', config_details.working_dir
     )
-    service_dicts = load_services(config_details, main_file, compatibility)
+    service_dicts = load_services(config_details, main_file, compatibility, interpolate=interpolate)
 
     if main_file.version != V1:
         for service_dict in service_dicts:
@@ -460,7 +460,7 @@ def validate_external(entity_type, name, config, version):
                 entity_type, name, ', '.join(k for k in config if k != 'external')))
 
 
-def load_services(config_details, config_file, compatibility=False):
+def load_services(config_details, config_file, compatibility=False, interpolate=True):
     def build_service(service_name, service_dict, service_names):
         service_config = ServiceConfig.with_abs_paths(
             config_details.working_dir,
@@ -479,7 +479,8 @@ def load_services(config_details, config_file, compatibility=False):
             service_names,
             config_file.version,
             config_details.environment,
-            compatibility
+            compatibility,
+            interpolate
         )
         return service_dict
 
@@ -679,13 +680,13 @@ class ServiceExtendsResolver(object):
         return filename
 
 
-def resolve_environment(service_dict, environment=None):
+def resolve_environment(service_dict, environment=None, interpolate=True):
     """Unpack any environment variables from an env_file, if set.
     Interpolate environment values if set.
     """
     env = {}
     for env_file in service_dict.get('env_file', []):
-        env.update(env_vars_from_file(env_file))
+        env.update(env_vars_from_file(env_file, interpolate))
 
     env.update(parse_environment(service_dict.get('environment')))
     return dict(resolve_env_var(k, v, environment) for k, v in six.iteritems(env))
@@ -881,11 +882,12 @@ def finalize_service_volumes(service_dict, environment):
     return service_dict
 
 
-def finalize_service(service_config, service_names, version, environment, compatibility):
+def finalize_service(service_config, service_names, version, environment, compatibility,
+                     interpolate=True):
     service_dict = dict(service_config.config)
 
     if 'environment' in service_dict or 'env_file' in service_dict:
-        service_dict['environment'] = resolve_environment(service_dict, environment)
+        service_dict['environment'] = resolve_environment(service_dict, environment, interpolate)
         service_dict.pop('env_file', None)
 
     if 'volumes_from' in service_dict:

+ 2 - 1
compose/config/environment.py

@@ -30,7 +30,7 @@ def split_env(env):
     return key, value
 
 
-def env_vars_from_file(filename):
+def env_vars_from_file(filename, interpolate=True):
     """
     Read in a line delimited file of environment variables.
     """
@@ -39,6 +39,7 @@ def env_vars_from_file(filename):
     elif not os.path.isfile(filename):
         raise EnvFileNotFound("{} is not a file.".format(filename))
 
+    # TODO: now we should do something with interpolate here, but what?
     return dotenv.dotenv_values(dotenv_path=filename, encoding='utf-8-sig')
 
 

+ 2 - 0
tests/fixtures/env/three.env

@@ -0,0 +1,2 @@
+FOO=NO $ENV VAR
+DOO=NO ${ENV} VAR

+ 5 - 1
tests/unit/config/config_test.py

@@ -5420,15 +5420,19 @@ class SerializeTest(unittest.TestCase):
                     'environment': {
                         'CURRENCY': '$'
                     },
+                    'env_file': ['tests/fixtures/env/three.env'],
                     'entrypoint': ['$SHELL', '-c'],
                 }
             }
         }
-        config_dict = config.load(build_config_details(cfg), interpolate=False)
+        config_dict = config.load(build_config_details(cfg, working_dir='.'), interpolate=False)
 
         serialized_config = yaml.safe_load(serialize_config(config_dict, escape_dollar=False))
         serialized_service = serialized_config['services']['web']
         assert serialized_service['environment']['CURRENCY'] == '$'
+        # Values coming from env_files are not allowed to have variables
+        assert serialized_service['environment']['FOO'] == 'NO $$ENV VAR'
+        assert serialized_service['environment']['DOO'] == 'NO $${ENV} VAR'
         assert serialized_service['command'] == 'echo $FOO'
         assert serialized_service['entrypoint'][0] == '$SHELL'