Remove activeTab permission; make background sole icon authority#1464
Merged
Conversation
── What this is ──
This is an architectural tidy-up, not a feature change. It removes a
redundant permission and eliminates a dual-writer pattern on the
toolbar icon. No user-visible behaviour changes.
── Permission model (activeTab removal) ──
The manifest declared both broad host-matched content_scripts and the
activeTab permission. activeTab grants *temporary* host access to the
active tab when the user clicks the toolbar icon. But because the
extension already injects content scripts on http, https, and file URLs
via the content_scripts manifest key, Chrome grants *permanent* host
permissions for those origins. chrome.tabs.query() and
chrome.tabs.sendMessage() — the only two APIs that consumed activeTab,
both in popup.js — work identically without it.
activeTab was likely carried forward from the original MV2 codebase
where the permission landscape was different. Removing it shrinks the
install-time permission surface with zero functional cost.
── Icon update consolidation ──
Before this change, toggling the extension via the popup power button
caused the toolbar icon to be set three times per click:
1. popup.js called chrome.action.setIcon() directly (instant feedback)
2. popup.js sent an EXTENSION_TOGGLE runtime message → background
onMessage handler called updateIcon()
3. popup.js wrote { enabled } to chrome.storage.sync → background
storage.onChanged handler called updateIcon()
Path 3 is the only one that is both necessary and sufficient. It fires
for every write to the enabled key regardless of origin (popup, options
page, future UI). Paths 1 and 2 were redundant fast-paths that created
a dual-writer race: popup and background both calling setIcon with the
same intent but no coordination, which could drift under service-worker
lifecycle edge cases (wake, suspend, stale contexts).
After this change:
- Popup writes enabled to storage and updates its own DOM. That's it.
- Background owns icon state exclusively via storage.onChanged.
- The EXTENSION_TOGGLE runtime message and its handler are removed.
- No runtime.sendMessage calls remain in popup.js.
── Icon design (unchanged, documented here for context) ──
The toolbar icon has exactly two states: enabled (colour) and disabled
(greyscale). There is no per-tab state, no speed badge, no dynamic
text overlay — this was a deliberate simplification from an earlier
design that tracked per-tab icon state (see tests/e2e/icon.e2e.js
which documents this as "ultra-simplified architecture").
Icon state is derived solely from the enabled boolean in
chrome.storage.sync. Background reads it on install, on startup, and
on every service-worker wake (initializeIcon called at module scope),
and reacts to changes via storage.onChanged. This is resilient to
service-worker suspension because Chrome persists storage.sync
independently and fires onChanged on wake.
── Files changed ──
manifest.json Remove activeTab from permissions array.
src/background.js Remove EXTENSION_TOGGLE onMessage listener.
src/ui/popup/popup.js Remove chrome.action.setIcon() call and
chrome.runtime.sendMessage() call from
toggleEnabledUI(). Function now only updates
popup DOM (class toggle + tooltip text).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
── What this is ──
This is an architectural tidy-up, not a feature change. It removes a
redundant permission and eliminates a dual-writer pattern on the
toolbar icon. No user-visible behaviour changes.
── Permission model (activeTab removal) ──
The manifest declared both broad host-matched content_scripts and the
activeTab permission. activeTab grants temporary host access to the
active tab when the user clicks the toolbar icon. But because the
extension already injects content scripts on http, https, and file URLs
via the content_scripts manifest key, Chrome grants permanent host
permissions for those origins. chrome.tabs.query() and
chrome.tabs.sendMessage() — the only two APIs that consumed activeTab,
both in popup.js — work identically without it.
activeTab was likely carried forward from the original MV2 codebase
where the permission landscape was different. Removing it shrinks the
install-time permission surface with zero functional cost.
── Icon update consolidation ──
Before this change, toggling the extension via the popup power button
caused the toolbar icon to be set three times per click:
onMessage handler called updateIcon()
storage.onChanged handler called updateIcon()
Path 3 is the only one that is both necessary and sufficient. It fires
for every write to the enabled key regardless of origin (popup, options
page, future UI). Paths 1 and 2 were redundant fast-paths that created
a dual-writer race: popup and background both calling setIcon with the
same intent but no coordination, which could drift under service-worker
lifecycle edge cases (wake, suspend, stale contexts).
After this change:
── Icon design (unchanged, documented here for context) ──
The toolbar icon has exactly two states: enabled (colour) and disabled
(greyscale). There is no per-tab state, no speed badge, no dynamic
text overlay — this was a deliberate simplification from an earlier
design that tracked per-tab icon state (see tests/e2e/icon.e2e.js
which documents this as "ultra-simplified architecture").
Icon state is derived solely from the enabled boolean in
chrome.storage.sync. Background reads it on install, on startup, and
on every service-worker wake (initializeIcon called at module scope),
and reacts to changes via storage.onChanged. This is resilient to
service-worker suspension because Chrome persists storage.sync
independently and fires onChanged on wake.
── Files changed ──
manifest.json Remove activeTab from permissions array.
src/background.js Remove EXTENSION_TOGGLE onMessage listener.
src/ui/popup/popup.js Remove chrome.action.setIcon() call and
chrome.runtime.sendMessage() call from
toggleEnabledUI(). Function now only updates
popup DOM (class toggle + tooltip text).