Skip to content

Commit daabc03

Browse files
arimu1claude
andcommitted
Warn when 'baseCommand' is a single string with whitespace (#2240)
A CommandLineTool 'baseCommand' given as a single string with internal whitespace (e.g. "tar xf" instead of [tar, xf]) is passed to the OS as one program name, which almost never exists. --validate previously accepted it silently. Emit a warning at construction time pointing at the offending line and suggesting the list form. List- and single-word baseCommands are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 8949fc2 commit daabc03

4 files changed

Lines changed: 59 additions & 0 deletions

File tree

cwltool/command_line_tool.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,17 @@ class CommandLineTool(Process):
403403
def __init__(self, toolpath_object: CommentedMap, loadingContext: LoadingContext) -> None:
404404
"""Initialize this CommandLineTool."""
405405
super().__init__(toolpath_object, loadingContext)
406+
base_command = self.tool.get("baseCommand")
407+
if isinstance(base_command, str) and len(base_command.split()) > 1:
408+
_logger.warning(
409+
SourceLine(self.tool, "baseCommand", str).makeError(
410+
"'baseCommand' is a single string containing whitespace: %r. "
411+
"It will be passed to the operating system as one program name, "
412+
"which is unlikely to exist. If you meant a program plus arguments, "
413+
"provide a list instead, e.g. [%s]."
414+
% (base_command, ", ".join(repr(p) for p in base_command.split()))
415+
)
416+
)
406417
self.prov_obj = loadingContext.prov_obj
407418
self.path_check_mode: PathCheckingMode = (
408419
PathCheckingMode.RELAXED

tests/test_validate.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import logging
55
import re
66

7+
import pytest
8+
79
from .util import get_data, get_main_output
810

911

@@ -125,3 +127,37 @@ def test_validate_custom_logger() -> None:
125127
assert "tests/CometAdapter.cwl#out' previously defined" not in stdout
126128
assert "tests/CometAdapter.cwl#out' previously defined" not in stderr
127129
assert "tests/CometAdapter.cwl#out' previously defined" in custom_log_text
130+
131+
132+
def test_validate_warns_on_basecommand_with_space() -> None:
133+
"""A 'baseCommand' string containing whitespace warns but still validates."""
134+
custom_log = io.StringIO()
135+
handler = logging.StreamHandler(custom_log)
136+
handler.setLevel(logging.DEBUG)
137+
exit_code, stdout, stderr = get_main_output(
138+
["--validate", get_data("tests/wf/2240-basecommand-space.cwl")],
139+
logger_handler=handler,
140+
)
141+
custom_log_text = re.sub(r"\s\s+", " ", custom_log.getvalue())
142+
assert exit_code == 0
143+
assert "is valid CWL" in stdout
144+
assert "'baseCommand' is a single string containing whitespace" in custom_log_text
145+
assert "'tar xf'" in custom_log_text
146+
assert "['tar', 'xf']" in custom_log_text
147+
148+
149+
@pytest.mark.parametrize(
150+
"cwl_file",
151+
["tests/wf/2240-basecommand-list.cwl", "tests/CometAdapter.cwl"],
152+
)
153+
def test_validate_no_basecommand_space_warning(cwl_file: str) -> None:
154+
"""A list-form (or absent) 'baseCommand' does not trigger the whitespace warning."""
155+
custom_log = io.StringIO()
156+
handler = logging.StreamHandler(custom_log)
157+
handler.setLevel(logging.DEBUG)
158+
exit_code, _, _ = get_main_output(
159+
["--validate", get_data(cwl_file)],
160+
logger_handler=handler,
161+
)
162+
assert exit_code == 0
163+
assert "single string containing whitespace" not in custom_log.getvalue()

tests/wf/2240-basecommand-list.cwl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env cwl-runner
2+
cwlVersion: v1.2
3+
class: CommandLineTool
4+
baseCommand: [tar, xf]
5+
inputs: []
6+
outputs: []
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env cwl-runner
2+
cwlVersion: v1.2
3+
class: CommandLineTool
4+
baseCommand: "tar xf"
5+
inputs: []
6+
outputs: []

0 commit comments

Comments
 (0)