Skip to content

feat(updater): skip update checks on Microsoft Store installs#127

Merged
nelsonduarte merged 1 commit into
mainfrom
fix/remove-store-update-check
Jul 18, 2026
Merged

feat(updater): skip update checks on Microsoft Store installs#127
nelsonduarte merged 1 commit into
mainfrom
fix/remove-store-update-check

Conversation

@nelsonduarte

Copy link
Copy Markdown
Owner

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 None in check_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() 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, 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.exe inside 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, _download with mandatory SHA256 + hmac.compare_digest, _apply_update_windows/unix path-traversal and symlink validation, and UpdateDialog. All 36 existing tests in tests/test_updater.py still pass unmodified.

Removed

  • app/store_updater.py (only is_msix_install survived, moved to app/updater.py)
  • tests/test_store_updater.py (55 tests)
  • _notify_store_update in window.py plus its MSIX branches in _notify_update and _show_update_dialog
  • get_dismissed_store_version / set_dismissed_store_version and the dismissed_store_version config key in i18n.py
  • update.store.* keys across all 8 languages (5 keys x 8 = 40 lines); translations.json remains valid JSON with 608 identical keys per language

Docs correction

docs/privacy.html claimed "You can disable update checks in the app settings" and docs/docs.html said "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.md and 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/Linux
  • check_for_update() returns None on MSIX and makes no network call (urlopen.assert_not_called()), including when GitHub would advertise a newer release
  • check_for_update() still returns the release for NSIS when newer, None when not newer, and swallows network errors — no regression
  • Regression guards that the Store mechanism is fully gone (module removed, no {"msix": True} plumbing, no orphan i18n or config keys)

Suite: 441 passed, 2 skipped, 0 failed (478 - 55 removed + 18 new = 441).

ruff check clean on app/updater.py, app/i18n.py and the new test file. app/window.py has 0 F/E9 errors; its pre-existing E702 semicolon-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

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>
@nelsonduarte
nelsonduarte merged commit 67eb97b into main Jul 18, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant