diff --git a/nanobot/cli/onboard.py b/nanobot/cli/onboard.py index 1185f851..7104ae69 100644 --- a/nanobot/cli/onboard.py +++ b/nanobot/cli/onboard.py @@ -1612,6 +1612,13 @@ def _quick_start_requires_api_key(provider_name: str, info: _QuickStartProviderI return provider_name == "custom" or not (info and (info.is_local or info.is_oauth)) +def _quick_start_codex_proxy(config: Config) -> str | None: + """Resolve only the Codex proxy without validating unrelated provider secrets.""" + proxy_config = Config() + proxy_config.providers.openai_codex.proxy = config.providers.openai_codex.proxy + return resolve_config_env_vars(proxy_config).providers.openai_codex.proxy or None + + def _quick_start_oauth_login(config: Config, provider_name: str) -> bool: """Authenticate an OAuth provider supported by Quick Start.""" if provider_name != "openai_codex": @@ -1625,7 +1632,7 @@ def _quick_start_oauth_login(config: Config, provider_name: str) -> bool: return False try: - proxy = resolve_config_env_vars(config).providers.openai_codex.proxy or None + proxy = _quick_start_codex_proxy(config) except ValueError as exc: console.print(f"[red]{exc}[/red]") return False @@ -1662,7 +1669,7 @@ def _quick_start_oauth_is_authenticated(config: Config, provider_name: str) -> b try: from oauth_cli_kit import get_token - proxy = resolve_config_env_vars(config).providers.openai_codex.proxy or None + proxy = _quick_start_codex_proxy(config) token = get_token(proxy=proxy) except Exception: return False diff --git a/tests/agent/test_onboard_logic.py b/tests/agent/test_onboard_logic.py index e1174188..88947862 100644 --- a/tests/agent/test_onboard_logic.py +++ b/tests/agent/test_onboard_logic.py @@ -1066,10 +1066,19 @@ class TestMainMenuUpdate: import oauth_cli_kit config = Config() + config.providers.openai.api_key = "${UNRELATED_MISSING_KEY}" + config.providers.openai_codex.proxy = "${CODEX_PROXY}" token = SimpleNamespace(access="existing-token", account_id="account-123") + token_proxies: list[str | None] = [] login_calls: list[object] = [] - monkeypatch.setattr(oauth_cli_kit, "get_token", lambda **kwargs: token) + monkeypatch.setenv("CODEX_PROXY", "http://127.0.0.1:8080") + monkeypatch.delenv("UNRELATED_MISSING_KEY", raising=False) + monkeypatch.setattr( + oauth_cli_kit, + "get_token", + lambda **kwargs: token_proxies.append(kwargs.get("proxy")) or token, + ) monkeypatch.setattr( oauth_cli_kit, "login_oauth_interactive", @@ -1078,7 +1087,28 @@ class TestMainMenuUpdate: monkeypatch.setattr(onboard_wizard.console, "print", lambda *args, **kwargs: None) assert onboard_wizard._quick_start_oauth_login(config, "openai_codex") is True + assert token_proxies == ["http://127.0.0.1:8080"] assert login_calls == [] + assert config.providers.openai.api_key == "${UNRELATED_MISSING_KEY}" + assert config.providers.openai_codex.proxy == "${CODEX_PROXY}" + + def test_quick_start_codex_auth_check_ignores_unrelated_missing_env(self, monkeypatch): + """OAuth readiness should depend only on the Codex proxy and token.""" + import oauth_cli_kit + + config = Config() + config.providers.anthropic.api_key = "${UNRELATED_MISSING_KEY}" + monkeypatch.delenv("UNRELATED_MISSING_KEY", raising=False) + monkeypatch.setattr( + oauth_cli_kit, + "get_token", + lambda **kwargs: SimpleNamespace(access="existing-token"), + ) + + assert ( + onboard_wizard._quick_start_oauth_is_authenticated(config, "openai_codex") + is True + ) def test_quick_start_summary_reports_missing_codex_oauth(self, monkeypatch): """The review step should distinguish OAuth from an API-key setup."""