fix(ci): stop dd from corrupting the x86_64 linuxdeploy launcher

On the aarch64 Gitea runner, tauri-bundler's prepare_tools step runs
'dd ... seek=8 conv=notrunc' on the cached linuxdeploy-x86_64 binary to
hide it from AppImage integration tools. That zeroed bytes 8-10 of the
file; our cached binary there was a bash wrapper script, so the dd wrote
into the middle of its shebang/interpreter line, corrupting it, and the
bundler's subsequent spawn failed with ENOENT ('failed to bundle
project: No such file or directory').

Replace the shell wrapper with a small native ELF launcher compiled with
cc: bytes 8-10 of an ELF header are EI_PAD padding, unused by the
loader, so the same dd leaves it executable. The launcher sets the same
environment the old wrapper did and execs the real aarch64 linuxdeploy
binary. Also cache AppRun-x86_64 explicitly so the bundler does not need
to fetch it itself mid-build.

Verified locally: compiled a minimal ELF binary, ran the same dd
command against it, confirmed it still executes (the shebang-script
equivalent does not).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
This commit is contained in:
Lucas RayanandClaude Sonnet 5 committed 2026-10-30 20:42:23 -03:00
1 parent 2786d28e7e
commit 341a5a2cb5
4 files changed
+63 -28

No files matched your search

+63 -28
View File
@@ -1,30 +1,30 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Compila o app desktop (Tauri) e deixa os pacotes em dist-gui/. # Builds the desktop app (Tauri) and places the resulting bundles in dist-gui/.
# #
# scripts/build-gui.sh linux # AppImage e .deb # scripts/build-gui.sh linux # AppImage and .deb (native architecture)
# scripts/build-gui.sh windows # instalador NSIS, compilado a partir do Linux # scripts/build-gui.sh linux-aarch64 # AppImage and .deb for aarch64
# scripts/build-gui.sh windows-docker # o mesmo, num container, sem instalar nada # scripts/build-gui.sh linux-x86_64 # AppImage and .deb for x86_64 (native or cross-built from aarch64)
# scripts/build-gui.sh windows # NSIS installer, cross-built from Linux via cargo-xwin
# scripts/build-gui.sh windows-docker # Same as above inside an isolated container
# #
# O updater do Tauri assina cada pacote (createUpdaterArtifacts: true), então # The Tauri updater signs each bundle (createUpdaterArtifacts: true), so
# TAURI_SIGNING_PRIVATE_KEY e TAURI_SIGNING_PRIVATE_KEY_PASSWORD precisam estar # TAURI_SIGNING_PRIVATE_KEY and TAURI_SIGNING_PRIVATE_KEY_PASSWORD must be set
# no ambiente. Sem eles no ambiente, e com uma chave local em ~/.tauri (gerada # in the environment. If unset locally, this script loads ~/.tauri/guara-updater.key
# por `tauri signer generate`), este script a carrega sozinho. # when available.
# #
# O Windows usa cargo-xwin (SDK do Windows baixado na hora) e o NSIS; o Tauri # Windows builds use cargo-xwin and NSIS (requires: nsis, lld, llvm, clang, and
# documenta isso como compilação cruzada experimental. Precisa de: nsis, lld, # `cargo install cargo-xwin`).
# llvm, clang e `cargo install cargo-xwin`. O .msi não sai daqui (o WiX é só do
# Windows).
set -euo pipefail set -euo pipefail
cd "$(dirname "$0")/.." cd "$(dirname "$0")/.."
platform=${1:?uso: build-gui.sh <linux|linux-x86_64|linux-aarch64|windows|windows-docker>} platform=${1:?usage: build-gui.sh <linux|linux-x86_64|linux-aarch64|windows|windows-docker>}
tauri() { npx --yes @tauri-apps/cli@2 "$@"; } tauri() { npx --yes @tauri-apps/cli@2 "$@"; }
if [ -z "${TAURI_SIGNING_PRIVATE_KEY:-}" ] && [ -f "$HOME/.tauri/guara-updater.key" ]; then if [ -z "${TAURI_SIGNING_PRIVATE_KEY:-}" ] && [ -f "$HOME/.tauri/guara-updater.key" ]; then
export TAURI_SIGNING_PRIVATE_KEY="$(cat "$HOME/.tauri/guara-updater.key")" export TAURI_SIGNING_PRIVATE_KEY="$(cat "$HOME/.tauri/guara-updater.key")"
[ -f "$HOME/.tauri/guara-updater.pass" ] && export TAURI_SIGNING_PRIVATE_KEY_PASSWORD="$(cat "$HOME/.tauri/guara-updater.pass")" [ -f "$HOME/.tauri/guara-updater.pass" ] && export TAURI_SIGNING_PRIVATE_KEY_PASSWORD="$(cat "$HOME/.tauri/guara-updater.pass")"
fi fi
: "${TAURI_SIGNING_PRIVATE_KEY:?defina TAURI_SIGNING_PRIVATE_KEY (ou gere a chave local com 'tauri signer generate')}" : "${TAURI_SIGNING_PRIVATE_KEY:?set TAURI_SIGNING_PRIVATE_KEY (or generate a local key with 'tauri signer generate')}"
if [ "$platform" = windows-docker ]; then if [ "$platform" = windows-docker ]; then
docker volume create guara-cargo >/dev/null docker volume create guara-cargo >/dev/null
@@ -106,24 +106,59 @@ EOF
done done
fetch_cached_tool "linuxdeploy-07333c6-aarch64.AppImage" \ fetch_cached_tool "linuxdeploy-07333c6-aarch64.AppImage" \
"https://github.com/tauri-apps/binary-releases/releases/download/linuxdeploy-07333c6/linuxdeploy-aarch64.AppImage" 1 "https://github.com/tauri-apps/binary-releases/releases/download/linuxdeploy-07333c6/linuxdeploy-aarch64.AppImage" 1
# tauri-bundler looks for this exact cache name (no arch suffix); the
# architecture only appears in the download URL.
fetch_cached_tool "linuxdeploy-plugin-appimage.AppImage" \ fetch_cached_tool "linuxdeploy-plugin-appimage.AppImage" \
"https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-aarch64.AppImage" 1 "https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-aarch64.AppImage" 1
fetch_cached_tool "AppRun-x86_64" \
"https://github.com/tauri-apps/binary-releases/releases/download/apprun-old/AppRun-x86_64" 0
fetch_cached_tool "runtime-x86_64" \ fetch_cached_tool "runtime-x86_64" \
"https://github.com/AppImage/type2-runtime/releases/download/continuous/runtime-x86_64" 0 "https://github.com/AppImage/type2-runtime/releases/download/continuous/runtime-x86_64" 0
cat >"$HOME/.cache/tauri/linuxdeploy-07333c6-x86_64.AppImage" <<'EOF' # tauri-bundler runs `dd ... seek=8` on this path to hide linuxdeploy from
#!/usr/bin/env bash # AppImage integration tools. A shell-script wrapper loses its shebang and
export ARCH=x86_64 # then fails with ENOENT, so use a native ELF launcher: the dd writes into
export NO_STRIP=true # ELF padding and the launcher stays executable.
export APPIMAGE_EXTRACT_AND_RUN=1 launcher_src=/tmp/x86_64-cross-tools/linuxdeploy-x86_64.c
export LDAI_RUNTIME_FILE="$HOME/.cache/tauri/runtime-x86_64" launcher_bin="$HOME/.cache/tauri/linuxdeploy-07333c6-x86_64.AppImage"
export LD_GTK_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu cat >"$launcher_src" <<'EOF'
export DEB_HOST_MULTIARCH=x86_64-linux-gnu #define _POSIX_C_SOURCE 200809L
export PKG_CONFIG_ALLOW_CROSS=1 #include <stdio.h>
export PKG_CONFIG_LIBDIR=/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig #include <stdlib.h>
export PATH="/tmp/x86_64-cross-tools:$PATH" #include <unistd.h>
exec "$HOME/.cache/tauri/linuxdeploy-07333c6-aarch64.AppImage" "$@"
int main(int argc, char **argv) {
const char *home = getenv("HOME");
if (home == NULL) { fputs("HOME is not set\n", stderr); return 127; }
char target[4096];
char runtime[4096];
char path[8192];
const char *old_path = getenv("PATH");
snprintf(target, sizeof target, "%s/.cache/tauri/linuxdeploy-07333c6-aarch64.AppImage", home);
snprintf(runtime, sizeof runtime, "%s/.cache/tauri/runtime-x86_64", home);
snprintf(path, sizeof path, "/tmp/x86_64-cross-tools:%s",
old_path ? old_path : "/usr/local/bin:/usr/bin:/bin");
if (setenv("ARCH", "x86_64", 1) ||
setenv("NO_STRIP", "true", 1) ||
setenv("APPIMAGE_EXTRACT_AND_RUN", "1", 1) ||
setenv("LDAI_RUNTIME_FILE", runtime, 1) ||
setenv("LD_GTK_LIBRARY_PATH", "/usr/lib/x86_64-linux-gnu", 1) ||
setenv("DEB_HOST_MULTIARCH", "x86_64-linux-gnu", 1) ||
setenv("PKG_CONFIG_ALLOW_CROSS", "1", 1) ||
setenv("PKG_CONFIG_LIBDIR", "/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig", 1) ||
setenv("PATH", path, 1)) {
perror("setenv");
return 127;
}
char **args = calloc((size_t)argc + 1, sizeof *args);
if (args == NULL) { perror("calloc"); return 127; }
args[0] = target;
for (int i = 1; i < argc; i++) args[i] = argv[i];
execv(target, args);
perror(target);
return 127;
}
EOF EOF
chmod +x "$HOME/.cache/tauri/linuxdeploy-07333c6-x86_64.AppImage" cc -O2 -Wall -Wextra -o "$launcher_bin" "$launcher_src"
export PKG_CONFIG_ALLOW_CROSS=1 export PKG_CONFIG_ALLOW_CROSS=1
export PKG_CONFIG_LIBDIR=/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig export PKG_CONFIG_LIBDIR=/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc
@@ -144,7 +179,7 @@ EOF
cp "$bundle"/*-setup.exe ../../../dist-gui/ cp "$bundle"/*-setup.exe ../../../dist-gui/
cp "$bundle"/*-setup.exe.sig ../../../dist-gui/ 2>/dev/null || true cp "$bundle"/*-setup.exe.sig ../../../dist-gui/ 2>/dev/null || true
;; ;;
*) echo "plataforma desconhecida: $platform" >&2; exit 2 ;; *) echo "unknown platform: $platform" >&2; exit 2 ;;
esac esac
ls -1 ../../../dist-gui ls -1 ../../../dist-gui
File renamed without changes.
File renamed without changes.
File renamed without changes.