From 2d21bf6a50a7cda0b7c99d7605b0b2c2a89a191d Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Wed, 5 Jul 2017 19:21:07 -0700 Subject: [PATCH] Make sure y/n values are quoted in serialized output Signed-off-by: Joffrey F --- compose/config/serialize.py | 15 ++++++++++++++- tests/unit/config/config_test.py | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/compose/config/serialize.py b/compose/config/serialize.py index beafe02b9..306f86969 100644 --- a/compose/config/serialize.py +++ b/compose/config/serialize.py @@ -21,11 +21,23 @@ def serialize_dict_type(dumper, data): return dumper.represent_dict(data.repr()) +def serialize_string(dumper, data): + """ Ensure boolean-like strings are quoted in the output """ + representer = dumper.represent_str if six.PY3 else dumper.represent_unicode + if data.lower() in ('y', 'n', 'yes', 'no', 'on', 'off', 'true', 'false'): + # Empirically only y/n appears to be an issue, but this might change + # depending on which PyYaml version is being used. Err on safe side. + return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"') + return representer(data) + + yaml.SafeDumper.add_representer(types.VolumeFromSpec, serialize_config_type) yaml.SafeDumper.add_representer(types.VolumeSpec, serialize_config_type) yaml.SafeDumper.add_representer(types.ServiceSecret, serialize_dict_type) yaml.SafeDumper.add_representer(types.ServiceConfig, serialize_dict_type) yaml.SafeDumper.add_representer(types.ServicePort, serialize_dict_type) +yaml.SafeDumper.add_representer(str, serialize_string) +yaml.SafeDumper.add_representer(six.text_type, serialize_string) def denormalize_config(config, image_digests=None): @@ -58,7 +70,8 @@ def serialize_config(config, image_digests=None): denormalize_config(config, image_digests), default_flow_style=False, indent=2, - width=80) + width=80 + ) def serialize_ns_time_value(value): diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py index 721a428e1..6731a6bbc 100644 --- a/tests/unit/config/config_test.py +++ b/tests/unit/config/config_test.py @@ -4163,3 +4163,21 @@ class SerializeTest(unittest.TestCase): assert secret_sort(serialized_service['configs']) == secret_sort(service_dict['configs']) assert 'configs' in serialized_config assert serialized_config['configs']['two'] == configs_dict['two'] + + def test_serialize_bool_string(self): + cfg = { + 'version': '2.2', + 'services': { + 'web': { + 'image': 'example/web', + 'command': 'true', + 'environment': {'FOO': 'Y', 'BAR': 'on'} + } + } + } + config_dict = config.load(build_config_details(cfg)) + + serialized_config = serialize_config(config_dict) + assert 'command: "true"\n' in serialized_config + assert 'FOO: "Y"\n' in serialized_config + assert 'BAR: "on"\n' in serialized_config