Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/mobile-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,24 @@ jobs:
name: maple-ios
path: artifacts

- name: Prepare App Store Connect API key
env:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
APPLE_API_PRIVATE_KEY: ${{ secrets.APPLE_API_PRIVATE_KEY }}
run: |
set -euo pipefail
if [ -z "${APPLE_API_KEY}" ] || [ -z "${APPLE_API_PRIVATE_KEY}" ]; then
echo "APPLE_API_KEY and APPLE_API_PRIVATE_KEY are required to submit to TestFlight." >&2
exit 1
Comment on lines +163 to +170

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 | ⚡ Quick win

Validate APPLE_API_ISSUER in the same fail-fast guard.

This step still lets the job reach altool with an empty issuer, even though Line 192 requires it. Adding the issuer here makes the TestFlight failure immediate and actionable.

Suggested patch
       - name: Prepare App Store Connect API key
         env:
+          APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
           APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
           APPLE_API_PRIVATE_KEY: ${{ secrets.APPLE_API_PRIVATE_KEY }}
         run: |
           set -euo pipefail
-          if [ -z "${APPLE_API_KEY}" ] || [ -z "${APPLE_API_PRIVATE_KEY}" ]; then
-            echo "APPLE_API_KEY and APPLE_API_PRIVATE_KEY are required to submit to TestFlight." >&2
+          if [ -z "${APPLE_API_ISSUER}" ] || [ -z "${APPLE_API_KEY}" ] || [ -z "${APPLE_API_PRIVATE_KEY}" ]; then
+            echo "APPLE_API_ISSUER, APPLE_API_KEY, and APPLE_API_PRIVATE_KEY are required to submit to TestFlight." >&2
             exit 1
           fi
🤖 Prompt for 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.

In @.github/workflows/mobile-build.yml around lines 163 - 170, Add
APPLE_API_ISSUER to the environment and include it in the fail-fast guard inside
the run block so the job errors immediately if the issuer is missing;
specifically, export APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} in the
env section and update the if check that currently tests APPLE_API_KEY and
APPLE_API_PRIVATE_KEY to also test APPLE_API_ISSUER and print a clear error
(e.g., "APPLE_API_KEY, APPLE_API_PRIVATE_KEY and APPLE_API_ISSUER are required
to submit to TestFlight.") before exiting; this prevents the later altool
invocation from running with an empty issuer.

fi

mkdir -p "${HOME}/.private_keys"
key_path="${HOME}/.private_keys/AuthKey_${APPLE_API_KEY}.p8"
if ! printf '%s' "${APPLE_API_PRIVATE_KEY}" | base64 --decode > "${key_path}" 2>/dev/null; then
printf '%s' "${APPLE_API_PRIVATE_KEY}" | base64 -D > "${key_path}"
fi
chmod 600 "${key_path}"

- name: Submit verified IPA to TestFlight
run: |
set -euo pipefail
Expand Down
99 changes: 79 additions & 20 deletions scripts/ci/_common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -742,26 +742,58 @@ prepare_tauri_linuxdeploy_tools_cache() {
return 1
fi

local arch linuxdeploy_arch tools cache wrapper
local arch linuxdeploy_arch tools cache bash_path linuxdeploy_wrapper appimage_wrapper
arch="$(linuxdeploy_tools_arch)"
linuxdeploy_arch="${arch}"
tools="${MAPLE_NIX_TAURI_LINUXDEPLOY_TOOLS}"
cache="${TAURI_DIR}/target/.tauri"
wrapper="${cache}/linuxdeploy-plugin-appimage.AppImage"
bash_path="$(command -v bash)"
Comment on lines +745 to +750

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 | ⚡ Quick win

Use a sandbox-stable shebang for the generated wrappers.

Line 750 captures the host bash path, but these wrappers are later executed inside run_with_nix_usr_bin, which only guarantees bash at /bin/bash. On merged-/usr runners where command -v bash resolves to /usr/bin/bash, rebinding /usr makes both wrappers unexecutable and breaks AppImage bundling.

Suggested fix
-  local arch linuxdeploy_arch tools cache bash_path linuxdeploy_wrapper appimage_wrapper
+  local arch linuxdeploy_arch tools cache linuxdeploy_wrapper appimage_wrapper
@@
-  bash_path="$(command -v bash)"
   linuxdeploy_wrapper="${cache}/linuxdeploy-${linuxdeploy_arch}.AppImage"
   appimage_wrapper="${cache}/linuxdeploy-plugin-appimage.AppImage"
@@
-#!${bash_path}
+#!/bin/bash
@@
-#!${bash_path}
+#!/bin/bash

Also applies to: 764-766, 791-793

🤖 Prompt for 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.

In `@scripts/ci/_common.sh` around lines 745 - 750, The generated wrapper shebangs
currently use the host bash path via bash_path="$(command -v bash)", which can
resolve to /usr/bin/bash and break inside run_with_nix_usr_bin; change these to
use the sandbox-stable path by setting bash_path="/bin/bash" (and update the
other occurrences that build wrappers to use this variable) so wrapper scripts
always use /bin/bash when writing their shebangs (referencing the bash_path
variable and the wrapper-generation sites that currently call command -v bash).

linuxdeploy_wrapper="${cache}/linuxdeploy-${linuxdeploy_arch}.AppImage"
appimage_wrapper="${cache}/linuxdeploy-plugin-appimage.AppImage"

mkdir -p "${cache}"
install -m 0755 "${tools}/AppRun-${arch}" "${cache}/AppRun-${arch}"
install -m 0755 "${tools}/linuxdeploy-${linuxdeploy_arch}.AppImage" "${cache}/linuxdeploy-${linuxdeploy_arch}.AppImage"
install -m 0755 "${tools}/linuxdeploy-${linuxdeploy_arch}.AppImage" "${cache}/linuxdeploy-${linuxdeploy_arch}.real.AppImage"
install -m 0755 "${tools}/linuxdeploy-plugin-appimage.real.AppImage" "${cache}/linuxdeploy-plugin-appimage.real.AppImage"
install -m 0755 "${tools}/linuxdeploy-plugin-gtk.sh" "${cache}/linuxdeploy-plugin-gtk.sh"
install -m 0755 "${tools}/linuxdeploy-plugin-gstreamer.sh" "${cache}/linuxdeploy-plugin-gstreamer.sh"

cat > "${wrapper}" <<'EOF'
#!/usr/bin/env bash
extract_appimage_tool "${cache}/linuxdeploy-${linuxdeploy_arch}.real.AppImage" "${cache}/linuxdeploy-${linuxdeploy_arch}.AppDir"
extract_appimage_tool "${cache}/linuxdeploy-plugin-appimage.real.AppImage" "${cache}/linuxdeploy-plugin-appimage.AppDir"

cat > "${linuxdeploy_wrapper}" <<EOF
#!${bash_path}
set -euo pipefail

script_dir="\$(CDPATH= cd -- "\$(dirname -- "\$0")" && pwd)"
app_run="\${script_dir}/linuxdeploy-${linuxdeploy_arch}.AppDir/AppRun"

if [ ! -x "\${app_run}" ]; then
echo "Missing extracted linuxdeploy AppRun at \${app_run}" >&2
exit 1
fi

args=()
for arg in "\$@"; do
case "\${arg}" in
--appimage-extract-and-run)
;;
*)
args+=("\${arg}")
;;
esac
done

exec "\${app_run}" "\${args[@]}"
EOF
chmod +x "${linuxdeploy_wrapper}"

cat > "${appimage_wrapper}" <<EOF
#!${bash_path}
set -euo pipefail

for arg in "$@"; do
case "${arg}" in
for arg in "\$@"; do
case "\${arg}" in
--plugin-type)
printf '%s\n' output
exit 0
Expand All @@ -775,48 +807,75 @@ done

appdir=""
previous=""
for arg in "$@"; do
if [ "${previous}" = "--appdir" ]; then
appdir="${arg}"
for arg in "\$@"; do
if [ "\${previous}" = "--appdir" ]; then
appdir="\${arg}"
previous=""
continue
fi

case "${arg}" in
case "\${arg}" in
--appdir=*)
appdir="${arg#--appdir=}"
appdir="\${arg#--appdir=}"
;;
--appdir)
previous="--appdir"
;;
esac
done

if [ -n "${appdir}" ]; then
rm -f "${appdir}/.DirIcon"
if [ -n "\${appdir}" ]; then
rm -f "\${appdir}/.DirIcon"
fi

script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
real_plugin="${script_dir}/linuxdeploy-plugin-appimage.real.AppImage"
script_dir="\$(CDPATH= cd -- "\$(dirname -- "\$0")" && pwd)"
real_plugin="\${script_dir}/linuxdeploy-plugin-appimage.AppDir/AppRun"

if [ ! -x "${real_plugin}" ]; then
echo "Missing real linuxdeploy AppImage plugin at ${real_plugin}" >&2
if [ ! -x "\${real_plugin}" ]; then
echo "Missing extracted linuxdeploy AppImage plugin at \${real_plugin}" >&2
exit 1
fi

APPIMAGE_EXTRACT_AND_RUN=1 exec "${real_plugin}" --appimage-extract-and-run "$@"
exec "\${real_plugin}" "\$@"
EOF
chmod +x "${wrapper}"
chmod +x "${appimage_wrapper}"

print_file_hashes \
"${cache}/AppRun-${arch}" \
"${cache}/linuxdeploy-${linuxdeploy_arch}.real.AppImage" \
"${cache}/linuxdeploy-${linuxdeploy_arch}.AppImage" \
"${cache}/linuxdeploy-${linuxdeploy_arch}.AppDir/AppRun" \
"${cache}/linuxdeploy-plugin-appimage.real.AppImage" \
"${cache}/linuxdeploy-plugin-appimage.AppImage" \
"${cache}/linuxdeploy-plugin-appimage.AppDir/AppRun" \
"${cache}/linuxdeploy-plugin-gtk.sh" \
"${cache}/linuxdeploy-plugin-gstreamer.sh"
}

extract_appimage_tool() {
local appimage="$1"
local out="$2"
local tmp

tmp="$(mktemp -d)"
rm -rf "${out}"

if ! (cd "${tmp}" && "${appimage}" --appimage-extract >/dev/null); then
rm -rf "${tmp}"
return 1
fi

if [ ! -x "${tmp}/squashfs-root/AppRun" ]; then
echo "Extracted AppImage is missing AppRun: ${appimage}" >&2
rm -rf "${tmp}"
return 1
fi

mv "${tmp}/squashfs-root" "${out}"
chmod -R u+w "${out}" 2>/dev/null || true
rm -rf "${tmp}"
}

print_tree_hash() {
local dir="$1"
local label="${2:-$(repo_relative_path "${dir}")}"
Expand Down
Loading