mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-13 18:32:12 +03:00
Real and nasty precisely because it is silent: `z.string().url()` accepts `localhost:20128` as scheme `localhost:` plus a path, every model gets published with an unusable api url, and the failure happens inside the client so the gateway logs show nothing. Backing the option schema, the publish boundary and the snapshot filter with one `isHttpUrl` in v2 is the right call — those three cannot drift apart. Duplicating the predicate in v1 rather than sharing it is also correct, since the two packages ship independently. --- Validated in one consolidated worktree cut from `release/v3.8.51`, boarded together with the rest of this batch — zero conflicts between them. - `typecheck:core` clean; `check:changelog-integrity` OK - complexity 2799 / baseline 3218 and cognitive-complexity 1265 / baseline 1437 — both under baseline - 86 focused assertions green across the batch's 10 unit test files, plus 16/16 on the v1 plugin option schema and 16/16 on the v2 option tests - `check-file-size` rebaselined for this batch's real growth (annotation `_rebaseline_2026_09_11_mergebatch_v3851_maxmad_opencode`, landed on #13141). `open-sse/utils/stream.ts` was deliberately left frozen: it is already 3115 > 3098 on the pure tip with zero contribution from this batch. ⚠️ base-red inherited: #12732 — `Docs Gates`, `Merge integrity`, `No new ESLint warnings`, `Unit Tests fast-path` and `Fast Quality Gates` all reproduce on the pure `release/v3.8.51` tip (provider count 356 vs the 358 the modules define, SKILL.md drift, and the `stream.ts` freeze above). None of them touch these diffs. Thanks @maxmad64bis.
162 lines
5.8 KiB
TypeScript
162 lines
5.8 KiB
TypeScript
import { describe, it } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import {
|
|
integrationIdFor,
|
|
parsePluginOptions,
|
|
PLUGIN_ID,
|
|
providerIdFor,
|
|
resolveTimeouts,
|
|
} from "../src/options.js";
|
|
|
|
describe("parsePluginOptions", () => {
|
|
it("applies defaults for providerId, timeoutMs, usableOnly, enrichment", () => {
|
|
const opts = parsePluginOptions({ baseURL: "https://gw.example.com" });
|
|
assert.equal(opts.providerId, "omniroute");
|
|
assert.equal(opts.timeoutMs, 10000);
|
|
assert.equal(opts.usableOnly, false);
|
|
assert.equal(opts.enrichment, true);
|
|
assert.equal(opts.modelCacheTtlMs, undefined);
|
|
});
|
|
it("accepts a positive modelCacheTtlMs (in-memory TTL cache, default 300s)", () => {
|
|
const opts = parsePluginOptions({ baseURL: "https://gw.example.com", modelCacheTtlMs: 60000 });
|
|
assert.equal(opts.modelCacheTtlMs, 60000);
|
|
});
|
|
it("rejects a non-positive modelCacheTtlMs", () => {
|
|
assert.throws(() =>
|
|
parsePluginOptions({ baseURL: "https://gw.example.com", modelCacheTtlMs: 0 })
|
|
);
|
|
});
|
|
it("requires baseURL", () => {
|
|
assert.throws(() => parsePluginOptions({}), /baseURL/);
|
|
});
|
|
it("rejects a baseURL that is not an http(s) URL", () => {
|
|
// `new URL()` reads "localhost:20128" as the scheme "localhost:" followed
|
|
// by a path, so a gateway address typed without "http://" parses. Every
|
|
// model would then be published with "localhost:20128/v1" as its api url
|
|
// and every call would fail in the client on an unknown scheme, with no
|
|
// request on the wire and nothing in the gateway logs.
|
|
for (const baseURL of [
|
|
"localhost:20128",
|
|
"localhost:20128/v1",
|
|
"ftp://gw.example.com/v1",
|
|
"gw.example.com/v1",
|
|
]) {
|
|
assert.throws(
|
|
() => parsePluginOptions({ baseURL }),
|
|
/baseURL must be an http\(s\) URL/,
|
|
`expected ${baseURL} to be rejected`
|
|
);
|
|
}
|
|
});
|
|
it("accepts http and https baseURLs, with or without a port or path", () => {
|
|
for (const baseURL of [
|
|
"http://localhost:20128/v1",
|
|
"http://localhost:20128",
|
|
"https://gw.example.com/v1",
|
|
"https://gw.example.com/omniroute/v1",
|
|
]) {
|
|
assert.equal(parsePluginOptions({ baseURL }).baseURL, baseURL);
|
|
// Padding a copied address is trimmed rather than rejected, matching the
|
|
// treatment `headroomUrl` already gets in the settings schema.
|
|
assert.equal(parsePluginOptions({ baseURL: ` ${baseURL} ` }).baseURL, baseURL);
|
|
}
|
|
});
|
|
it("rejects unknown top-level keys (strict)", () => {
|
|
assert.throws(() => parsePluginOptions({ baseURL: "https://gw.example.com", bogus: 1 }));
|
|
});
|
|
it("rejects unknown apiFormat keys (strict)", () => {
|
|
assert.throws(() =>
|
|
parsePluginOptions({
|
|
baseURL: "https://gw.example.com",
|
|
apiFormat: { bogus: ["claude"] },
|
|
})
|
|
);
|
|
});
|
|
it("accepts deprecated anthropicPrefixes (warn at resolve time, not parse time)", () => {
|
|
const opts = parsePluginOptions({
|
|
baseURL: "https://gw.example.com",
|
|
apiFormat: { allowAnthropic: true, anthropicPrefixes: ["cc", "claude"] },
|
|
});
|
|
assert.deepEqual(opts.apiFormat, {
|
|
allowAnthropic: true,
|
|
anthropicPrefixes: ["cc", "claude"],
|
|
});
|
|
});
|
|
it("passes apiFormat allowlist through (shared enforces semantics)", () => {
|
|
const opts = parsePluginOptions({
|
|
baseURL: "https://gw.example.com",
|
|
apiFormat: { allowAnthropic: true, anthropicModels: ["anthropic/claude-x"] },
|
|
});
|
|
assert.deepEqual(opts.apiFormat, {
|
|
allowAnthropic: true,
|
|
anthropicModels: ["anthropic/claude-x"],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("identity table", () => {
|
|
it("maps providerId X to provider X and integration X, under one fixed plugin id", () => {
|
|
assert.equal(providerIdFor("omniroute"), "omniroute");
|
|
assert.equal(integrationIdFor("omniroute"), "omniroute");
|
|
assert.equal(providerIdFor("second-gateway"), "second-gateway");
|
|
// The host reads the plugin id before any option exists, so it never
|
|
// varies with providerId.
|
|
assert.equal(PLUGIN_ID, "omniroute-v2");
|
|
});
|
|
});
|
|
|
|
describe("invalid options say what to fix", () => {
|
|
it("names an unknown key instead of dumping the validator output", () => {
|
|
assert.throws(
|
|
() => parsePluginOptions({ baseURL: "http://gw.example.com", modelCacheTtl: 300000 }),
|
|
(err: Error) => {
|
|
assert.match(err.message, /invalid plugin options/);
|
|
assert.match(err.message, /unknown option "modelCacheTtl"/);
|
|
return true;
|
|
}
|
|
);
|
|
});
|
|
|
|
it("names the offending field for a wrong type", () => {
|
|
assert.throws(
|
|
() => parsePluginOptions({ baseURL: 42 }),
|
|
(err: Error) => {
|
|
assert.match(err.message, /baseURL/);
|
|
return true;
|
|
}
|
|
);
|
|
});
|
|
|
|
it("accepts the documented option names", () => {
|
|
const parsed = parsePluginOptions({
|
|
baseURL: "http://gw.example.com",
|
|
modelCacheTtlMs: 300000,
|
|
timeouts: { models: 15000, combos: 8000 },
|
|
geminiSanitization: false,
|
|
});
|
|
assert.equal(parsed.modelCacheTtlMs, 300000);
|
|
assert.equal(resolveTimeouts(parsed).models, 15000);
|
|
});
|
|
});
|
|
|
|
describe("providerId is bounded because it reaches a filesystem path", () => {
|
|
it("rejects a traversal attempt instead of writing outside the snapshot directory", () => {
|
|
for (const bad of ["../../etc/cron.d/x", "a/b", "..", "."]) {
|
|
assert.throws(
|
|
() => parsePluginOptions({ baseURL: "https://gw.example.com", providerId: bad }),
|
|
/invalid plugin options/,
|
|
`providerId ${JSON.stringify(bad)} must be rejected`
|
|
);
|
|
}
|
|
});
|
|
|
|
it("keeps the ids a user would actually pick", () => {
|
|
for (const ok of ["omniroute", "omniroute-2", "gw.staging", "gw_prod"]) {
|
|
assert.equal(
|
|
parsePluginOptions({ baseURL: "https://gw.example.com", providerId: ok }).providerId,
|
|
ok
|
|
);
|
|
}
|
|
});
|
|
});
|