From 0f0673c6210eb2c028737de76787f69ad21c2a85 Mon Sep 17 00:00:00 2001 From: Eu Pin Tien Date: Tue, 21 Apr 2026 16:26:54 +0100 Subject: [PATCH 1/4] Add keys to the MachineConfig model to control the 'rsync' and 'mkdir' permissions --- src/murfey/util/config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/murfey/util/config.py b/src/murfey/util/config.py index 5e50d7c2..37d4568d 100644 --- a/src/murfey/util/config.py +++ b/src/murfey/util/config.py @@ -58,11 +58,13 @@ class MachineConfig(BaseModel): # type: ignore "directories": [], "files": [], } + mkdir_chmod: int = 0o750 # Rsync setup rsync_url: str = "" rsync_module: str = "" rsync_basepath: Optional[Path] = None + rsync_chmod: str = "D0750,F0750" allow_removal: bool = False # Upstream data download setup From f7e39b5d8bd7cb49ade10859d62cfda2beeed234 Mon Sep 17 00:00:00 2001 From: Eu Pin Tien Date: Tue, 21 Apr 2026 16:33:51 +0100 Subject: [PATCH 2/4] Create attribute in RSyncer to store 'chmod' permissions value, and pass it to RSyncer from the machine config through the MultigridController --- src/murfey/client/multigrid_control.py | 1 + src/murfey/client/rsync.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/murfey/client/multigrid_control.py b/src/murfey/client/multigrid_control.py index de47ddee..dae0e7fb 100644 --- a/src/murfey/client/multigrid_control.py +++ b/src/murfey/client/multigrid_control.py @@ -378,6 +378,7 @@ def _start_rsyncer( stop_callback=self._rsyncer_stopped, do_transfer=self.do_transfer, remove_files=remove_files, + chmod=self._machine_config.get("rsync_chmod", "D0750,F0750"), substrings_blacklist=self._machine_config.get( "substrings_blacklist", {"directories": [], "files": []} ), diff --git a/src/murfey/client/rsync.py b/src/murfey/client/rsync.py index 5d27dc0d..475d3157 100644 --- a/src/murfey/client/rsync.py +++ b/src/murfey/client/rsync.py @@ -61,6 +61,7 @@ def __init__( local: bool = False, do_transfer: bool = True, remove_files: bool = False, + chmod: str = "D0750,F0750", required_substrings_for_removal: List[str] = [], substrings_blacklist: dict[str, list[str]] = {}, notify: bool = True, @@ -75,6 +76,7 @@ def __init__( self._local = local self._do_transfer = do_transfer self._remove_files = remove_files + self._chmod = chmod self._required_substrings_for_removal = required_substrings_for_removal self._substrings_blacklist = substrings_blacklist self._notify = notify @@ -501,7 +503,7 @@ def parse_stderr(line: str): # Needed as a pair to trigger permission modifications # Ref: https://serverfault.com/a/796341 "-p", - "--chmod=D0750,F0750", # Use extended chmod format + f"--chmod={self._chmod}", # Set permissions for transferred files and folders ] # Add file locations rsync_cmd.extend([".", self._remote]) From df8d58ff07cd961daf14ab8a2fdbe6dcd28a53f2 Mon Sep 17 00:00:00 2001 From: Eu Pin Tien Date: Tue, 21 Apr 2026 16:47:01 +0100 Subject: [PATCH 3/4] Use folder permissions logic from the machine config for functions in 'file_io_instrument' --- src/murfey/server/api/file_io_instrument.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/murfey/server/api/file_io_instrument.py b/src/murfey/server/api/file_io_instrument.py index bbe12f1b..6346fc32 100644 --- a/src/murfey/server/api/file_io_instrument.py +++ b/src/murfey/server/api/file_io_instrument.py @@ -86,9 +86,11 @@ def suggest_path( count = count + 1 if count else 2 check_path = check_path.parent / f"{check_path_name}{count}" if params.touch: - check_path.mkdir(mode=0o750) + check_path.mkdir(mode=machine_config.mkdir_chmod) if params.extra_directory: - (check_path / secure_filename(params.extra_directory)).mkdir(mode=0o750) + (check_path / secure_filename(params.extra_directory)).mkdir( + mode=machine_config.mkdir_chmod + ) return {"suggested_path": check_path.relative_to(rsync_basepath)} @@ -112,7 +114,7 @@ def make_rsyncer_destination(session_id: int, destination: Dest, db=murfey_db): machine_config.rsync_basepath or Path("") ).resolve() / destination_path for parent_path in full_destination_path.parents: - parent_path.mkdir(mode=0o750, exist_ok=True) + parent_path.mkdir(mode=machine_config.mkdir_chmod, exist_ok=True) return destination From 9f48b27ebe2cc582a4e213c009df386b7627ac68 Mon Sep 17 00:00:00 2001 From: Eu Pin Tien Date: Tue, 21 Apr 2026 18:13:08 +0100 Subject: [PATCH 4/4] Add basic model validator to convert 'mkdir_chmod' string into an int --- src/murfey/util/config.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/murfey/util/config.py b/src/murfey/util/config.py index 37d4568d..580f423a 100644 --- a/src/murfey/util/config.py +++ b/src/murfey/util/config.py @@ -153,6 +153,15 @@ def validate_software_versions(cls, v: dict[str, Any]) -> dict[str, str]: # Let it validate and fail as-is return v + @field_validator("mkdir_chmod", mode="before") + @classmethod + def parse_octal_int(cls, value): + # Attempt to parse the string as an octal int + if isinstance(value, str): + return int(value, 8) + # Return value as-is otherwise + return value + @lru_cache(maxsize=1) def machine_config_from_file(