@@ -30,22 +30,28 @@ def _normalize_pack_id(value: Any) -> str:
3030 return re .sub (r"[^A-Za-z0-9_.-]" , "" , raw )
3131
3232
33+ def _resolve_workspace_path (candidate : Path ) -> Path | None :
34+ try :
35+ workspace_root = WORKSPACE_ROOT .resolve ()
36+ raw_path = candidate if candidate .is_absolute () else (workspace_root / candidate )
37+ resolved = raw_path .resolve (strict = False )
38+ resolved .relative_to (workspace_root )
39+ return resolved
40+ except (OSError , RuntimeError , ValueError ):
41+ return None
42+
43+
3344def _resolve_safe_root (raw_value : str , default_path : Path ) -> Path :
34- workspace_base = os .path .normpath (str (WORKSPACE_ROOT .resolve ()))
35- default_root = Path (default_path ).resolve ()
45+ default_root = _resolve_workspace_path (default_path )
46+ if default_root is None :
47+ return WORKSPACE_ROOT .resolve ()
3648
3749 raw = str (raw_value or "" ).strip ()
3850 if not raw :
3951 return default_root
4052
41- if not os .path .isabs (raw ):
42- fullpath = os .path .normpath (os .path .join (workspace_base , raw ))
43- else :
44- fullpath = os .path .normpath (raw )
45-
46- if os .path .commonpath ([workspace_base , fullpath ]) != workspace_base :
47- return default_root
48- return Path (fullpath )
53+ resolved = _resolve_workspace_path (Path (raw ))
54+ return resolved or default_root
4955
5056
5157def _render_json (path : str , payload : dict [str , Any ] | None ) -> None :
@@ -58,21 +64,20 @@ def _render_json(path: str, payload: dict[str, Any] | None) -> None:
5864
5965def _read_json_file (* , base_dir : Path , pack_id : str , filename : str ) -> dict [str , Any ] | None :
6066 try :
61- workspace_base = os .path .normpath (str (WORKSPACE_ROOT .resolve ()))
62- base_path_obj = base_dir if base_dir .is_absolute () else (WORKSPACE_ROOT / base_dir )
63- base_path = os .path .normpath (str (base_path_obj .resolve ()))
64- if os .path .commonpath ([workspace_base , base_path ]) != workspace_base :
67+ base_path = _resolve_workspace_path (base_dir )
68+ if base_path is None :
6569 return None
6670
6771 safe_pack_id = _normalize_pack_id (pack_id )
6872 if not safe_pack_id :
6973 return None
7074
71- fullpath = os .path .normpath (os .path .join (base_path , safe_pack_id , filename ))
72- if os .path .commonpath ([base_path , fullpath ]) != base_path :
75+ resolved_path = (base_path / safe_pack_id / filename ).resolve (strict = False )
76+ try :
77+ resolved_path .relative_to (base_path )
78+ except ValueError :
7379 return None
7480
75- resolved_path = Path (fullpath )
7681 if not resolved_path .exists () or not resolved_path .is_file ():
7782 return None
7883
0 commit comments