diff --git a/extensions/tlon/src/monitor/index.ts b/extensions/tlon/src/monitor/index.ts index 1dbbbf1c7be..a111d2122df 100644 --- a/extensions/tlon/src/monitor/index.ts +++ b/extensions/tlon/src/monitor/index.ts @@ -27,6 +27,7 @@ import { applyTlonSettingsOverrides, buildTlonSettingsMigrations, mergeUniqueStrings, + shouldMigrateTlonSetting, } from "./settings-helpers.js"; import { extractMessageText, @@ -180,13 +181,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise 0 : fileValue != null; - const hasSettingsValue = Array.isArray(settingsValue) - ? settingsValue.length > 0 - : settingsValue != null; - - if (hasFileValue && !hasSettingsValue) { + if (shouldMigrateTlonSetting(fileValue, settingsValue)) { try { await api!.poke({ app: "settings", diff --git a/extensions/tlon/src/monitor/settings-helpers.test.ts b/extensions/tlon/src/monitor/settings-helpers.test.ts index 7580909397d..246aaa9809d 100644 --- a/extensions/tlon/src/monitor/settings-helpers.test.ts +++ b/extensions/tlon/src/monitor/settings-helpers.test.ts @@ -1,6 +1,10 @@ import { describe, expect, it } from "vitest"; import type { TlonResolvedAccount } from "../types.js"; -import { applyTlonSettingsOverrides } from "./settings-helpers.js"; +import { + applyTlonSettingsOverrides, + buildTlonSettingsMigrations, + shouldMigrateTlonSetting, +} from "./settings-helpers.js"; const baseAccount: TlonResolvedAccount = { accountId: "default", @@ -22,6 +26,58 @@ const baseAccount: TlonResolvedAccount = { ownerShip: "~marzod", }; +describe("shouldMigrateTlonSetting", () => { + it("does not rehydrate explicit empty-array revocations during startup migration", () => { + const migrations = buildTlonSettingsMigrations(baseAccount, { + dmAllowlist: [], + groupInviteAllowlist: [], + defaultAuthorizedShips: [], + }); + + expect( + Object.fromEntries( + migrations + .filter((migration) => + ["dmAllowlist", "groupInviteAllowlist", "defaultAuthorizedShips"].includes( + migration.key, + ), + ) + .map((migration) => [ + migration.key, + shouldMigrateTlonSetting(migration.fileValue, migration.settingsValue), + ]), + ), + ).toEqual({ + dmAllowlist: false, + groupInviteAllowlist: false, + defaultAuthorizedShips: false, + }); + }); + + it("still seeds file-config allowlists on first run when settings are missing", () => { + const migrations = buildTlonSettingsMigrations(baseAccount, {}); + + expect( + Object.fromEntries( + migrations + .filter((migration) => + ["dmAllowlist", "groupInviteAllowlist", "defaultAuthorizedShips"].includes( + migration.key, + ), + ) + .map((migration) => [ + migration.key, + shouldMigrateTlonSetting(migration.fileValue, migration.settingsValue), + ]), + ), + ).toEqual({ + dmAllowlist: true, + groupInviteAllowlist: true, + defaultAuthorizedShips: true, + }); + }); +}); + describe("applyTlonSettingsOverrides", () => { it("treats explicit empty settings allowlists as authoritative deny-all", () => { const result = applyTlonSettingsOverrides({ diff --git a/extensions/tlon/src/monitor/settings-helpers.ts b/extensions/tlon/src/monitor/settings-helpers.ts index ea92be76531..8df6c38e318 100644 --- a/extensions/tlon/src/monitor/settings-helpers.ts +++ b/extensions/tlon/src/monitor/settings-helpers.ts @@ -62,6 +62,12 @@ export function buildTlonSettingsMigrations( ]; } +export function shouldMigrateTlonSetting(fileValue: unknown, settingsValue: unknown): boolean { + const hasFileValue = Array.isArray(fileValue) ? fileValue.length > 0 : fileValue != null; + const hasSettingsValue = settingsValue != null; + return hasFileValue && !hasSettingsValue; +} + export function applyTlonSettingsOverrides(params: { account: TlonResolvedAccount; currentSettings: TlonSettingsStore;