From 7aa24b8dad50449fc4ad99f64b9707d2716e47e9 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Wed, 5 Aug 2026 21:27:38 +0200 Subject: [PATCH] ProjectServer: Configure trusted hosts for localhost case --- CHANGELOG.md | 1 + src/serena/cli.py | 7 ++----- src/serena/project_server.py | 29 +++++++++++++++++++---------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dca327a5..98bcf0c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Status of the `main` branch. Changes prior to the next official version change w - Project activation errors are now reported to the client in Serena's system prompt, instead of failures being visible only in the log. This applies both to a failed activation of an explicitly given project and to a failed `--project-from-cwd` auto-detection (#1773). + - ProjectServer: Configure trusted hosts for localhost case * CLI: - Fix: `start-mcp-server` help text for `--project-from-cwd` falsely promised a fallback to the CWD, which was diff --git a/src/serena/cli.py b/src/serena/cli.py index f5613d14..f6471733 100644 --- a/src/serena/cli.py +++ b/src/serena/cli.py @@ -489,11 +489,8 @@ class TopLevelCommands(AutoRegisteringGroup): log.info("Starting Serena project server") log.info("Storing logs in %s", log_path) - server = ProjectServer() - run_kwargs: dict[str, Any] = {"host": host} - if port is not None: - run_kwargs["port"] = port - server.run(**run_kwargs) + server = ProjectServer(host=host, port=port) + server.run() @staticmethod @click.command( diff --git a/src/serena/project_server.py b/src/serena/project_server.py index ceec43a9..12c5e907 100644 --- a/src/serena/project_server.py +++ b/src/serena/project_server.py @@ -44,9 +44,16 @@ class ProjectServer: PORT = SerenaPorts.PROJECT_SERVER_PORT - def __init__(self) -> None: + def __init__(self, host: str = "127.0.0.1", port: int | None = None) -> None: + """ + :param host: the host address to listen on. + :param port: the port to listen on; if None, use default + """ from serena.agent import SerenaAgent + if port is None: + port = self.PORT + serena_config = SerenaConfig.from_config_file() serena_config.gui_log_window = False serena_config.web_dashboard = False @@ -54,9 +61,15 @@ class ProjectServer: self._agent = SerenaAgent(serena_config=serena_config) self._loaded_projects_by_root: dict[str, "Project"] = {} + self._port = port + self._host = host - # create the Flask application + # create the Flask application, limiting trusted hosts for the case where the server is running on localhost self._app = Flask(__name__) + local_hosts = ["localhost", "127.0.0.1"] + if self._host in local_hosts: + self._app.config["TRUSTED_HOSTS"] = local_hosts + self._setup_routes() def _setup_routes(self) -> None: @@ -97,12 +110,9 @@ class ProjectServer: params = json.loads(req.tool_params_json) return tool.apply_ex(**params) - def run(self, host: str = "127.0.0.1", port: int = PORT) -> int: - """Run the server on the given host and port. - - :param host: the host address to listen on. - :param port: the port to listen on. - :return: the port number the server is running on. + def run(self) -> None: + """ + Run the server on the given host and port. """ from flask import cli @@ -111,8 +121,7 @@ class ProjectServer: # replacement, even one with an identical signature), so the monkeypatch is suppressed here cli.show_server_banner = lambda *args, **kwargs: None # ty: ignore[invalid-assignment] - self._app.run(host=host, port=port, debug=False, use_reloader=False, threaded=True) - return port + self._app.run(host=self._host, port=self._port, debug=False, use_reloader=False, threaded=True) class ProjectServerClient: