Repository: common-workflow-language/cwltool

Issue:
upgrade filename validation regex
from  non-unicode to one that doesn't exclude 80% of the world's population



Discussion:

Resolving patch:
diff --git a/cwltool/command_line_tool.py b/cwltool/command_line_tool.py
--- a/cwltool/command_line_tool.py
+++ b/cwltool/command_line_tool.py
@@ -10,6 +10,7 @@
 import shutil
 import threading
 import urllib
+import urllib.parse
 from functools import cmp_to_key, partial
 from typing import (
     Any,
@@ -83,7 +84,9 @@
 if TYPE_CHECKING:
     from .provenance_profile import ProvenanceProfile  # pylint: disable=unused-import
 
-ACCEPTLIST_EN_STRICT_RE = re.compile(r"^[a-zA-Z0-9._+-]+$")
+ACCEPTLIST_EN_STRICT_RE = re.compile(
+    r"^[\w.+\-\u2600-\u26FF\U0001f600-\U0001f64f]+$"
+)  # accept unicode word characters and emojis
 ACCEPTLIST_EN_RELAXED_RE = re.compile(r".*")  # Accept anything
 ACCEPTLIST_RE = ACCEPTLIST_EN_STRICT_RE
 DEFAULT_CONTAINER_MSG = """
@@ -1178,7 +1181,10 @@ def collect_output(
                                     {
                                         "location": g,
                                         "path": fs_access.join(
-                                            builder.outdir, g[len(prefix[0]) + 1 :]
+                                            builder.outdir,
+                                            urllib.parse.unquote(
+                                                g[len(prefix[0]) + 1 :]
+                                            ),
                                         ),
                                         "basename": os.path.basename(g),
                                         "nameroot": os.path.splitext(


Test patch:
diff --git a/tests/test_path_checks.py b/tests/test_path_checks.py
new file mode 100644
--- /dev/null
+++ b/tests/test_path_checks.py
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+import pytest
+from pathlib import Path
+
+from cwltool.main import main
+
+from .util import needs_docker
+
+script = """
+#!/usr/bin/env cwl-runner
+cwlVersion: v1.0
+class: CommandLineTool
+inputs:
+  - id: input
+    type: File
+    inputBinding:
+      position: 0
+  - id: output
+    type: string
+outputs:
+  - id: output
+    type: File
+    outputBinding:
+      glob: "$(inputs.output)"
+stdout: "$(inputs.output)"
+baseCommand: [cat]
+"""
+
+
+@needs_docker
+def test_spaces_in_input_files(tmp_path: Path) -> None:
+    script_name = tmp_path / "script"
+    spaces = tmp_path / "test with spaces"
+    spaces.touch()
+    with script_name.open(mode="w") as script_file:
+        script_file.write(script)
+
+    params = [
+        "--debug",
+        "--outdir",
+        str(tmp_path / "outdir"),
+        str(script_name),
+        "--input",
+        str(spaces),
+        "--output",
+        "test.txt",
+    ]
+    assert main(params) == 1
+    assert main(["--relax-path-checks"] + params) == 0
+
+
+@needs_docker
+@pytest.mark.parametrize(
+    "filename", ["測試", "그래프", "график", "𒁃", "☕😍", "امتحان", "abc+DEFGZ.z_12345-"]
+)
+def test_unicode_in_input_files(tmp_path: Path, filename: str) -> None:
+    script_name = tmp_path / "script"
+    inputfile = tmp_path / filename
+    inputfile.touch()
+    with script_name.open(mode="w") as script_file:
+        script_file.write(script)
+
+    params = [
+        "--debug",
+        "--outdir",
+        str(tmp_path / "outdir"),
+        str(script_name),
+        "--input",
+        str(inputfile),
+        "--output",
+        "test.txt",
+    ]
+    assert main(params) == 0
+
+
+@needs_docker
+@pytest.mark.parametrize(
+    "filename", ["測試", "그래프", "график", "𒁃", "☕😍", "امتحان", "abc+DEFGZ.z_12345-"]
+)
+def test_unicode_in_output_files(tmp_path: Path, filename: str) -> None:
+    script_name = tmp_path / "script"
+    inputfile = tmp_path / "test"
+    inputfile.touch()
+    with script_name.open(mode="w") as script_file:
+        script_file.write(script)
+
+    params = [
+        "--debug",
+        "--outdir",
+        str(tmp_path / "outdir"),
+        str(script_name),
+        "--input",
+        str(inputfile),
+        "--output",
+        filename,
+    ]
+    assert main(params) == 0
diff --git a/tests/test_relax_path_checks.py b/tests/test_relax_path_checks.py
deleted file mode 100644
--- a/tests/test_relax_path_checks.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from pathlib import Path
-
-from cwltool.main import main
-
-from .util import needs_docker
-
-script = """
-#!/usr/bin/env cwl-runner
-cwlVersion: v1.0
-class: CommandLineTool
-inputs:
-  - id: input
-    type: File
-    inputBinding:
-      position: 0
-outputs:
-  - id: output
-    type: File
-    outputBinding:
-      glob: test.txt
-stdout: test.txt
-baseCommand: [cat]
-"""
-
-
-@needs_docker
-def test_spaces_in_input_files(tmp_path: Path) -> None:
-    script_name = tmp_path / "script"
-    spaces = tmp_path / "test with spaces"
-    spaces.touch()
-    with script_name.open(mode="w") as script_file:
-        script_file.write(script)
-
-    params = [
-        "--debug",
-        "--outdir",
-        str(tmp_path / "outdir"),
-        str(script_name),
-        "--input",
-        str(spaces),
-    ]
-    assert main(params) == 1
-    assert main(["--relax-path-checks"] + params) == 0