From e6320a0edf3d6bd056ac30e964809ccc5da2e2f5 Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Mon, 28 Sep 2026 14:38:55 -0400 Subject: [PATCH 01/10] Fix AppImage filesystem root permissions and test Firejail launch --- .github/workflows/linux-build.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 4f768cb..9cb0a2e 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -116,7 +116,7 @@ jobs: - name: Install Linux packaging prerequisites run: | sudo apt-get update - sudo apt-get install -y binutils imagemagick squashfs-tools unzip x11-utils xdotool xvfb zsync + sudo apt-get install -y binutils firejail imagemagick squashfs-tools unzip x11-utils xdotool xvfb zsync - name: Download appimagetool run: | set -euo pipefail @@ -159,6 +159,7 @@ jobs: ( cd "$appimage_dir" "./$appimage_name" --appimage-extract + chmod 755 squashfs-root mv "$appimage_name" "$appimage_name.electron-builder" if [ -n "$UPDATE_INFORMATION" ]; then ARCH=x86_64 APPIMAGE_EXTRACT_AND_RUN=1 "$APPIMAGETOOL_PATH" \ @@ -190,22 +191,30 @@ jobs: exit 1 fi fi + squashfs_listing="$RUNNER_TEMP/appimage-filesystem.txt" + unsquashfs -lln -o "$("$APPIMAGE_PATH" --appimage-offset)" "$APPIMAGE_PATH" > "$squashfs_listing" + awk '$NF == "squashfs-root" { found = 1; if ($1 != "drwxr-xr-x") { print "AppImage root must have mode 0755: " $0 > "/dev/stderr"; exit 1 } } END { if (!found) exit 1 }' "$squashfs_listing" extraction_dir="$(mktemp -d)" (cd "$extraction_dir" && "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --appimage-extract >/dev/null) test -x "$extraction_dir/squashfs-root/AppRun" rm -rf "$extraction_dir" - - name: Smoke test AppImage at 800x600 + - name: Smoke test AppImage at 800x600 with extraction and Firejail env: - APPIMAGE_EXTRACT_AND_RUN: "1" SCREENSHOT_PATH: ${{ runner.temp }}/PatchOpsIII-800x600.png run: | set -euo pipefail + for launch_mode in extract firejail; do + export LAUNCH_MODE="$launch_mode" xvfb-run --auto-servernum --server-args="-screen 0 800x600x24" bash -euo pipefail <<'SMOKE_TEST' screen_info="$(xwininfo -root)" grep -Eq "Width: +800" <<< "$screen_info" grep -Eq "Height: +600" <<< "$screen_info" - "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --no-sandbox --disable-gpu & + if [ "$LAUNCH_MODE" = firejail ]; then + firejail --quiet --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & + else + APPIMAGE_EXTRACT_AND_RUN=1 "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --no-sandbox --disable-gpu & + fi app_pid=$! cleanup() { if kill -0 "$app_pid" 2>/dev/null; then @@ -249,6 +258,7 @@ jobs: sleep 20 kill -0 "$app_pid" SMOKE_TEST + done - name: Upload AppImage visual review screenshot uses: actions/upload-artifact@v4 with: From ad32f73d6fb9fee0f0cad96123e0cdd0a7aac1ea Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Mon, 28 Sep 2026 14:42:55 -0400 Subject: [PATCH 02/10] Show Firejail diagnostics in the catalog smoke test --- .github/workflows/linux-build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 9cb0a2e..f8b05bd 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -205,13 +205,14 @@ jobs: set -euo pipefail for launch_mode in extract firejail; do export LAUNCH_MODE="$launch_mode" + echo "Testing AppImage launch mode: $LAUNCH_MODE" xvfb-run --auto-servernum --server-args="-screen 0 800x600x24" bash -euo pipefail <<'SMOKE_TEST' screen_info="$(xwininfo -root)" grep -Eq "Width: +800" <<< "$screen_info" grep -Eq "Height: +600" <<< "$screen_info" if [ "$LAUNCH_MODE" = firejail ]; then - firejail --quiet --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & + firejail --debug --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & else APPIMAGE_EXTRACT_AND_RUN=1 "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --no-sandbox --disable-gpu & fi From abbb478584804444775466010964b96b4e5d5a6d Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Mon, 28 Sep 2026 14:46:29 -0400 Subject: [PATCH 03/10] Isolate smoke test state and clean up application process groups --- .github/workflows/linux-build.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index f8b05bd..6dc15f2 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -203,23 +203,26 @@ jobs: SCREENSHOT_PATH: ${{ runner.temp }}/PatchOpsIII-800x600.png run: | set -euo pipefail - for launch_mode in extract firejail; do + for launch_mode in firejail extract; do export LAUNCH_MODE="$launch_mode" echo "Testing AppImage launch mode: $LAUNCH_MODE" + export XDG_CONFIG_HOME="$RUNNER_TEMP/patchops-config-$launch_mode" + export XDG_CACHE_HOME="$RUNNER_TEMP/patchops-cache-$launch_mode" + mkdir -p "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" xvfb-run --auto-servernum --server-args="-screen 0 800x600x24" bash -euo pipefail <<'SMOKE_TEST' screen_info="$(xwininfo -root)" grep -Eq "Width: +800" <<< "$screen_info" grep -Eq "Height: +600" <<< "$screen_info" if [ "$LAUNCH_MODE" = firejail ]; then - firejail --debug --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & + setsid firejail --debug --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & else - APPIMAGE_EXTRACT_AND_RUN=1 "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --no-sandbox --disable-gpu & + APPIMAGE_EXTRACT_AND_RUN=1 setsid "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --no-sandbox --disable-gpu & fi app_pid=$! cleanup() { if kill -0 "$app_pid" 2>/dev/null; then - kill "$app_pid" 2>/dev/null || true + kill -- "-$app_pid" 2>/dev/null || true wait "$app_pid" 2>/dev/null || true fi } @@ -254,7 +257,9 @@ jobs: fi sleep 2 - import -window root "$SCREENSHOT_PATH" + if [ "$LAUNCH_MODE" = firejail ]; then + import -window root "$SCREENSHOT_PATH" + fi test -s "$SCREENSHOT_PATH" sleep 20 kill -0 "$app_pid" From 0bba9de1efbe628e6dd641567ae342d92ba71e98 Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Mon, 28 Sep 2026 14:49:25 -0400 Subject: [PATCH 04/10] Trace the remaining Firejail startup failure --- .github/workflows/linux-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 6dc15f2..d1ee2fc 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -215,7 +215,7 @@ jobs: grep -Eq "Height: +600" <<< "$screen_info" if [ "$LAUNCH_MODE" = firejail ]; then - setsid firejail --debug --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & + setsid firejail --debug --trace --env=ELECTRON_ENABLE_LOGGING=1 --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & else APPIMAGE_EXTRACT_AND_RUN=1 setsid "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --no-sandbox --disable-gpu & fi From 27ce70adde922b6440cce6e9770dca1925b50404 Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Mon, 28 Sep 2026 14:54:08 -0400 Subject: [PATCH 05/10] Use verified catalog Firejail dependencies for the smoke test --- .github/workflows/linux-build.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index d1ee2fc..ad7d779 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -116,7 +116,7 @@ jobs: - name: Install Linux packaging prerequisites run: | sudo apt-get update - sudo apt-get install -y binutils firejail imagemagick squashfs-tools unzip x11-utils xdotool xvfb zsync + sudo apt-get install -y binutils imagemagick squashfs-tools unzip x11-utils xdotool xvfb zsync - name: Download appimagetool run: | set -euo pipefail @@ -198,6 +198,26 @@ jobs: (cd "$extraction_dir" && "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --appimage-extract >/dev/null) test -x "$extraction_dir/squashfs-root/AppRun" rm -rf "$extraction_dir" + - name: Install catalog Firejail test runtime + run: | + set -euo pipefail + catalog_firejail="$RUNNER_TEMP/catalog-firejail" + mkdir -p "$catalog_firejail" + curl --fail --location --retry 3 \ + https://github.com/AppImage/appimage.github.io/releases/download/deps/alpine-firejail-git20230825.tar.gz \ + --output "$catalog_firejail/firejail.tar.gz" + echo "e346e52ac7dbff3a3f1e8aad3cbb2f06584afcb51c840de07cb8d50e134492d9 $catalog_firejail/firejail.tar.gz" | sha256sum --check + curl --fail --location --retry 3 \ + https://dl-cdn.alpinelinux.org/alpine/v3.13/main/x86_64/musl-1.2.2-r2.apk \ + --output "$catalog_firejail/musl.apk" + echo "3d459f4f3a83e60c6c260c6aee26745e7aa22697f53e3a01445227d2cfeeae8a $catalog_firejail/musl.apk" | sha256sum --check + tar -xzf "$catalog_firejail/firejail.tar.gz" -C "$catalog_firejail" + tar --warning=no-unknown-keyword -xzf "$catalog_firejail/firejail-0_git20230825-r0.apk" -C "$catalog_firejail" etc/firejail usr/bin/firejail usr/lib/firejail + tar --warning=no-unknown-keyword -xzf "$catalog_firejail/musl.apk" -C "$catalog_firejail" lib + sudo cp -a "$catalog_firejail/lib/." /lib/ + sudo cp -a "$catalog_firejail/etc/firejail" /etc/ + sudo cp -a "$catalog_firejail/usr/lib/firejail" /usr/lib/ + sudo install -o root -g root -m 4755 "$catalog_firejail/usr/bin/firejail" /usr/bin/firejail - name: Smoke test AppImage at 800x600 with extraction and Firejail env: SCREENSHOT_PATH: ${{ runner.temp }}/PatchOpsIII-800x600.png @@ -215,7 +235,7 @@ jobs: grep -Eq "Height: +600" <<< "$screen_info" if [ "$LAUNCH_MODE" = firejail ]; then - setsid firejail --debug --trace --env=ELECTRON_ENABLE_LOGGING=1 --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & + setsid firejail --debug --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & else APPIMAGE_EXTRACT_AND_RUN=1 setsid "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --no-sandbox --disable-gpu & fi From d00c2d2ff7daa372038e645120d999d78b37805e Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Mon, 28 Sep 2026 14:57:04 -0400 Subject: [PATCH 06/10] Install catalog sandbox helpers with root ownership --- .github/workflows/linux-build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index ad7d779..5a3f5c2 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -214,9 +214,9 @@ jobs: tar -xzf "$catalog_firejail/firejail.tar.gz" -C "$catalog_firejail" tar --warning=no-unknown-keyword -xzf "$catalog_firejail/firejail-0_git20230825-r0.apk" -C "$catalog_firejail" etc/firejail usr/bin/firejail usr/lib/firejail tar --warning=no-unknown-keyword -xzf "$catalog_firejail/musl.apk" -C "$catalog_firejail" lib - sudo cp -a "$catalog_firejail/lib/." /lib/ - sudo cp -a "$catalog_firejail/etc/firejail" /etc/ - sudo cp -a "$catalog_firejail/usr/lib/firejail" /usr/lib/ + sudo cp -R "$catalog_firejail/lib/." /lib/ + sudo cp -R "$catalog_firejail/etc/firejail" /etc/ + sudo cp -R "$catalog_firejail/usr/lib/firejail" /usr/lib/ sudo install -o root -g root -m 4755 "$catalog_firejail/usr/bin/firejail" /usr/bin/firejail - name: Smoke test AppImage at 800x600 with extraction and Firejail env: From d893211e2fdb5e8bc366a823d443e8acc8626f67 Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Mon, 28 Sep 2026 15:00:11 -0400 Subject: [PATCH 07/10] Trace AppRun startup without dumping the environment --- .github/workflows/linux-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 5a3f5c2..4eb54e5 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -235,7 +235,7 @@ jobs: grep -Eq "Height: +600" <<< "$screen_info" if [ "$LAUNCH_MODE" = firejail ]; then - setsid firejail --debug --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & + setsid firejail --debug --env=SHELLOPTS=xtrace --env=DEBUG= --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & else APPIMAGE_EXTRACT_AND_RUN=1 setsid "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --no-sandbox --disable-gpu & fi From 69e933c828d1f5773801f5eec8a70ec3cbee4b02 Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Mon, 28 Sep 2026 15:01:23 -0400 Subject: [PATCH 08/10] Normalize and verify permissions on every AppImage directory --- .github/workflows/linux-build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 4eb54e5..a58ffdc 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -159,7 +159,7 @@ jobs: ( cd "$appimage_dir" "./$appimage_name" --appimage-extract - chmod 755 squashfs-root + find squashfs-root -type d -exec chmod 755 {} + mv "$appimage_name" "$appimage_name.electron-builder" if [ -n "$UPDATE_INFORMATION" ]; then ARCH=x86_64 APPIMAGE_EXTRACT_AND_RUN=1 "$APPIMAGETOOL_PATH" \ @@ -193,7 +193,7 @@ jobs: fi squashfs_listing="$RUNNER_TEMP/appimage-filesystem.txt" unsquashfs -lln -o "$("$APPIMAGE_PATH" --appimage-offset)" "$APPIMAGE_PATH" > "$squashfs_listing" - awk '$NF == "squashfs-root" { found = 1; if ($1 != "drwxr-xr-x") { print "AppImage root must have mode 0755: " $0 > "/dev/stderr"; exit 1 } } END { if (!found) exit 1 }' "$squashfs_listing" + awk '$1 ~ /^d/ { found = 1; if ($1 != "drwxr-xr-x") { print "AppImage directory must have mode 0755: " $0 > "/dev/stderr"; exit 1 } } END { if (!found) exit 1 }' "$squashfs_listing" extraction_dir="$(mktemp -d)" (cd "$extraction_dir" && "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --appimage-extract >/dev/null) test -x "$extraction_dir/squashfs-root/AppRun" @@ -235,7 +235,7 @@ jobs: grep -Eq "Height: +600" <<< "$screen_info" if [ "$LAUNCH_MODE" = firejail ]; then - setsid firejail --debug --env=SHELLOPTS=xtrace --env=DEBUG= --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & + setsid firejail --quiet --noprofile --net=none --appimage "$GITHUB_WORKSPACE/$APPIMAGE_PATH" & else APPIMAGE_EXTRACT_AND_RUN=1 setsid "$GITHUB_WORKSPACE/$APPIMAGE_PATH" --no-sandbox --disable-gpu & fi From abc2f2b521c7cdbdae8a6d4fad0d2d78752e1342 Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Mon, 28 Sep 2026 15:13:49 -0400 Subject: [PATCH 09/10] Bump PatchOpsIII version to v1.3.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5981c28..7bda4cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "patchopsiii-electron", - "version": "v1.3.3", + "version": "v1.3.4", "description": "Electron control center for Call of Duty: Black Ops III maintenance, mod setup, and performance tuning.", "author": "boggedbrush", "private": true, From a307e8e79f70f9bd3cb4d75b873875817e2ab996 Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Mon, 28 Sep 2026 15:14:01 -0400 Subject: [PATCH 10/10] Add v1.3.4 release notes for AppImage launch fix --- Release Notes/PatchOpsIII v1.3.4.md | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Release Notes/PatchOpsIII v1.3.4.md diff --git a/Release Notes/PatchOpsIII v1.3.4.md b/Release Notes/PatchOpsIII v1.3.4.md new file mode 100644 index 0000000..142079d --- /dev/null +++ b/Release Notes/PatchOpsIII v1.3.4.md @@ -0,0 +1,40 @@ +# PatchOpsIII v1.3.4 Release Notes + +## Overview + +PatchOpsIII v1.3.4 fixes Linux AppImage startup in sandboxed environments, including the AppImage catalog's Firejail test. + +## Highlights + +- Correct directory permissions inside the AppImage so Firejail can access the application. +- Verify the packaged filesystem's directory permissions before release. +- Test the AppImage at 800×600 using both Firejail and extraction-based launch. + +## Detailed Changes + +### Linux & Steam Deck + +- Normalize all AppImage directories to mode `0755` before repacking. The v1.3.3 AppImage stored its directories as root-owned `0700`, which prevented Firejail from launching it. +- Inspect the stored SquashFS filesystem to catch inaccessible directories. +- Run the automated GUI smoke test with the AppImage catalog's Firejail runtime and with extraction-based startup. + +## Upgrade Notes + +- Linux users affected by the v1.3.3 AppImage launch failure should install v1.3.4. +- No settings migration is required. + +## Downloads & Verification + +The release workflow fills in the download URLs, SHA-256 hashes, and VirusTotal links below when publishing. + +- **Windows MSI** + - Download: [PatchOpsIII v1.3.4 for Windows]({{WINDOWS_DOWNLOAD_URL}}) + - SHA256: `{{WINDOWS_SHA256}}` + - VirusTotal: [Windows MSI scan]({{WINDOWS_VT_URL}}) + - Older updater compatibility: [PatchOpsIII.exe](https://github.com/boggedbrush/PatchOpsIII/releases/download/v1.3.4/PatchOpsIII.exe) + +- **Linux & Steam Deck** + - Download: [PatchOpsIII v1.3.4 for Linux & Steam Deck]({{LINUX_DOWNLOAD_URL}}) + - SHA256: `{{LINUX_SHA256}}` + - VirusTotal: [Linux scan]({{LINUX_VT_URL}}) + - Stable AppImages include update information and a matching zsync file.