From e4af86be058b233f62eeea970e4e34b1c5cac8e1 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Tue, 9 Jun 2026 12:05:03 +0200 Subject: [PATCH] Fix: Incorrect file access when loading context/mode Context or mode argument referencing a known name (e.g. `--context anitgravity`) could result in incorrect file access if a corresponding local file existed (e.g. `./antigravity` binary); file access is now guarded with path detection (file ending or path separator must be present) Fixes #1558 --- CHANGELOG.md | 3 +++ src/serena/config/context_mode.py | 37 ++++++++++++++++--------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 056390fa..6046633a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ Status of the `main` branch. Changes prior to the next official version change w Gemini) launched from inside a worktree to the parent repo, causing stale reads and misdirected edits. - Fix: CLI flags on `start-mcp-server` could incorrectly be saved to the global configuration file if the list of projects was modified (triggering a save of the configuration with transient overrides applied) + - Fix: context or mode argument referencing a known name (e.g. `--context anitgravity`) could result in + incorrect file access if a corresponding local file existed (e.g. `./antigravity` binary); + file access is now guarded with path detection (file ending or path separator must be present) * Language Servers: - `typescript_vts`: Add `initialization_options` setting in `ls_specific_settings.typescript_vts`. diff --git a/src/serena/config/context_mode.py b/src/serena/config/context_mode.py index bb3164c9..5d42d650 100644 --- a/src/serena/config/context_mode.py +++ b/src/serena/config/context_mode.py @@ -26,6 +26,10 @@ if TYPE_CHECKING: log = logging.getLogger(__name__) +def looks_like_yaml_path(s: str) -> bool: + return os.sep in s or (os.altsep and os.altsep in s) or s.lower().endswith((".yml", ".yaml")) + + @dataclass(kw_only=True) class SerenaAgentMode(ToolInclusionDefinition, ToStringMixin): """Represents a mode of operation for the agent, typically read off a YAML file. @@ -124,16 +128,15 @@ class SerenaAgentMode(ToolInclusionDefinition, ToStringMixin): @classmethod def load(cls, name_or_path: str | Path) -> Self: - # Check if it's a file path that exists - path = Path(name_or_path) - if path.exists() and path.is_file(): - return cls.from_yaml(name_or_path) - - # If it looks like a file path but doesn't exist, raise FileNotFoundError - name_or_path_str = str(name_or_path) - if os.sep in name_or_path_str or (os.altsep and os.altsep in name_or_path_str) or name_or_path_str.endswith((".yml", ".yaml")): - raise FileNotFoundError(f"Mode file not found: {path.resolve()}") + # If it is a path or looks like a path, load from file + if isinstance(name_or_path, Path) or looks_like_yaml_path(str(name_or_path)): + path = Path(name_or_path) + if path.exists() and path.is_file(): + return cls.from_yaml(name_or_path) + else: + raise FileNotFoundError(f"Mode file not found: {path.resolve()}") + # load from name return cls.from_name(str(name_or_path)) def has_prompt(self) -> bool: @@ -239,15 +242,13 @@ class SerenaAgentContext(ToolInclusionDefinition, ToStringMixin): @classmethod def load(cls, name_or_path: str | Path) -> Self: - # Check if it's a file path that exists - path = Path(name_or_path) - if path.exists() and path.is_file(): - return cls.from_yaml(name_or_path) - - # If it looks like a file path but doesn't exist, raise FileNotFoundError - name_or_path_str = str(name_or_path) - if os.sep in name_or_path_str or (os.altsep and os.altsep in name_or_path_str) or name_or_path_str.endswith((".yml", ".yaml")): - raise FileNotFoundError(f"Context file not found: {path.resolve()}") + # If it is a path or looks like a path, load from file + if isinstance(name_or_path, Path) or looks_like_yaml_path(str(name_or_path)): + path = Path(name_or_path) + if path.exists() and path.is_file(): + return cls.from_yaml(name_or_path) + else: + raise FileNotFoundError(f"Context file not found: {path.resolve()}") return cls.from_name(str(name_or_path))