Skip to content

v2.4.0 - Portable Distribution & External Updater

Choose a tag to compare

@github-actions github-actions released this 18 Jul 19:23

Changed — breaking

  • In-app auto-update is removed. Sky Player now notifies you when a new version is available; applying it is done by running the new updater.bat in the install folder, then reopening Sky-Player.exe. This moves Sky Player to a portable-distribution model and removes in-place file-replacement logic from the running app. The previous "Auto-apply without asking" toggle is removed from Update Settings.
  • "Check for Update" in the picker now surfaces a banner modal with three actions: Open Releases page, Skip this version, Dismiss. The Download-and-apply progress modal is removed.
  • The update.auto_apply and update.pending_update_version fields in config.json are no longer read or written. Existing entries in older config.json files are ignored silently and stripped on next save.

Added

  • External updaterupdater.bat (repo root) + installer/updater.ps1. Verifies SHA256 before any install mutation; stages in TEMP; backs up and copies binaries transactionally with fallback rollback on failure. Preserves config.json and skips songs/ entirely. Log: %LOCALAPPDATA%\Sky-Player\updater.log. Supports -Channel stable|beta, -DryRun, -ForceClose, -Restart.
  • update.channel (default stable), update.last_notified_version, and (until 2.4.1) update.legacy_old_dir_sweep_pending in config.json. Channel is wired to the in-app check (include_prerelease) and to the external updater.
  • One-time sweep of legacy .old.{guid} install siblings left from pre-2.4.0 atomic swaps.
  • Release pipeline (.github/workflows/release.yml) — tag-driven build with tag↔pyproject.toml version lock, free-threaded audit, build-provenance attestation, three-artifact triple (zip + sha256 + MANIFEST.json).
  • CI workflow (.github/workflows/ci.yml) executes the full altitude table on windows-latest against the free-threaded interpreter.
  • Pre-commit config (.pre-commit-config.yaml) mirrors the same gates locally and adds check-yaml / check-toml / check-json / eol / trailing-whitespace.
  • Pytest markers (scheduler, windows, golden, slow) and norecursedirs declared via [tool.pytest.ini_options].
  • .editorconfig pins UTF-8, LF, 4-space indent for Python and 2-space for YAML/TOML/JSON; CRLF preserved on *.bat.
  • PULL_REQUEST_TEMPLATE.md + issue templates (bug_report.md, feature_request.md, security_p0.md, config.yml).
  • docs/distribution-and-update.md — contributor documentation.

Removed

  • apply_update_and_restart, write_apply_batch, apply_staged_update, download_and_verify_update, download_and_apply_update_worker, _apply_staged from the app and service layers.
  • UpdateProgressModal from src/sky_music/ui/textual_app/modals.py.
  • find_old_backups, post_update_flag_path, write_apply_batch, apply_update_and_restart from src/sky_music/infrastructure/update_installer.py.
  • simulate_update.py scenarios download-ok and download-bad-sha.
  • use_ll_hook machinery — opt-in global WH_KEYBOARD_LL hook (SetWindowsHookExW), the dormant hotkey_hook.py module, the AppConfig.use_ll_hook field, and the PlaybackControls._hook slot. The hotkey mechanism now relies exclusively on the focus-gated poll path (is_virtual_key_down), aligning the runtime with AGENTS.md P0.1 ("NO GAME TAMPERING — no hooks") and clearing the only outstanding entry in .config/security_audit_baseline.json.

Security

  • AGENTS.md P0 audit enforced in CI. New scripts/audit_security_mandates.py (AST scanner) runs on every push and PR alongside the existing audit_free_threaded_wheels.py precheck. It forbids ReadProcessMemory, WriteProcessMemory, SetWindowsHookEx*, CreateRemoteThread, DebugActiveProcess, NtQueryInformationProcess, imports of pymem/pyinject/win32api, and WinDLL("ntdll.dll"), while explicitly allowing only the SendInput family.
  • Public SECURITY.md restates the P0 mandates and the disclosure channel (security@pumni.dev) for vulnerability-grade findings.

Full changelog: see CHANGELOG.md.