From 874f8df5c97f20feb6570b68d0d33fdef7ef8d5a Mon Sep 17 00:00:00 2001 From: ghost <49853598+JSONbored@users.noreply.github.com> Date: Sun, 12 Jul 2026 16:10:14 -0700 Subject: [PATCH] fix(miner-extension): clear stale discovery index URL --- apps/gittensory-miner-extension/options.js | 7 ++++++ test/unit/miner-extension-content.test.ts | 25 ++++++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/gittensory-miner-extension/options.js b/apps/gittensory-miner-extension/options.js index 6e2c5062ed..fc12ab2320 100644 --- a/apps/gittensory-miner-extension/options.js +++ b/apps/gittensory-miner-extension/options.js @@ -15,10 +15,15 @@ function parseRankedCandidatesJson(text) { return parsed; } +async function removeLegacyDiscoveryIndexUrl() { + await chrome.storage.sync.remove("discoveryIndexUrl"); +} + if (globalThis.__GITTENSORY_MINER_EXTENSION_TEST__) { globalThis.__gittensoryMinerOptionsInternals = { parseWatchedRepos, parseRankedCandidatesJson, + removeLegacyDiscoveryIndexUrl, }; } @@ -38,6 +43,7 @@ form.addEventListener("submit", async (event) => { const repos = parseWatchedRepos(watchedRepos.value); const rankedCandidates = parseRankedCandidatesJson(rankedCandidatesJson.value); await chrome.storage.sync.set({ watchedRepos: repos }); + await removeLegacyDiscoveryIndexUrl(); await chrome.storage.local.set({ rankedCandidates }); await refreshSettings(); showStatus( @@ -53,6 +59,7 @@ form.addEventListener("submit", async (event) => { async function refreshSettings() { const stored = await chrome.storage.sync.get({ watchedRepos: [] }); + await removeLegacyDiscoveryIndexUrl(); const local = await chrome.storage.local.get({ rankedCandidates: [] }); const repos = Array.isArray(stored.watchedRepos) ? stored.watchedRepos : []; watchedRepos.value = repos.join("\n"); diff --git a/test/unit/miner-extension-content.test.ts b/test/unit/miner-extension-content.test.ts index 376ba101d0..8c7f98bf15 100644 --- a/test/unit/miner-extension-content.test.ts +++ b/test/unit/miner-extension-content.test.ts @@ -148,15 +148,18 @@ describe("miner extension opportunity badge", () => { expect(() => internals.parseRankedCandidatesJson('{"not":"array"}')).toThrow(); }); - it("REGRESSION (dead-field removal): no discoveryIndexUrl config field remains anywhere in the extension", () => { + it("REGRESSION (dead-field removal): no discoveryIndexUrl config field remains in UI or background reads", () => { expect(optionsHtml).not.toMatch(/discoveryIndexUrl/); - expect(optionsScript).not.toMatch(/discoveryIndexUrl/); expect(backgroundScript).not.toMatch(/discoveryIndexUrl/); }); - it("saves and restores settings without ever writing or reading discoveryIndexUrl", async () => { - const synced: Record = { watchedRepos: [] }; + it("removes stale discoveryIndexUrl values from synced options storage", async () => { + const synced: Record = { + watchedRepos: [], + discoveryIndexUrl: "https://private.example.test/index.json", + }; const setCalls: Array> = []; + const removeCalls: string[] = []; const elements = { "#settings": createFormMock(), "#status": { textContent: "" }, @@ -174,6 +177,10 @@ describe("miner extension opportunity badge", () => { setCalls.push(value); Object.assign(synced, value); }, + remove: async (key: string) => { + removeCalls.push(key); + delete synced[key]; + }, }, local: { get: async () => ({ rankedCandidates: [] }), set: async () => {} }, }, @@ -184,11 +191,17 @@ describe("miner extension opportunity badge", () => { const vmContext = createContext(context); new Script(optionsScript).runInContext(vmContext); + await flushPromises(); + expect(removeCalls).toEqual(["discoveryIndexUrl"]); + expect("discoveryIndexUrl" in synced).toBe(false); + + synced.discoveryIndexUrl = "https://private.example.test/index.json"; elements["#watchedRepos"].value = "JSONbored/gittensory"; await elements["#settings"].dispatchSubmit(); expect(setCalls).toHaveLength(1); expect(setCalls[0]).toEqual({ watchedRepos: ["JSONbored/gittensory"] }); + expect(removeCalls).toEqual(["discoveryIndexUrl", "discoveryIndexUrl", "discoveryIndexUrl"]); expect("discoveryIndexUrl" in synced).toBe(false); }); }); @@ -205,6 +218,10 @@ function createFormMock() { }; } +function flushPromises() { + return new Promise((resolve) => setTimeout(resolve, 0)); +} + function createMockContainer() { const container = { hidden: false,