refactor(constants): single source of truth for data dir (#3368)

* refactor(constants): single source of truth for data dir + merge core/src constants

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(contributing): use named src.constants for data paths, drop core/constants references

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mike
2026-06-08 09:58:52 +02:00
committed by GitHub
parent adc6ac9394
commit ac94885c84
56 changed files with 279 additions and 243 deletions
+5 -4
View File
@@ -118,10 +118,11 @@ def test_pairing_payload_shape():
@pytest.mark.parametrize("payload", ["[]", '{"users": []}'])
def test_find_admin_user_ignores_invalid_auth_shape(tmp_path, monkeypatch, payload):
data_dir = tmp_path / "data"
data_dir.mkdir()
(data_dir / "auth.json").write_text(payload)
monkeypatch.chdir(tmp_path)
auth_file = tmp_path / "auth.json"
auth_file.write_text(payload)
# find_admin_user reads the import-time AUTH_FILE constant, so redirect that
# rather than relying on cwd.
monkeypatch.setattr(P, "AUTH_FILE", str(auth_file))
assert P.find_admin_user() is None
-29
View File
@@ -1,29 +0,0 @@
"""Guard: cookbook_state.json must be located via DATA_DIR, not hardcoded /app/data
(which breaks native runs) or a relative os.environ fallback."""
import pathlib
ROOT = pathlib.Path(__file__).resolve().parent.parent
FILES = [
"src/cookbook_serve_lifecycle.py",
"src/builtin_actions.py",
"routes/codex_routes.py",
"routes/cookbook_routes.py",
]
def test_no_hardcoded_app_data_cookbook_state():
for rel in FILES:
text = (ROOT / rel).read_text(encoding="utf-8")
for ln in text.splitlines():
if ln.strip().startswith("#"):
continue
assert "/app/data/cookbook_state" not in ln, f"{rel}: hardcoded /app/data: {ln.strip()}"
assert 'os.environ.get("DATA_DIR"' not in ln, f"{rel}: relative DATA_DIR env fallback: {ln.strip()}"
def test_cookbook_state_uses_datadir_constant():
# Each file that references cookbook_state.json should import the DATA_DIR constant.
for rel in FILES:
text = (ROOT / rel).read_text(encoding="utf-8")
if "cookbook_state.json" in text:
assert "from core.constants import DATA_DIR" in text, f"{rel}: missing DATA_DIR import"
+10
View File
@@ -11,6 +11,16 @@ from fastapi import HTTPException
from routes.research_routes import setup_research_routes
@pytest.fixture(autouse=True)
def _redirect_research_dir(tmp_path, monkeypatch):
# Deep-research paths are resolved from an import-time constant now, so chdir
# no longer redirects them. Point the constant the routes read at the temp dir.
monkeypatch.setattr(
"routes.research_routes.DEEP_RESEARCH_DIR",
str(tmp_path / "data" / "deep_research"),
)
def _request(user: str):
return SimpleNamespace(state=SimpleNamespace(current_user=user))
+4 -4
View File
@@ -946,7 +946,7 @@ def _import_mcp_routes():
def test_mcp_oauth_paths_resolve_under_data_dir(tmp_path, monkeypatch):
mcp_routes = _import_mcp_routes()
monkeypatch.setattr(mcp_routes, "DATA_DIR", str(tmp_path / "data"))
monkeypatch.setattr(mcp_routes, "MCP_OAUTH_DIR", str(tmp_path / "data" / "mcp_oauth"))
resolved = Path(mcp_routes._resolve_mcp_oauth_path("gmail/credentials.json", "token_file"))
@@ -963,7 +963,7 @@ def test_mcp_oauth_paths_reject_escapes(tmp_path, monkeypatch, raw_path):
from fastapi import HTTPException
mcp_routes = _import_mcp_routes()
monkeypatch.setattr(mcp_routes, "DATA_DIR", str(tmp_path / "data"))
monkeypatch.setattr(mcp_routes, "MCP_OAUTH_DIR", str(tmp_path / "data" / "mcp_oauth"))
with pytest.raises(HTTPException) as exc:
mcp_routes._resolve_mcp_oauth_path(raw_path, "token_file")
@@ -974,7 +974,7 @@ def test_mcp_oauth_filename_join_cannot_escape_base(tmp_path, monkeypatch):
from fastapi import HTTPException
mcp_routes = _import_mcp_routes()
monkeypatch.setattr(mcp_routes, "DATA_DIR", str(tmp_path / "data"))
monkeypatch.setattr(mcp_routes, "MCP_OAUTH_DIR", str(tmp_path / "data" / "mcp_oauth"))
safe_dir = mcp_routes._resolve_mcp_oauth_path("gmail", "dir")
with pytest.raises(HTTPException):
@@ -983,7 +983,7 @@ def test_mcp_oauth_filename_join_cannot_escape_base(tmp_path, monkeypatch):
def test_mcp_oauth_config_sanitizes_paths_and_env(tmp_path, monkeypatch):
mcp_routes = _import_mcp_routes()
monkeypatch.setattr(mcp_routes, "DATA_DIR", str(tmp_path / "data"))
monkeypatch.setattr(mcp_routes, "MCP_OAUTH_DIR", str(tmp_path / "data" / "mcp_oauth"))
cfg = mcp_routes._sanitize_mcp_oauth_config({
"provider": "google",
+1 -1
View File
@@ -13,7 +13,7 @@ def _load_setup_module():
def test_create_default_admin_normalizes_env_username(tmp_path, monkeypatch):
setup_module = _load_setup_module()
monkeypatch.setattr(setup_module, "DATA_DIR", str(tmp_path))
monkeypatch.setattr(setup_module, "AUTH_FILE", str(tmp_path / "auth.json"))
monkeypatch.setenv("ODYSSEUS_ADMIN_USER", " AdminUser ")
monkeypatch.setenv("ODYSSEUS_ADMIN_PASSWORD", "temporary-password")