From fa623d19c6fc1fa4977a8dedcef88c751059dcbb Mon Sep 17 00:00:00 2001 From: Elioooon Date: Tue, 1 Sep 2026 17:04:42 +0800 Subject: [PATCH] Validate gateway port range --- src/opensquilla/cli/main.py | 15 +++++++++++++++ src/opensquilla/gateway/config.py | 2 +- tests/test_cli/test_config_set_key_validation.py | 13 +++++++++++++ tests/test_cli/test_gateway_cmd.py | 16 ++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/opensquilla/cli/main.py b/src/opensquilla/cli/main.py index 821fcbd43e..5e18fec787 100644 --- a/src/opensquilla/cli/main.py +++ b/src/opensquilla/cli/main.py @@ -698,6 +698,9 @@ def gateway_run( None, "--port", "-p", + min=0, + max=65535, + metavar="PORT", help="Port to bind (default: config port, usually 18791)", ), bind: str | None = typer.Option( @@ -772,6 +775,9 @@ def gateway_start( None, "--port", "-p", + min=0, + max=65535, + metavar="PORT", help="Port to bind (default: config port, usually 18791)", ), bind: str | None = typer.Option( @@ -804,6 +810,9 @@ def gateway_status( None, "--port", "-p", + min=0, + max=65535, + metavar="PORT", help="Port to inspect (default: config port, usually 18791)", ), bind: str | None = typer.Option( @@ -840,6 +849,9 @@ def gateway_stop( None, "--port", "-p", + min=0, + max=65535, + metavar="PORT", help="Port to stop (default: config port, usually 18791)", ), bind: str | None = typer.Option( @@ -872,6 +884,9 @@ def gateway_restart( None, "--port", "-p", + min=0, + max=65535, + metavar="PORT", help="Port to restart (default: config port, usually 18791)", ), bind: str | None = typer.Option( diff --git a/src/opensquilla/gateway/config.py b/src/opensquilla/gateway/config.py index 278387d7c7..6a18e20311 100644 --- a/src/opensquilla/gateway/config.py +++ b/src/opensquilla/gateway/config.py @@ -2338,7 +2338,7 @@ class GatewayConfig(BaseSettings): # precedence order (explicit kwarg/flag > OPENSQUILLA_LISTEN > OPENSQUILLA_GATEWAY_HOST # > default) is testable without the pydantic-settings env cache. host: str = "127.0.0.1" - port: int = 18791 + port: int = Field(default=18791, ge=0, le=65535) # Resolved from installed distribution metadata (opensquilla.__version__), # not operator config. UI/RPC surfaces read __version__ directly, so any # stale value persisted in config.toml has no display effect. diff --git a/tests/test_cli/test_config_set_key_validation.py b/tests/test_cli/test_config_set_key_validation.py index e32f5f8d5b..c9c06583b8 100644 --- a/tests/test_cli/test_config_set_key_validation.py +++ b/tests/test_cli/test_config_set_key_validation.py @@ -86,6 +86,19 @@ def test_a_real_key_still_prints_its_export(key: str, env_var: str) -> None: assert f"export {env_var}=18823" in result.stdout +def test_invalid_port_is_not_persisted(tmp_path: Path) -> None: + target = _empty_config(tmp_path) + + result = runner.invoke( + app, + ["config", "set", "port", "65536", "--config", str(target)], + ) + + assert result.exit_code == 2 + assert "Invalid value for port" in result.stdout + assert tomllib.loads(target.read_text(encoding="utf-8")) == {} + + @pytest.mark.parametrize( ("key", "env_var", "value", "expected"), [ diff --git a/tests/test_cli/test_gateway_cmd.py b/tests/test_cli/test_gateway_cmd.py index 3937e4d219..196e92a9e3 100644 --- a/tests/test_cli/test_gateway_cmd.py +++ b/tests/test_cli/test_gateway_cmd.py @@ -667,6 +667,22 @@ def fake_popen(argv, **kwargs): assert payload["url"] == "http://127.0.0.2:19999" +def test_gateway_start_rejects_out_of_range_port_before_spawn( + tmp_path, monkeypatch +) -> None: + monkeypatch.setenv("OPENSQUILLA_STATE_DIR", str(tmp_path / "home")) + + def fail_popen(*_args, **_kwargs): + raise AssertionError("invalid port must not spawn a gateway") + + monkeypatch.setattr(gateway_lifecycle.subprocess, "Popen", fail_popen) + + result = runner.invoke(app, ["gateway", "start", "--port", "65536", "--json"]) + + assert result.exit_code == 2 + assert "65536 is not in the range 0<=x<=65535" in result.stderr + + def test_gateway_status_uses_config_host_port_when_flags_are_omitted( tmp_path, monkeypatch ) -> None: