diff --git a/cylc/flow/scheduler_cli.py b/cylc/flow/scheduler_cli.py index 09b405aaa21..2ab793f18e7 100644 --- a/cylc/flow/scheduler_cli.py +++ b/cylc/flow/scheduler_cli.py @@ -20,7 +20,7 @@ from functools import lru_cache from shlex import quote import sys -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, List from cylc.flow import LOG, RSYNC_LOG from cylc.flow.exceptions import ServiceFileError @@ -360,14 +360,22 @@ def scheduler_cli(options: 'Values', workflow_id: str) -> None: sys.exit(ret) +def _protect_remote_cmd_args(cmd: List[str]) -> List[str]: + """Protect command args from second shell interpretation. + + Escape quoting for --set="FOO='foo'" args. + (Separate function for unit testing.) + """ + return [quote(c) for c in cmd] + + def _distribute(host): """Re-invoke this command on a different host if requested.""" # Check whether a run host is explicitly specified, else select one. if not host: host = select_workflow_host()[0] if is_remote_host(host): - # quote here for (e.g.) --set='TEST="test"' - cmd = [quote(c) for c in sys.argv[1:]] + cmd = _protect_remote_cmd_args(sys.argv[1:]) # Prevent recursive host selection cmd.append("--host=localhost") _remote_cylc_cmd(cmd, host=host) diff --git a/tests/unit/test_scheduler_cli.py b/tests/unit/test_scheduler_cli.py new file mode 100644 index 00000000000..f4b9cab2f63 --- /dev/null +++ b/tests/unit/test_scheduler_cli.py @@ -0,0 +1,24 @@ +# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE. +# Copyright (C) NIWA & British Crown (Met Office) & Contributors. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +"""Tests for Cylc scheduler CLI.""" + +from cylc.flow.scheduler_cli import _protect_remote_cmd_args + + +def test__protect_remote_cmd_args(): + cmd = ['cylc', 'play', '-n', '--set=FOO="foo"', 'wf'] + exp = ['cylc', 'play', '-n', '\'--set=FOO="foo"\'', 'wf'] + assert _protect_remote_cmd_args(cmd) == exp