Files
zero/internal/cli/provider_setup_test.go
ba99fa8d48 fix(provider): stop dropping custom no-auth providers on restart (#558)
* fix(provider): stop dropping custom no-auth providers on restart

Custom OpenAI/Anthropic-compatible catalog entries hardcode
RequiresAuth as a template default for the setup wizard, not a fact
about the user's actual endpoint. Leaving the credential step blank
(e.g. a local llama.cpp server) still stamped the saved profile with
a guessed OPENAI_API_KEY/ANTHROPIC_API_KEY env var, and that same
static RequiresAuth flag then made the profile look like it was
missing a required credential on the next run, silently filtering it
out of /model.

Add a Custom flag to the catalog descriptor so both the wizard
(write side) and setupMissingCredentialEnv (read side) judge these
profiles by their own explicit APIKeyEnv instead of the catalog's
static default.

Fixes #555

Co-Authored-By: Claude Sonnet 5 <[email protected]>

Co-authored-by: Pierre Bruno <[email protected]>

* fix(provider): self-heal legacy custom profiles stamped by the old wizard bug

CodeRabbit flagged that profiles saved before this fix could already
carry the phantom APIKeyEnv the old wizard stamped on every custom
provider (e.g. OPENAI_API_KEY), and the new custom-branch logic would
keep treating any non-empty APIKeyEnv as an explicit requirement —
leaving already-affected users' providers filtered out of /model even
after upgrading.

Treat an APIKeyEnv that exactly matches the catalog's own guessed
default as indistinguishable from unset, so already-broken saved
profiles self-heal without a config.json migration. A deliberately
different env var name (e.g. via --api-key-env) still means auth is
required.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

Co-authored-by: Pierre Bruno <[email protected]>

* fix(provider): centralize custom-endpoint credential logic, fix two more surfaces

Copilot's review of the earlier fix found the same RequiresAuth-as-
authoritative bug in two more places that decide whether a saved
provider needs a credential:

- validateProviderRuntimeReady (zero providers check) would hard-error
  a no-auth custom endpoint with "requires API key".
- providerWizardCredentialLabel and providerCredentialRequired (/providers
  status, wizard summary) would still claim/warn that one was needed.

Added config.ProviderProfile.MissingCredentialEnv as the single source
of truth for this decision (custom-endpoint self-heal included), and
had setupMissingCredentialEnv and validateProviderRuntimeReady delegate
to it. providerWizardCredentialLabel and providerCredentialRequired
take the same Custom-aware fix directly, since their non-catalog
fallback path uses runtime-resolved provider-kind metadata that
shouldn't be collapsed into the canonical helper.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

Co-authored-by: Pierre Bruno <[email protected]>

* fix(ci): request pinned Go toolchain directly

Co-authored-by: Pierre Bruno <[email protected]>

---------

Co-authored-by: Amp <[email protected]>
2026-07-08 08:54:39 +08:00

69 lines
1.8 KiB
Go

package cli
import (
"testing"
"github.com/Gitlawb/zero/internal/config"
)
// Regression for issue #555's follow-up: `zero providers check` must not
// error that a no-auth custom endpoint requires an API key, matching what
// /model and /providers already treat as usable.
func TestValidateProviderRuntimeReadyCustomEndpoint(t *testing.T) {
cases := []struct {
name string
profile config.ProviderProfile
wantErr bool
}{
{
name: "custom openai compatible with no credential configured",
profile: config.ProviderProfile{
Name: "local-llama",
CatalogID: "custom-openai-compatible",
BaseURL: "http://192.168.1.50:8080/v1",
Model: "custom-model",
},
wantErr: false,
},
{
name: "custom openai compatible with stale legacy default env",
profile: config.ProviderProfile{
Name: "local-llama",
CatalogID: "custom-openai-compatible",
BaseURL: "http://192.168.1.50:8080/v1",
APIKeyEnv: "OPENAI_API_KEY",
Model: "custom-model",
},
wantErr: false,
},
{
name: "custom openai compatible with explicit non-default env still requires it",
profile: config.ProviderProfile{
Name: "local-llama",
CatalogID: "custom-openai-compatible",
BaseURL: "http://192.168.1.50:8080/v1",
APIKeyEnv: "LLAMA_CPP_API_KEY",
Model: "custom-model",
},
wantErr: true,
},
{
name: "catalog provider missing key still errors",
profile: config.ProviderProfile{
Name: "groq",
CatalogID: "groq",
Model: "llama-3.3-70b-versatile",
},
wantErr: true,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
err := validateProviderRuntimeReady(c.profile)
if (err != nil) != c.wantErr {
t.Fatalf("validateProviderRuntimeReady() error = %v, wantErr %v", err, c.wantErr)
}
})
}
}