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
# 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 windows # instalador NSIS, compilado a partir do Linux
# scripts/build-gui.sh windows-docker # o mesmo, num container, sem instalar nada
# scripts/build-gui.sh linux # AppImage and .deb (native architecture)
# scripts/build-gui.sh linux-aarch64 # AppImage and .deb for aarch64
# 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
# TAURI_SIGNING_PRIVATE_KEY e TAURI_SIGNING_PRIVATE_KEY_PASSWORD precisam estar
# no ambiente. Sem eles no ambiente, e com uma chave local em ~/.tauri (gerada
# por `tauri signer generate`), este script a carrega sozinho.
# The Tauri updater signs each bundle (createUpdaterArtifacts: true), so
# TAURI_SIGNING_PRIVATE_KEY and TAURI_SIGNING_PRIVATE_KEY_PASSWORD must be set
# in the environment. If unset locally, this script loads ~/.tauri/guara-updater.key
# when available.
#
# O Windows usa cargo-xwin (SDK do Windows baixado na hora) e o NSIS; o Tauri
# documenta isso como compilação cruzada experimental. Precisa de: nsis, lld,
# llvm, clang e `cargo install cargo-xwin`. O .msi não sai daqui (o WiX é só do
# Windows).
# Windows builds use cargo-xwin and NSIS (requires: nsis, lld, llvm, clang, and
# `cargo install cargo-xwin`).
set -euo pipefail
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 "$@"; }
if [ -z "${TAURI_SIGNING_PRIVATE_KEY:-}" ] && [ -f "$HOME/.tauri/guara-updater.key" ]; then
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")"
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
docker volume create guara-cargo >/dev/null
@@ -106,24 +106,59 @@ EOF
done
fetch_cached_tool "linuxdeploy-07333c6-aarch64.AppImage" \
"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" \
"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" \
"https://github.com/AppImage/type2-runtime/releases/download/continuous/runtime-x86_64" 0
cat >"$HOME/.cache/tauri/linuxdeploy-07333c6-x86_64.AppImage" <<'EOF'
#!/usr/bin/env bash
export ARCH=x86_64
export NO_STRIP=true
export APPIMAGE_EXTRACT_AND_RUN=1
export LDAI_RUNTIME_FILE="$HOME/.cache/tauri/runtime-x86_64"
export LD_GTK_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu
export DEB_HOST_MULTIARCH=x86_64-linux-gnu
export PKG_CONFIG_ALLOW_CROSS=1
export PKG_CONFIG_LIBDIR=/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig
export PATH="/tmp/x86_64-cross-tools:$PATH"
exec "$HOME/.cache/tauri/linuxdeploy-07333c6-aarch64.AppImage" "$@"
# tauri-bundler runs `dd ... seek=8` on this path to hide linuxdeploy from
# AppImage integration tools. A shell-script wrapper loses its shebang and
# then fails with ENOENT, so use a native ELF launcher: the dd writes into
# ELF padding and the launcher stays executable.
launcher_src=/tmp/x86_64-cross-tools/linuxdeploy-x86_64.c
launcher_bin="$HOME/.cache/tauri/linuxdeploy-07333c6-x86_64.AppImage"
cat >"$launcher_src" <<'EOF'
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
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
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_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
@@ -144,7 +179,7 @@ EOF
cp "$bundle"/*-setup.exe ../../../dist-gui/
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
ls -1 ../../../dist-gui
File renamed without changes.
File renamed without changes.
File renamed without changes.