Skip to content

Steam Runtime support#85

Open
iczero wants to merge 8 commits into
masterfrom
steamrt4
Open

Steam Runtime support#85
iczero wants to merge 8 commits into
masterfrom
steamrt4

Conversation

@iczero
Copy link
Copy Markdown
Member

@iczero iczero commented Apr 26, 2026

They stopped giving TF2 codenames to steamrt since 4 :(

Launch FA using GE-Proton running in the Steam Runtime. Setup will fetch both GE-Proton and steamrt without depending on a Steam install. Should hopefully fix a bunch of strange issues and ease installation.

Unfortunately the FAF client depends on libraries that are not included in steamrt, so it still runs outside the container.

Fixes #42

Summary by CodeRabbit

  • Documentation

    • Added an experimental-branch notice, streamlined Linux prerequisites, simplified troubleshooting, removed some distro-specific guidance, and bumped the recommended Java to Java 25.
  • New Features

    • Added official Steam Runtime and Proton update flows, improved Steam integration, and optional containerized runtime support for launches.
  • Chores

    • Switched downloads from wget to curl and expanded ignored runtime/artifact paths.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 26, 2026

Warning

Rate limit exceeded

@iczero has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 43 minutes and 8 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e7a216e0-ee30-415b-89fe-b67ae1b0d28c

📥 Commits

Reviewing files that changed from the base of the PR and between b814aea and d5a6fde.

📒 Files selected for processing (2)
  • README.md
  • setup.sh
📝 Walkthrough

Walkthrough

Adds Steam Runtime and Proton update flows, switches downloads from wget to curl/curlp, canonicalizes several paths, relocates env sourcing to basedir, introduces a containerized launch path (steamrt/run → launchwrapper-srt → wine), updates versions (DFC, Java, SteamRT, Proton GE), and removes XComposite checker tooling.

Changes

Ignore & Documentation

Layer / File(s) Summary
Ignore & README updates
.gitignore, README.md
Add ignore patterns for /steamrt, GE-Proton*/, *.exe, /directx; update README with SteamRT experimental notice, switch wgetcurl, add bubblewrap, adjust distro prerequisites, and update Java recommendation to JDK 25.

Launch & Runtime

Layer / File(s) Summary
Containerized launch flow
launchwrapper, launchwrapper-env, launchwrapper-srt
Make wrappers fail-fast, source env from basedir, canonicalize WINE/DXVK paths with readlink -f, construct bind mounts and PRESSURE_VESSEL vars, and exec into steamrt/run which runs launchwrapper-srt inside the container.

Setup & Paths

Layer / File(s) Summary
Setup adjustments
setup.sh, set-client-paths.sh, setup_dxvk.sh.patch
Add early bwrap preflight, require only Vulkan, switch downloads to curlp, simplify Proton/Wine discovery, generate relative common-env settings, enable Steam integration and use_wine_wow64, and hardcode wine wineboot for DXVK flow.

Updater changes

Layer / File(s) Summary
Update detection & component updaters
update.sh, update-component.sh
Add SteamRT and Proton update detection and update-component subcommands, switch fetches to curlp, make updater variables local, and persist steamrt/proton URLs to env.

Sequence Diagram(s)

sequenceDiagram
  participant User as User/Steam
  participant LW as launchwrapper
  participant LWE as launchwrapper-env
  participant SRT as steamrt/run
  participant LWSRT as launchwrapper-srt
  participant Wine as Wine/Proton

  User->>LW: invoke wrapper (game launch)
  LW->>LW: source common.sh (absolute path)\nset -e
  LW->>LWE: exec launchwrapper-env wine [args]

  LWE->>LWE: source common.sh & load-env\nnormalize paths (readlink -f)\nconfigure Wine env & bind list
  LWE->>SRT: exec steamrt/run launchwrapper-srt [args]

  SRT->>SRT: initialize container runtime
  SRT->>LWSRT: start launchwrapper-srt inside container

  LWSRT->>LWSRT: determine basedir\nadjust PATH (WOW64/non-WOW64)\noptionally append host usr paths
  LWSRT->>Wine: exec wine [original args]

  Wine->>User: run game and return status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I hopped into scripts at dawn,
I curled the streams and stripped the brawn,
SteamRT hummed a cozy tune,
Proton danced beneath the moon,
A launcher leaps — the game is on!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Steam Runtime support' accurately describes the primary change: adding Steam Runtime support for launching Forged Alliance.
Linked Issues check ✅ Passed The PR successfully implements all core requirements from issue #42: adopts Steam Linux Runtime (steamrt), integrates pressure-vessel for containerized runtime, uses GE-Proton instead of prebuilt Wine, reduces host environment dependencies, and improves reproducibility.
Out of Scope Changes check ✅ Passed All changes align with Steam Runtime integration objectives: dependency updates (wget→curl, Java 17→25, DXVK/Proton versions), shell script refactoring (readlink canonicalization, environment variables), removal of obsolete checks, and documentation updates are all within scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch steamrt4

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (11)
update-component.sh (3)

1-10: Stale top-of-file comment.

The header still says it supports only dxvk and faf-client, but the script now also handles java, steamrt, and proton.

♻️ Proposed fix
 #!/usr/bin/env bash
 # Update specific components
-# Currently supports updating dxvk and the faf client
+# Supports updating: dxvk, faf-client, java, steamrt, proton
 set -e
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@update-component.sh` around lines 1 - 10, Update the stale script header in
update-component.sh: replace or expand the top-of-file comment that currently
reads "Currently supports updating dxvk and the faf client" to accurately
reflect all supported components (dxvk, faf-client, java, steamrt, proton) or
change it to a generic statement like "Supports updating various components
(dxvk, faf-client, java, steamrt, proton)"; ensure this updated summary is the
first comment block immediately after the shebang so callers and maintainers see
the correct supported list.

118-141: update-proton is not atomic — a failed extract leaves a half-populated Proton dir.

update-steamrt (lines 90–116) carefully extracts into steamrt.new, swaps steamrtsteamrt.old, then renames. update-proton instead extracts straight into the cwd, so an interrupted/failed tar (network drop, OOM, bad archive) yields a partially extracted GE-ProtonX-XX/ that subsequent runs may mistake for a complete install ([[ -d "$proton_path" ]] on line 125 only logs an overwrite note, it does not re-extract from scratch).

Recommend mirroring the steamrt pattern, or at minimum removing the target dir before extraction so a partial result is never treated as valid.

♻️ Suggested approach (minimal)
 function update-proton() {
     local proton_url="$1"

     block-print "Downloading Proton"
     curlp -o "proton.tar.gz" "$proton_url"
     block-print "Extracting Proton"
     local proton_path="$(tar -tf "proton.tar.gz" | head -n 1 | cut -d '/' -f 1)"
+    if [[ -z "$proton_path" ]]; then
+        echo "ERROR: could not determine proton archive top-level dir" >&2
+        exit 1
+    fi
     if [[ -d "$proton_path" ]]; then
-        echo "note: requested proton version already exists, overwriting"
+        echo "note: requested proton version already exists, removing for clean re-extract"
+        rm -rf "$proton_path"
     fi
     # exclude wine mono and gecko, they are somewhat large (~450MB combined) and we never use them
     tar \
         --exclude="$proton_path/files/share/wine/mono" \
         --exclude="$proton_path/files/share/wine/gecko" \
         --exclude="$proton_path/protonfixes" \
         -xvf "proton.tar.gz"
     rm "proton.tar.gz"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@update-component.sh` around lines 118 - 141, The update-proton function is
not atomic: modify update-proton so it extracts into a temporary directory
(e.g., "$proton_path.new") instead of directly into cwd, validate/complete the
extraction there, then atomically rename/swap the directories (move existing
"$proton_path" to "$proton_path.old" and rename "$proton_path.new" to
"$proton_path"); ensure you still pass the same --exclude flags to tar, clean up
any ".new" or ".old" on failure, and only call write-env ("proton_path" and
"proton_download_url_current") after the rename succeeds; reference
update-proton, proton_path, and write-env when making the change.

90-116: LGTM — atomic swap pattern for steamrt is well done.

Extract-to-steamrt.new → rename current to steamrt.old → promote steamrt.new → cleanup steamrt.old is exactly the right pattern: an interrupted run is recoverable on the next invocation, and there's no window where steamrt doesn't exist while a new one is half-extracted. Nice.

One minor follow-up: consider also recovering from a stale steamrt.old left behind by a previous interrupted run (e.g., move it out of the way or remove it before starting), otherwise that path is only cleaned up after a successful extraction.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@update-component.sh` around lines 90 - 116, The update-steamrt function
currently only removes steamrt.old after a successful swap, so a stale
steamrt.old from a prior interrupted run can persist and never be cleaned;
modify update-steamrt to detect and handle an existing "steamrt.old" early (for
example before extraction or before renaming the current steamrt) by moving it
out of the way or removing it (ensure you reference the same "steamrt.old"
symbol), so the atomic-swap logic (mkdir steamrt.new, tar into steamrt.new, mv
steamrt steamrt.old, mv steamrt.new steamrt) can run without accumulating old
backups and still remain recoverable on interruption.
.gitignore (1)

15-15: Anchor GE-Proton*/ to repo root for consistency.

Other top-level directory entries (e.g., /steamrt, /jdk-*, /dxvk-*, /prefix) are anchored with a leading slash. Without it, GE-Proton*/ would also match nested directories with the same naming pattern, which is likely not intended given Proton is extracted at the repo root.

♻️ Proposed fix
 /steamrt
-GE-Proton*/
+/GE-Proton*/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.gitignore at line 15, The .gitignore entry "GE-Proton*/" is not anchored
and may match nested directories; update the entry to anchor it to the
repository root by prefixing it with a leading slash (i.e., change "GE-Proton*/"
to "/GE-Proton*/") so it only ignores top-level Proton extractions; make this
edit in the .gitignore file where the "GE-Proton*/" pattern appears.
common.sh (1)

46-49: Add -f (or --fail-with-body) to curlp to surface HTTP errors.

Without --fail, curl exits with status 0 on 4xx/5xx and writes the server's error body into the output file. Downstream tar -xvf will then fail with a confusing message far from the root cause (a 404 or transient 5xx). This will bite particularly hard on the update-steamrt and update-proton paths.

--fail-with-body (available since curl 7.76.0) is preferable as it returns an error code while preserving error details. If broader compatibility is needed, use --fail alone.

🛡️ Proposed fix
 function curlp() {
     # curl with progress bar
-    curl --progress-bar -L "$@"
+    curl --fail-with-body --progress-bar -L "$@"
 }

For older curl versions or if --fail-with-body is unavailable, use --fail instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@common.sh` around lines 46 - 49, Update the curlp() helper to pass curl's
failure flag so HTTP 4xx/5xx return non-zero; in the curlp() function add
--fail-with-body to the curl invocation (or --fail as a fallback for older curl
versions) so errors are surfaced instead of producing a successful exit code
with an error body; ensure the change targets the curl --progress-bar -L "$@"
invocation inside function curlp.
launchwrapper-env (2)

10-10: pushd/popd print to stdout and pollute downstream consumers.

launchwrapper-env is invoked by launchwrapper and by setup.sh, and its stdout may be read by tools/log scrapers. pushd "$basedir" will emit the directory stack to stdout (and popd likewise). Redirect both to /dev/null, or just use cd "$basedir" since you don’t actually need a stack here.

♻️ Proposed change
-pushd "$basedir"
+pushd "$basedir" > /dev/null
@@
-popd
+popd > /dev/null

Also applies to: 59-59

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@launchwrapper-env` at line 10, The use of pushd "$basedir" (and the matching
popd) in launchwrapper-env prints the directory stack to stdout and pollutes
downstream consumers; change these to either redirect their output to /dev/null
(e.g., pushd "$basedir" > /dev/null 2>&1 and popd > /dev/null 2>&1) or simply
replace pushd/popd with cd "$basedir" since no directory stack is required —
update the occurrences of pushd "$basedir" and the corresponding popd
accordingly.

12-12: readlink -f on potentially missing/empty values can silently produce surprising paths.

If wineprefix, dxvk_config_file, dxvk_cache_dir, or proton_path are unset/empty (e.g., upgrading without re-running setup.sh, or update-component.sh proton failing midway and not writing proton_path), readlink -f "" returns the empty string and the export ends up as KEY="". Combined with set -e, that won’t fail here, but later pressure-vessel invocations will get an empty proton_path and produce confusing errors. Consider validating these in load-env (or right here) before exporting:

for v in wineprefix dxvk_config_file dxvk_cache_dir proton_path; do
    [[ -n "${!v}" ]] || { echo "error: $v is not set; please re-run setup.sh" >&2; exit 1; }
done

Also applies to: 17-18, 33-33

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@launchwrapper-env` at line 12, The exports that use readlink -f (e.g., export
WINEPREFIX="$(readlink -f "$wineprefix")") can silently produce empty values if
variables like wineprefix, dxvk_config_file, dxvk_cache_dir, or proton_path are
unset; add a pre-export validation loop (run in load-env or at top of this file)
that iterates over those variable names (wineprefix, dxvk_config_file,
dxvk_cache_dir, proton_path) and fails fast with a clear error and non-zero exit
if any are empty, before calling readlink -f and exporting them, so downstream
pressure-vessel/proton invocations never receive empty paths.
launchwrapper-srt (2)

5-5: Unused basedir.

basedir is computed but never referenced in this script. Either remove it or use it (e.g., to source common.sh/load-env if you want consistent env semantics inside the container).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@launchwrapper-srt` at line 5, The script defines basedir via
basedir="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" but never uses it;
either remove that line or use basedir to locate and source shared files—e.g.,
change calls that source environment or helpers to use "${basedir}/common.sh" or
"${basedir}/load-env" (or similar) so the script consistently loads env/commons
relative to its location; if you opt to remove it simply delete the basedir
assignment.

13-15: Quote the literal and align indentation.

For consistency with line 7 and to avoid surprises if path_append_host_usr ever contains whitespace/glob chars, quote "1". Also, this block uses 4-space indent while the block above uses 2-space — pick one.

♻️ Proposed change
-if [[ "$path_append_host_usr" = 1 ]]; then
-    export PATH="$PATH:/run/host/usr/bin:/run/host/usr/sbin"
-fi
+if [[ "$path_append_host_usr" = "1" ]]; then
+  export PATH="$PATH:/run/host/usr/bin:/run/host/usr/sbin"
+fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@launchwrapper-srt` around lines 13 - 15, Update the conditional to quote the
literal and match the surrounding indentation: change the test to compare
"$path_append_host_usr" = "1" (quote the "1") and align the block's indentation
to the existing style used above (use the same 2-space indentation for the
export line and fi) so the PATH export lines and conditional use consistent
quoting and spacing; locate the block around the variable path_append_host_usr
and the export PATH assignment to apply this fix.
launchwrapper (1)

17-24: Dead gamescope block — consider removing rather than commenting out.

The : <<'EOF' … EOF heredoc neutralizes the gamescope selection logic, but the resulting $GAMESCOPE variable is never consumed by line 26 anyway (the new exec ignores it). Either restore gamescope support by passing it through launchwrapper-env, or drop the dead block to keep the file readable. Leaving it as a heredoc invites bitrot.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@launchwrapper` around lines 17 - 24, The heredoc block neutralizing the
gamescope logic (the GAMESCOPE variable and the use_gamescope check) is dead
code because exec no longer consumes GAMESCOPE; either restore gamescope support
by wiring GAMESCOPE into the startup path (e.g., pass it through
launchwrapper-env or incorporate it before the exec that starts the game) or
remove the entire heredoc and related GAMESCOPE/use_gamescope handling to avoid
bitrot; update or delete references to GAMESCOPE and use_gamescope so the script
is consistent with the new exec behavior.
setup.sh (1)

157-173: Switching wineprefix/DXVK paths to relative may break existing installs on upgrade.

Pre-PR, these were typically absolute paths written into common-env. Existing users who only run update.sh (not setup.sh) will retain their old absolute paths, but new launchwrapper-env/launchwrapper-srt containerized code now relies on pushd "$basedir" + readlink -f to resolve them. That works for either form, so nothing breaks today — but if you intend the relative form to be canonical (e.g., for portability of the install dir), document the expectation, or have setup.sh fail-soft warn users to re-run setup after the SteamRT migration.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@setup.sh` around lines 157 - 173, The change to write relative paths
(wineprefix, dxvk_cache_dir, game_path, game_data_path, steam_path) can break
upgrades; fix it by canonicalizing paths before calling write-env: resolve
wineprefix, STEAM_PATH, GAME_PATH, and GAME_DATA_PATH with readlink -f (or
otherwise convert to absolute) so the values written by write-env are stable,
and add a fail-soft warning in setup.sh (near the wineprefix/dxvk_cache_dir
block) telling users to re-run setup if they previously had absolute paths or
after the SteamRT migration; reference the write-env calls and variables
wineprefix, dxvk_cache_dir, GAME_PATH, GAME_DATA_PATH, STEAM_PATH, and the
existing pushd "$basedir" + readlink -f logic to guide where to apply the fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@launchwrapper`:
- Around line 11-15: The comment incorrectly claims pressure-vessel filters
LD_PRELOAD; update the launchwrapper to remove or revise the TODO and clarify
that LD_PRELOAD set by the script (export LD_PRELOAD="$(readlink -f
"$steam_path/ubuntu12_32/gameoverlayrenderer.so")") will propagate into the
SteamRT container via launchwrapper-env, and that the real concern is whether
that path is bind-mounted (PRESSURE_VESSEL_FILESYSTEMS_RW) and accessible inside
the container; either remove the misleading TODO, or replace it with a note to
prefer setting LD_PRELOAD inside the container after mount setup (or use
pressure-vessel env mechanisms) and also remove or mark the dead gamescope block
(lines containing the disabled gamescope code) as intentional dead code.

In `@launchwrapper-env`:
- Around line 45-57: The script currently builds bind_paths and exports
PRESSURE_VESSEL_FILESYSTEMS_RW using only basedir, game_path, and steam_path,
which will leave proton_path unmounted if Proton is outside basedir; modify the
bind_paths logic (the array used to compute PRESSURE_VESSEL_FILESYSTEMS_RW) to
either append "$(readlink -f "$proton_path")" when proton_path is set and
non-empty or add a runtime assertion that proton_path resides under basedir
(e.g., compare readlink -f "$proton_path" with readlink -f "$basedir") and fail
early with a clear error; update the code that constructs bind_paths (the
bind_paths array and its conditional for steam_path) so proton_path is handled
the same way as steam_path to avoid silent runtime failures.

In `@launchwrapper-srt`:
- Around line 7-11: The faf_use_wow64 conditional in the launchwrapper script is
dead code because faf_use_wow64 is never initialized; either wire faf_use_wow64
into the initialization chain (set it in setup.sh or export it from
launchwrapper-env) so the branch can be taken, or remove the branch and always
use the regular bin path; specifically either add a clear assignment/export of
faf_use_wow64 (true/1 or false/0) in setup.sh or launchwrapper-env before the
block that references faf_use_wow64, or delete the if/else that toggles between
"$proton_path/files/bin-wow64/" and "$proton_path/files/bin/" to avoid
maintaining unused bin-wow64 logic.

In `@set-client-paths.sh`:
- Around line 12-14: The jq invocation that sets installationPath and
preferencesFile uses readlink -f on $game_path and $game_data_path which can
return empty on error and silently write "" into client.prefs; update the script
to capture the results of readlink -f into temporaries (e.g. resolved_game_path
and resolved_prefs_path), validate they are non-empty before calling jq (or fall
back to the original $game_path/$game_data_path), and if they are empty either
abort with a clear error or use the original literal path so installationPath
and preferencesFile are not overwritten with an empty string; adjust the jq
--arg invocations to use these validated variables (referencing installationPath
/ preferencesFile, $game_path, $game_data_path, and the jq call that builds
wrapper).

In `@update-component.sh`:
- Around line 70-88: In update-java(), the overwrite check references an
undefined variable java_path_orig so it never triggers; change the existence
check to use the computed java_path (or capture the pre-extract path into
java_path_orig before extraction) — e.g., compute local java_path="$(tar -tf
"java.tar.gz" | head -n 1 | cut -d '/' -f 1)" and then test [[ -d "$java_path"
]] (or assign that value to java_path_orig and test it) before running tar -xvf,
so the "overwriting" warning is shown correctly.

In `@update.sh`:
- Around line 97-103: The branch comparing proton_download_url_target and
proton_download_url_current dispatches the wrong subcommand: change the call to
./update-component.sh from steamrt to proton so the Proton update path is used;
specifically, in the block where proton_download_url_target !=
proton_download_url_current (and where has_updates and perform_update are
set/checked), replace ./update-component.sh steamrt
"$proton_download_url_target" with ./update-component.sh proton
"$proton_download_url_target" to ensure the Proton installer is invoked.

---

Nitpick comments:
In @.gitignore:
- Line 15: The .gitignore entry "GE-Proton*/" is not anchored and may match
nested directories; update the entry to anchor it to the repository root by
prefixing it with a leading slash (i.e., change "GE-Proton*/" to "/GE-Proton*/")
so it only ignores top-level Proton extractions; make this edit in the
.gitignore file where the "GE-Proton*/" pattern appears.

In `@common.sh`:
- Around line 46-49: Update the curlp() helper to pass curl's failure flag so
HTTP 4xx/5xx return non-zero; in the curlp() function add --fail-with-body to
the curl invocation (or --fail as a fallback for older curl versions) so errors
are surfaced instead of producing a successful exit code with an error body;
ensure the change targets the curl --progress-bar -L "$@" invocation inside
function curlp.

In `@launchwrapper`:
- Around line 17-24: The heredoc block neutralizing the gamescope logic (the
GAMESCOPE variable and the use_gamescope check) is dead code because exec no
longer consumes GAMESCOPE; either restore gamescope support by wiring GAMESCOPE
into the startup path (e.g., pass it through launchwrapper-env or incorporate it
before the exec that starts the game) or remove the entire heredoc and related
GAMESCOPE/use_gamescope handling to avoid bitrot; update or delete references to
GAMESCOPE and use_gamescope so the script is consistent with the new exec
behavior.

In `@launchwrapper-env`:
- Line 10: The use of pushd "$basedir" (and the matching popd) in
launchwrapper-env prints the directory stack to stdout and pollutes downstream
consumers; change these to either redirect their output to /dev/null (e.g.,
pushd "$basedir" > /dev/null 2>&1 and popd > /dev/null 2>&1) or simply replace
pushd/popd with cd "$basedir" since no directory stack is required — update the
occurrences of pushd "$basedir" and the corresponding popd accordingly.
- Line 12: The exports that use readlink -f (e.g., export WINEPREFIX="$(readlink
-f "$wineprefix")") can silently produce empty values if variables like
wineprefix, dxvk_config_file, dxvk_cache_dir, or proton_path are unset; add a
pre-export validation loop (run in load-env or at top of this file) that
iterates over those variable names (wineprefix, dxvk_config_file,
dxvk_cache_dir, proton_path) and fails fast with a clear error and non-zero exit
if any are empty, before calling readlink -f and exporting them, so downstream
pressure-vessel/proton invocations never receive empty paths.

In `@launchwrapper-srt`:
- Line 5: The script defines basedir via basedir="$(dirname "$(readlink -f
"${BASH_SOURCE[0]}")")" but never uses it; either remove that line or use
basedir to locate and source shared files—e.g., change calls that source
environment or helpers to use "${basedir}/common.sh" or "${basedir}/load-env"
(or similar) so the script consistently loads env/commons relative to its
location; if you opt to remove it simply delete the basedir assignment.
- Around line 13-15: Update the conditional to quote the literal and match the
surrounding indentation: change the test to compare "$path_append_host_usr" =
"1" (quote the "1") and align the block's indentation to the existing style used
above (use the same 2-space indentation for the export line and fi) so the PATH
export lines and conditional use consistent quoting and spacing; locate the
block around the variable path_append_host_usr and the export PATH assignment to
apply this fix.

In `@setup.sh`:
- Around line 157-173: The change to write relative paths (wineprefix,
dxvk_cache_dir, game_path, game_data_path, steam_path) can break upgrades; fix
it by canonicalizing paths before calling write-env: resolve wineprefix,
STEAM_PATH, GAME_PATH, and GAME_DATA_PATH with readlink -f (or otherwise convert
to absolute) so the values written by write-env are stable, and add a fail-soft
warning in setup.sh (near the wineprefix/dxvk_cache_dir block) telling users to
re-run setup if they previously had absolute paths or after the SteamRT
migration; reference the write-env calls and variables wineprefix,
dxvk_cache_dir, GAME_PATH, GAME_DATA_PATH, STEAM_PATH, and the existing pushd
"$basedir" + readlink -f logic to guide where to apply the fix.

In `@update-component.sh`:
- Around line 1-10: Update the stale script header in update-component.sh:
replace or expand the top-of-file comment that currently reads "Currently
supports updating dxvk and the faf client" to accurately reflect all supported
components (dxvk, faf-client, java, steamrt, proton) or change it to a generic
statement like "Supports updating various components (dxvk, faf-client, java,
steamrt, proton)"; ensure this updated summary is the first comment block
immediately after the shebang so callers and maintainers see the correct
supported list.
- Around line 118-141: The update-proton function is not atomic: modify
update-proton so it extracts into a temporary directory (e.g.,
"$proton_path.new") instead of directly into cwd, validate/complete the
extraction there, then atomically rename/swap the directories (move existing
"$proton_path" to "$proton_path.old" and rename "$proton_path.new" to
"$proton_path"); ensure you still pass the same --exclude flags to tar, clean up
any ".new" or ".old" on failure, and only call write-env ("proton_path" and
"proton_download_url_current") after the rename succeeds; reference
update-proton, proton_path, and write-env when making the change.
- Around line 90-116: The update-steamrt function currently only removes
steamrt.old after a successful swap, so a stale steamrt.old from a prior
interrupted run can persist and never be cleaned; modify update-steamrt to
detect and handle an existing "steamrt.old" early (for example before extraction
or before renaming the current steamrt) by moving it out of the way or removing
it (ensure you reference the same "steamrt.old" symbol), so the atomic-swap
logic (mkdir steamrt.new, tar into steamrt.new, mv steamrt steamrt.old, mv
steamrt.new steamrt) can run without accumulating old backups and still remain
recoverable on interruption.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 06f86a78-dd1a-4af8-831e-1abe80082c9f

📥 Commits

Reviewing files that changed from the base of the PR and between 0a98a3f and f549744.

📒 Files selected for processing (15)
  • .gitignore
  • README.md
  • common.sh
  • install-shortcut.sh
  • launchwrapper
  • launchwrapper-env
  • launchwrapper-srt
  • run
  • set-client-paths.sh
  • setup.sh
  • setup_dxvk.sh.patch
  • tools/check_xcomposite.py
  • update-component.sh
  • update.sh
  • versions
💤 Files with no reviewable changes (2)
  • setup_dxvk.sh.patch
  • tools/check_xcomposite.py

Comment thread launchwrapper
Comment thread launchwrapper-env
Comment thread launchwrapper-srt Outdated
Comment thread set-client-paths.sh
Comment thread update-component.sh
Comment thread update.sh Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (7)
setup.sh (2)

181-184: Component install ordering: confirm steamrt is downloaded before any launchwrapper-env invocation.

steamrt and proton are downloaded at lines 183–184, then launchwrapper-env wine wineboot -u runs at line 187. Since launchwrapper-env now execs "$basedir/steamrt/run" (line 61 of launchwrapper-env), this ordering is required — please keep these update-component.sh steamrt|proton calls strictly before any launchwrapper-env usage. Consider adding a brief comment at line 181 to document that invariant.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@setup.sh` around lines 181 - 184, The script currently must ensure steamrt
and proton are downloaded before any use of launchwrapper-env because
launchwrapper-env execs "$basedir/steamrt/run"; move or confirm the two
update-component.sh calls for "steamrt" and "proton" remain immediately before
any launchwrapper-env invocation (e.g., before the line that runs
launchwrapper-env wine wineboot -u), and add a short comment above those
update-component.sh lines noting the invariant ("steamrt/proton must be updated
before any launchwrapper-env execs $basedir/steamrt/run") so future edits don’t
reorder them.

157-172: Relative paths written to common-env rely on consumers cd-ing to basedir first.

wineprefix, dxvk_config_file, and dxvk_cache_dir are now stored as bare relative names (prefix, dxvk.conf, dxvk-cache). This works because launchwrapper-env was updated to pushd "$basedir" before resolving them with readlink -f, and update-component.sh does its own cd "$basedir". Be aware that any future script consuming these values must do the same — otherwise readlink -f will silently return a path relative to the caller's CWD. Worth a brief comment in common-env/common.sh noting this contract, or alternatively writing them as "$basedir/prefix" etc. to be self-contained.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@setup.sh` around lines 157 - 172, The values written by write-env for
wineprefix, dxvk_config_file and dxvk_cache_dir are relative (e.g.,
wineprefix="prefix") which will produce caller-dependent results when later
resolved with readlink -f; update the write to store absolute paths (prefix with
the base directory) or add a clear comment in common-env/common.sh documenting
the contract that every consumer (e.g., launchwrapper-env and
update-component.sh) must cd/pushd to $basedir before resolving these variables;
target the write-env calls for wineprefix, dxvk_config_file and dxvk_cache_dir
(and any other relative path variables) and either prepend "$basedir/" when
writing them or add the contract comment near common-env/common.sh so future
consumers know to cd into $basedir first.
update-component.sh (2)

118-141: update-proton extracts over an existing install in place — stale files can persist.

Unlike update-steamrt, this overwrites the existing $proton_path directory directly. If the new tarball renames or drops files (or if the user switches to a different Proton-GE version that maps to the same top-level directory), residual files from the previous install will linger inside files/. Consider applying the same stage-and-rename pattern as update-steamrt, or at minimum rm -rf "$proton_path" before extracting when the directory already exists. Note this is consistent with how update-java behaves today, so it's a pre-existing pattern — flagging for visibility, not a blocker.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@update-component.sh` around lines 118 - 141, The update-proton function
currently extracts the tarball into the existing proton_path which can leave
stale files; fix it by adopting the same pattern as update-steamrt/update-java:
either remove the existing directory before extraction (rm -rf "$proton_path")
or, better, extract into a temporary staging directory and atomically rename it
to proton_path after successful extraction; ensure you reference update-proton,
proton_path, proton_url, the tar extraction step and the write-env calls so the
staging/cleanup happens before write-env "proton_path" and
"proton_download_url_current" are written and only on successful extraction.

76-76: Shellcheck SC2155: declare and assign separately.

local foo="$(...)" masks the subshell's exit status, so a failure of tar -tf | head | cut (e.g., a corrupted archive) won't trip set -e. Low-impact here because the subsequent tar -xvf would also fail, but worth fixing per shellcheck.

♻️ Proposed fix (apply analogously to lines 42, 76, 124)
-    local proton_path="$(tar -tf "proton.tar.gz" | head -n 1 | cut -d '/' -f 1)"
+    local proton_path
+    proton_path="$(tar -tf "proton.tar.gz" | head -n 1 | cut -d '/' -f 1)"

Also applies to: 124-124

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@update-component.sh` at line 76, The local variable assignment for java_path
is done in one step using a subshell which masks the subshell exit status;
change to declare the variable first (local java_path) and then assign it in a
separate statement (java_path="$(tar -tf "java.tar.gz" | head -n 1 | cut -d '/'
-f 1)") so failures in the pipeline won't be hidden; apply the same pattern to
the other similar occurrences (the other places that currently use local
VAR="$(...)" in this script).
launchwrapper-env (1)

33-33: readlink -f "$proton_path" on an unset/empty proton_path will produce an empty string under set -e-safe code.

If common-env has not yet had proton_path written (e.g., a partial setup or hand-edited env), readlink -f "" outputs an empty string, and the subsequent pressure-vessel invocation will then run with proton_path="" — failing later with a less obvious error. Consider asserting proton_path is non-empty here:

🛡️ Proposed guard
+if [[ -z "$proton_path" ]]; then
+    echo "error: proton_path is not set; did setup.sh / update-component.sh proton run successfully?" >&2
+    exit 1
+fi
 export proton_path="$(readlink -f "$proton_path")"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@launchwrapper-env` at line 33, The line exporting proton_path via export
proton_path="$(readlink -f "$proton_path")" can yield an empty string when
proton_path is unset, so add an explicit guard before this transformation: check
that the variable proton_path is non-empty (e.g., test -n "$proton_path") and
fail with a clear error message and non-zero exit if it is empty, then only call
readlink -f and export the resolved path; reference the proton_path variable and
the readlink -f usage to locate where to add the check and exit to prevent
running pressure-vessel with an empty proton_path.
update.sh (1)

73-79: Consider whether a Proton bump should re-run wineboot or refresh DXVK in the existing prefix.

When the bundled Proton/Wine version changes, the existing $wineprefix may end up running against newer Wine binaries without an updater pass, and the previously installed DXVK DLLs are still those of the prior version. setup.sh runs wineboot -u and dxvk-install.sh after Proton install; update.sh does not. Worth confirming whether at least a wineboot -u (and possibly re-running update-component.sh dxvk) is desired here — otherwise users may hit subtle prefix/DLL version skew after a Proton bump.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@update.sh` around lines 73 - 79, When the Proton download URL changes
(compare proton_download_url_target vs proton_download_url_current) ensure the
update path not only calls update-component.sh proton but also refreshes the
existing prefix: after a successful Proton update (inside the
perform_update="yes" branch where update-component.sh proton is invoked) run a
wineboot -u against the configured $wineprefix and re-run the DXVK installer
(either dxvk-install.sh or update-component.sh dxvk) so the prefix DLLs match
the new Wine/Proton binaries; guard these steps to only run if the $wineprefix
exists and the proton update completed successfully.
common.sh (1)

4-9: block-print no longer space-separates multiple args.

Switching from echo "$@" to printf '%s' "$@" concatenates positional args without separators. All current callers pass a single string, so this is fine, but if a future caller writes block-print "Downloading" "Steam Runtime", it will print DownloadingSteam Runtime. Consider printf '%s\n' "$*" (or printf '%s ' "$@"; echo) if you want IFS-separated joining; otherwise this is OK as-is.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@common.sh` around lines 4 - 9, The block-print function currently uses printf
'%s' "$@" which concatenates multiple positional arguments without separators
(e.g., "Downloading" "Steam Runtime" -> "DownloadingSteam Runtime"); update
block-print (function name block-print) to join args with spaces or print each
arg on its own line—for example replace the printf call with printf '%s\n' "$*"
to preserve spaces between arguments or use printf '%s ' "$@"; echo to produce a
single space-separated line—so future callers passing multiple args behave as
expected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@update-component.sh`:
- Around line 90-116: In update-steamrt, prevent accidental nesting when
renaming by ensuring any stale "steamrt.old" is removed before calling mv
"steamrt" "steamrt.old" (or use mv -T "steamrt" "steamrt.old" on systems with
GNU mv); specifically, before the mv call in update-steamrt, check for and rm
-rf "steamrt.old" if it exists so the rename cannot move the new steamrt into an
existing directory, then proceed with the mv and subsequent cleanup and
write-env steps.

---

Nitpick comments:
In `@common.sh`:
- Around line 4-9: The block-print function currently uses printf '%s' "$@"
which concatenates multiple positional arguments without separators (e.g.,
"Downloading" "Steam Runtime" -> "DownloadingSteam Runtime"); update block-print
(function name block-print) to join args with spaces or print each arg on its
own line—for example replace the printf call with printf '%s\n' "$*" to preserve
spaces between arguments or use printf '%s ' "$@"; echo to produce a single
space-separated line—so future callers passing multiple args behave as expected.

In `@launchwrapper-env`:
- Line 33: The line exporting proton_path via export proton_path="$(readlink -f
"$proton_path")" can yield an empty string when proton_path is unset, so add an
explicit guard before this transformation: check that the variable proton_path
is non-empty (e.g., test -n "$proton_path") and fail with a clear error message
and non-zero exit if it is empty, then only call readlink -f and export the
resolved path; reference the proton_path variable and the readlink -f usage to
locate where to add the check and exit to prevent running pressure-vessel with
an empty proton_path.

In `@setup.sh`:
- Around line 181-184: The script currently must ensure steamrt and proton are
downloaded before any use of launchwrapper-env because launchwrapper-env execs
"$basedir/steamrt/run"; move or confirm the two update-component.sh calls for
"steamrt" and "proton" remain immediately before any launchwrapper-env
invocation (e.g., before the line that runs launchwrapper-env wine wineboot -u),
and add a short comment above those update-component.sh lines noting the
invariant ("steamrt/proton must be updated before any launchwrapper-env execs
$basedir/steamrt/run") so future edits don’t reorder them.
- Around line 157-172: The values written by write-env for wineprefix,
dxvk_config_file and dxvk_cache_dir are relative (e.g., wineprefix="prefix")
which will produce caller-dependent results when later resolved with readlink
-f; update the write to store absolute paths (prefix with the base directory) or
add a clear comment in common-env/common.sh documenting the contract that every
consumer (e.g., launchwrapper-env and update-component.sh) must cd/pushd to
$basedir before resolving these variables; target the write-env calls for
wineprefix, dxvk_config_file and dxvk_cache_dir (and any other relative path
variables) and either prepend "$basedir/" when writing them or add the contract
comment near common-env/common.sh so future consumers know to cd into $basedir
first.

In `@update-component.sh`:
- Around line 118-141: The update-proton function currently extracts the tarball
into the existing proton_path which can leave stale files; fix it by adopting
the same pattern as update-steamrt/update-java: either remove the existing
directory before extraction (rm -rf "$proton_path") or, better, extract into a
temporary staging directory and atomically rename it to proton_path after
successful extraction; ensure you reference update-proton, proton_path,
proton_url, the tar extraction step and the write-env calls so the
staging/cleanup happens before write-env "proton_path" and
"proton_download_url_current" are written and only on successful extraction.
- Line 76: The local variable assignment for java_path is done in one step using
a subshell which masks the subshell exit status; change to declare the variable
first (local java_path) and then assign it in a separate statement
(java_path="$(tar -tf "java.tar.gz" | head -n 1 | cut -d '/' -f 1)") so failures
in the pipeline won't be hidden; apply the same pattern to the other similar
occurrences (the other places that currently use local VAR="$(...)" in this
script).

In `@update.sh`:
- Around line 73-79: When the Proton download URL changes (compare
proton_download_url_target vs proton_download_url_current) ensure the update
path not only calls update-component.sh proton but also refreshes the existing
prefix: after a successful Proton update (inside the perform_update="yes" branch
where update-component.sh proton is invoked) run a wineboot -u against the
configured $wineprefix and re-run the DXVK installer (either dxvk-install.sh or
update-component.sh dxvk) so the prefix DLLs match the new Wine/Proton binaries;
guard these steps to only run if the $wineprefix exists and the proton update
completed successfully.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f6a2e483-88db-4efd-8e26-a9199038d3b4

📥 Commits

Reviewing files that changed from the base of the PR and between f549744 and 0c6bcb1.

📒 Files selected for processing (7)
  • common.sh
  • launchwrapper
  • launchwrapper-env
  • launchwrapper-srt
  • setup.sh
  • update-component.sh
  • update.sh
✅ Files skipped from review due to trivial changes (1)
  • launchwrapper-srt
🚧 Files skipped from review as they are similar to previous changes (1)
  • launchwrapper

Comment thread update-component.sh
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Around line 11-18: Add a note to the README prerequisites that some kernels or
distro configs disable user namespaces and will cause setup.sh and update.sh to
exit with "cannot proceed: user namespaces not allowed"; document how to check
(e.g., sysctl kernel.unprivileged_userns_clone or
/proc/sys/kernel/unprivileged_userns_clone) and provide a safe remediation or
link (e.g., enable via sudo sysctl -w kernel.unprivileged_userns_clone=1 or
distro-specific guidance), and mention that both setup.sh and update.sh will
abort with that message so users should verify this prerequisite before running
those scripts.

In `@setup.sh`:
- Around line 101-104: Add a preflight check for the bubblewrap binary by
invoking the same helper used for other required tools: call ensure-bin bwrap
--version alongside the existing ensure-bin curl/jq/cabextract checks so bwrap
is validated early; ensure this check occurs before any heavy download/extract
work or before the first use of launchwrapper-env so the script fails fast if
bwrap is missing.

In `@update-component.sh`:
- Around line 168-175: The fallback case (case *) currently only prints usage
and exits successfully; update the case *) branch in the main argument dispatch
(the case statement handling subcommands) so it returns a non-zero exit status
for invalid subcommands (e.g., call exit 1 after printing the usage) to ensure
callers detect failure when an unknown component is passed.

In `@update.sh`:
- Around line 13-16: The script currently aborts early when
/proc/sys/kernel/apparmor_restrict_unprivileged_userns is set, which prevents
unrelated update steps (autoupdate-notify, git self-update, download/extract,
FAF client, Java, Proton, SteamRT) from running; change the behavior so the
AppArmor userns check only blocks the runtime/container-specific update path
instead of exiting the entire script—i.e., remove the global exit and relocate
or duplicate the check into the container/runtime update function or the
specific block that starts the runtime/container, and ensure non-container
updates (autoupdate-notify, git self-update, download/extract) run regardless of
that kernel setting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2f701601-a6b4-4576-b6ad-d35e2ae0d5ea

📥 Commits

Reviewing files that changed from the base of the PR and between 0c6bcb1 and cccb7ae.

📒 Files selected for processing (8)
  • README.md
  • common.sh
  • launchwrapper
  • launchwrapper-env
  • launchwrapper-srt
  • setup.sh
  • update-component.sh
  • update.sh
✅ Files skipped from review due to trivial changes (2)
  • launchwrapper-srt
  • launchwrapper-env
🚧 Files skipped from review as they are similar to previous changes (1)
  • launchwrapper

Comment thread README.md
Comment thread setup.sh Outdated
Comment thread update-component.sh
Comment on lines +168 to +175
*)
echo "Unknown component $1"
echo "Usage: $0 dxvk <dxvk version>"
echo " $0 faf-client <downlords-faf-client tag>"
echo " $0 java <java url>"
echo " $0 steamrt <steamrt url>"
echo " $0 proton <proton url>"
;;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Return a non-zero status for invalid subcommands.

The fallback branch only prints usage and then exits successfully. Typos like an unsupported component name will look like a successful update to callers and scripts.

Suggested fix
     *)
-        echo "Unknown component $1"
-        echo "Usage: $0 dxvk <dxvk version>"
-        echo "       $0 faf-client <downlords-faf-client tag>"
-        echo "       $0 java <java url>"
-        echo "       $0 steamrt <steamrt url>"
-        echo "       $0 proton <proton url>"
+        echo "Unknown component $1" >&2
+        echo "Usage: $0 dxvk <dxvk version>" >&2
+        echo "       $0 faf-client <downlords-faf-client tag>" >&2
+        echo "       $0 java <java url>" >&2
+        echo "       $0 steamrt <steamrt url>" >&2
+        echo "       $0 proton <proton url>" >&2
+        exit 1
         ;;
 esac
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
*)
echo "Unknown component $1"
echo "Usage: $0 dxvk <dxvk version>"
echo " $0 faf-client <downlords-faf-client tag>"
echo " $0 java <java url>"
echo " $0 steamrt <steamrt url>"
echo " $0 proton <proton url>"
;;
*)
echo "Unknown component $1" >&2
echo "Usage: $0 dxvk <dxvk version>" >&2
echo " $0 faf-client <downlords-faf-client tag>" >&2
echo " $0 java <java url>" >&2
echo " $0 steamrt <steamrt url>" >&2
echo " $0 proton <proton url>" >&2
exit 1
;;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@update-component.sh` around lines 168 - 175, The fallback case (case *)
currently only prints usage and exits successfully; update the case *) branch in
the main argument dispatch (the case statement handling subcommands) so it
returns a non-zero exit status for invalid subcommands (e.g., call exit 1 after
printing the usage) to ensure callers detect failure when an unknown component
is passed.

Comment thread update.sh Outdated
Comment on lines +13 to +16
if [[ -f /proc/sys/kernel/apparmor_restrict_unprivileged_userns ]] && [[ "$(cat /proc/sys/kernel/apparmor_restrict_unprivileged_userns)" != "0" ]]; then
echo "cannot proceed: user namespaces not allowed"
exit 1
fi
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't gate the whole updater on user namespaces.

This runs before autoupdate-notify, git self-update, and the pure download/extract component updates. On a host with that AppArmor setting, ./update.sh cannot even refresh scripts, FAF client, Java, Proton, or SteamRT, even though those paths do not enter the runtime container.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@update.sh` around lines 13 - 16, The script currently aborts early when
/proc/sys/kernel/apparmor_restrict_unprivileged_userns is set, which prevents
unrelated update steps (autoupdate-notify, git self-update, download/extract,
FAF client, Java, Proton, SteamRT) from running; change the behavior so the
AppArmor userns check only blocks the runtime/container-specific update path
instead of exiting the entire script—i.e., remove the global exit and relocate
or duplicate the check into the container/runtime update function or the
specific block that starts the runtime/container, and ensure non-container
updates (autoupdate-notify, git self-update, download/extract) run regardless of
that kernel setting.

@iczero
Copy link
Copy Markdown
Member Author

iczero commented Apr 28, 2026

AppArmor userns restrictions seem to only really happen on Ubuntu; and furthermore not Debian nor most Ubuntu derivatives either. Probably best to just add something to the readme to disable userns enforcement The security benefits of the restriction are highly questionable at best

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Line 136: Update the user-facing sentence in README.md to use the hyphenated
adjective "open-source" instead of "open source"; find the line containing "I
stole a bunch of open source stuff from Steam that makes the game run better
(thanks Valve)" and replace "open source" with "open-source" so the sentence
reads "...open-source stuff...".

In `@setup.sh`:
- Around line 100-102: Update the comment that lists required programs to match
the actual checks: either remove "cabextract" from the comment if it's no longer
required, or add an ensure-bin call (ensure-bin cabextract --version) alongside
ensure-bin curl and ensure-bin jq; locate the requirement text near the existing
ensure-bin calls in setup.sh and make the comment and checks consistent.
- Around line 194-195: The test that checks for an existing directx path uses [[
-f "$basedir/directx" ]] which only matches regular files; change it to [[ -e
"$basedir/directx" ]] so leftover directories are also detected and removed
before extraction; update the conditional guarding rm -rv "$basedir/directx" to
use [[ -e "$basedir/directx" ]] while keeping rm -rv and mkdir -p
"$basedir/directx" as-is to ensure stale directories are removed and the
directory is recreated.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d30953db-4fe1-4d10-9636-f392c5d248db

📥 Commits

Reviewing files that changed from the base of the PR and between cccb7ae and b814aea.

📒 Files selected for processing (6)
  • .gitignore
  • README.md
  • launchwrapper-env
  • launchwrapper-srt
  • setup.sh
  • update.sh
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (2)
  • launchwrapper-srt
  • launchwrapper-env

Comment thread README.md
Comment thread setup.sh Outdated
Comment thread setup.sh Outdated
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.

Switch to the Steam Runtime

1 participant