3434from pydantic import ValidationError
3535from typing_extensions import override
3636
37+ from . import artifact_util
3738from ..errors .input_validation_error import InputValidationError
3839from .base_artifact_service import ArtifactVersion
3940from .base_artifact_service import BaseArtifactService
@@ -142,39 +143,14 @@ def _is_user_scoped(session_id: Optional[str], filename: str) -> bool:
142143 return session_id is None or _file_has_user_namespace (filename )
143144
144145
145- def _validate_path_segment (value : str , field_name : str ) -> None :
146- """Rejects values that could alter the constructed filesystem path.
147-
148- Args:
149- value: The caller-supplied identifier (e.g. user_id or session_id).
150- field_name: Human-readable name used in the error message.
151-
152- Raises:
153- InputValidationError: If the value contains path separators, traversal
154- segments, or null bytes.
155- """
156- if not value :
157- raise InputValidationError (f"{ field_name } must not be empty." )
158- if "\x00 " in value :
159- raise InputValidationError (f"{ field_name } must not contain null bytes." )
160- if "/" in value or "\\ " in value :
161- raise InputValidationError (
162- f"{ field_name } { value !r} must not contain path separators."
163- )
164- if value in ("." , ".." ) or ".." in value .split ("/" ):
165- raise InputValidationError (
166- f"{ field_name } { value !r} must not contain traversal segments."
167- )
168-
169-
170146def _user_artifacts_dir (base_root : Path ) -> Path :
171147 """Returns the path that stores user-scoped artifacts."""
172148 return base_root / "artifacts"
173149
174150
175151def _session_artifacts_dir (base_root : Path , session_id : str ) -> Path :
176152 """Returns the path that stores session-scoped artifacts."""
177- _validate_path_segment (session_id , "session_id" )
153+ artifact_util . validate_path_segment (session_id , "session_id" )
178154 return base_root / "sessions" / session_id / "artifacts"
179155
180156
@@ -256,7 +232,7 @@ def __init__(self, root_dir: Path | str):
256232
257233 def _base_root (self , user_id : str , / ) -> Path :
258234 """Returns the artifacts root directory for a user."""
259- _validate_path_segment (user_id , "user_id" )
235+ artifact_util . validate_path_segment (user_id , "user_id" )
260236 return self .root_dir / "users" / user_id
261237
262238 def _scope_root (
@@ -269,7 +245,7 @@ def _scope_root(
269245 base = self ._base_root (user_id )
270246 if _is_user_scoped (session_id , filename ):
271247 return _user_artifacts_dir (base )
272- if not session_id :
248+ if session_id is None :
273249 raise InputValidationError (
274250 "Session ID must be provided for session-scoped artifacts."
275251 )
@@ -543,7 +519,7 @@ def _list_artifact_keys_sync(
543519
544520 base_root = self ._base_root (user_id )
545521
546- if session_id :
522+ if session_id is not None :
547523 session_root = _session_artifacts_dir (base_root , session_id )
548524 for artifact_dir in _iter_artifact_dirs (session_root ):
549525 metadata = self ._latest_metadata (artifact_dir )
0 commit comments