diff --git a/mempalace/config.py b/mempalace/config.py index a9bcc7f..616334e 100644 --- a/mempalace/config.py +++ b/mempalace/config.py @@ -168,7 +168,10 @@ class MempalaceConfig: """Path to the memory palace data directory.""" env_val = os.environ.get("MEMPALACE_PALACE_PATH") or os.environ.get("MEMPAL_PALACE_PATH") if env_val: - return env_val + # Normalize: expand ~ and collapse .. to match the CLI --palace + # code path (mcp_server.py:62) and prevent surprise redirection + # when the env var contains unresolved components. + return os.path.abspath(os.path.expanduser(env_val)) return self._file_config.get("palace_path", DEFAULT_PALACE_PATH) @property diff --git a/tests/test_config.py b/tests/test_config.py index e6dffc3..f41b3df 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -27,6 +27,42 @@ def test_env_override(): del os.environ["MEMPALACE_PALACE_PATH"] +def test_env_path_expanduser(): + os.environ["MEMPALACE_PALACE_PATH"] = "~/mempalace-test" + try: + cfg = MempalaceConfig(config_dir=tempfile.mkdtemp()) + # Tilde must be expanded to match the --palace CLI code path. + assert "~" not in cfg.palace_path + assert cfg.palace_path.endswith("mempalace-test") + assert cfg.palace_path == os.path.expanduser("~/mempalace-test") + finally: + del os.environ["MEMPALACE_PALACE_PATH"] + + +def test_env_path_abspath_collapses_traversal(): + os.environ["MEMPALACE_PALACE_PATH"] = "/tmp/palace/../mempalace-test" + try: + cfg = MempalaceConfig(config_dir=tempfile.mkdtemp()) + # .. segments must be collapsed, not preserved literally. + assert ".." not in cfg.palace_path + assert cfg.palace_path == "/tmp/mempalace-test" + finally: + del os.environ["MEMPALACE_PALACE_PATH"] + + +def test_env_path_legacy_alias_normalized(): + # Legacy MEMPAL_PALACE_PATH gets the same normalization treatment. + os.environ.pop("MEMPALACE_PALACE_PATH", None) + os.environ["MEMPAL_PALACE_PATH"] = "~/legacy-alias/../mempalace-test" + try: + cfg = MempalaceConfig(config_dir=tempfile.mkdtemp()) + assert "~" not in cfg.palace_path + assert ".." not in cfg.palace_path + assert cfg.palace_path == os.path.expanduser("~/mempalace-test") + finally: + del os.environ["MEMPAL_PALACE_PATH"] + + def test_init(): tmpdir = tempfile.mkdtemp() cfg = MempalaceConfig(config_dir=tmpdir)