fix: refuse the Docker-only options in native mode instead of ignoring them

`up --native` took --expose, --domain and --docling and did nothing with them.
Asking for network exposure and silently getting a loopback-only install, or
asking for docling and getting an install without it, is worse than being told.
Each now says what to do instead: a reverse proxy or the Docker stack for
exposure, and the docling extra for the parser engine. --expose local and
--no-docling already describe native mode, so they stay silent.
This commit is contained in:
Alex committed 2026-09-16 23:03:03 +01:00
1 parent 501baf8aae
commit 6cfd0948bc
2 files changed
+33

No files matched your search

+17
View File
@@ -240,6 +240,22 @@ def _docsgpt_launcher() -> list[str]:
)
def _refuse_docker_only_options(args) -> None:
"""Options that only mean something to the Docker stack, refused rather than quietly ignored."""
if getattr(args, "domain", None) or getattr(args, "expose", None) in ("network", "domain"):
raise DeployError(
"a native install serves on 127.0.0.1 only, so --domain, --expose network and "
"--expose domain have nothing to act on here. Put a reverse proxy in front of it, or run "
"the Docker stack with `docsgpt up --expose ...`, which brings its own Caddy for a domain."
)
if getattr(args, "docling", None):
raise DeployError(
"--docling selects a Docker image variant, which a native install does not use. Install the "
'parser engine into this environment instead, with `uv tool install "docsgpt[docling]"` or '
'`pip install "docsgpt[docling]"`, then run `docsgpt up --native` again.'
)
def _native_port(env: Mapping[str, str]) -> str:
"""The port a native install listens on."""
return str(env.get("DOCSGPT_PORT") or stack.DEFAULT_PORT)
@@ -252,6 +268,7 @@ def _native_address(env: Mapping[str, str]) -> str:
def _native_up(args, context: Context, directory: Path) -> int:
"""Run the API and the worker as services on this machine, against an existing Postgres and Redis."""
_refuse_docker_only_options(args)
services = context.service_manager()
env_path = directory / ".env"
existing = envfile.read(env_path)
+16
View File
@@ -164,6 +164,22 @@ class TestNativeUp:
assert _run(["uninstall", "--yes", "--dir", str(tmp_path)], _native_context(services)) == 0
assert sorted(services.removed) == ["docsgpt-api", "docsgpt-worker"]
def test_docker_only_options_are_refused_rather_than_ignored(self, tmp_path):
"""Asking for network exposure and silently getting loopback is the worst of both."""
base = ["up", "--native", "--dir", str(tmp_path), "--yes", "--postgres-uri", "postgresql://localhost/d"]
with pytest.raises(DeployError, match="127.0.0.1 only"):
_run([*base, "--expose", "network"], _native_context())
with pytest.raises(DeployError, match="127.0.0.1 only"):
_run([*base, "--domain", "docs.example.com"], _native_context())
with pytest.raises(DeployError, match=r"docsgpt\[docling\]"):
_run([*base, "--docling"], _native_context())
assert not (tmp_path / ".env").exists(), "it refuses before writing anything"
def test_the_options_that_describe_what_native_already_does_are_kept(self, tmp_path):
argv = ["up", "--native", "--dir", str(tmp_path), "--yes", "--postgres-uri", "postgresql://localhost/d",
"--expose", "local", "--no-docling"]
assert _run(argv, _native_context()) == 0
def test_a_database_url_is_required(self, tmp_path):
with pytest.raises(DeployError, match="--postgres-uri"):
_run(["up", "--native", "--dir", str(tmp_path), "--yes"], _native_context())