From b793e917046c6cbad6846e06a88eb3d378d9a202 Mon Sep 17 00:00:00 2001 From: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Date: Fri, 9 Oct 2026 15:24:51 -0300 Subject: [PATCH] =?UTF-8?q?fix(release):=20drain=20v3.8.52=20base-reds=20?= =?UTF-8?q?=E2=80=94=20sqlite=20report=20stall,=20zh-CN=20glossary,=20rout?= =?UTF-8?q?e=20map,=20ToS-default=20test=20fallout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fix(db): construct better-sqlite3 with process.report.excludeNetwork on. Its isLinuxMusl() probe calls process.report.getReport(), which reverse-resolves every open TCP handle; with sockets open the first DB open blocked ~6s on hosts with slow reverse DNS — the shared root cause of the four autoCombo/antigravity vitest 5s timeouts (#15106). - fix(i18n): zh-CN codexKeyServiceMode 提供商 -> 提供者 (glossary) and regenerate routeNamespaces.generated.json for the namespace added by #13554. - test: opt out of excludeTosAvoid in the auto-combo suites whose subject is not the ToS filter — #15979 made uncataloged models inherit the provider verdict, so opencode/antigravity left every default auto pool (contract change). - test: zai-web #13232 pins DISPLAY so the missing-Chromium branch is exercised after #15851 started Xvfb first; quota-trackers-batch-init matches the awaited import independent of the Prettier reflow from #13330. --- .../basereds-1009a-drain-v3852-base-reds.md | 2 + src/i18n/messages/zh-CN.json | 4 +- src/i18n/routeNamespaces.generated.json | 60 +++++++++++++++++++ src/lib/db/adapters/driverFactory.ts | 24 +++++++- ...auto-combo-credentialed-model-pool.test.ts | 7 +++ tests/unit/db-adapters/driverFactory.test.ts | 30 ++++++++++ tests/unit/noauth-autocombo-allowlist.test.ts | 7 +++ .../unit/noauth-autocombo-hidden-7620.test.ts | 6 ++ tests/unit/quota-trackers-batch-init.test.ts | 6 +- ...-noauth-connection-disable-ignored.test.ts | 7 +++ tests/unit/virtual-auto-combo.test.ts | 6 ++ ...b-missing-browser-executable-13232.test.ts | 13 ++++ 12 files changed, 167 insertions(+), 5 deletions(-) create mode 100644 changelog.d/fixes/basereds-1009a-drain-v3852-base-reds.md diff --git a/changelog.d/fixes/basereds-1009a-drain-v3852-base-reds.md b/changelog.d/fixes/basereds-1009a-drain-v3852-base-reds.md new file mode 100644 index 000000000000..f7bdc9f3b029 --- /dev/null +++ b/changelog.d/fixes/basereds-1009a-drain-v3852-base-reds.md @@ -0,0 +1,2 @@ +- **fix(db):** the first better-sqlite3 open no longer blocks for seconds on hosts with slow reverse DNS — the addon's musl probe calls `process.report.getReport()`, whose network section reverse-resolves every open TCP handle; the driver now constructs it with `process.report.excludeNetwork` on and restores the caller's value (~6.5s → ~0.6s first capability lookup under vitest, #15106) +- **fix(i18n):** zh-CN `codexKeyServiceMode` uses the glossary term 提供者 instead of 提供商, and the route-namespace map is regenerated to carry the new namespace (#13554) diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index d066722de458..f2166be1da78 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -1,13 +1,13 @@ { "codexKeyServiceMode": { "title": "此 API 密钥的 Codex 服务模式", - "description": "适用于 Codex 请求,包括组合中的 Codex 模型。强制模式会覆盖客户端、全局设置和连接默认值。其他提供商不受影响。", + "description": "适用于 Codex 请求,包括组合中的 Codex 模型。强制模式会覆盖客户端、全局设置和连接默认值。其他提供者不受影响。", "label": "服务模式", "inherit": "继承现有行为", "default": "强制使用标准模式(默认)", "priority": "强制使用快速/优先模式", "flex": "强制使用弹性模式", - "warning": "此设置不会授予提供商访问权限。可用性、费用和配额消耗取决于您的 Codex 账户和模型。强制模式要求使用 HTTP 或 Responses WebSocket 传输;app-server 请求将被拒绝。", + "warning": "此设置不会授予提供者访问权限。可用性、费用和配额消耗取决于您的 Codex 账户和模型。强制模式要求使用 HTTP 或 Responses WebSocket 传输;app-server 请求将被拒绝。", "confirm": "要将“{mode}”应用于此 API 密钥吗?此设置将对后续请求生效。", "save": "保存模式", "retry": "重试", diff --git a/src/i18n/routeNamespaces.generated.json b/src/i18n/routeNamespaces.generated.json index 9e554a18bf54..cb49a00648d4 100644 --- a/src/i18n/routeNamespaces.generated.json +++ b/src/i18n/routeNamespaces.generated.json @@ -6,6 +6,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -36,6 +37,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -64,6 +66,7 @@ "cache", "cheaperInferenceSponsorBanner", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -97,6 +100,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -127,6 +131,7 @@ "cliCommon", "cliTools", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -155,6 +160,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -182,6 +188,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -209,6 +216,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -237,6 +245,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -267,6 +276,7 @@ "cache", "chaosConfig", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -296,6 +306,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "compliance", "costs", @@ -324,6 +335,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -351,6 +363,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -378,6 +391,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -409,6 +423,7 @@ "cache", "changelogPage", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -437,6 +452,7 @@ "cache", "chaosConfig", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -467,6 +483,7 @@ "cliCommon", "cliTools", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -497,6 +514,7 @@ "cliCommon", "cliTools", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -525,6 +543,7 @@ "cache", "cloudAgents", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -552,6 +571,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "comboControl", "combos", "common", @@ -582,6 +602,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "compressionStudio", "costs", @@ -611,6 +632,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "conductor", "costs", @@ -639,6 +661,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "compressionEngineConfig", "contextCaveman", @@ -672,6 +695,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -699,6 +723,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -732,6 +757,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -761,6 +787,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -790,6 +817,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -818,6 +846,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -846,6 +875,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -874,6 +904,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -906,6 +937,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -934,6 +966,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -961,6 +994,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -988,6 +1022,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1017,6 +1052,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1045,6 +1081,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1075,6 +1112,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1103,6 +1141,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1131,6 +1170,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1159,6 +1199,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1187,6 +1228,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "combos", "common", "costs", @@ -1216,6 +1258,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1245,6 +1288,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1273,6 +1317,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1301,6 +1346,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1330,6 +1376,7 @@ "cache", "cliproxyProviderExposure", "cloudSyncStatus", + "codexKeyServiceMode", "common", "connectionTest", "costs", @@ -1364,6 +1411,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "connectionTest", "costs", @@ -1394,6 +1442,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1426,6 +1475,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1454,6 +1504,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1483,6 +1534,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1512,6 +1564,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1541,6 +1594,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "connectionTest", "costs", @@ -1579,6 +1633,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1608,6 +1663,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1637,6 +1693,7 @@ "cache", "cliTools", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1664,6 +1721,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", @@ -1693,6 +1751,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "connectionTest", "costs", @@ -1724,6 +1783,7 @@ "breadcrumbs", "cache", "cloudSyncStatus", + "codexKeyServiceMode", "common", "costs", "cursorAuthModal", diff --git a/src/lib/db/adapters/driverFactory.ts b/src/lib/db/adapters/driverFactory.ts index c5bbe92e848c..f5b214dbb673 100644 --- a/src/lib/db/adapters/driverFactory.ts +++ b/src/lib/db/adapters/driverFactory.ts @@ -10,7 +10,6 @@ import { } from "./nodeSqliteShared"; import type { SqliteAdapter } from "./types"; - type DriverLoader = (moduleName: string) => unknown; type SpawnSyncLike = ( @@ -197,6 +196,27 @@ function getSqlJsPendingCache(): Map> { return globalThis.__omnirouteSqlJsInitPromises; } +/** + * better-sqlite3 13 picks its prebuild with `process.report.getReport()` (isLinuxMusl) the + * first time a Database is constructed. That report includes a network section that + * reverse-resolves every open TCP handle, so once the process holds sockets (a listening + * server, an upstream keep-alive) the first DB open blocked the event loop for ~6s on hosts + * with slow reverse DNS (#15106). Only `header.glibcVersionRuntime` is read, so drop the + * network section for the construction and restore the caller's setting afterwards. + */ +function withReportNetworkExcluded(fn: () => T): T { + const report = process.report as + (NodeJS.ProcessReport & { excludeNetwork?: boolean }) | undefined; + if (!report || typeof report.excludeNetwork !== "boolean") return fn(); + const previous = report.excludeNetwork; + report.excludeNetwork = true; + try { + return fn(); + } finally { + report.excludeNetwork = previous; + } +} + /** * @internal * @@ -250,7 +270,7 @@ export function createSyncDriverFactory(load: DriverLoader, betterSqliteProbe?: const BetterSqlite = load("better-sqlite3") as { new (p: string, o?: object): import("better-sqlite3").Database; }; - const db = new BetterSqlite(filePath, options); + const db = withReportNetworkExcluded(() => new BetterSqlite(filePath, options)); return createBetterSqliteAdapter(db); } catch (err) { logSwallowedDriverError("better-sqlite3", err); diff --git a/tests/unit/auto-combo-credentialed-model-pool.test.ts b/tests/unit/auto-combo-credentialed-model-pool.test.ts index daea5e672e99..ae7de6d00ffd 100644 --- a/tests/unit/auto-combo-credentialed-model-pool.test.ts +++ b/tests/unit/auto-combo-credentialed-model-pool.test.ts @@ -12,6 +12,7 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); const modelsDb = await import("../../src/lib/db/models.ts"); +const settingsDb = await import("../../src/lib/db/settings.ts"); const virtualFactory = await import("../../open-sse/services/autoCombo/virtualFactory.ts"); const candidateHandler = await import("../../open-sse/handlers/autoComboCandidates.ts"); @@ -59,6 +60,12 @@ async function seedConnections(firstExcludedModels?: string[]) { test.beforeEach(async () => { await resetStorage(); + // contract changed by #15979 (on top of #15839): `excludeTosAvoid` defaults to on and + // uncataloged models inherit the provider's curated `tos: "avoid"` verdict, so every antigravity + // model (now `antigravity: "avoid"`) is ToS-filtered out of auto/*. Opt out so this file keeps + // guarding the per-model candidate pool shape; the ToS default is covered by + // issue-15059-tos-avoid-auto-default. + await settingsDb.updateSettings({ excludeTosAvoid: false }); }); test.after(async () => { diff --git a/tests/unit/db-adapters/driverFactory.test.ts b/tests/unit/db-adapters/driverFactory.test.ts index 4623ae96b51e..7d4d06a7228e 100644 --- a/tests/unit/db-adapters/driverFactory.test.ts +++ b/tests/unit/db-adapters/driverFactory.test.ts @@ -462,6 +462,36 @@ describe("driverFactory", () => { assert.equal(openWithoutNativeDrivers(":memory:"), null); }); + test("opens better-sqlite3 with the network section excluded from process.report", () => { + // better-sqlite3 13 resolves its prebuild via process.report.getReport() (isLinuxMusl). + // With open TCP handles that report reverse-resolves every socket, which took ~6s per + // first DB open on a host with slow reverse DNS (#15106 vitest timeouts). The driver + // must construct the addon with excludeNetwork on, then restore the caller's value. + const report = process.report as NodeJS.ProcessReport & { excludeNetwork: boolean }; + const original = report.excludeNetwork; + let seenDuringConstruct: boolean | undefined; + const open = createSyncDriverFactory((moduleName: string) => { + if (moduleName === "better-sqlite3") { + return class { + constructor() { + seenDuringConstruct = report.excludeNetwork; + throw new Error("stop after observing the report flag"); + } + }; + } + throw new Error("forced driver load failure"); + }); + + report.excludeNetwork = false; + try { + open(":memory:"); + assert.equal(seenDuringConstruct, true); + assert.equal(report.excludeNetwork, false, "the caller's excludeNetwork must be restored"); + } finally { + report.excludeNetwork = original; + } + }); + test("pack-boot sql.js forcing requires both smoke-only markers", () => { assert.equal(isPackBootForcedSqlJsSmoke({}), false); assert.equal(isPackBootForcedSqlJsSmoke({ OMNIROUTE_PACK_BOOT_SMOKE: "1" }), false); diff --git a/tests/unit/noauth-autocombo-allowlist.test.ts b/tests/unit/noauth-autocombo-allowlist.test.ts index fecf2a98a5f9..fbb4c29dfc16 100644 --- a/tests/unit/noauth-autocombo-allowlist.test.ts +++ b/tests/unit/noauth-autocombo-allowlist.test.ts @@ -23,6 +23,7 @@ const ORIGINAL_DATA_DIR = process.env.DATA_DIR; process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); +const settingsDb = await import("../../src/lib/db/settings.ts"); const virtualFactory = await import("../../open-sse/services/autoCombo/virtualFactory.ts"); async function resetStorage() { @@ -33,6 +34,12 @@ async function resetStorage() { test.beforeEach(async () => { await resetStorage(); + // contract changed by #15979 (on top of #15839): `excludeTosAvoid` defaults to on and + // uncataloged models inherit the provider's curated `tos: "avoid"` verdict, so a fresh + // install filters every opencode model out of auto/*. Opt out so this file keeps guarding + // the no-auth allowlist itself; the ToS default is covered by + // tests/unit/issue-15059-tos-avoid-auto-default.test.ts and tos-provider-alias-15059. + await settingsDb.updateSettings({ excludeTosAvoid: false }); }); test.after(async () => { diff --git a/tests/unit/noauth-autocombo-hidden-7620.test.ts b/tests/unit/noauth-autocombo-hidden-7620.test.ts index 6ec9dea14920..c491dd22b499 100644 --- a/tests/unit/noauth-autocombo-hidden-7620.test.ts +++ b/tests/unit/noauth-autocombo-hidden-7620.test.ts @@ -21,6 +21,7 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); const modelsDb = await import("../../src/lib/db/models.ts"); +const settingsDb = await import("../../src/lib/db/settings.ts"); const virtualFactory = await import("../../open-sse/services/autoCombo/virtualFactory.ts"); async function resetStorage() { @@ -31,6 +32,11 @@ async function resetStorage() { test.beforeEach(async () => { await resetStorage(); + // contract changed by #15979 (on top of #15839): `excludeTosAvoid` defaults to on and + // uncataloged models inherit the provider's curated `tos: "avoid"` verdict, so every opencode + // model is ToS-filtered out of auto/*. Opt out so this file keeps guarding the #7620 + // hidden-model behaviour; the ToS default is covered by issue-15059-tos-avoid-auto-default. + await settingsDb.updateSettings({ excludeTosAvoid: false }); }); test.after(async () => { diff --git a/tests/unit/quota-trackers-batch-init.test.ts b/tests/unit/quota-trackers-batch-init.test.ts index 018d38fc210e..5ea4820008e9 100644 --- a/tests/unit/quota-trackers-batch-init.test.ts +++ b/tests/unit/quota-trackers-batch-init.test.ts @@ -38,7 +38,11 @@ test("chat route calls the batch registrar after imports, before generic", () => test("node instrumentation calls the batch registrar after the dynamic import resolves", () => { const source = read("src/instrumentation-node.ts"); - const imported = source.indexOf('await import(\n "@omniroute/open-sse/services/quotaTrackersBatch.ts"'); + // contract changed by #13330: Prettier reflowed the dynamic import onto one line, so match + // the awaited import independent of whitespace instead of a hard-coded line break. + const importMatch = + /await\s+import\(\s*"@omniroute\/open-sse\/services\/quotaTrackersBatch\.ts"/.exec(source); + const imported = importMatch ? importMatch.index : -1; const called = source.indexOf("registerQuotaTrackersBatch()"); assert.ok(imported >= 0, "instrumentation must await the batch module"); assert.ok(called > imported, "the call must follow the resolved import"); diff --git a/tests/unit/repro-6557-noauth-connection-disable-ignored.test.ts b/tests/unit/repro-6557-noauth-connection-disable-ignored.test.ts index b680e65ac129..2c6103614022 100644 --- a/tests/unit/repro-6557-noauth-connection-disable-ignored.test.ts +++ b/tests/unit/repro-6557-noauth-connection-disable-ignored.test.ts @@ -33,6 +33,7 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); +const settingsDb = await import("../../src/lib/db/settings.ts"); const virtualFactory = await import("../../open-sse/services/autoCombo/virtualFactory.ts"); async function resetStorage() { @@ -43,6 +44,12 @@ async function resetStorage() { test.beforeEach(async () => { await resetStorage(); + // contract changed by #15979 (on top of #15839): `excludeTosAvoid` defaults to on and + // uncataloged models inherit the provider's curated `tos: "avoid"` verdict, so every opencode + // model is ToS-filtered out of auto/*. Opt out so this file keeps guarding the #6557 + // connection-disable behaviour; the ToS default is covered by + // issue-15059-tos-avoid-auto-default. + await settingsDb.updateSettings({ excludeTosAvoid: false }); }); test.after(async () => { diff --git a/tests/unit/virtual-auto-combo.test.ts b/tests/unit/virtual-auto-combo.test.ts index 95850cb40c5f..d455a290d90f 100644 --- a/tests/unit/virtual-auto-combo.test.ts +++ b/tests/unit/virtual-auto-combo.test.ts @@ -284,6 +284,12 @@ test("createVirtualAutoCombo restricts the no-auth pool to the allowlist", async // egress. The others stay usable via direct `/` calls but must // NOT be auto-routed to. Dedicated guard: // tests/unit/noauth-autocombo-allowlist.test.ts. + // contract changed by #15979 (on top of #15839): `excludeTosAvoid` is ON by default and + // uncataloged models now inherit the provider's curated `tos: "avoid"` verdict, so every + // opencode model is ToS-filtered out by default. Opt out explicitly so this test keeps + // asserting the no-auth allowlist, not the ToS filter (covered by + // tests/unit/issue-15059-tos-avoid-auto-default.test.ts and tos-provider-alias-15059). + await settingsDb.updateSettings({ excludeTosAvoid: false }); const combo: VirtualComboResult = await virtualFactory.createVirtualAutoCombo("fast"); for (const allowed of ["opencode"]) { diff --git a/tests/unit/zai-web-missing-browser-executable-13232.test.ts b/tests/unit/zai-web-missing-browser-executable-13232.test.ts index 8795c2e03050..2b390737c011 100644 --- a/tests/unit/zai-web-missing-browser-executable-13232.test.ts +++ b/tests/unit/zai-web-missing-browser-executable-13232.test.ts @@ -25,6 +25,7 @@ const TEST_TOKEN = `e30.${Buffer.from(JSON.stringify({ id: "user-123" })).toStri describe("issue #13232 — Z.ai browser transport classifies a missing Chromium install", () => { let emptyBrowsersDir: string; let originalBrowsersPath: string | undefined; + let originalDisplay: string | undefined; before(() => { emptyBrowsersDir = fs.mkdtempSync(path.join(os.tmpdir(), "playwright-empty-")); @@ -33,6 +34,13 @@ describe("issue #13232 — Z.ai browser transport classifies a missing Chromium // ("Executable doesn't exist at ..."), without touching any real ~/.cache/ms-playwright // install. process.env.PLAYWRIGHT_BROWSERS_PATH = emptyBrowsersDir; + // contract changed by #15851 (#15300): a headed launch on a display-less Linux host now + // starts Xvfb first and fails with the missing-display 503 when Xvfb is absent, before + // Playwright ever resolves the Chromium binary. Pin a DISPLAY so this test keeps exercising + // the missing-executable branch on any host (Playwright checks the binary before it touches + // the display, so the fake value is never used). + originalDisplay = process.env.DISPLAY; + process.env.DISPLAY = ":99"; }); after(() => { @@ -41,6 +49,11 @@ describe("issue #13232 — Z.ai browser transport classifies a missing Chromium } else { process.env.PLAYWRIGHT_BROWSERS_PATH = originalBrowsersPath; } + if (originalDisplay === undefined) { + delete process.env.DISPLAY; + } else { + process.env.DISPLAY = originalDisplay; + } fs.rmSync(emptyBrowsersDir, { recursive: true, force: true }); });