mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-24 16:12:23 +03:00
Two defects exposed by #11226 (the 401 "User not found." itself is upstream OpenRouter's response to a bad key — not an OmniRoute bug): 1. OpenRouter key validation was vacuous. Both the dashboard Check (via validateProviderApiKey -> validateOpenAILikeProvider) and 'omniroute providers test' (bin/cli/provider-test.mjs) probed /api/v1/models, which is PUBLIC and answers 200 to any key — so invalid keys were saved/marked valid and only failed on real chat traffic. OpenRouter's authenticated key-info endpoint (GET /api/v1/auth/key, 200 = valid / 401 = invalid) is now the probe: registered as testKeyModelsUrl on the openrouter registry entry (same mechanism as perplexity) and as keyCheckPath in the CLI test configs. No other provider's probe changes; error results keep using canned strings, never the raw upstream body (Hard Rule #12). 2. 'omniroute auth export' crashed with "cmd.optsWithGlobals is not a function". .command("auth export") does not register a two-word command: commander parses the bare word 'export' as a required positional argument, so the action received (exportArgValue, options, command) while expecting (options, command). Registered 'export' as a proper nested subcommand of 'auth' — the documented CLI surface 'omniroute auth export [--force] [--id] [--format] [--out]' is unchanged, and unknown positionals (e.g. 'omniroute auth bogus') are now rejected instead of silently running the export. TDD: tests/unit/openrouter-key-validation-auth-endpoint.test.ts (stub mimics the real OpenRouter: /models public-200, /auth/key 401 'User not found.') and tests/unit/cli-auth-export-wiring.test.ts (real commander wiring via createProgram) were RED before the fix and are GREEN after. Co-authored-by: Xiangzhe <bakryun0718@proton.me>
This commit is contained in:
committed by
GitHub
parent
b5e4c2c0ce
commit
5cf16028fe
@@ -22,8 +22,15 @@ const VALID_FORMATS = new Set(["json", "env"]);
|
||||
const SECURE_FILE_MODE = 0o600;
|
||||
|
||||
export function registerAuthExport(program) {
|
||||
// #11226: `.command("auth export")` does NOT register a two-word command — commander
|
||||
// parses the bare word `export` as a required positional argument of `auth`, so the
|
||||
// action received (exportArgValue, options, command) while expecting (options, command)
|
||||
// and crashed with "cmd.optsWithGlobals is not a function". Register `export` as a
|
||||
// proper nested subcommand instead; the CLI surface stays `omniroute auth export`.
|
||||
program
|
||||
.command("auth export")
|
||||
.command("auth")
|
||||
.description(t("authExport.description"))
|
||||
.command("export")
|
||||
.description(t("authExport.description"))
|
||||
.option("--id <id>", t("authExport.idOpt"))
|
||||
.option("--format <format>", t("authExport.formatOpt"), "json")
|
||||
|
||||
@@ -10,6 +10,10 @@ const PROVIDER_TEST_CONFIGS = {
|
||||
format: "openai",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
model: "openai/gpt-4o-mini",
|
||||
// #11226: /models is public on OpenRouter (200 with any or no key) — probe the
|
||||
// authenticated key-info endpoint instead so a bad key fails the test here
|
||||
// instead of on the first real chat request.
|
||||
keyCheckPath: "/auth/key",
|
||||
},
|
||||
groq: {
|
||||
format: "openai",
|
||||
@@ -101,13 +105,19 @@ async function testOpenAILikeProvider(input, config) {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
const modelsRes = await fetchWithTimeout(joinUrl(config.baseUrl, "/models"), {
|
||||
method: "GET",
|
||||
headers,
|
||||
});
|
||||
// Providers whose /models endpoint is public (e.g. OpenRouter) declare a
|
||||
// keyCheckPath pointing at an authenticated endpoint so the probe actually
|
||||
// exercises the key instead of the public catalog.
|
||||
const probeRes = await fetchWithTimeout(
|
||||
joinUrl(config.baseUrl, config.keyCheckPath || "/models"),
|
||||
{
|
||||
method: "GET",
|
||||
headers,
|
||||
}
|
||||
);
|
||||
|
||||
if (modelsRes.ok || modelsRes.status === 401 || modelsRes.status === 403) {
|
||||
return classifyResponse(modelsRes);
|
||||
if (probeRes.ok || probeRes.status === 401 || probeRes.status === 403) {
|
||||
return classifyResponse(probeRes);
|
||||
}
|
||||
|
||||
const chatRes = await fetchWithTimeout(joinUrl(config.baseUrl, "/chat/completions"), {
|
||||
|
||||
Reference in New Issue
Block a user