Releases: I4cTime/protonshift
v0.9.7 — packaged-build CSS fix + docs refresh
Quality + docs release. One real bug fix, plus a long-overdue docs pass.
Bug fix
- Packaged builds rendered unstyled. The static-export HTTP server inside the Electron main process rejected any request whose pathname contained `..` as a traversal attempt. That blanket check also matched Turbopack's content-hashed CSS chunk filenames (e.g. `16-.0wq_hn57..css`), so the renderer 403'd its own stylesheet and loaded as raw HTML.
- Fix replaces the substring check with a per-segment check that only rejects literal traversal segments (`..` / `.`), so dots inside filenames pass through.
- File: `electron/main.ts`.
- User-visible: AppImage / deb / rpm / flatpak builds now look the same as `pnpm dev` again.
Docs
- New ARCHITECTURE.md (326 lines): system diagram, renderer & backend layout, HTTP API contract, project layout, build-from-source, VM-testing harness, pre-commit checks, contributing guide, and the release process used here.
- README rewrite: social-card hero image, CI / release / downloads / license badges, "Why ProtonShift?" intro, consolidated install section with copy-pasteable per-format commands (AppImage, deb, dnf, zypper, flatpak), roadmap, and a link to ARCHITECTURE.md in the nav strip.
Housekeeping
- Version bumped to 0.9.7 in all six sources (electron, renderer, python `version`, AppStream metainfo with new `<release date="2026-05-14">` entry, bug-report issue template placeholder, nav-bar fallback string).
- Zero open Dependabot alerts — all 18 from the previous window were closed by v0.9.6 and no new advisories appeared.
Verification
- `tsc` on Electron main: clean.
- `next build` (static export, Next 16.2.6): clean, 8/8 routes prerendered.
v0.9.6 — security hardening
Security maintenance release. Closes 18 open Dependabot alerts; no functional changes.
Direct bump
- Next.js 16.2.3 → 16.2.6 — closes 13 CVEs:
- High: segment-prefetch proxy bypass (incl. 16.2.6 incomplete-fix follow-up
GHSA-26hh-7cqf-hhc6), Pages-Router i18n proxy bypass, dynamic-route-param proxy bypass, SSRF on WebSocket upgrades, Server Component DoS, Cache-Components connection-exhaustion DoS. - Medium: CSP-nonce XSS in App Router,
beforeInteractivescript XSS, RSC response cache poisoning, Image Optimization API DoS, transitive postcss. - Low: Middleware/Proxy redirect cache poisoning, RSC cache-key collisions.
- High: segment-prefetch proxy bypass (incl. 16.2.6 incomplete-fix follow-up
Transitive overrides added (electron/package.json)
- postcss
<8.5.10→ ^8.5.10 (now 8.5.14 acrossnextand@tailwindcss/postcss) —GHSA-qx2v-qp2m-jg93(XSS via unescaped `</style>` in CSS stringify). - ip-address
<=10.1.0→ ^10.1.1 (now 10.2.0 viaelectron-builder → node-gyp → socks) —GHSA-v2v4-37r5-5v8g(XSS inAddress6HTML methods). Build-time only. - @xmldom/xmldom
<0.8.13→ ^0.8.13 (viaelectron-builder → plist) — closes 3 high CVEs (GHSA-f6ww-3ggp-fr8h,GHSA-j759-j44w-7fr8,GHSA-x6wf-f3px-wcqx: XML/PI/comment injection). Build-time only.
Overrides are version-pinned narrowly so they auto-disengage once upstreams legitimately ship the patched floor.
Context
- The renderer ships as a Next.js static export packaged inside Electron, so Next's server-runtime attack surface (Middleware, Image Optimization API, RSC server cache, WebSocket upgrades) is not reachable at runtime — but bundled dep versions are still patched.
- Electron is already on 39.8.5, which closes the 35 previously-listed Electron CVEs from the 38.x and 39.x advisories. No Electron change this round.
Verification
pnpm install(workspace, both packages) clean.tscon Electron main: clean.next build(static export, Next 16.2.6): clean — 8/8 routes prerendered.
v0.9.5
ProtonShift v0.9.5 — ScopeBuddy, gamepad tester, Ctrl+K command palette, new VM test harness.
Install
Grab the asset for your distro below once the build job finishes.
# AppImage (any distro)
chmod +x ProtonShift-*.AppImage && ./ProtonShift-*.AppImage
# .deb (Ubuntu / Pop!_OS / Mint / elementary OS)
sudo dpkg -i protonshift_*_amd64.deb
# .rpm (Fedora / openSUSE / RHEL)
sudo dnf install ProtonShift-*.rpm
# Flatpak
flatpak install ProtonShift-*.flatpak && flatpak run io.github.protonshiftWhat's new
App + UI
- Navbar version now reads
app.getVersion()via a new IPC bridge — no more stalev0.1brand string drifting behind releases. - Version sources synced to
0.9.5in lockstep:electron/package.json,electron/renderer/package.json,src/game_setup_hub/__init__.py, AppStream metainfo, bug report template.
Renderer features
- ScopeBuddy: dedicated
/scopebuddypage with KV override editor, per-game overrides, and detection toasts in the Gamescope builder. - Command palette (Ctrl+K) with cross-page navigation.
- Gamepad tester component on the Controllers page.
- Game detail rebuilt as KPI strip + tabs + profiles menu.
- Renderer-wide HeroUI v3 polish (semantic tokens replace ad-hoc opacity classes).
Python backend
- New
scopebuddymodule +/scopebuddyAPI routes (detect, read, write KV overrides). - Hardening across
gamescope,protontricks,presets,steam,tool_check,_vendor_compat. - API state/model split for testability; new
tests/test_scopebuddy.py.
Repo & dev experience
- New
vm-test/harness for exercising packaged builds against real distros via Quickemu (Ubuntu 24.04, Fedora 41, Debian 12, CachyOS, openSUSE Tumbleweed, Bazzite).run-vm.shstages docs into the SMB share so guests canless /mnt/protonshift-build/_docs/<distro>.mdwhile testing. docs/python-review.mdmoved underdocs/internal/.scripts/linux-matrix.shmoved underscripts/ci/.- Fixed accidentally-gitignored
vm-test/andtests/paths that had been hiding the harness and new tests from git.
Pre-release checks (local)
ruff check src/— cleanpytest -q— 103 passedtsc(electron-main) — cleantsc --noEmit(renderer) — clean
Linux packages (AppImage, .deb, .rpm, .flatpak) are built automatically by build-release.yml and attached to this release once the job finishes.
ProtonShift v0.9.0
Highlights
AppImage compatibility (closes #13 follow-up)
The vendored-native-extension fix shipped in v0.8.11 was a no-op on read-only squashfs. v0.9.0 ships the real fix:
_vendor_compat.pymutatessys.pathin memory instead of trying toshutil.rmtreethe bundledpydantic_core. AppImage users on a different Python minor version now silently fall back to the system copy.electron/main.tsno longer setsPYTHONNOUSERSITE=""(CPython treats that as truthy and disables user site-packages — the opposite of what we wanted).- Bundled native deps trimmed from 5 to 1: switched
uvicorn[standard]-> bareuvicorn(drops uvloop / httptools / watchfiles, all unnecessary for a localhost workload).
Backend security hardening
- 2 critical command-injection fixes:
protontricks.py(whitelist Steam app id + winetricks verb) anddisplay.py:set_resolution(whitelist monitor name againstget_monitors(), bound width/height/refresh). - Removed
--print-tokenCLI flag (avoids credentials ending up in journald / Electron logs). - Defense-in-depth
validate_user_path()calls insideprefix.pyandsaves.pyso each FS function refuses paths outside the user-writable roots even when called directly. - Per-launch bearer-token auth on every API endpoint (except
/health//docs). - CORS narrowed to
127.0.0.1/localhost.
Reliability
- Atomic writes everywhere. All config / VDF / env / profile / MangoHud / Heroic writes go through
fsutil.atomic_write_text(tempfile + fsync +os.replace). VDF endpoints also refuse to write while Steam is running, so we can't clobberlocalconfig.vdfmid-session. - Centralized path sanitizer (
paths.py) at every API boundary: rejects.., absolute overrides, null bytes, anything outside~//run/media//media//mnt//tmp. - Hardened backup/restore against zip-slip and added size + file-count tripwires.
Refactor
- The 1183-LOC
api.pyis now anapi/package:_state.py,_models.py,_helpers.py,_app.py, and 8 domain-specific routers underroutes/(games, system, saves, mangohud, heroic, profiles, utility, health). - Consolidated FS helpers into
fsutil.py(dir_size, human_size, atomic writes). - Promoted
_resolve_heroic_root->resolve_heroic_root. - Centralized logging setup (
logging_setup.py). - TTL cache on
steam.discover_games(200 ms). - Real SDL controller GUIDs (16-byte little-endian bus/vendor/product/version).
gamescopereturns both an argv list and a shell-safe quoted string.
Cleanup
- Deleted dead GTK4 UI (
app.py,__main__.py,theme.css) and the obsoleteprotonshiftconsole script. - Single source of truth for the version (
game_setup_hub.__version__-> exposed via FastAPIapp.version).
Tests + tooling
- New
tests/suite: 96 cases (was 0), covering VDF round-trip, env-var management, gamescope arg building, controllers, paths, fsutil, vendor-compat, protontricks/display whitelists, and a FastAPI smoke suite. ruff+pyright(standard mode) both clean.
Compatibility
- Bundled vs system Python: when the AppImage runs against a Python whose minor version doesn't match the build, the API now falls back to a system copy of
pydantic_core. If neither matches, you'll get a loud actionable warning instead of a silentModuleNotFoundError. - Token auth: any external integration calling the API directly must now send
Authorization: Bearer <token>(the token is inPROTONSHIFT_API_TOKEN, set by Electron at launch).
Full changelog
ProtonShift v0.8.11
Fix: AppImage crash on Python 3.13 systems (#13)
The AppImage failed to start on distros with Python 3.13 (e.g. CachyOS, latest Arch) with:
ModuleNotFoundError: No module named 'pydantic_core._pydantic_core'
Cause: The vendored pydantic_core native extension was compiled for Python 3.12 and wouldn't load on 3.13 due to ABI mismatch.
Fix: Added a startup compatibility layer (_vendor_compat.py) that detects when vendored native extensions don't match the running Python version and removes them so the system-installed packages are used instead. Also added python3-pydantic as a package dependency for .deb and .rpm builds.
Other changes
- CI now pins Python 3.12 via
actions/setup-python - Vendor script cleans up
__pycache__and dist-info bloat
Install
| Format | File |
|---|---|
| AppImage | ProtonShift-0.8.11.AppImage |
| Debian/Ubuntu | protonshift_0.8.11_amd64.deb |
| Fedora/RHEL | protonshift-0.8.11.x86_64.rpm |
| Flatpak | ProtonShift-0.8.11-x86_64.flatpak |
Full Changelog: v0.8.10...v0.8.11
ProtonShift v0.8.10
Fixes
- Controllers page crash — Fixed "This page couldn't load" error on the Controllers page. The HeroUI Alert component was missing a required
Alert.Contentwrapper, causing a React render crash when the error state was shown (e.g. backend unreachable).
Install
| Format | File |
|---|---|
| AppImage | ProtonShift-0.8.10.AppImage |
| Debian/Ubuntu | protonshift_0.8.10_amd64.deb |
| Fedora/RHEL | protonshift-0.8.10.x86_64.rpm |
| Flatpak | ProtonShift-0.8.10-x86_64.flatpak |
Full Changelog: v0.8.9...v0.8.10
ProtonShift v0.8.9
Fix: Tool detection on Bazzite & immutable distros
Gamescope, MangoHud, GameMode, and Protontricks were reported as "Not Installed" on Bazzite and other immutable Fedora Atomic distros (Kinoite, Silverblue, SteamOS) even when present on the system. (#10)
What changed
- New
tool_check.pymodule — all tool detection now uses a three-tier strategy: normal PATH lookup → extra immutable-distro bin directories (/var/usrlocal/bin,/usr/lib/extensions/, NixOS paths) → tool-specific known paths - Electron PATH augmentation — the Python backend now inherits additional bin paths that AppImage/Flatpak wrappers may strip
- Bazzite/SteamOS install hints — the "Not Installed" screens for Gamescope and MangoHud now list Bazzite/SteamOS as the first entry (pre-installed)
- All detection in
gamescope.py,mangohud.py,presets.py,protontricks.py, anddisplay.pymigrated to the shared helper
Install
Download the package for your distro below. Requires Python 3.12+.
| Format | File |
|---|---|
| AppImage | ProtonShift-0.8.9.AppImage |
| Debian/Ubuntu | protonshift_0.8.9_amd64.deb |
| Fedora/RHEL | protonshift-0.8.9.x86_64.rpm |
| Flatpak | ProtonShift-0.8.9-x86_64.flatpak |
Full Changelog: v0.8.8...v0.8.9
ProtonShift v0.8.8
What's Changed
Full Changelog: v0.8.7...v0.8.8
ProtonShift v0.8.7
Fix: packaged UI looked broken (unstyled / blank)
The Electron build loaded the Next static export with file://. Root-relative URLs such as /_next/static/... and /splash.png do not resolve correctly in that context, so scripts and CSS never loaded.
0.8.7 serves renderer/out/ from http://127.0.0.1:<ephemeral-port> when packaged (same idea as dev on http://localhost:3000), then opens that URL in the window.
Install
.deb:sudo apt install ./protonshift_0.8.7_amd64.deb- AppImage:
chmod +x ProtonShift-0.8.7.AppImage && ./ProtonShift-0.8.7.AppImage
ProtonShift v0.8.6
Fix: packaged app would not start
0.8.5 shipped the Python source tree but not FastAPI / Uvicorn / VDF, so the backend exited immediately and the window never appeared. 0.8.6 vendors those dependencies into the AppImage and .deb.
Install
- .deb:
sudo apt install ./protonshift_0.8.6_amd64.deb(orsudo dpkg -i …thensudo apt-get install -fif needed) - AppImage:
chmod +x ProtonShift-0.8.6.AppImage && ./ProtonShift-0.8.6.AppImage
You still need Python 3.12+ as python3 on your PATH; everything else for the API is bundled.
Debug from a terminal
If anything still fails, run /opt/ProtonShift/protonshift from a terminal and check [python] lines on stderr.