feat(updater): skip update checks on Microsoft Store installs#127
Merged
Conversation
The Microsoft Store updates MSIX packages automatically by default, so the in-app "update available on the Store" notification was redundant. Worse, it kept nagging users about updates that were not actually pending, because Store propagation lags behind our GitHub releases. MSIX installs now short-circuit in check_for_update() exactly like every other externally-managed install (Snap, Flatpak, AUR, apt, rpm): no polling, no dialog, no button. The detection is folded into is_system_install() via is_msix_install(), which moved from the deleted app/store_updater.py into app/updater.py with identical semantics (PACKAGE_FULL_NAME env var OR \WindowsApps\ in the executable path). The short-circuit is load-bearing rather than cosmetic: simply dropping the MSIX branch would let Store installs fall through to the NSIS path and attempt to download and run PDFAppsSetup.exe inside the AppContainer sandbox, which cannot execute it and would leave a second, parallel installation behind. The NSIS/direct-install updater is untouched: _find_asset, _get_expected_hash, mandatory SHA256 with hmac.compare_digest, _apply_update_windows/unix path-traversal and symlink validation, and UpdateDialog all keep their existing behaviour and tests. Removed: app/store_updater.py, tests/test_store_updater.py, the _notify_store_update dialog and its two MSIX branches in window.py, the get/set_dismissed_store_version helpers and dismissed_store_version config key in i18n.py, and the update.store.* keys across all 8 languages. Docs: privacy.html and docs.html claimed update checks could be disabled in app settings, which was never true. Both now describe the real behaviour — direct installs check on startup, system-managed installs (including the Store) do not check at all. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Why
The Microsoft Store updates MSIX packages automatically by default, so the in-app "update available on the Store" notification was redundant. In practice it was also wrong: because Store propagation lags 1-7 days behind our GitHub releases, users were being told an update was available when nothing was actually pending on their side.
Decision: MSIX/Store installs should not check for updates at all.
What changed
MSIX installs now short-circuit to
Noneincheck_for_update(), exactly like every other externally-managed install (Snap, Flatpak, AUR, apt, rpm). No polling, no dialog, no update button.Detection is folded into
is_system_install()viais_msix_install(), which moved from the deletedapp/store_updater.pyintoapp/updater.pywith identical semantics (PACKAGE_FULL_NAMEenv var OR\WindowsApps\in the executable path).The short-circuit is load-bearing, not cosmetic
Simply deleting the MSIX branch would have been a regression: Store installs would fall through to the NSIS path and try to download and
ShellExecuteW("runas", ...)PDFAppsSetup.exeinside the AppContainer sandbox, which cannot execute it — and if it somehow did, the user would end up with two parallel installations.NSIS updater untouched
The direct-install security path is deliberately unchanged:
_find_asset,_get_expected_hash,_downloadwith mandatory SHA256 +hmac.compare_digest,_apply_update_windows/unixpath-traversal and symlink validation, andUpdateDialog. All 36 existing tests intests/test_updater.pystill pass unmodified.Removed
app/store_updater.py(onlyis_msix_installsurvived, moved toapp/updater.py)tests/test_store_updater.py(55 tests)_notify_store_updateinwindow.pyplus its MSIX branches in_notify_updateand_show_update_dialogget_dismissed_store_version/set_dismissed_store_versionand thedismissed_store_versionconfig key ini18n.pyupdate.store.*keys across all 8 languages (5 keys x 8 = 40 lines);translations.jsonremains valid JSON with 608 identical keys per languageDocs correction
docs/privacy.htmlclaimed "You can disable update checks in the app settings" anddocs/docs.htmlsaid "an optional update check on startup (which can be disabled)". Neither was ever true — no such setting exists. Both now describe the real behaviour: direct installs check on startup; system-managed installs (including the Store) make no update request at all.README.mdand the docs troubleshooting entry were aligned too.Tests
18 new tests in
tests/test_updater_msix.py:is_msix_install()detection — env var,\WindowsApps\path (incl. case-insensitivity), and negatives for NSIS/macOS/Linuxcheck_for_update()returnsNoneon MSIX and makes no network call (urlopen.assert_not_called()), including when GitHub would advertise a newer releasecheck_for_update()still returns the release for NSIS when newer,Nonewhen not newer, and swallows network errors — no regression{"msix": True}plumbing, no orphan i18n or config keys)Suite: 441 passed, 2 skipped, 0 failed (478 - 55 removed + 18 new = 441).
ruff checkclean onapp/updater.py,app/i18n.pyand the new test file.app/window.pyhas 0F/E9errors; its pre-existingE702semicolon-style count is unchanged at 62 before and after.Grep for
store_updater,dismissed_store_version,update.store,_notify_store_update,check_for_store_update,store_deep_link,ms-windows-store: zero orphans outside the intentional regression guards in the new test file.🤖 Generated with Claude Code