mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-26 21:26:39 +00:00
fix(support-bundle): retain diagnostics when dotenv cannot be read (#6536)
Co-authored-by: Zhangchenhao-111 <285911435+Zhangchenhao-111@users.noreply.github.com> Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
parent
737492d4e1
commit
8377aa3d39
@ -201,7 +201,8 @@ streams simulate chunks from a non-streaming response, while no-tool streams sta
|
||||
values override shell exports, and a project-root override alone still uses
|
||||
`backend/.deer-flow` first. Simple variable references such as
|
||||
`DEER_FLOW_HOME="$PWD/backend/.deer-flow"` use the checkout as `PWD`;
|
||||
single-quoted references remain literal. For standalone Gateway launches using `backend/.env`
|
||||
single-quoted references remain literal. If the checkout `.env` cannot be read or decoded
|
||||
as UTF-8, thread diagnostics retain shell exports and default storage paths. For standalone Gateway launches using `backend/.env`
|
||||
or `DEER_FLOW_ENV_FILE`, export the effective `DEER_FLOW_HOME` when collecting
|
||||
the bundle and ensure the checkout `.env` does not override it.
|
||||
Doctor's internal tool probes also decode UTF-8 with replacement for invalid
|
||||
|
||||
@ -25,6 +25,32 @@ def _zip_text(zip_path, name: str) -> str:
|
||||
return zf.read(name).decode("utf-8")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("failure", ["permission", "encoding"])
|
||||
@pytest.mark.parametrize("configured_home", [False, True])
|
||||
def test_unreadable_dotenv_keeps_thread_diagnostics(tmp_path, monkeypatch, failure, configured_home):
|
||||
project = tmp_path / "checkout"
|
||||
project.mkdir()
|
||||
home = tmp_path / "data" if configured_home else project / ".deer-flow"
|
||||
(home / "threads" / "broken-env" / "user-data").mkdir(parents=True)
|
||||
env_file = project / ".env"
|
||||
# A valid prefix must not partially change runtime paths when decoding fails.
|
||||
env_file.write_bytes(b"DEER_FLOW_HOME=wrong-home\n" + b"#" * 10000 + b"\xff")
|
||||
if configured_home:
|
||||
monkeypatch.setenv("DEER_FLOW_HOME", str(home))
|
||||
if failure == "permission":
|
||||
original_open = Path.open
|
||||
|
||||
def guarded_open(path, *args, **kwargs):
|
||||
if path == env_file:
|
||||
raise PermissionError("Cannot read .env")
|
||||
return original_open(path, *args, **kwargs)
|
||||
|
||||
monkeypatch.setattr(Path, "open", guarded_open)
|
||||
|
||||
summary = support_bundle.collect_thread_summary(project, "broken-env")
|
||||
assert summary["found"] is True
|
||||
|
||||
|
||||
@pytest.mark.parametrize("layout", ["threads/thread-home", "users/alice/threads/thread-home"])
|
||||
def test_thread_summary_uses_configured_runtime_home(tmp_path, monkeypatch, layout):
|
||||
project = tmp_path / "checkout"
|
||||
|
||||
@ -4,7 +4,9 @@ Thread manifests use a nonempty `DEER_FLOW_HOME` exclusively, resolving relative
|
||||
values from the checkout like the local launcher. Read root `.env` path settings
|
||||
without exporting secrets; dotenv overrides shell exports, including empty values.
|
||||
Expand unquoted leading tildes, preserving quoted literals. If python-dotenv is
|
||||
unavailable, retain shell/legacy lookup so troubleshooting remains usable.
|
||||
unavailable or `.env` cannot be read/decoded as UTF-8, retain shell/legacy lookup
|
||||
so troubleshooting remains usable. Read the complete file before applying any
|
||||
assignments so a decoding failure cannot partially override shell values.
|
||||
Resolve `$NAME`, `${NAME}` and `${NAME:-literal}` in unquoted/double-quoted
|
||||
values using a private environment with checkout `PWD` and earlier dotenv
|
||||
assignments. Single-quoted values and escaped dollars stay literal. Parse the
|
||||
|
||||
@ -12,6 +12,7 @@ import subprocess
|
||||
import sys
|
||||
import zipfile
|
||||
from datetime import UTC, datetime
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
@ -283,14 +284,16 @@ def _thread_data_roots(project_root: Path) -> list[tuple[Path, str]]:
|
||||
if env_file.is_file():
|
||||
try:
|
||||
from dotenv.parser import parse_stream
|
||||
except ImportError:
|
||||
# Diagnostics must still work in an incomplete backend environment.
|
||||
|
||||
contents = env_file.read_text(encoding="utf-8-sig")
|
||||
except (ImportError, OSError, UnicodeError):
|
||||
# Diagnostics must still work with a broken environment or unreadable .env.
|
||||
pass
|
||||
else:
|
||||
# serve.sh changes to the checkout before sourcing .env. Keep its
|
||||
# assignment order in a private mapping; never export parsed secrets.
|
||||
environment = {**os.environ, "PWD": str(project_root.resolve())}
|
||||
with env_file.open(encoding="utf-8-sig") as stream:
|
||||
with StringIO(contents) as stream:
|
||||
for binding in parse_stream(stream):
|
||||
if not binding.key or binding.value is None or binding.error:
|
||||
continue
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user