import { promises as nodeFs } from "node:fs"; import type { FileHandle } from "node:fs/promises"; import { mkdtemp, mkdir, symlink, writeFile } from "node:fs/promises"; import { createHash } from "node:crypto"; import os from "node:os"; import path from "node:path"; import { beforeEach, describe, expect, test, vi } from "vitest"; import type { PluginManifest } from "@toolctrl/plugin-runtime"; const getPluginForTenantMock = vi.fn(); const publishAuditEventViaOutboxMock = vi.fn(); const dbMock = { $transaction: vi.fn(), pluginUserConfig: { findUnique: vi.fn(), upsert: vi.fn(), }, }; vi.mock("./PluginLifecycleService", () => ({ getPluginForTenant: (...args: unknown[]) => getPluginForTenantMock(...args), })); vi.mock("@toolctrl/db/audit-events.server", () => ({ publishAuditEventViaOutbox: (...args: unknown[]) => publishAuditEventViaOutboxMock(...args), })); vi.mock("~/utils/db.server", () => ({ db: dbMock, })); const baseManifest = { schemaVersion: 1, id: "com.acme.settings", version: "1.0.0", name: "Settings", entry: "plugin.wasm", wasmSha256: "0".repeat(64), signature: "0".repeat(128), signedBy: "0".repeat(64), allowedHosts: [], capabilities: [], hooks: [{ name: "entity.created", export: "handleEntityCreated" }], } satisfies PluginManifest; const settingsHtml = "
Settings
"; const settingsHtmlSha256 = createHash("sha256").update(settingsHtml).digest("hex"); const settingsHtmlIntegrity = `sha256-${createHash("sha256").update(settingsHtml).digest("base64")}`; function pluginFixture(manifest: PluginManifest = { ...baseManifest, ui: { settings: { entry: "ui/settings.html", sha256: settingsHtmlSha256 } } }) { return { id: "plugin-row-1", pluginId: "com.acme.settings", version: "1.0.0", enabled: true, manifest, installedAt: new Date("2026-05-01T00:00:00.000Z"), updatedAt: new Date("2026-05-01T00:00:00.000Z"), }; } beforeEach(() => { getPluginForTenantMock.mockReset(); publishAuditEventViaOutboxMock.mockReset(); publishAuditEventViaOutboxMock.mockResolvedValue(undefined); dbMock.$transaction.mockReset(); dbMock.$transaction.mockImplementation((callback: (tx: typeof dbMock) => unknown) => callback(dbMock)); dbMock.pluginUserConfig.findUnique.mockReset(); dbMock.pluginUserConfig.upsert.mockReset(); delete process.env.PLUGIN_BINARY_BASE_PATH; }); describe("PluginSettingsService", () => { test("loads settings HTML through tenant-scoped plugin lookup", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "plugin-settings-")); const bundleRoot = path.join(root, "com.acme.settings", "1.0.0", "ui"); await mkdir(bundleRoot, { recursive: true }); await writeFile(path.join(bundleRoot, "settings.html"), settingsHtml); process.env.PLUGIN_BINARY_BASE_PATH = root; getPluginForTenantMock.mockResolvedValue(pluginFixture()); const { loadPluginSettingsHtml } = await import("./PluginSettingsService"); const result = await loadPluginSettingsHtml({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" }); expect(getPluginForTenantMock).toHaveBeenCalledWith({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" }); expect(result.entry).toBe("ui/settings.html"); expect(result.trustedHtml).toBe(settingsHtml); }); test("loads settings HTML declared with SRI integrity metadata", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "plugin-settings-")); const bundleRoot = path.join(root, "com.acme.settings", "1.0.0", "ui"); await mkdir(bundleRoot, { recursive: true }); await writeFile(path.join(bundleRoot, "settings.html"), settingsHtml); process.env.PLUGIN_BINARY_BASE_PATH = root; getPluginForTenantMock.mockResolvedValue( pluginFixture({ ...baseManifest, ui: { settings: { entry: "ui/settings.html", integrity: settingsHtmlIntegrity } } }) ); const { loadPluginSettingsHtml } = await import("./PluginSettingsService"); const result = await loadPluginSettingsHtml({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" }); expect(result.trustedHtml).toBe(settingsHtml); }); test("rejects manifests without settings UI", async () => { getPluginForTenantMock.mockResolvedValue(pluginFixture(baseManifest)); const { loadPluginSettingsHtml } = await import("./PluginSettingsService"); await expect(loadPluginSettingsHtml({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" })).rejects.toMatchObject({ code: "settings_ui_unavailable", }); }); test("rejects settings UI manifests without HTML integrity metadata before touching the filesystem", async () => { getPluginForTenantMock.mockResolvedValue(pluginFixture({ ...baseManifest, ui: { settings: { entry: "ui/settings.html" } } as never })); const openSpy = vi.spyOn(nodeFs, "open"); const { loadPluginSettingsHtml } = await import("./PluginSettingsService"); try { await expect(loadPluginSettingsHtml({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" })).rejects.toMatchObject({ code: "settings_ui_integrity_missing", }); expect(openSpy).not.toHaveBeenCalled(); } finally { openSpy.mockRestore(); } }); test("rejects unsafe entries before touching the filesystem", async () => { getPluginForTenantMock.mockResolvedValue(pluginFixture({ ...baseManifest, ui: { settings: { entry: "../settings.html" } } })); const { loadPluginSettingsHtml } = await import("./PluginSettingsService"); await expect(loadPluginSettingsHtml({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" })).rejects.toMatchObject({ code: "settings_ui_entry_unsafe", }); }); test("rejects settings HTML whose bytes differ from the manifest sha256", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "plugin-settings-")); const bundleRoot = path.join(root, "com.acme.settings", "1.0.0", "ui"); await mkdir(bundleRoot, { recursive: true }); await writeFile(path.join(bundleRoot, "settings.html"), "
Tampered
"); process.env.PLUGIN_BINARY_BASE_PATH = root; getPluginForTenantMock.mockResolvedValue(pluginFixture()); const { loadPluginSettingsHtml } = await import("./PluginSettingsService"); await expect(loadPluginSettingsHtml({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" })).rejects.toMatchObject({ code: "settings_ui_integrity_mismatch", }); }); test("rejects symlink traversal out of the plugin bundle", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "plugin-settings-")); const outside = path.join(root, "outside.html"); const bundleRoot = path.join(root, "com.acme.settings", "1.0.0", "ui"); await mkdir(bundleRoot, { recursive: true }); await writeFile(outside, "
Outside
"); await symlink(outside, path.join(bundleRoot, "settings.html")); process.env.PLUGIN_BINARY_BASE_PATH = root; getPluginForTenantMock.mockResolvedValue(pluginFixture()); const { loadPluginSettingsHtml } = await import("./PluginSettingsService"); await expect(loadPluginSettingsHtml({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" })).rejects.toMatchObject({ code: "settings_ui_entry_unsafe", }); }); test("rejects oversized settings HTML after opening the file handle and before reading it into the route payload", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "plugin-settings-")); const bundleRoot = path.join(root, "com.acme.settings", "1.0.0", "ui"); const settingsPath = path.join(bundleRoot, "settings.html"); await mkdir(bundleRoot, { recursive: true }); await writeFile(settingsPath, settingsHtml); process.env.PLUGIN_BINARY_BASE_PATH = root; getPluginForTenantMock.mockResolvedValue(pluginFixture()); const originalOpen = nodeFs.open.bind(nodeFs); const openSpy = vi.spyOn(nodeFs, "open").mockImplementation(async (...args: Parameters) => { const fileHandle = (await originalOpen(...args)) as FileHandle; const originalStat = fileHandle.stat.bind(fileHandle); vi.spyOn(fileHandle, "stat").mockImplementation(async (...statArgs: Parameters) => { await writeFile(settingsPath, `
${"x".repeat(257 * 1024)}
`); return originalStat(...statArgs); }); return fileHandle; }); const { loadPluginSettingsHtml } = await import("./PluginSettingsService"); try { await expect(loadPluginSettingsHtml({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" })).rejects.toMatchObject({ code: "settings_ui_file_too_large", }); expect(openSpy).toHaveBeenCalledWith(expect.stringContaining("settings.html"), "r"); } finally { openSpy.mockRestore(); } }); test("loads per-user settings through tenant-scoped plugin lookup", async () => { getPluginForTenantMock.mockResolvedValue(pluginFixture()); dbMock.pluginUserConfig.findUnique.mockResolvedValue({ configJson: { theme: "dark", count: 2, apiKey: "must-not-reach-frame", password: "must-not-reach-frame", "../escape": "unsafe", __proto__: "polluted", constructor: "unsafe", prototype: "unsafe", oversized: "x".repeat(33 * 1024), tooManyItems: Array.from({ length: 513 }, (_, index) => index), tooManyKeys: Object.fromEntries(Array.from({ length: 257 }, (_, index) => [`k${index}`, index])), nestedReserved: JSON.parse('{"safe":true,"__proto__":{"polluted":true}}'), nestedSecret: { appearance: { apiKey: "must-not-reach-frame" } }, ignored: () => "nope", }, }); const { loadPluginUserSettings } = await import("./PluginSettingsService"); const result = await loadPluginUserSettings({ tenantId: "tenant-1", pluginRowId: "plugin-row-1", userId: "user-1" }); expect(getPluginForTenantMock).toHaveBeenCalledWith({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" }); expect(dbMock.pluginUserConfig.findUnique).toHaveBeenCalledWith({ where: { pluginId_userId: { pluginId: "plugin-row-1", userId: "user-1" } }, select: { configJson: true }, }); expect(result).toEqual({ theme: "dark", count: 2 }); expect(JSON.stringify(result)).not.toContain("must-not-reach-frame"); expect(result).not.toHaveProperty("apiKey"); expect(result).not.toHaveProperty("password"); expect(result).not.toHaveProperty("../escape"); expect(result).not.toHaveProperty("__proto__"); expect(result).not.toHaveProperty("constructor"); expect(result).not.toHaveProperty("prototype"); expect(result).not.toHaveProperty("oversized"); expect(result).not.toHaveProperty("tooManyItems"); expect(result).not.toHaveProperty("tooManyKeys"); expect(result).not.toHaveProperty("nestedReserved"); expect(result).not.toHaveProperty("nestedSecret"); }); test("loads settings page data with a single tenant plugin lookup", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "plugin-settings-")); const bundleRoot = path.join(root, "com.acme.settings", "1.0.0", "ui"); await mkdir(bundleRoot, { recursive: true }); await writeFile(path.join(bundleRoot, "settings.html"), settingsHtml); process.env.PLUGIN_BINARY_BASE_PATH = root; getPluginForTenantMock.mockResolvedValue(pluginFixture()); dbMock.pluginUserConfig.findUnique.mockResolvedValue({ configJson: { theme: "dark" } }); const { loadPluginSettingsPageData } = await import("./PluginSettingsService"); const result = await loadPluginSettingsPageData({ tenantId: "tenant-1", pluginRowId: "plugin-row-1", userId: "user-1" }); expect(getPluginForTenantMock).toHaveBeenCalledOnce(); expect(getPluginForTenantMock).toHaveBeenCalledWith({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" }); expect(dbMock.pluginUserConfig.findUnique).toHaveBeenCalledWith({ where: { pluginId_userId: { pluginId: "plugin-row-1", userId: "user-1" } }, select: { configJson: true }, }); expect(result).toMatchObject({ entry: "ui/settings.html", trustedHtml: settingsHtml, settings: { theme: "dark" }, plugin: { id: "plugin-row-1", pluginId: "com.acme.settings", version: "1.0.0" }, }); }); test("rejects per-user settings reads for disabled plugins before reading config", async () => { getPluginForTenantMock.mockResolvedValue({ ...pluginFixture(), enabled: false }); const { loadPluginUserSettings } = await import("./PluginSettingsService"); await expect(loadPluginUserSettings({ tenantId: "tenant-1", pluginRowId: "plugin-row-1", userId: "user-1" })).rejects.toMatchObject({ code: "plugin_disabled", }); expect(dbMock.pluginUserConfig.findUnique).not.toHaveBeenCalled(); }); test("rejects per-user settings reads when no safe settings UI is declared before reading config", async () => { const { loadPluginUserSettings } = await import("./PluginSettingsService"); const args = { tenantId: "tenant-1", pluginRowId: "plugin-row-1", userId: "user-1" }; getPluginForTenantMock.mockResolvedValueOnce(pluginFixture(baseManifest)); await expect(loadPluginUserSettings(args)).rejects.toMatchObject({ code: "settings_ui_unavailable" }); getPluginForTenantMock.mockResolvedValueOnce(pluginFixture({ ...baseManifest, ui: { settings: { entry: "../settings.html" } } })); await expect(loadPluginUserSettings(args)).rejects.toMatchObject({ code: "settings_ui_entry_unsafe" }); expect(dbMock.pluginUserConfig.findUnique).not.toHaveBeenCalled(); }); test("upserts a single per-user setting without storing secret-like keys", async () => { getPluginForTenantMock.mockResolvedValue(pluginFixture()); dbMock.pluginUserConfig.findUnique.mockResolvedValue({ configJson: { theme: "dark" } }); dbMock.pluginUserConfig.upsert.mockResolvedValue({}); const { setPluginUserSetting } = await import("./PluginSettingsService"); const result = await setPluginUserSetting({ tenantId: "tenant-1", pluginRowId: "plugin-row-1", userId: "user-1", key: "layout.mode", value: "compact", actor: { userId: "user-1", email: "user@example.com", ip: "127.0.0.1" }, }); expect(dbMock.pluginUserConfig.upsert).toHaveBeenCalledWith({ where: { pluginId_userId: { pluginId: "plugin-row-1", userId: "user-1" } }, create: { pluginId: "plugin-row-1", userId: "user-1", configJson: { theme: "dark", "layout.mode": "compact" } }, update: { configJson: { theme: "dark", "layout.mode": "compact" } }, }); expect(dbMock.$transaction).toHaveBeenCalledOnce(); expect(publishAuditEventViaOutboxMock).toHaveBeenCalledWith( dbMock, expect.objectContaining({ tenantId: "tenant-1", actorId: "user-1", action: "plugin.configuration.updated", targetId: "plugin-row-1", metadata: { pluginId: "com.acme.settings", key: "layout.mode" }, }) ); expect(JSON.stringify(publishAuditEventViaOutboxMock.mock.calls[0]?.[1]?.metadata)).not.toContain("compact"); expect(result.settings).toEqual({ theme: "dark", "layout.mode": "compact" }); }); test("merges per-user settings from the write transaction snapshot", async () => { getPluginForTenantMock.mockResolvedValue(pluginFixture()); dbMock.pluginUserConfig.findUnique.mockResolvedValue({ configJson: { theme: "stale" } }); const tx = { pluginUserConfig: { findUnique: vi.fn().mockResolvedValue({ configJson: { theme: "dark", density: "comfortable" } }), upsert: vi.fn().mockResolvedValue({}), }, }; dbMock.$transaction.mockImplementationOnce((callback: (tx: typeof tx) => unknown) => callback(tx)); const { setPluginUserSetting } = await import("./PluginSettingsService"); const result = await setPluginUserSetting({ tenantId: "tenant-1", pluginRowId: "plugin-row-1", userId: "user-1", key: "layout.mode", value: "compact", actor: { userId: "user-1", email: "user@example.com", ip: "127.0.0.1" }, }); expect(dbMock.pluginUserConfig.findUnique).not.toHaveBeenCalled(); expect(tx.pluginUserConfig.findUnique).toHaveBeenCalledWith({ where: { pluginId_userId: { pluginId: "plugin-row-1", userId: "user-1" } }, select: { configJson: true }, }); expect(tx.pluginUserConfig.upsert).toHaveBeenCalledWith({ where: { pluginId_userId: { pluginId: "plugin-row-1", userId: "user-1" } }, create: { pluginId: "plugin-row-1", userId: "user-1", configJson: { theme: "dark", density: "comfortable", "layout.mode": "compact" } }, update: { configJson: { theme: "dark", density: "comfortable", "layout.mode": "compact" } }, }); expect(publishAuditEventViaOutboxMock).toHaveBeenCalledWith(tx, expect.objectContaining({ action: "plugin.configuration.updated" })); expect(result.settings).toEqual({ theme: "dark", density: "comfortable", "layout.mode": "compact" }); }); test("rolls back per-user setting writes when audit enqueue fails", async () => { getPluginForTenantMock.mockResolvedValue(pluginFixture()); dbMock.pluginUserConfig.findUnique.mockResolvedValue({ configJson: {} }); dbMock.pluginUserConfig.upsert.mockResolvedValue({}); publishAuditEventViaOutboxMock.mockRejectedValueOnce(new Error("outbox unavailable")); const { setPluginUserSetting } = await import("./PluginSettingsService"); await expect( setPluginUserSetting({ tenantId: "tenant-1", pluginRowId: "plugin-row-1", userId: "user-1", key: "theme", value: "dark", actor: { userId: "user-1", email: "user@example.com", ip: "127.0.0.1" }, }) ).rejects.toThrow("outbox unavailable"); expect(dbMock.$transaction).toHaveBeenCalledOnce(); expect(dbMock.pluginUserConfig.upsert).toHaveBeenCalledOnce(); expect(publishAuditEventViaOutboxMock).toHaveBeenCalledOnce(); }); test("reports settings iframe violations as redacted tenant-scoped audit events", async () => { getPluginForTenantMock.mockResolvedValue(pluginFixture()); const { reportPluginSettingsFrameViolation } = await import("./PluginSettingsService"); await reportPluginSettingsFrameViolation({ tenantId: "tenant-1", pluginRowId: "plugin-row-1", reason: "wrong_origin", actor: { userId: "user-1", email: "user@example.com", ip: "203.0.113.7" }, }); expect(getPluginForTenantMock).toHaveBeenCalledWith({ tenantId: "tenant-1", pluginRowId: "plugin-row-1" }); expect(publishAuditEventViaOutboxMock).toHaveBeenCalledWith(dbMock, { tenantId: "tenant-1", actorId: "user-1", actorType: "user", actorEmail: "user@example.com", actorIp: "203.0.113.7", action: "plugin.settings_frame.violation", targetType: "plugin", targetId: "plugin-row-1", sourceModule: "plugin-settings", outcome: "blocked", dataSensitivity: "internal", metadata: { pluginId: "com.acme.settings", pluginRowId: "plugin-row-1", reason: "wrong_origin", reportedByClient: true }, }); expect(JSON.stringify(publishAuditEventViaOutboxMock.mock.calls[0]?.[1])).not.toContain("payload"); }); test("rejects settings iframe violation reports for disabled plugins or missing settings UI", async () => { const { reportPluginSettingsFrameViolation } = await import("./PluginSettingsService"); const base = { tenantId: "tenant-1", pluginRowId: "plugin-row-1", reason: "invalid_payload" as const, actor: { userId: "user-1", email: "user@example.com", ip: null }, }; getPluginForTenantMock.mockResolvedValueOnce({ ...pluginFixture(), enabled: false }); await expect(reportPluginSettingsFrameViolation(base)).rejects.toMatchObject({ code: "plugin_disabled" }); getPluginForTenantMock.mockResolvedValueOnce(pluginFixture(baseManifest)); await expect(reportPluginSettingsFrameViolation(base)).rejects.toMatchObject({ code: "settings_ui_unavailable" }); expect(publishAuditEventViaOutboxMock).not.toHaveBeenCalled(); }); test("rejects direct per-user setting writes for disabled plugins", async () => { getPluginForTenantMock.mockResolvedValue({ ...pluginFixture(), enabled: false }); const { setPluginUserSetting } = await import("./PluginSettingsService"); await expect( setPluginUserSetting({ tenantId: "tenant-1", pluginRowId: "plugin-row-1", userId: "user-1", key: "theme", value: "dark", actor: { userId: "user-1", email: "user@example.com", ip: "127.0.0.1" }, }) ).rejects.toMatchObject({ code: "plugin_disabled" }); expect(dbMock.pluginUserConfig.findUnique).not.toHaveBeenCalled(); expect(dbMock.pluginUserConfig.upsert).not.toHaveBeenCalled(); expect(publishAuditEventViaOutboxMock).not.toHaveBeenCalled(); }); test("rejects direct per-user setting writes when no safe settings UI is declared", async () => { const { setPluginUserSetting } = await import("./PluginSettingsService"); const base = { tenantId: "tenant-1", pluginRowId: "plugin-row-1", userId: "user-1", key: "theme", value: "dark", actor: { userId: "user-1", email: "user@example.com", ip: "127.0.0.1" }, }; getPluginForTenantMock.mockResolvedValueOnce(pluginFixture(baseManifest)); await expect(setPluginUserSetting(base)).rejects.toMatchObject({ code: "settings_ui_unavailable" }); getPluginForTenantMock.mockResolvedValueOnce(pluginFixture({ ...baseManifest, ui: { settings: { entry: "../settings.html" } } })); await expect(setPluginUserSetting(base)).rejects.toMatchObject({ code: "settings_ui_entry_unsafe" }); expect(dbMock.pluginUserConfig.findUnique).not.toHaveBeenCalled(); expect(dbMock.pluginUserConfig.upsert).not.toHaveBeenCalled(); expect(publishAuditEventViaOutboxMock).not.toHaveBeenCalled(); }); test("rejects unsafe, secret-like, invalid, and oversized setting writes", async () => { getPluginForTenantMock.mockResolvedValue(pluginFixture()); dbMock.pluginUserConfig.findUnique.mockResolvedValue({ configJson: {} }); const { setPluginUserSetting } = await import("./PluginSettingsService"); const base = { tenantId: "tenant-1", pluginRowId: "plugin-row-1", userId: "user-1", actor: { userId: "user-1", email: null, ip: null }, }; await expect(setPluginUserSetting({ ...base, key: "../theme", value: "dark" })).rejects.toMatchObject({ code: "settings_key_invalid" }); await expect(setPluginUserSetting({ ...base, key: "k".repeat(129), value: "dark" })).rejects.toMatchObject({ code: "settings_key_invalid" }); await expect(setPluginUserSetting({ ...base, key: "__proto__", value: "polluted" })).rejects.toMatchObject({ code: "settings_key_invalid" }); await expect(setPluginUserSetting({ ...base, key: "constructor", value: "unsafe" })).rejects.toMatchObject({ code: "settings_key_invalid" }); await expect(setPluginUserSetting({ ...base, key: "prototype", value: "unsafe" })).rejects.toMatchObject({ code: "settings_key_invalid" }); await expect(setPluginUserSetting({ ...base, key: "apiKey", value: "abc" })).rejects.toMatchObject({ code: "settings_key_secret_like" }); await expect(setPluginUserSetting({ ...base, key: "theme", value: Number.NaN as never })).rejects.toMatchObject({ code: "settings_value_invalid" }); await expect( setPluginUserSetting({ ...base, key: "deep", value: { a: { b: { c: { d: { e: { f: { g: { h: { i: true } } } } } } } } } }) ).rejects.toMatchObject({ code: "settings_value_invalid", }); await expect(setPluginUserSetting({ ...base, key: "array", value: Array.from({ length: 513 }, (_, index) => index) })).rejects.toMatchObject({ code: "settings_value_invalid", }); await expect( setPluginUserSetting({ ...base, key: "object", value: Object.fromEntries(Array.from({ length: 257 }, (_, index) => [`k${index}`, index])) }) ).rejects.toMatchObject({ code: "settings_value_invalid", }); await expect( setPluginUserSetting({ ...base, key: "nestedReserved", value: JSON.parse('{"theme":"dark","__proto__":{"polluted":true}}') }) ).rejects.toMatchObject({ code: "settings_value_invalid", }); await expect(setPluginUserSetting({ ...base, key: "appearance", value: { theme: { accessToken: "must-not-persist" } } })).rejects.toMatchObject({ code: "settings_value_invalid", }); await expect(setPluginUserSetting({ ...base, key: "blob", value: "x".repeat(70 * 1024) })).rejects.toMatchObject({ code: "settings_value_too_large", }); expect(dbMock.pluginUserConfig.upsert).not.toHaveBeenCalled(); }); });