Codex harness reports "Sign-in needed" when authenticated via a provider `env_key`
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
### Summary
The Codex runtime's auth probe is `codex login status`, which only reports a
*stored* credential. It exits non-zero when Codex is authenticated the
documented way for a custom provider — an API key supplied through the
environment via `[model_providers.] env_key` — so Buzz shows
"Sign-in needed" and won't start the agent, even though the runtime can
make successful API calls.
### Where
`desktop/src-tauri/src/managed_agents/discovery.rs`, `codex` entry:
```rust
login_hint: Some("Run `codex login` to authenticate."),
// Verified: `codex login status` exits 0 when logged in, non-zero otherwise.
auth_probe_args: Some(&["codex", "login", "status"]),
```
`probe_auth_status()` maps a non-zero exit to `AuthStatus::LoggedOut`, and
`harnessCatalogLogic.ts` turns that into the "Sign-in needed" chip:
```ts
return entry.authStatus.status === "logged_out" ? "Sign-in needed" : null;
```
The same entry has `provider_env_var: None` and `default_env: &[]`, so the
catalog has no notion that this runtime may be authenticated by an
environment variable.
### Reproduce
1. Configure a custom provider in `$CODEX_HOME/config.toml`:
```toml
model_provider = "myprovider"
model = "some-model"
[model_providers.myprovider]
base_url = "https://api.example.com/v1"
env_key = "OPENAI_API_KEY"
wire_api = "responses"
```
2. Launch Buzz Desktop with `OPENAI_API_KEY` set in its environment (exec the
binary directly — `open -a` drops the environment).
3. The Codex runtime shows **Sign-in needed** and cannot be started.
Observed with codex-cli 0.146.0, desktop-v0.5.4:
```
$ codex login status; echo $? # no key in env
Not logged in
1
$ OPENAI_API_KEY= codex login status; echo $?
Not logged in
1
```
The exit code is identical with a valid key present, so the probe cannot
distinguish "unauthenticated" from "authenticated via env_key".
Meanwhile the same configuration makes successful requests — a direct
`POST /v1/responses` with that key streams to `response.completed`, and
`codex exec` gets past auth and reaches the model.
### Impact
The only workaround is `printenv OPENAI_API_KEY | codex login --with-api-key`,
which writes the key to `$CODEX_HOME/auth.json`. For setups whose requirement
is that API keys are supplied at launch and never persisted, that converts a
memory-only credential into a plaintext key at rest — a security regression
accepted purely to satisfy a UI readiness check.
### Suggested fixes (any one would do)
1. **Treat a satisfied `env_key` as authenticated.** Read the active
provider from `$CODEX_HOME/config.toml`; if its `env_key` is present and
non-empty in the runtime environment, report `logged_in` without
shelling out.
2. **Model it in the catalog.** Give the `codex` entry a
`provider_env_var`/`auth_env_var` and let `probe_auth_status()` short-circuit
when that variable is set.
3. **Fail open instead of closed.** When a custom provider is configured,
map probe failure to `AuthStatus::Unknown` rather than `LoggedOut`, so the
runtime is startable and any real auth error surfaces at first use.
4. **Don't gate start on the probe.** Keep the chip as advisory and let the
user launch anyway.
### Environment
- Buzz Desktop `desktop-v0.5.4` (OSS build, macOS arm64)
- Relay: self-hosted `deploy/compose` at upstream `318fbf89`
- codex-cli `0.146.0`
Contributor guide
Research direction
Start in desktop/src-tauri/src/managed_agents/discovery.rs and trace probe_auth_status(), then follow the status handling in harnessCatalogLogic.ts. Reproduce the custom provider with env_key and compare the catalog status with codex login status. Done means a valid environment-supplied key no longer blocks Codex startup without requiring the key to be persisted.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, typescript
- Domain
- authentication, desktop
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100