Conversation
- Introduced a new Flatpak manifest for the ProtonShift application, defining runtime, SDK, and necessary permissions. - Added build instructions for Python dependencies and the ProtonShift application itself. - Included a new social card image asset for enhanced sharing capabilities. This setup lays the groundwork for packaging ProtonShift as a Flatpak application.
* refactor(python): execute full backend review plan (P0+P1+P2+P3)
Implements every item from docs/python-review.md except a deferred follow-up
on bundling python-build-standalone. 70 new pytest cases, ruff and pyright
clean across src/ + tests/.
P0 — release blockers
- P0-1 AppImage native ext compatibility: rewrite _vendor_compat.py to mutate
sys.path instead of shutil.rmtree-ing files (no-op on read-only squashfs).
Drop uvicorn[standard] -> uvicorn (kills uvloop/httptools/watchfiles, 3 of
4 vendored .so). Trim _NATIVE_PACKAGES to actual deps (pydantic_core only).
Fix electron/main.ts: PYTHONNOUSERSITE = "" was truthy and disabled the
user site-packages fallback we wanted; now `delete env.PYTHONNOUSERSITE`.
- P0-2 single version source: __version__ in __init__.py is the only place,
api app + electron package.json read from it. Bump 0.8.11 -> 0.9.0.
- P0-3 declare pydantic in pyproject.toml + python-runtime-requirements.txt.
P1 — correctness / safety
- P1-1 path traversal: new paths.py with sanitize_filename, safe_join,
validate_user_path (rejects anything outside HOME / mounts / tmp).
Applied at every API boundary that accepts a caller-supplied path
(open-path, saves/restore, prefix delete, mangohud per-game,
profiles, fixes, heroic configs).
- P1-2 API auth + CORS: per-launch bearer token via PROTONSHIFT_API_TOKEN,
enforced by FastAPI middleware (compare_digest). CORS narrowed to
localhost:3000 + file:// renderer. /health exempt for readiness probe.
Electron mints the token, attaches it to every api-fetch.
- P1-3 atomic writes everywhere + Steam-running guard: vdf_config,
env_vars, mangohud, profiles_storage, fixes, heroic_config all use
fsutil.atomic_write_text now. update_launch_options + update_compat_tool
return 409 when Steam is running so we don't get clobbered.
- P1-4 fix get_power_profiles parsing bug (was overwriting parsed list with
a hardcoded one).
- P1-5 controllers: replace fake SDL GUID with canonical 16-byte
little-endian bus/vendor/product/version layout from libsdl2.
- P1-6 remove dead BUILTIN_PROTON constant; discovery already returns
these dynamically.
- P1-7 gamescope: build_gamescope_argv returns list[str] for Popen,
build_gamescope_cmd returns shlex.join'd shell-safe string.
P2 — maintainability
- P2-1 pytest suite: 70 tests covering fsutil, paths, env_vars, vdf_config,
tool_check, gamescope, controllers, vendor_compat, and end-to-end FastAPI
smoke (auth, CORS, Steam guard, path traversal rejection).
- P2-2 delete dead GTK app.py + __main__.py + theme.css; drop the
protonshift console script.
- P2-3 logging_setup.py: structured logging, replace silent except: pass
with logged warnings on narrow exception types.
- P2-4 split api.py (1183 LOC) into api/ package: _state, _models,
_helpers, _app + routes/{health,games,system,saves,mangohud,heroic,
profiles,utility}. Backwards-compat __getattr__ shim on the package
init for the legacy _API_TOKEN / _config_path attribute names.
- P2-5/7 fsutil.py: dir_size, human_size, atomic_write_text/bytes —
replaces 3 duplicated _dir_size implementations.
- P2-6 cache discover_games with a 5s TTL.
- P2-9 promote heroic._resolve_heroic_root to public resolve_heroic_root.
- P2-10 Electron picks the API port locally and passes --port; drops the
fragile stdout regex parsing.
P3 — style nits
- Hoist subprocess to module-level imports, fix ruff B904 chains, ruff
I001 import ordering, datetime.UTC for UP017, etc.
Files: 57 changed, +3669 / -2638. Net code is much smaller than it looks
(GTK app removed). Verification: ruff, pyright (strict), pytest all green.
Deferred to a separate PR: bundling python-build-standalone in the AppImage
to remove the residual system-pydantic dependency entirely.
Made-with: Cursor
* security: fix CodeQL alerts (2 critical command injection + 1 high token leak)
Addressed all alerts CodeQL flagged on PR #15:
Critical fixes:
- protontricks.py: whitelist app_id (digits) and verb (alphanumeric+._-)
before assembling the subprocess argv. Even though Popen with list args
doesn't shell-execute, validating at the boundary keeps the surface clean
and gives CodeQL a recognised sanitizer.
- display.py:set_resolution: whitelist monitor name against actually-detected
outputs from get_monitors(), and bound width/height/refresh to sane ranges.
High fixes:
- api/_app.py: remove the --print-token CLI flag. Standalone curl users
should set PROTONSHIFT_API_TOKEN themselves; we never want credentials
leaking into journald, IDE consoles, or Electron logs.
- prefix.py / saves.py: defensively call validate_user_path() inside
delete_prefix, get_prefix_info, find_save_paths, restore_backup, and
backup_saves so each function refuses paths outside the user-writable
roots even when called directly. This also satisfies CodeQL's data-flow
analysis on the path-injection chain that previously fired 17 times.
- saves.py: sanitize app_id everywhere it joins onto a path, not just
in backup_saves.
New tests (26 cases across 2 files):
- tests/test_protontricks.py — app_id and verb whitelist coverage incl.
shell metachars, traversal attempts, oversize values.
- tests/test_display.py — set_resolution rejects shell metachars,
unknown monitors, oversize dimensions, silly refresh rates.
Verification: ruff clean, pyright 0 errors, pytest 96/96.
Made-with: Cursor
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.
Release v0.9.0
This is the cumulative develop -> main promotion for the v0.9.0 release.
Headline changes
_vendor_compat.pynow mutatessys.pathinstead of attemptingshutil.rmtree(which is a silent no-op on read-only squashfs).electron/main.tsno longer setsPYTHONNOUSERSITE=""(which CPython treats as truthy and used to disable user site-packages). Vendored native deps trimmed from 5 to 1 (pydantic_core) by switchinguvicorn[standard]-> bareuvicorn.protontricks.py,display.py) and 1 high token-leak (api/_app.py --print-token). Added defensivevalidate_user_path()calls insideprefix.pyandsaves.pyFS functions for defense in depth on the path-injection chain./health//docs. CORS narrowed to127.0.0.1/localhostorigins.fsutil.atomic_write_text(tempfile + fsync +os.replace) so a crash mid-write can't truncate user data. VDF endpoints also refuse to write while Steam is running.api/package with_state.py,_models.py,_helpers.py,_app.py, and 8 domain-specific routers underroutes/.app.py,__main__.py,theme.cssdeleted along with the obsoleteprotonshiftconsole script.What's in this PR
refactor(python): execute full backend review plan)Verification
ruff check .cleanpyright0 errorspytest96/96 passingRelease plan
After merge, tag
v0.9.0and publish a GitHub release; that triggers.github/workflows/build-release.ymland ships the AppImage / .deb artifacts.Made with Cursor