import { describe, expect, it } from "vitest"; import { PLUGIN_SETTING_ARRAY_MAX_LENGTH, PLUGIN_SETTING_KEY_MAX_LENGTH, PLUGIN_SETTING_OBJECT_MAX_KEYS, PLUGIN_SETTING_VALUE_MAX_BYTES, isPluginSettingKeyFormatSafe, isPluginSettingKeyReserved, isPluginSettingKeySecretLike, isPluginSettingValue, isPluginSettingValueShapeSafe, isPluginSettingValueWithinSize, isSafePluginSettingKey, } from "./pluginSettingsValidation"; describe("plugin settings validation", () => { it("keeps frame and persistence setting keys on the same safe-key contract", () => { expect(isSafePluginSettingKey("theme.accent:color-1")).toBe(true); expect(isPluginSettingKeyFormatSafe("k".repeat(PLUGIN_SETTING_KEY_MAX_LENGTH))).toBe(true); expect(isPluginSettingKeyFormatSafe("k".repeat(PLUGIN_SETTING_KEY_MAX_LENGTH + 1))).toBe(false); for (const key of [ "../theme", "__proto__", "constructor", "prototype", "apiKey", "access-token", "password", "secret.value", "authorization", "credentials", "auth.header", "bearer", "cookie", "sessionId", "private_key", "clientSecret", "webhookUrl", ]) { expect(isSafePluginSettingKey(key)).toBe(false); } expect(isPluginSettingKeyReserved("__proto__")).toBe(true); expect(isPluginSettingKeySecretLike("refresh-token")).toBe(true); expect(isPluginSettingKeySecretLike("authorization")).toBe(true); expect(isPluginSettingKeySecretLike("clientSecret")).toBe(true); }); it("rejects values that cannot cross the iframe-to-persistence boundary safely", () => { expect(isPluginSettingValue({ theme: "dark", flags: [true, false], count: 2 })).toBe(true); expect(isPluginSettingValue(Number.NaN)).toBe(false); expect(isPluginSettingValue(Array.from({ length: PLUGIN_SETTING_ARRAY_MAX_LENGTH + 1 }, () => true))).toBe(false); expect(isPluginSettingValue(Object.fromEntries(Array.from({ length: PLUGIN_SETTING_OBJECT_MAX_KEYS + 1 }, (_, index) => [`key${index}`, true])))).toBe( false ); expect(isPluginSettingValue(JSON.parse('{"theme":"dark","__proto__":{"polluted":true}}'))).toBe(false); expect(isPluginSettingValue({ theme: { accessToken: "must-not-persist" } })).toBe(false); expect(isPluginSettingValue({ request: { authorization: "Bearer must-not-persist" } })).toBe(false); expect(isPluginSettingValue({ endpoint: { webhookUrl: "https://hooks.example.test/secret" } })).toBe(false); }); it("separates JSON shape errors from serialized size errors for server error mapping", () => { const oversized = "x".repeat(PLUGIN_SETTING_VALUE_MAX_BYTES); expect(isPluginSettingValueShapeSafe(oversized)).toBe(true); expect(isPluginSettingValueWithinSize(oversized)).toBe(false); expect(isPluginSettingValue(oversized)).toBe(false); }); });