From a43c0e61e48a9971109d6aa44bf171c2c5d4b8b7 Mon Sep 17 00:00:00 2001 From: Alexei Znamensky Date: Sun, 10 May 2026 22:39:29 +1200 Subject: [PATCH 1/3] fix(iso_create): sanitize ISO9660 path components to replace invalid characters Characters outside [A-Z0-9_] (e.g. hyphens in directory names like en-us) were passed raw to pycdlib, causing it to reject them with an ISO9660 filename validation error. Replace invalid chars with underscores while preserving original names in Rock Ridge / Joliet / UDF extension paths. Fixes #5103 Co-Authored-By: Claude Sonnet 4.6 --- plugins/modules/iso_create.py | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/plugins/modules/iso_create.py b/plugins/modules/iso_create.py index 264ab6524a..a8c99c0498 100644 --- a/plugins/modules/iso_create.py +++ b/plugins/modules/iso_create.py @@ -222,6 +222,7 @@ boot_options: """ import os +import re import traceback PLATFORM_ID_MAP = { @@ -230,6 +231,24 @@ PLATFORM_ID_MAP = { "mac": b"\x02", } +_ISO9660_INVALID = re.compile(r"[^A-Z0-9_]") + + +def _sanitize_iso_path(path, is_file=False): + parts = path.split("/") + result = [] + for i, part in enumerate(parts): + if not part: + result.append(part) + continue + if is_file and i == len(parts) - 1 and "." in part: + name, ext = part.upper().rsplit(".", 1) + result.append(_ISO9660_INVALID.sub("_", name) + "." + _ISO9660_INVALID.sub("_", ext)) + else: + result.append(_ISO9660_INVALID.sub("_", part.upper())) + return "/".join(result) + + PYCDLIB_IMP_ERR = None try: import pycdlib @@ -249,10 +268,11 @@ def add_file(module, iso_file=None, src_file=None, file_path=None, rock_ridge=No # In standard ISO interchange level 1, file names have a maximum of 8 characters, followed by a required dot, # followed by a maximum 3 character extension, followed by a semicolon and a version file_name = os.path.basename(file_path) + sanitized_path = _sanitize_iso_path(file_path, is_file=True) if "." not in file_name: - file_in_iso_path = f"{file_path.upper()}.;1" + file_in_iso_path = f"{sanitized_path}.;1" else: - file_in_iso_path = f"{file_path.upper()};1" + file_in_iso_path = f"{sanitized_path};1" if rock_ridge: rr_name = file_name if use_joliet: @@ -271,7 +291,7 @@ def add_directory(module, iso_file=None, dir_path=None, rock_ridge=None, use_jol rr_name = None joliet_path = None udf_path = None - iso_dir_path = dir_path.upper() + iso_dir_path = _sanitize_iso_path(dir_path) if rock_ridge: rr_name = os.path.basename(dir_path) if use_joliet: @@ -419,10 +439,11 @@ def main(): if boot_options: boot_file = boot_options["boot_file"] boot_file_basename = os.path.basename(boot_file) + sanitized_boot_path = _sanitize_iso_path(f"/{boot_file_basename}", is_file=True) if "." not in boot_file_basename: - boot_iso_path = f"/{boot_file_basename.upper()}.;1" + boot_iso_path = f"{sanitized_boot_path}.;1" else: - boot_iso_path = f"/{boot_file_basename.upper()};1" + boot_iso_path = f"{sanitized_boot_path};1" add_file( module, iso_file=iso_file, From 5f1600e2858ddf97ebd1fbcf22c4b033e739dd34 Mon Sep 17 00:00:00 2001 From: Alexei Znamensky Date: Sun, 10 May 2026 22:41:24 +1200 Subject: [PATCH 2/3] docs(iso_create): add changelog fragment for #12028 Co-Authored-By: Claude Sonnet 4.6 --- changelogs/fragments/12028-iso-create-sanitize.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/fragments/12028-iso-create-sanitize.yml diff --git a/changelogs/fragments/12028-iso-create-sanitize.yml b/changelogs/fragments/12028-iso-create-sanitize.yml new file mode 100644 index 0000000000..4d84925889 --- /dev/null +++ b/changelogs/fragments/12028-iso-create-sanitize.yml @@ -0,0 +1,4 @@ +bugfixes: + - iso_create - fix failure with non-conforming ISO9660 path characters + (https://github.com/ansible-collections/community.general/issues/5103, + https://github.com/ansible-collections/community.general/pull/12028). From 53fb20f659561b7c7c1240a551600b15f58b44aa Mon Sep 17 00:00:00 2001 From: Alexei Znamensky Date: Sun, 17 May 2026 13:56:45 +1200 Subject: [PATCH 3/3] ensure all code is below all imports --- plugins/modules/iso_create.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/plugins/modules/iso_create.py b/plugins/modules/iso_create.py index a8c99c0498..ae1dedb140 100644 --- a/plugins/modules/iso_create.py +++ b/plugins/modules/iso_create.py @@ -225,6 +225,17 @@ import os import re import traceback +PYCDLIB_IMP_ERR = None +try: + import pycdlib + + HAS_PYCDLIB = True +except ImportError: + PYCDLIB_IMP_ERR = traceback.format_exc() + HAS_PYCDLIB = False + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + PLATFORM_ID_MAP = { "x86": b"\x00", "efi": b"\xef", @@ -249,18 +260,6 @@ def _sanitize_iso_path(path, is_file=False): return "/".join(result) -PYCDLIB_IMP_ERR = None -try: - import pycdlib - - HAS_PYCDLIB = True -except ImportError: - PYCDLIB_IMP_ERR = traceback.format_exc() - HAS_PYCDLIB = False - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib - - def add_file(module, iso_file=None, src_file=None, file_path=None, rock_ridge=None, use_joliet=None, use_udf=None): rr_name = None joliet_path = None