diff --git a/docsgpt/deploy/commands.py b/docsgpt/deploy/commands.py index 19d4aae2..eaa38f44 100644 --- a/docsgpt/deploy/commands.py +++ b/docsgpt/deploy/commands.py @@ -219,6 +219,12 @@ def up(args, context: Optional[Context] = None) -> int: if stack.exposure(existing) == "domain" and stack.exposure(env) != "domain": # With the https profile off, `up --remove-orphans` would leave Caddy running on ports 80 and 443. context.docker.compose(directory, *_EVERY_PROFILE, "rm", "--stop", "--force", "caddy", check=False) + if stack.exposure(env) == "network": + print( + "DocsGPT will listen on every interface over plain HTTP: its access token travels as " + "readable text. Use `docsgpt up --domain ` for HTTPS outside a trusted network.", + file=sys.stderr, + ) up_args = ["up", "-d", "--remove-orphans", *recreate] if image_tag in _MOVING_TAGS: up_args += ["--pull", "always"] @@ -246,9 +252,7 @@ def up(args, context: Optional[Context] = None) -> int: if env.get("AUTH_TYPE") == "simple_jwt" and env.get("JWT_SECRET_KEY"): print("Access token (the page asks for it; `docsgpt token` prints it again):") print(f" {stack.simple_jwt_token(env['JWT_SECRET_KEY'])}") - if mode == "network": - print("Traffic is plain HTTP. Outside a trusted network, use a domain with HTTPS: docsgpt up --domain ") - elif mode == "domain": + if mode == "domain": print("Caddy gets the certificate when it starts: DNS must point at this machine and ports 80 and 443 be open.") print(f"Settings: {env_path} (change the model provider or access with `docsgpt up --reconfigure`)") print("Manage it with: docsgpt status | logs | upgrade | down | uninstall") diff --git a/docsgpt/deploy/docker.py b/docsgpt/deploy/docker.py index e5ba9cb9..795aaeb9 100644 --- a/docsgpt/deploy/docker.py +++ b/docsgpt/deploy/docker.py @@ -138,6 +138,7 @@ def wait_healthy( if 200 <= response.status < 300: return True except (OSError, http.client.HTTPException): + # Not answering yet: refused, reset, timed out or a broken response. Keep polling. pass remaining = deadline - clock() if remaining <= 0: diff --git a/tests/deploy/test_commands.py b/tests/deploy/test_commands.py index 44398703..db9a9698 100644 --- a/tests/deploy/test_commands.py +++ b/tests/deploy/test_commands.py @@ -140,6 +140,18 @@ class TestUpFirstInstall: # A moving tag is pulled every time, not only when missing. assert (tmp_path, ["up", "-d", "--remove-orphans", "--pull", "always"]) in docker.calls + def test_network_mode_warns_about_plain_http_before_starting(self, tmp_path, capsys): + """The token travels as readable text, so say so before the stack is up, not only after.""" + docker = FakeDocker() + assert _run(["up", "--yes", "--dir", str(tmp_path), "--expose", "network"], _context(docker)) == 0 + err = capsys.readouterr().err + assert "plain HTTP" in err + assert "--domain" in err + + def test_a_local_install_does_not_warn(self, tmp_path, capsys): + assert _run(["up", "--yes", "--dir", str(tmp_path)], _context()) == 0 + assert "plain HTTP" not in capsys.readouterr().err + def test_an_unhealthy_start_points_at_the_logs(self, tmp_path, capsys): assert _run(["up", "--yes", "--dir", str(tmp_path)], _context(healthy=False)) == 1 assert "docsgpt logs" in capsys.readouterr().err