fix(gateway): require API_SERVER_KEY to load the api_server platform

Previously API_SERVER_ENABLED=true without a key caused the adapter to
be instantiated (opening a ResponseStore/SQLite connection) even
though the HTTP server would immediately refuse to start. Changing the
load condition from `or` to `if api_server_key` prevents the spurious
load. Setting only API_SERVER_KEY (without the explicit flag) still
works — the key alone is sufficient intent to enable the platform.

Also fixes the _PLATFORM_CONNECTED_CHECKERS entry for API_SERVER,
which was a no-op `lambda: True`; it now returns True only when the
platform config has a `key` stored, matching actual readiness.

Fixes #36111

Note: an earlier version of this PR also closed the adapter's
ResponseStore in disconnect() to fix a related fd leak — that part is
now redundant, since 4b06c98fe4 ("fix(gateway): close ResponseStore +
dispose unowned adapter on reconnect failure", #37011) already covers
it more thoroughly. Dropped that half and kept only the require-key
fix, which isn't covered elsewhere.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nawfal 2026-06-01 08:49:31 +07:00 committed by arimu1
parent c1b0f6f3c1
commit 68dfeb4b16
3 changed files with 19 additions and 4 deletions

View file

@ -797,7 +797,9 @@ _PLATFORM_CONNECTED_CHECKERS: dict[Platform, Callable[[PlatformConfig], bool]] =
cfg.extra.get("phone_number_id") and cfg.extra.get("access_token")
),
Platform.SIGNAL: lambda cfg: bool(cfg.extra.get("http_url")),
Platform.API_SERVER: lambda cfg: True,
Platform.EMAIL: lambda cfg: bool(cfg.extra.get("address")),
Platform.SMS: lambda cfg: bool(os.getenv("TWILIO_ACCOUNT_SID")),
Platform.API_SERVER: lambda cfg: bool(cfg.extra.get("key")) if cfg else False,
Platform.WEBHOOK: lambda cfg: True,
Platform.MSGRAPH_WEBHOOK: lambda cfg: bool(
str(cfg.extra.get("client_state") or "").strip()
@ -2008,7 +2010,10 @@ def _apply_env_overrides(config: GatewayConfig) -> None:
api_server_cors_origins = getenv("API_SERVER_CORS_ORIGINS", "")
api_server_port = getenv("API_SERVER_PORT")
api_server_host = getenv("API_SERVER_HOST")
if api_server_enabled or api_server_key:
# Require the key: API_SERVER_ENABLED alone would load an unauthenticated
# platform, and the connected-checker below only reports "up" when a key
# is present anyway.
if api_server_key:
if Platform.API_SERVER not in config.platforms:
config.platforms[Platform.API_SERVER] = PlatformConfig()
config.platforms[Platform.API_SERVER].enabled = True

View file

@ -3097,11 +3097,18 @@ class TestConfigIntegration:
def test_env_override_enables_api_server(self, monkeypatch):
monkeypatch.setenv("API_SERVER_ENABLED", "true")
monkeypatch.setenv("API_SERVER_KEY", "sk-mykey")
from gateway.config import load_gateway_config
config = load_gateway_config()
assert Platform.API_SERVER in config.platforms
assert config.platforms[Platform.API_SERVER].enabled is True
def test_env_override_enabled_without_key_does_not_load(self, monkeypatch):
monkeypatch.setenv("API_SERVER_ENABLED", "true")
from gateway.config import load_gateway_config
config = load_gateway_config()
assert Platform.API_SERVER not in config.platforms
def test_env_override_with_key(self, monkeypatch):
monkeypatch.setenv("API_SERVER_KEY", "sk-mykey")
from gateway.config import load_gateway_config
@ -3111,6 +3118,7 @@ class TestConfigIntegration:
def test_env_override_port_and_host(self, monkeypatch):
monkeypatch.setenv("API_SERVER_ENABLED", "true")
monkeypatch.setenv("API_SERVER_KEY", "sk-mykey")
monkeypatch.setenv("API_SERVER_PORT", "9999")
monkeypatch.setenv("API_SERVER_HOST", "0.0.0.0")
from gateway.config import load_gateway_config
@ -3120,6 +3128,7 @@ class TestConfigIntegration:
def test_env_override_cors_origins(self, monkeypatch):
monkeypatch.setenv("API_SERVER_ENABLED", "true")
monkeypatch.setenv("API_SERVER_KEY", "sk-mykey")
monkeypatch.setenv(
"API_SERVER_CORS_ORIGINS",
"http://localhost:3000, http://127.0.0.1:3000",
@ -3133,7 +3142,7 @@ class TestConfigIntegration:
def test_api_server_in_connected_platforms(self):
config = GatewayConfig()
config.platforms[Platform.API_SERVER] = PlatformConfig(enabled=True)
config.platforms[Platform.API_SERVER] = PlatformConfig(enabled=True, extra={"key": "sk-mykey"})
connected = config.get_connected_platforms()
assert Platform.API_SERVER in connected

View file

@ -98,8 +98,9 @@ def test_checker_returns_true_when_configured(platform, checker, monkeypatch):
elif platform == Platform.SMS:
monkeypatch.setenv("TWILIO_ACCOUNT_SID", "ACtest")
mock_config.extra = {}
elif platform == Platform.API_SERVER:
mock_config.extra = {"key": "sk-mykey"}
elif platform in {
Platform.API_SERVER,
Platform.WEBHOOK,
Platform.WHATSAPP,
}: