fix(tlon): preserve explicit empty settings during migration (#58370)

This commit is contained in:
Jacob Tomlinson 2026-03-31 06:57:03 -07:00 committed by GitHub
parent c1ea0ae9c8
commit a4d72a83f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 65 additions and 8 deletions

View File

@ -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<v
const migrations = buildTlonSettingsMigrations(account, currentSettings);
for (const { key, fileValue, settingsValue } of migrations) {
// Only migrate if file has a value and settings store doesn't
const hasFileValue = Array.isArray(fileValue) ? fileValue.length > 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",

View File

@ -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({

View File

@ -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;