Files
luma/.github/workflows/build.yml
Ole André Vadla Ravnås 3d2c912c8c ci: Give frida-core's cgo the MinGW it looks for
Its detection wants MINGW64's gcc on x86_64, which went missing when
MSYS2 moved to UCRT64 for QEMU. A cached frida-core hid this until
the 17.19.0 bump.
2026-09-25 19:12:26 +02:00

1854 lines
72 KiB
YAML

name: Build
on:
push:
branches: [main]
tags: ['[0-9]+.[0-9]+.[0-9]+']
pull_request:
workflow_dispatch:
env:
SPARKLE_VERSION: "2.9.6"
SWIFT_VERSION: "6.2"
# ilammy/msvc-dev-cmd hasn't cut a Node-24-compatible release yet
# (v1 is its only major). Opt into Node 24 ahead of GitHub's
# forced migration in June 2026 so the warning doesn't clutter
# every build log in the meantime.
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.compute.outputs.version }}
build: ${{ steps.compute.outputs.build }}
frida_core_ref: ${{ steps.refs.outputs.FRIDA_CORE_REF }}
radare2_ref: ${{ steps.refs.outputs.RADARE2_REF }}
swifty_pharo_ref: ${{ steps.refs.outputs.SWIFTY_PHARO_REF }}
qemu_build: ${{ steps.refs.outputs.QEMU_BUILD }}
qemu_version: ${{ steps.refs.outputs.QEMU_VERSION }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
# Cache keys are interpolated before any step of the job they
# belong to has run, so the pinned revisions cannot be read from a
# file by the jobs that use them. Publishing them from here, where
# every such job already waits, keeps
# .github/dependency-refs.env the only place they are written.
- name: Read the pinned dependency revisions
id: refs
run: grep -E '^[A-Z0-9_]+=' .github/dependency-refs.env >> $GITHUB_OUTPUT
- id: compute
run: |
DESCRIPTION=$(git describe --tags --always --long --match='[0-9]*.[0-9]*.[0-9]*')
if [[ "$DESCRIPTION" != *-*-g* ]]; then
VERSION="0.0.0"
else
TAG="${DESCRIPTION%-*-g*}"
REST="${DESCRIPTION#${TAG}-}"
DISTANCE="${REST%-g*}"
if [[ "$TAG" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(-(.+))?$ ]]; then
MAJOR="${BASH_REMATCH[1]}"
MINOR="${BASH_REMATCH[2]}"
MICRO="${BASH_REMATCH[3]}"
SUFFIX="${BASH_REMATCH[5]}"
if [ -z "$SUFFIX" ]; then
if [ "$DISTANCE" -eq 0 ]; then
VERSION="$MAJOR.$MINOR.$MICRO"
else
VERSION="$MAJOR.$MINOR.$((MICRO + 1))-dev.$((DISTANCE - 1))"
fi
else
BASE="$MAJOR.$MINOR.$MICRO-$SUFFIX"
if [ "$DISTANCE" -eq 0 ]; then
VERSION="$BASE"
else
VERSION="$BASE-dev.$((DISTANCE - 1))"
fi
fi
else
echo "Unexpected tag format: $TAG" >&2
exit 1
fi
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "build=${{ github.run_number }}" >> $GITHUB_OUTPUT
checks:
runs-on: macos-26
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "20"
# The examples are Smalltalk inside Swift string literals, and a patch
# that has gone silent sounds fine to a compiler.
- name: Read the example catalogue
run: make check-examples
- name: Play every patch
run: make check-patches
- name: Ask the language server
run: make check-editor
frida-core:
runs-on: macos-26
needs: version
env:
FRIDA_CORE_REF: ${{ needs.version.outputs.frida_core_ref }}
strategy:
fail-fast: false
matrix:
include:
- { slice: macos-arm64, min_os: 'macos=15.0', extra_disables: '', extra_meson: '-Dfrida-gum:v8=disabled' }
- { slice: macos-x86_64, min_os: 'macos=15.0', extra_disables: '', extra_meson: '-Dfrida-gum:v8=disabled' }
- { slice: ios-arm64, min_os: 'ios=26.0', extra_disables: '--disable-local-backend --disable-simmy-backend --disable-fruity-backend --disable-droidy-backend --disable-barebone-backend', extra_meson: '-Dfrida-gum:jailbreak=disabled -Dfrida-gum:v8=disabled -Dglib-networking:apple_api_surface=public' }
- { slice: ios-arm64-simulator, min_os: 'ios=26.0', extra_disables: '--disable-local-backend --disable-simmy-backend --disable-fruity-backend --disable-droidy-backend --disable-barebone-backend', extra_meson: '-Dfrida-gum:jailbreak=disabled -Dfrida-gum:v8=disabled' }
steps:
- uses: actions/setup-node@v6
with:
node-version: "20"
- name: Restore frida-core cache
id: cache
uses: actions/cache/restore@v5
with:
path: ${{ runner.temp }}/devkit
key: ${{ runner.os }}-frida-core-devkit-${{ matrix.slice }}-${{ matrix.min_os }}-${{ env.FRIDA_CORE_REF }}-v4
- name: Set up Apple codesigning identities
if: steps.cache.outputs.cache-hit != 'true'
env:
CERTIFICATES_P12: ${{ secrets.APPLE_CERTIFICATES_P12 }}
CERTIFICATES_PASSWORD: ${{ secrets.APPLE_CERTIFICATES_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
run: |
if [ -z "$CERTIFICATES_P12" ]; then
echo "MACOS_CERTID=-" >> $GITHUB_ENV
echo "IOS_CERTID=-" >> $GITHUB_ENV
exit 0
fi
CERTIFICATE_PATH=$RUNNER_TEMP/apple-certificates.p12
KEYCHAIN_PATH=$RUNNER_TEMP/luma-frida-core.keychain-db
echo -n "$CERTIFICATES_P12" | base64 --decode -o $CERTIFICATE_PATH
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security import $CERTIFICATE_PATH -P "$CERTIFICATES_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
rm $CERTIFICATE_PATH
{
echo "MACOS_CERTID=$(security find-identity -v -p codesigning | grep 'Developer ID Application: ' | awk '{ print $2 }')"
echo "IOS_CERTID=$(security find-identity -v -p codesigning | grep 'Apple Distribution: ' | awk '{ print $2 }')"
} >> $GITHUB_ENV
- name: Clone frida-core
if: steps.cache.outputs.cache-hit != 'true'
run: |
git clone https://github.com/frida/frida-core.git $RUNNER_TEMP/frida-core
cd $RUNNER_TEMP/frida-core
git checkout $FRIDA_CORE_REF
git submodule update --init --recursive --depth 1
- name: Install Go toolchain
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/setup-go@v6
with:
go-version-file: ${{ runner.temp }}/frida-core/src/compiler/go.mod
cache: false
- name: Build frida-core
if: steps.cache.outputs.cache-hit != 'true'
env:
GOTOOLCHAIN: auto
run: |
cd $RUNNER_TEMP/frida-core
./configure \
--host=${{ matrix.slice }} \
--prefix=$RUNNER_TEMP/frida-prefix \
--with-apple-min-os=${{ matrix.min_os }} \
--with-devkits=core \
--enable-compiler-backend \
--disable-server \
--disable-portal \
--disable-inject \
--disable-gadget \
--disable-tests \
${{ matrix.extra_disables }} \
-- --force-fallback-for=nice ${{ matrix.extra_meson }}
make -j$(sysctl -n hw.ncpu)
make install
DEVKIT_SRC=$RUNNER_TEMP/frida-prefix/lib/frida-1.0/devkits/core
mkdir -p $RUNNER_TEMP/devkit
cp $DEVKIT_SRC/libfrida-core.a $RUNNER_TEMP/devkit/
cp $DEVKIT_SRC/frida-core.h $RUNNER_TEMP/devkit/
- name: Save frida-core cache
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: ${{ runner.temp }}/devkit
key: ${{ runner.os }}-frida-core-devkit-${{ matrix.slice }}-${{ matrix.min_os }}-${{ env.FRIDA_CORE_REF }}-v4
- uses: actions/upload-artifact@v7
with:
name: frida-core-devkit-${{ matrix.slice }}
path: ${{ runner.temp }}/devkit
if-no-files-found: error
macos:
# Apple Silicon Xcode cross-compiles to x86_64 natively, so both
# matrix entries run on the free arm64 runner — no paid -large
# runner needed for the Intel slice.
runs-on: macos-26
needs: [version, frida-core]
env:
LUMA_VERSION: ${{ needs.version.outputs.version }}
LUMA_BUILD: ${{ needs.version.outputs.build }}
QEMU_BUILD: ${{ needs.version.outputs.qemu_build }}
strategy:
fail-fast: false
matrix:
arch: [arm64, x86_64]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "20"
- name: Install the Apple certificates
env:
CERTIFICATES_P12: ${{ secrets.APPLE_CERTIFICATES_P12 }}
CERTIFICATES_PASSWORD: ${{ secrets.APPLE_CERTIFICATES_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
run: |
if [ -z "$CERTIFICATES_P12" ]; then
echo "No signing certificates configured, skipping"
exit 0
fi
CERTIFICATE_PATH=$RUNNER_TEMP/apple-certificates.p12
KEYCHAIN_PATH=$RUNNER_TEMP/luma-signing.keychain-db
echo -n "$CERTIFICATES_P12" | base64 --decode -o $CERTIFICATE_PATH
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security import $CERTIFICATE_PATH -P "$CERTIFICATES_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
rm $CERTIFICATE_PATH
MACOS_CERTID=$(security find-identity -v -p codesigning | grep "Developer ID Application: " | awk '{ print $2 }')
echo "MACOS_CERTID=$MACOS_CERTID" >> $GITHUB_ENV
echo "CAN_SIGN=true" >> $GITHUB_ENV
- name: Install the Developer ID provisioning profile
env:
DEVELOPER_ID_PROFILE: ${{ secrets.APPLE_DEVELOPER_ID_PROFILE }}
run: |
if [ "$CAN_SIGN" != "true" ]; then
echo "Not signing; skipping provisioning profile"
exit 0
fi
if [ -z "$DEVELOPER_ID_PROFILE" ]; then
echo "CAN_SIGN=true but APPLE_DEVELOPER_ID_PROFILE is not set." >&2
echo "The aps-environment entitlement requires an embedded Developer ID" >&2
echo "provisioning profile, or macOS will refuse to launch the app." >&2
exit 1
fi
PROFILE_PATH=$RUNNER_TEMP/developer-id.provisionprofile
echo -n "$DEVELOPER_ID_PROFILE" | base64 --decode -o $PROFILE_PATH
echo "DEVELOPER_ID_PROFILE_PATH=$PROFILE_PATH" >> $GITHUB_ENV
- name: Download frida-core devkits
uses: actions/download-artifact@v8
with:
pattern: frida-core-devkit-macos-*
path: ${{ runner.temp }}/devkits
- name: Publish frida-core through pkg-config
run: |
DEVKIT=$RUNNER_TEMP/frida-core
# The build tools run on the runner while the app is built for the
# slice, so both architectures have to be there to link.
cp -R $RUNNER_TEMP/devkits/frida-core-devkit-macos-arm64 $DEVKIT
lipo -create \
$RUNNER_TEMP/devkits/frida-core-devkit-macos-arm64/libfrida-core.a \
$RUNNER_TEMP/devkits/frida-core-devkit-macos-x86_64/libfrida-core.a \
-output $DEVKIT/libfrida-core-1.0.a
rm $DEVKIT/libfrida-core.a
brew install glib
mkdir -p $DEVKIT/pkgconfig
cat > $DEVKIT/pkgconfig/frida-core-1.0.pc <<EOF
prefix=$DEVKIT
Name: frida-core
Description: Frida core library
Version: 17.0.0
Cflags: -I\${prefix} $(pkg-config --cflags gio-unix-2.0)
Libs: -L\${prefix} -lfrida-core-1.0 -framework Network
EOF
echo "USE_SYSTEM_FRIDA=1" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH=$DEVKIT/pkgconfig" >> $GITHUB_ENV
- name: Point frida-swift at it
run: |
git clone https://github.com/frida/frida-swift.git $RUNNER_TEMP/frida-swift
python3 - <<'PY'
import os, re
swift_pkg = os.path.join(os.environ["RUNNER_TEMP"], "frida-swift", "Package.swift")
with open(swift_pkg) as f:
text = f.read()
# gioapple pulls in Network.framework, which frida-swift does not
# declare: it only asks for resolv.
text = re.sub(
r"linkerSettings:\s*\[",
'linkerSettings: [\n .linkedFramework("Network", .when(platforms: [.macOS, .iOS])),',
text,
count=1,
)
with open(swift_pkg, "w") as f:
f.write(text)
luma_pkg = "Package.swift"
with open(luma_pkg) as f:
text = f.read()
frida_swift_path = os.path.join(os.environ["RUNNER_TEMP"], "frida-swift")
text = re.sub(
r'\.package\(url:\s*"https://github\.com/frida/frida-swift"[^)]*\)',
f'.package(path: "{frida_swift_path}")',
text,
count=1,
)
with open(luma_pkg, "w") as f:
f.write(text)
PY
- name: Install shader toolchain
run: brew install glslang spirv-cross
- name: Generate sources
run: scripts/generate-sources.sh
- name: Build
run: |
xcodebuild \
-project Luma.xcodeproj \
-scheme Luma \
-configuration Release \
-derivedDataPath build/.derived \
-arch ${{ matrix.arch }} \
MARKETING_VERSION=$LUMA_VERSION \
CURRENT_PROJECT_VERSION=$LUMA_BUILD \
CODE_SIGN_IDENTITY=- \
CODE_SIGNING_ALLOWED=NO \
build
mkdir -p build
cp -r build/.derived/Build/Products/Release/Luma.app build/
- name: Bundle QEMU
run: |
ARCHIVE=qemu-$QEMU_BUILD-macos-${{ matrix.arch }}.zip
curl -sSfLO "https://github.com/frida/luma/releases/download/qemu-$QEMU_BUILD/$ARCHIVE"
EXPECTED=$(grep -E "^QEMU_MACOS_$(echo ${{ matrix.arch }} | tr a-z A-Z)_SHA256=" \
.github/dependency-refs.env | cut -d= -f2)
echo "$EXPECTED $ARCHIVE" | shasum -a 256 -c -
# QemuExecutable looks beside the LumaCore resource bundle, and
# -L points the emulators at the firmware that travels with them.
unzip -q "$ARCHIVE" -d build/Luma.app/Contents/Resources/qemu
chmod +x build/Luma.app/Contents/Resources/qemu/qemu-*
- name: Post-process binary
run: |
strip -Sx build/Luma.app/Contents/MacOS/Luma
R2_RES=build/Luma.app/Contents/Frameworks/Radare2.framework/Versions/A/Resources
rm -rf "$R2_RES/scripts" "$R2_RES/www"
for fw in build/Luma.app/Contents/Frameworks/*.framework; do
# xcodebuild's Embed Frameworks resolves the framework's
# symlinks (Versions/Current and the top-level Foo,
# Resources, Updater.app, ...) into real files/dirs, leaving
# parallel copies that confuse codesign with "bundle format
# is ambiguous". Restore the canonical structure.
ver=$(find "$fw/Versions" -mindepth 1 -maxdepth 1 -type d \
! -name Current 2>/dev/null | head -n 1)
if [ -n "$ver" ]; then
vername=$(basename "$ver")
if [ ! -L "$fw/Versions/Current" ]; then
rm -rf "$fw/Versions/Current"
ln -s "$vername" "$fw/Versions/Current"
fi
for entry in "$ver"/*; do
name=$(basename "$entry")
if [ -e "$fw/$name" ] && [ ! -L "$fw/$name" ]; then
rm -rf "$fw/$name"
ln -s "Versions/Current/$name" "$fw/$name"
fi
done
fi
name=$(basename "$fw" .framework)
bin="$fw/$name"
[ -L "$bin" ] && bin=$(realpath "$bin")
if lipo -info "$bin" 2>/dev/null | grep -q 'Architectures in the fat'; then
lipo -thin ${{ matrix.arch }} "$bin" -output "$bin.thin"
mv "$bin.thin" "$bin"
fi
done
- name: Sign
if: env.CAN_SIGN == 'true'
run: |
sign() {
codesign --force --options runtime --timestamp \
--sign "Developer ID Application" "$1"
}
SPARKLE=build/Luma.app/Contents/Frameworks/Sparkle.framework
if [ -d "$SPARKLE" ]; then
if [ -d "$SPARKLE/Versions/Current" ]; then
SPARKLE_ROOT="$SPARKLE/Versions/Current"
else
SPARKLE_ROOT="$SPARKLE"
fi
[ -f "$SPARKLE_ROOT/Autoupdate" ] && sign "$SPARKLE_ROOT/Autoupdate"
for xpc in "$SPARKLE_ROOT"/XPCServices/*.xpc; do
[ -d "$xpc" ] && sign "$xpc"
done
[ -d "$SPARKLE_ROOT/Updater.app" ] && sign "$SPARKLE_ROOT/Updater.app"
fi
QEMU=build/Luma.app/Contents/Resources/qemu
for macho in "$QEMU"/qemu-* "$QEMU"/lib/*.dylib; do
codesign --force --options runtime --timestamp \
--entitlements Luma/QEMU-macOS.entitlements \
--sign "Developer ID Application" "$macho"
done
# Signing a framework seals what is inside it, so the Pharo VM's
# plugins have to be signed before it is, not after.
find build/Luma.app/Contents/Frameworks -name '*.dylib' | while read dylib; do
sign "$dylib"
done
find build/Luma.app/Contents/Frameworks -name '*.framework' -maxdepth 1 | while read fw; do
sign "$fw"
done
cp "$DEVELOPER_ID_PROFILE_PATH" build/Luma.app/Contents/embedded.provisionprofile
codesign --force --options runtime \
--sign "Developer ID Application" \
--entitlements Luma/Luma-macOS.entitlements \
--timestamp \
build/Luma.app
- name: Notarize
if: env.CAN_SIGN == 'true'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
NOTARY_PASSWORD: ${{ secrets.APPLE_NOTARY_PASSWORD }}
run: |
xcrun notarytool store-credentials "notarytool-profile" \
--apple-id "$APPLE_ID" \
--team-id "$TEAM_ID" \
--password "$NOTARY_PASSWORD"
ditto -c -k --sequesterRsrc build/Luma.app Luma-notarize.zip
RESULT=$(xcrun notarytool submit Luma-notarize.zip \
--keychain-profile "notarytool-profile" \
--wait 2>&1) || true
echo "$RESULT"
ID=$(echo "$RESULT" | grep ' id:' | head -1 | awk '{print $2}')
STATUS=$(echo "$RESULT" | grep ' status:' | head -1 | awk '{print $2}')
if [ "$STATUS" != "Accepted" ]; then
echo "--- Notarization log ---"
xcrun notarytool log "$ID" --keychain-profile "notarytool-profile" 2>&1 || true
exit 1
fi
xcrun stapler staple build/Luma.app
- name: Install create-dmg
run: brew install create-dmg
- name: Create DMG
run: |
create-dmg \
--volname "Luma" \
--window-pos 200 120 \
--window-size 600 400 \
--icon-size 100 \
--icon "Luma.app" 150 185 \
--app-drop-link 450 185 \
--no-internet-enable \
Luma-${LUMA_VERSION}-${{ matrix.arch }}.dmg \
build/Luma.app
- name: Sign DMG for Sparkle
if: env.CAN_SIGN == 'true'
env:
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }}
run: |
if [ -z "$SPARKLE_PRIVATE_KEY" ]; then
echo "SPARKLE_PRIVATE_KEY secret is not set." >&2
echo "Sparkle requires every DMG to be signed with the EdDSA" >&2
echo "private key paired with SUPublicEDKey in Info.plist," >&2
echo "or the auto-updater will refuse the download." >&2
exit 1
fi
SPARKLE_DIR=$RUNNER_TEMP/sparkle
mkdir -p $SPARKLE_DIR
curl -sL "https://github.com/sparkle-project/Sparkle/releases/download/${SPARKLE_VERSION}/Sparkle-${SPARKLE_VERSION}.tar.xz" \
| tar -xJf - -C $SPARKLE_DIR
KEY_FILE=$RUNNER_TEMP/sparkle-priv.key
printf %s "$SPARKLE_PRIVATE_KEY" > $KEY_FILE
chmod 600 $KEY_FILE
DMG=Luma-${LUMA_VERSION}-${{ matrix.arch }}.dmg
SIG_LINE=$($SPARKLE_DIR/bin/sign_update -f $KEY_FILE "$DMG")
rm -f $KEY_FILE
echo "$SIG_LINE"
SIG=$(echo "$SIG_LINE" | sed -E 's/.*sparkle:edSignature="([^"]+)".*/\1/')
if [ -z "$SIG" ] || [ "$SIG" = "$SIG_LINE" ]; then
echo "Failed to extract edSignature from sign_update output." >&2
exit 1
fi
printf %s "$SIG" > "${DMG}.sig"
- uses: actions/upload-artifact@v7
with:
name: Luma-${{ env.LUMA_VERSION }}-${{ matrix.arch }}.dmg
path: Luma-${{ env.LUMA_VERSION }}-${{ matrix.arch }}.dmg
- uses: actions/upload-artifact@v7
if: env.CAN_SIGN == 'true'
with:
name: Luma-${{ env.LUMA_VERSION }}-${{ matrix.arch }}.dmg.sig
path: Luma-${{ env.LUMA_VERSION }}-${{ matrix.arch }}.dmg.sig
ios:
runs-on: macos-26
needs: [version, frida-core]
env:
LUMA_VERSION: ${{ needs.version.outputs.version }}
LUMA_BUILD: ${{ needs.version.outputs.build }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "20"
- name: Install the Apple certificates
env:
CERTIFICATES_P12: ${{ secrets.APPLE_CERTIFICATES_P12 }}
CERTIFICATES_PASSWORD: ${{ secrets.APPLE_CERTIFICATES_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
run: |
if [ -z "$CERTIFICATES_P12" ]; then
echo "No signing certificates configured, will build unsigned"
exit 0
fi
CERTIFICATE_PATH=$RUNNER_TEMP/apple-certificates.p12
KEYCHAIN_PATH=$RUNNER_TEMP/luma-signing.keychain-db
echo -n "$CERTIFICATES_P12" | base64 --decode -o $CERTIFICATE_PATH
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security import $CERTIFICATE_PATH -P "$CERTIFICATES_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
rm $CERTIFICATE_PATH
if ! security find-identity -v -p codesigning | grep -q "Apple Distribution"; then
echo "No Apple Distribution identity in the provided certificate bundle." >&2
echo "Add one to APPLE_CERTIFICATES_P12 to enable iOS archive builds." >&2
exit 0
fi
echo "CAN_SIGN=true" >> $GITHUB_ENV
- name: Install the App Store provisioning profile
if: env.CAN_SIGN == 'true'
env:
APP_STORE_PROFILE: ${{ secrets.APPLE_APP_STORE_PROFILE }}
run: |
if [ -z "$APP_STORE_PROFILE" ]; then
echo "CAN_SIGN=true but APPLE_APP_STORE_PROFILE is not set." >&2
echo "An App Store provisioning profile for re.frida.Luma is" >&2
echo "required to archive for iOS." >&2
exit 1
fi
PROFILE_PATH=$RUNNER_TEMP/app-store.mobileprovision
echo -n "$APP_STORE_PROFILE" | base64 --decode -o $PROFILE_PATH
UUID=$(security cms -D -i $PROFILE_PATH | plutil -extract UUID raw -)
INSTALL_DIR="$HOME/Library/MobileDevice/Provisioning Profiles"
mkdir -p "$INSTALL_DIR"
cp $PROFILE_PATH "$INSTALL_DIR/$UUID.mobileprovision"
echo "LUMA_IOS_PROFILE=$UUID" >> $GITHUB_ENV
- name: Install the App Store Connect API key
if: env.CAN_SIGN == 'true' && github.ref_type == 'tag'
env:
KEY_ID: ${{ secrets.APPLE_APP_STORE_CONNECT_KEY_ID }}
ISSUER_ID: ${{ secrets.APPLE_APP_STORE_CONNECT_ISSUER_ID }}
KEY_P8: ${{ secrets.APPLE_APP_STORE_CONNECT_KEY_P8 }}
run: |
if [ -z "$KEY_ID" ] || [ -z "$ISSUER_ID" ] || [ -z "$KEY_P8" ]; then
echo "Tag push with CAN_SIGN=true but App Store Connect API" >&2
echo "credentials are not set. Configure _KEY_ID, _ISSUER_ID" >&2
echo "and _KEY_P8 so altool can upload to TestFlight." >&2
exit 1
fi
KEYS_DIR=$HOME/.appstoreconnect/private_keys
mkdir -p $KEYS_DIR
KEY_FILE=$KEYS_DIR/AuthKey_${KEY_ID}.p8
printf %s "$KEY_P8" > $KEY_FILE
echo "ASC_KEY_ID=$KEY_ID" >> $GITHUB_ENV
echo "ASC_ISSUER_ID=$ISSUER_ID" >> $GITHUB_ENV
echo "ASC_KEY_FILE=$KEY_FILE" >> $GITHUB_ENV
- name: Download frida-core devkits
uses: actions/download-artifact@v8
with:
pattern: frida-core-devkit-*
path: ${{ runner.temp }}/devkits
- name: Assemble FridaCore.xcframework
run: |
# One .pc names one library, and this build links two platforms at
# once: the bundle compiler runs on the runner while the app is
# built for the device. Only an xcframework can say both.
DEVKITS=$RUNNER_TEMP/devkits
MACOS=$RUNNER_TEMP/frida-core-macos
mkdir -p $MACOS
lipo -create \
$DEVKITS/frida-core-devkit-macos-arm64/libfrida-core.a \
$DEVKITS/frida-core-devkit-macos-x86_64/libfrida-core.a \
-output $MACOS/libfrida-core.a
headers() {
out=$RUNNER_TEMP/headers-$1
mkdir -p $out/FridaCore
cp $2/frida-core.h $out/
cat > $out/FridaCore/module.modulemap <<'EOF'
module FridaCore [extern_c] {
header "../frida-core.h"
export *
}
EOF
}
headers macos $DEVKITS/frida-core-devkit-macos-arm64
headers ios $DEVKITS/frida-core-devkit-ios-arm64
headers simulator $DEVKITS/frida-core-devkit-ios-arm64-simulator
xcodebuild -create-xcframework \
-library $MACOS/libfrida-core.a \
-headers $RUNNER_TEMP/headers-macos \
-library $DEVKITS/frida-core-devkit-ios-arm64/libfrida-core.a \
-headers $RUNNER_TEMP/headers-ios \
-library $DEVKITS/frida-core-devkit-ios-arm64-simulator/libfrida-core.a \
-headers $RUNNER_TEMP/headers-simulator \
-output $RUNNER_TEMP/FridaCore.xcframework
- name: Point frida-swift at it
run: |
git clone https://github.com/frida/frida-swift.git $RUNNER_TEMP/frida-swift
cp -R $RUNNER_TEMP/FridaCore.xcframework $RUNNER_TEMP/frida-swift/
python3 - <<'PY'
import os, re
swift_pkg = os.path.join(os.environ["RUNNER_TEMP"], "frida-swift", "Package.swift")
with open(swift_pkg) as f:
text = f.read()
text = re.sub(
r"\.binaryTarget\(\s*name:\s*\"FridaCore\",\s*url:[^)]+\)",
'.binaryTarget(\n name: "FridaCore",\n path: "FridaCore.xcframework"\n )',
text,
count=1,
flags=re.DOTALL,
)
# gioapple pulls in Network.framework, which frida-swift does not
# declare: it only asks for resolv.
text = re.sub(
r"linkerSettings:\s*\[",
'linkerSettings: [\n .linkedFramework("Network", .when(platforms: [.macOS, .iOS])),',
text,
count=1,
)
with open(swift_pkg, "w") as f:
f.write(text)
luma_pkg = "Package.swift"
with open(luma_pkg) as f:
text = f.read()
frida_swift_path = os.path.join(os.environ["RUNNER_TEMP"], "frida-swift")
text = re.sub(
r'\.package\(url:\s*"https://github\.com/frida/frida-swift"[^)]*\)',
f'.package(path: "{frida_swift_path}")',
text,
count=1,
)
with open(luma_pkg, "w") as f:
f.write(text)
PY
- name: Install shader toolchain
run: brew install glslang spirv-cross
- name: Generate sources
run: scripts/generate-sources.sh
- name: Build (unsigned, iOS Simulator)
if: env.CAN_SIGN != 'true'
run: |
xcodebuild \
-project Luma.xcodeproj \
-scheme Luma \
-configuration Release \
-destination 'generic/platform=iOS Simulator' \
-derivedDataPath build/.derived-ios \
ARCHS=arm64 \
ONLY_ACTIVE_ARCH=YES \
CODE_SIGN_IDENTITY=- \
CODE_SIGNING_ALLOWED=NO \
build
- name: Archive
if: env.CAN_SIGN == 'true'
env:
TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
xcodebuild \
-project Luma.xcodeproj \
-scheme Luma \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath build/Luma.xcarchive \
-derivedDataPath build/.derived-ios \
DEVELOPMENT_TEAM=$TEAM_ID \
LUMA_IOS_PROFILE=$LUMA_IOS_PROFILE \
MARKETING_VERSION=$LUMA_VERSION \
CURRENT_PROJECT_VERSION=$LUMA_BUILD \
archive
- name: Sanitize embedded Radare2 framework
if: env.CAN_SIGN == 'true'
run: |
APP=build/Luma.xcarchive/Products/Applications/Luma.app
FRAMEWORK="$APP/Frameworks/Radare2.framework"
rm -rf "$FRAMEWORK/scripts" "$FRAMEWORK/www"
MIN_IOS=$(plutil -extract MinimumOSVersion raw "$APP/Info.plist")
plutil -insert MinimumOSVersion -string "$MIN_IOS" "$FRAMEWORK/Info.plist"
SIGN_ID=$(security find-identity -v -p codesigning | awk '/Apple Distribution/ {print $2; exit}')
codesign --force --sign "$SIGN_ID" "$FRAMEWORK"
- name: Export IPA
if: env.CAN_SIGN == 'true'
env:
TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
EXPORT_OPTIONS=$RUNNER_TEMP/ExportOptions.plist
cat > $EXPORT_OPTIONS <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store-connect</string>
<key>destination</key>
<string>export</string>
<key>teamID</key>
<string>$TEAM_ID</string>
<key>signingStyle</key>
<string>manual</string>
<key>stripSwiftSymbols</key>
<true/>
<key>uploadSymbols</key>
<true/>
<key>provisioningProfiles</key>
<dict>
<key>re.frida.Luma</key>
<string>$LUMA_IOS_PROFILE</string>
</dict>
</dict>
</plist>
EOF
xcodebuild -exportArchive \
-archivePath build/Luma.xcarchive \
-exportPath build/ipa \
-exportOptionsPlist $EXPORT_OPTIONS
mv build/ipa/Luma.ipa Luma-${LUMA_VERSION}.ipa
- uses: actions/upload-artifact@v7
if: env.CAN_SIGN == 'true'
with:
name: Luma-${{ env.LUMA_VERSION }}.ipa
path: Luma-${{ env.LUMA_VERSION }}.ipa
- name: Upload to TestFlight
if: env.CAN_SIGN == 'true' && github.ref_type == 'tag'
run: |
xcrun altool --upload-app \
--type ios \
--file Luma-${LUMA_VERSION}.ipa \
--apiKey "$ASC_KEY_ID" \
--apiIssuer "$ASC_ISSUER_ID"
fedora:
runs-on: ubuntu-latest
container: fedora:44
needs: version
env:
LUMA_VERSION: ${{ needs.version.outputs.version }}
FRIDA_CORE_REF: ${{ needs.version.outputs.frida_core_ref }}
RADARE2_REF: ${{ needs.version.outputs.radare2_ref }}
SWIFTY_PHARO_REF: ${{ needs.version.outputs.swifty_pharo_ref }}
steps:
- name: Install system dependencies
run: |
dnf install -y --setopt=install_weak_deps=False \
gtk4-devel \
libadwaita-devel \
gtksourceview5-devel \
glib2-devel \
pango-devel \
cairo-devel \
harfbuzz-devel \
gdk-pixbuf2-devel \
graphene-devel \
libepoxy-devel \
librsvg2-devel \
libsoup3-devel \
xz-devel \
gobject-introspection-devel \
atk-devel \
libxml2-devel \
libzip-devel \
zlib-devel \
libgee-devel \
json-glib-devel \
libunwind-devel \
libdwarf-devel \
elfutils-devel \
libnice-devel \
ngtcp2-devel \
ngtcp2-crypto-ossl-devel \
openssl-devel \
libuuid-devel \
libffi-devel \
cmake \
unzip \
wget \
vala \
meson \
ninja-build \
nodejs \
npm \
gcc \
gcc-c++ \
libstdc++-devel \
libstdc++-static \
kernel-headers \
glibc-devel \
make \
git \
which \
curl \
pkg-config \
rpm-build \
python3-pip \
python3-setuptools \
swiftlang \
golang \
patchelf \
rsync
swift --version
- name: Restore frida-core cache
id: frida-cache
uses: actions/cache/restore@v5
with:
path: /tmp/frida-destdir
key: ${{ runner.os }}-fedora44-frida-core-${{ env.FRIDA_CORE_REF }}-v4
- name: Clone frida-core
if: steps.frida-cache.outputs.cache-hit != 'true'
run: |
git clone https://github.com/frida/frida-core.git /tmp/frida-core
cd /tmp/frida-core
git checkout $FRIDA_CORE_REF
- name: Install Go toolchain
if: steps.frida-cache.outputs.cache-hit != 'true'
uses: actions/setup-go@v6
with:
go-version-file: /tmp/frida-core/src/compiler/go.mod
cache: false
- name: Build frida-core (shared)
if: steps.frida-cache.outputs.cache-hit != 'true'
env:
CC: gcc
CXX: g++
run: |
cd /tmp/frida-core
./configure --enable-shared --enable-compiler-backend --without-prebuilds=sdk --prefix=/usr \
-- -Dfrida-gum:v8=disabled
make -j$(nproc)
DESTDIR=/tmp/frida-destdir make install
- name: Save frida-core cache
if: steps.frida-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: /tmp/frida-destdir
key: ${{ runner.os }}-fedora44-frida-core-${{ env.FRIDA_CORE_REF }}-v4
- name: Install frida-core
run: |
cp -a /tmp/frida-destdir/usr/. /usr/
ldconfig
- name: Restore radare2 cache
id: r2-cache
uses: actions/cache/restore@v5
with:
path: /tmp/r2-destdir
key: ${{ runner.os }}-fedora44-radare2-${{ env.RADARE2_REF }}-v2
- name: Build radare2 (static)
if: steps.r2-cache.outputs.cache-hit != 'true'
env:
CC: gcc
CXX: g++
run: |
git clone https://github.com/radareorg/radare2.git /tmp/radare2
cd /tmp/radare2
git checkout $RADARE2_REF
meson setup build --prefix=/usr --default-library=static -Dstatic_runtime=true -Dcli=disabled -Duse_sys_zip=true
DESTDIR=/tmp/r2-destdir ninja -C build install
- name: Save radare2 cache
if: steps.r2-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: /tmp/r2-destdir
key: ${{ runner.os }}-fedora44-radare2-${{ env.RADARE2_REF }}-v2
- name: Install radare2
run: |
cp -a /tmp/r2-destdir/usr/. /usr/
ldconfig
- name: Restore Pharo VM cache
id: pharo-cache
uses: actions/cache/restore@v5
with:
path: /tmp/pharo-destdir
key: ${{ runner.os }}-fedora44-pharo-vm-${{ env.SWIFTY_PHARO_REF }}-v9
- name: Build Pharo VM
if: steps.pharo-cache.outputs.cache-hit != 'true'
run: |
git clone https://github.com/frida/SwiftyPharo.git /tmp/SwiftyPharo
cd /tmp/SwiftyPharo
git checkout $SWIFTY_PHARO_REF
PLATFORM=linux PREFIX=/opt/pharo-vm tools/build-vm.sh
mv artifacts/destdir/linux-* /tmp/pharo-destdir
- name: Save Pharo VM cache
if: steps.pharo-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: /tmp/pharo-destdir
key: ${{ runner.os }}-fedora44-pharo-vm-${{ env.SWIFTY_PHARO_REF }}-v9
- name: Install Pharo VM
run: |
cp -a /tmp/pharo-destdir/. /
echo /opt/pharo-vm/lib > /etc/ld.so.conf.d/pharo-vm.conf
ldconfig
- uses: actions/checkout@v6
- name: Build
env:
PKG_CONFIG_PATH: /opt/pharo-vm/lib/pkgconfig
run: cd LumaGtk && make build SWIFT_BUILD_FLAGS="-c release"
- name: Package as .rpm
run: |
TOP=$PWD/rpmbuild
mkdir -p $TOP/{SOURCES/stage,SPECS,BUILD,BUILDROOT,RPMS,SRPMS}
LumaGtk/build-aux/linux/stage.sh \
$TOP/SOURCES/stage \
LumaGtk/.build/x86_64-unknown-linux-gnu/release/LumaGtk \
/usr/lib64 \
/opt/pharo-vm/lib
cp LumaGtk/build-aux/rpm/luma.spec $TOP/SPECS/
NATIVE_VERSION=$(echo "$LUMA_VERSION" | tr - '~')
rpmbuild --define "_topdir $TOP" \
--define "version $NATIVE_VERSION" \
-bb $TOP/SPECS/luma.spec
cp $TOP/RPMS/x86_64/luma-${NATIVE_VERSION}-*.x86_64.rpm luma-${LUMA_VERSION}-fedora-44-x86_64.rpm
- uses: actions/upload-artifact@v7
with:
name: luma-${{ env.LUMA_VERSION }}-fedora-44-x86_64.rpm
path: luma-${{ env.LUMA_VERSION }}-fedora-44-x86_64.rpm
ubuntu:
runs-on: ubuntu-latest
container: ubuntu:${{ matrix.release }}
needs: version
strategy:
fail-fast: false
matrix:
include:
- release: "24.04"
libzip_dep: libzip4t64
libxml2_path: ""
extra_runtime_deps: ", libxml2"
- release: "26.04"
libzip_dep: libzip5
libxml2_path: /usr/lib/x86_64-linux-gnu/libxml2.so.16
extra_runtime_deps: ""
env:
LUMA_VERSION: ${{ needs.version.outputs.version }}
FRIDA_CORE_REF: ${{ needs.version.outputs.frida_core_ref }}
RADARE2_REF: ${{ needs.version.outputs.radare2_ref }}
SWIFTY_PHARO_REF: ${{ needs.version.outputs.swifty_pharo_ref }}
steps:
- name: Install system dependencies
env:
DEBIAN_FRONTEND: noninteractive
run: |
apt-get update
apt-get install -y software-properties-common
add-apt-repository -y universe
apt-get update
apt-get install -y \
libgtk-4-dev \
libadwaita-1-dev \
libgtksourceview-5-dev \
libglib2.0-dev \
libpango1.0-dev \
libcairo2-dev \
libharfbuzz-dev \
libgdk-pixbuf-2.0-dev \
libgraphene-1.0-dev \
libepoxy-dev \
librsvg2-dev \
libsoup-3.0-dev \
liblzma-dev \
gobject-introspection \
libgirepository1.0-dev \
libatk1.0-dev \
libxml2-dev \
libzip-dev \
zlib1g-dev \
libgee-0.8-dev \
libjson-glib-dev \
libunwind-dev \
libnice-dev \
libssl-dev \
uuid-dev \
libffi-dev \
cmake \
unzip \
wget \
valac \
meson \
ninja-build \
pkg-config \
dpkg-dev \
nodejs \
npm \
curl \
git \
make \
binutils \
python3-pip \
gcc \
g++ \
libncurses6 \
libcurl4-openssl-dev \
golang-go \
patchelf \
rsync
- name: Install Swift
run: |
if [ "${{ matrix.release }}" = "26.04" ]; then
ln -sf libxml2.so.16 /usr/lib/x86_64-linux-gnu/libxml2.so.2
ldconfig
fi
curl -sLO "https://download.swift.org/swift-${SWIFT_VERSION}-release/ubuntu2404/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE-ubuntu24.04.tar.gz"
tar xzf swift-*.tar.gz -C /usr/local --strip-components=2
rm swift-*.tar.gz
ldconfig
swift --version
- name: Restore frida-core cache
id: frida-cache
uses: actions/cache/restore@v5
with:
path: /tmp/frida-destdir
key: ${{ runner.os }}-ubuntu${{ matrix.release }}-frida-core-${{ env.FRIDA_CORE_REF }}-v4
- name: Clone frida-core
if: steps.frida-cache.outputs.cache-hit != 'true'
run: |
git clone https://github.com/frida/frida-core.git /tmp/frida-core
cd /tmp/frida-core
git checkout $FRIDA_CORE_REF
- name: Install Go toolchain
if: steps.frida-cache.outputs.cache-hit != 'true'
uses: actions/setup-go@v6
with:
go-version-file: /tmp/frida-core/src/compiler/go.mod
cache: false
- name: Build frida-core (shared)
if: steps.frida-cache.outputs.cache-hit != 'true'
run: |
cd /tmp/frida-core
./configure --enable-shared --enable-compiler-backend --without-prebuilds=sdk --prefix=/usr \
-- --force-fallback-for=openssl -Dfrida-gum:v8=disabled
make -j$(nproc)
DESTDIR=/tmp/frida-destdir make install
- name: Save frida-core cache
if: steps.frida-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: /tmp/frida-destdir
key: ${{ runner.os }}-ubuntu${{ matrix.release }}-frida-core-${{ env.FRIDA_CORE_REF }}-v4
- name: Install frida-core
run: |
cp -a /tmp/frida-destdir/usr/. /usr/
ldconfig
- name: Restore radare2 cache
id: r2-cache
uses: actions/cache/restore@v5
with:
path: /tmp/r2-destdir
key: ${{ runner.os }}-ubuntu${{ matrix.release }}-radare2-${{ env.RADARE2_REF }}-v2
- name: Build radare2 (static)
if: steps.r2-cache.outputs.cache-hit != 'true'
run: |
git clone https://github.com/radareorg/radare2.git /tmp/radare2
cd /tmp/radare2
git checkout $RADARE2_REF
meson setup build --prefix=/usr --default-library=static -Dstatic_runtime=true -Dcli=disabled -Duse_sys_zip=true
DESTDIR=/tmp/r2-destdir ninja -C build install
- name: Save radare2 cache
if: steps.r2-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: /tmp/r2-destdir
key: ${{ runner.os }}-ubuntu${{ matrix.release }}-radare2-${{ env.RADARE2_REF }}-v2
- name: Install radare2
run: |
cp -a /tmp/r2-destdir/usr/. /usr/
ldconfig
- name: Restore Pharo VM cache
id: pharo-cache
uses: actions/cache/restore@v5
with:
path: /tmp/pharo-destdir
key: ${{ runner.os }}-ubuntu${{ matrix.release }}-pharo-vm-${{ env.SWIFTY_PHARO_REF }}-v9
- name: Build Pharo VM
if: steps.pharo-cache.outputs.cache-hit != 'true'
run: |
git clone https://github.com/frida/SwiftyPharo.git /tmp/SwiftyPharo
cd /tmp/SwiftyPharo
git checkout $SWIFTY_PHARO_REF
PLATFORM=linux PREFIX=/opt/pharo-vm tools/build-vm.sh
mv artifacts/destdir/linux-* /tmp/pharo-destdir
- name: Save Pharo VM cache
if: steps.pharo-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: /tmp/pharo-destdir
key: ${{ runner.os }}-ubuntu${{ matrix.release }}-pharo-vm-${{ env.SWIFTY_PHARO_REF }}-v9
- name: Install Pharo VM
run: |
cp -a /tmp/pharo-destdir/. /
echo /opt/pharo-vm/lib > /etc/ld.so.conf.d/pharo-vm.conf
ldconfig
- uses: actions/checkout@v6
- name: Build
env:
PKG_CONFIG_PATH: /opt/pharo-vm/lib/pkgconfig
run: cd LumaGtk && make build SWIFT_BUILD_FLAGS="-c release"
- name: Package as .deb
shell: bash
run: |
NATIVE_VERSION=$(echo "$LUMA_VERSION" | tr - '~')
PKG=luma_${NATIVE_VERSION}_amd64
LumaGtk/build-aux/linux/stage.sh \
$PKG \
LumaGtk/.build/x86_64-unknown-linux-gnu/release/LumaGtk \
/usr/lib/x86_64-linux-gnu \
/opt/pharo-vm/lib \
/usr/local/lib/swift/linux \
${{ matrix.libxml2_path }}
mkdir -p $PKG/DEBIAN
printf 'Package: luma\nVersion: %s\nSection: devel\nPriority: optional\nArchitecture: amd64\nDepends: libadwaita-1-0, libepoxy0, %s, libnice10, libgtksourceview-5-0, librsvg2-2, qemu-system-arm, qemu-system-x86, qemu-utils%s\nMaintainer: Ole Andre Vadla Ravnas <[email protected]>\nHomepage: https://luma.frida.re/\nDescription: the official Frida GUI\n Luma is a native app for interactive dynamic instrumentation,\n built on Frida. Persistent sessions, a live REPL, pluggable\n instruments, and real-time collaboration in a workspace that\n remembers where you left off.\n' "$NATIVE_VERSION" "${{ matrix.libzip_dep }}" "${{ matrix.extra_runtime_deps }}" > $PKG/DEBIAN/control
install -m0755 LumaGtk/build-aux/linux/deb-postinst $PKG/DEBIAN/postinst
install -m0755 LumaGtk/build-aux/linux/deb-postrm $PKG/DEBIAN/postrm
dpkg-deb --build $PKG
mv ${PKG}.deb luma-${LUMA_VERSION}-ubuntu-${{ matrix.release }}-x86_64.deb
- uses: actions/upload-artifact@v7
with:
name: luma-${{ env.LUMA_VERSION }}-ubuntu-${{ matrix.release }}-x86_64.deb
path: luma-${{ env.LUMA_VERSION }}-ubuntu-${{ matrix.release }}-x86_64.deb
appimage:
runs-on: ubuntu-latest
container: ghcr.io/pkgforge-dev/archlinux:latest
needs: [version, ubuntu]
env:
LUMA_VERSION: ${{ needs.version.outputs.version }}
steps:
- uses: actions/checkout@v6
- uses: actions/download-artifact@v8
with:
name: luma-${{ env.LUMA_VERSION }}-ubuntu-26.04-x86_64.deb
- name: Prepare container
uses: pkgforge-dev/anylinux-setup-action@v2
- name: Make AppImage
run: /bin/sh ./LumaGtk/build-aux/appimage/make-appimage.sh
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: Luma-${{ env.LUMA_VERSION }}-anylinux-x86_64.AppImage
path: Luma-${{ env.LUMA_VERSION }}-anylinux-x86_64.AppImage*
if-no-files-found: error
flatpak:
runs-on: ubuntu-latest
needs: version
env:
LUMA_VERSION: ${{ needs.version.outputs.version }}
FRIDA_CORE_REF: ${{ needs.version.outputs.frida_core_ref }}
steps:
- uses: actions/checkout@v6
- name: Free up disk space
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/opt/hostedtoolcache/CodeQL /usr/local/share/boost \
"$AGENT_TOOLSDIRECTORY"
sudo docker image prune --all --force || true
df -h
- name: Install Flatpak and flatpak-builder
run: |
sudo apt-get update
sudo apt-get install -y flatpak flatpak-builder
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
sudo flatpak install -y flathub org.gnome.Platform//50 org.gnome.Sdk//50
- name: Restore flatpak-builder cache
id: flatpak-cache
uses: actions/cache/restore@v5
with:
path: .flatpak-builder
key: flatpak-builder-v1
- name: Pin flatpak sources to the current tree
run: |
git archive --format=tar.gz --prefix=luma/ --output=/tmp/luma-source.tar.gz HEAD
python3 - <<'PY'
import json, os
path = "LumaGtk/build-aux/flatpak/re.frida.Luma.json"
with open(path) as f:
manifest = json.load(f)
for module in manifest.get("modules", []):
for i, source in enumerate(module.get("sources", [])):
url = source.get("url", "")
if url.endswith("frida/frida-core.git"):
source.pop("branch", None)
source["commit"] = os.environ["FRIDA_CORE_REF"]
elif url.endswith("frida/luma.git"):
module["sources"][i] = {
"type": "archive",
"path": "/tmp/luma-source.tar.gz",
}
with open(path, "w") as f:
json.dump(manifest, f, indent=4)
PY
- name: Build Flatpak
run: |
flatpak-builder \
--force-clean \
--disable-rofiles-fuse \
--keep-build-dirs \
--repo=flatpak-repo \
flatpak-build \
LumaGtk/build-aux/flatpak/re.frida.Luma.json
flatpak build-bundle flatpak-repo "luma-${LUMA_VERSION}-x86_64.flatpak" re.frida.Luma
- name: Save flatpak-builder cache
if: always()
uses: actions/cache/save@v5
with:
path: .flatpak-builder
key: flatpak-builder-v1
- uses: actions/upload-artifact@v7
with:
name: luma-${{ env.LUMA_VERSION }}-x86_64.flatpak
path: luma-${{ env.LUMA_VERSION }}-x86_64.flatpak
snap:
runs-on: ubuntu-latest
needs: version
env:
LUMA_VERSION: ${{ needs.version.outputs.version }}
FRIDA_CORE_REF: ${{ needs.version.outputs.frida_core_ref }}
# Kept non-blocking as a safety net while the core26 snap build
# settles on the hosted runners.
continue-on-error: true
steps:
- uses: actions/checkout@v6
- name: Free up disk space
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/opt/hostedtoolcache/CodeQL /usr/local/share/boost \
"$AGENT_TOOLSDIRECTORY"
sudo docker image prune --all --force || true
df -h
- name: Set snap version
run: |
sed -i "s/^version: .*/version: '${LUMA_VERSION}'/" \
LumaGtk/build-aux/snap/snapcraft.yaml
- name: Pin snap sources to the current tree
run: |
# The snapcraft VM only sees files under the project path
# (LumaGtk), so stage the tarball there.
git archive --format=tar.gz --output=LumaGtk/luma-source.tar.gz HEAD
python3 - <<'PY'
import os, re
path = "LumaGtk/build-aux/snap/snapcraft.yaml"
with open(path) as f:
text = f.read()
text = re.sub(
r"(source: https://github\.com/frida/frida-core\.git\n\s*)source-branch: main",
lambda m: m.group(1) + "source-commit: " + os.environ["FRIDA_CORE_REF"],
text,
)
text = re.sub(
r"source: https://github\.com/frida/luma\.git\n(\s*)source-branch: main",
r"source: luma-source.tar.gz\n\1source-type: tar",
text,
)
with open(path, "w") as f:
f.write(text)
PY
- uses: snapcore/[email protected]
id: snapcraft
with:
path: LumaGtk
- name: Rename snap artifact
run: cp "${{ steps.snapcraft.outputs.snap }}" "luma-${LUMA_VERSION}-x86_64.snap"
- uses: actions/upload-artifact@v7
with:
name: luma-${{ env.LUMA_VERSION }}-x86_64.snap
path: luma-${{ env.LUMA_VERSION }}-x86_64.snap
windows:
runs-on: ${{ matrix.runner }}
timeout-minutes: 240
needs: version
env:
LUMA_VERSION: ${{ needs.version.outputs.version }}
FRIDA_CORE_REF: ${{ needs.version.outputs.frida_core_ref }}
RADARE2_REF: ${{ needs.version.outputs.radare2_ref }}
SWIFTY_PHARO_REF: ${{ needs.version.outputs.swifty_pharo_ref }}
QEMU_VERSION: ${{ needs.version.outputs.qemu_version }}
strategy:
fail-fast: false
matrix:
include:
- runner: windows-2022
win_arch: x86_64
msvc_arch: amd64
swift_build_arch: amd64
vcpkg_triplet: x64-windows-release
toolcache_arch: x64
msys2_system: UCRT64
msys2_package: mingw-w64-ucrt-x86_64
cgo_package: mingw-w64-x86_64-gcc
- runner: windows-11-arm
win_arch: arm64
msvc_arch: arm64
swift_build_arch: arm64
vcpkg_triplet: arm64-windows-release
toolcache_arch: arm64
msys2_system: CLANGARM64
msys2_package: mingw-w64-clang-aarch64
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "20"
- name: Keep Node on PATH
shell: pwsh
run: Add-Content -Path $env:GITHUB_PATH -Value (Split-Path (Get-Command node).Source)
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.msvc_arch }}
- uses: compnerd/[email protected]
with:
swift-version: "swift-${{ env.SWIFT_VERSION }}-release"
swift-build: "${{ env.SWIFT_VERSION }}-RELEASE"
build_arch: ${{ matrix.swift_build_arch }}
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install build tools
run: |
pip install meson ninja setuptools
- name: Restore vcpkg cache
id: vcpkg-cache
uses: actions/cache/restore@v5
with:
path: C:\vcpkg\installed
key: vcpkg-${{ matrix.vcpkg_triplet }}-v15
- name: Install dependencies via vcpkg
shell: pwsh
run: >
./LumaGtk/scripts/windows/bootstrap.ps1
-Only vcpkg
-Arch ${{ matrix.win_arch == 'arm64' && 'arm64' || 'x64' }}
-VcpkgRoot C:\vcpkg
- name: Save vcpkg cache
if: steps.vcpkg-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: C:\vcpkg\installed
key: vcpkg-${{ matrix.vcpkg_triplet }}-v15
- name: Set up vcpkg environment
shell: bash
run: |
VCPKG_PREFIX="C:/vcpkg/installed/${{ matrix.vcpkg_triplet }}"
echo "$VCPKG_PREFIX/tools/pkgconf" >> $GITHUB_PATH
echo "$VCPKG_PREFIX/bin" >> $GITHUB_PATH
echo "$VCPKG_PREFIX/tools" >> $GITHUB_PATH
# A drive letter carries a colon, so pkgconf reads this list the way
# Windows writes one.
echo "PKG_CONFIG_PATH=$VCPKG_PREFIX/lib/pkgconfig;$(cygpath -m "$RUNNER_TEMP")/pharo-prefix/lib/pkgconfig" >> $GITHUB_ENV
# pkgconf on this runner classifies $VCPKG_PREFIX/include as a
# system path (via the INCLUDE env var MSVC sets) and strips
# -I fragments that live under it, which breaks glib's
# -I${includedir}/glib-2.0 Cflags. Opt back in.
echo "PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1" >> $GITHUB_ENV
echo "PKG_CONFIG_ALLOW_SYSTEM_LIBS=1" >> $GITHUB_ENV
echo "GIR_EXTRA_SEARCH_PATH=$VCPKG_PREFIX/share/gir-1.0" >> $GITHUB_ENV
# Package.swift calls "pkg-config"; vcpkg ships pkgconf.exe. Alias it.
if [ -f "$VCPKG_PREFIX/tools/pkgconf/pkgconf.exe" ] && [ ! -f "$VCPKG_PREFIX/tools/pkgconf/pkg-config.exe" ]; then
cp "$VCPKG_PREFIX/tools/pkgconf/pkgconf.exe" "$VCPKG_PREFIX/tools/pkgconf/pkg-config.exe"
fi
# Mirror root-level vcpkg headers (sqlite3.h,
# ...) into a staging dir, skipping dirent.h whose vcpkg
# polyfill clashes with Swift's _FoundationCShims. Put just
# the shim on CPATH — everything else (gtk4, libadwaita,
# frida-core, radare2, ...) propagates through SwiftPM's
# .systemLibrary(pkgConfig:) resolver.
STAGE="$VCPKG_PREFIX/include/vcpkg-shim"
mkdir -p "$STAGE"
for hdr in "$VCPKG_PREFIX"/include/*.h; do
name=$(basename "$hdr")
case "$name" in
dirent.h) ;;
*) cp "$hdr" "$STAGE/" ;;
esac
done
# SwiftPM's pkg-config reads its search path the way a unix shell
# writes one, which no path with a drive letter in it survives. What
# the compiler is told directly is what a Windows build goes on.
# The VM's headers reach for each other unqualified, so every place
# they sit has to be named -- the same four the .pc lists.
PHARO="$(cygpath -m "$RUNNER_TEMP")/pharo-prefix"
PHARO_INCLUDES="$PHARO/include;$PHARO/include/pharovm"
PHARO_INCLUDES="$PHARO_INCLUDES;$PHARO/include/pharovm/common"
PHARO_INCLUDES="$PHARO_INCLUDES;$PHARO/include/pharovm/win"
echo "CPATH=$STAGE;$PHARO_INCLUDES" >> $GITHUB_ENV
echo "CPLUS_INCLUDE_PATH=$STAGE;$PHARO_INCLUDES" >> $GITHUB_ENV
# A clang driving MSVC reads INCLUDE, whatever else it also reads.
echo "INCLUDE=$INCLUDE;$PHARO_INCLUDES" >> $GITHUB_ENV
echo "LIB=$LIB;$PHARO/lib" >> $GITHUB_ENV
# Chocolatey answers 0 when its feed is down and nothing was
# installed, so the toolset itself is what says whether this worked.
- name: Restore WiX cache
id: wix-cache
if: matrix.win_arch == 'arm64'
uses: actions/cache/restore@v5
with:
path: C:\Program Files (x86)\WiX Toolset v3.14
key: ${{ runner.os }}-arm64-wix-v1
- name: Install WiX Toolset
if: matrix.win_arch == 'arm64'
shell: pwsh
run: |
$roots = @(
'C:\Program Files (x86)\WiX Toolset v3.14',
'C:\Program Files (x86)\WiX Toolset v3.11'
)
foreach ($attempt in 1..4) {
if ($env:WIX -or ($roots | Where-Object { Test-Path $_ })) { exit 0 }
if ($attempt -gt 1) {
$pause = 20 * ($attempt - 1)
Write-Host "WiX is still missing; waiting ${pause}s before attempt $attempt"
Start-Sleep -Seconds $pause
}
choco install -y --no-progress wixtoolset
}
throw "WiX Toolset still missing after 4 attempts"
- name: Save WiX cache
if: matrix.win_arch == 'arm64' && steps.wix-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: C:\Program Files (x86)\WiX Toolset v3.14
key: ${{ runner.os }}-arm64-wix-v1
- name: Pre-fetch Adwaita icon theme
shell: pwsh
run: |
# Front-load the download so a flaky download.gnome.org or
# SHA-256 mismatch fails the job before we burn time on
# frida-core, radare2 and Swift builds. package-msi.ps1's
# existing "skip download if file exists" check picks the
# cached tarball up at staging time.
$version = '50.0'
$expectedSha = 'fac6e0401fca714780561a081b8f7e27c3bc1db34ebda4da175081f26b24d460'
$url = "https://download.gnome.org/sources/adwaita-icon-theme/50/adwaita-icon-theme-$version.tar.xz"
$dest = "$env:GITHUB_WORKSPACE\LumaGtk\build\adwaita-icon-theme-$version.tar.xz"
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $dest) | Out-Null
Invoke-WebRequest -Uri $url -OutFile $dest
$actualSha = (Get-FileHash $dest -Algorithm SHA256).Hash.ToLower()
if ($actualSha -ne $expectedSha) {
throw "Adwaita SHA-256 mismatch: expected $expectedSha, got $actualSha"
}
- name: Restore frida-core cache
id: frida-cache
uses: actions/cache/restore@v5
with:
path: ${{ runner.temp }}\frida-prefix
key: ${{ runner.os }}-${{ matrix.win_arch }}-frida-core-${{ env.FRIDA_CORE_REF }}-v8
# QEMU is built much further down, but whether it has to be
# decides whether the MSYS2 step below is wanted at all.
- name: Restore QEMU cache
id: qemu-cache
uses: actions/cache/restore@v5
with:
path: ${{ runner.temp }}\qemu
key: ${{ runner.os }}-${{ matrix.win_arch }}-qemu-${{ env.QEMU_VERSION }}-${{ hashFiles('LumaGtk/scripts/windows/build-qemu.sh') }}-v1
- name: Install Go toolchain
if: steps.frida-cache.outputs.cache-hit != 'true'
shell: pwsh
run: |
# setup-go@v6 runs `go env GOPATH` within the same step as
# addPath(), which on Node 24 + Windows never sees the
# updated PATH and fails with "'go' is not recognized".
# Hosted runners ship a preinstalled Go in the toolcache;
# just surface it on PATH ourselves.
$goRoot = Get-ChildItem 'C:\hostedtoolcache\windows\go' -Directory |
Sort-Object { [version]$_.Name } -Descending |
Select-Object -First 1
$goBin = Join-Path $goRoot.FullName '${{ matrix.toolcache_arch }}\bin'
"$goBin" >> $env:GITHUB_PATH
& (Join-Path $goBin 'go.exe') version
# frida-core's cgo wants a MinGW compiler, and QEMU builds under
# MinGW and nowhere else on Windows. Both environments here are
# UCRT ones, so the QEMU this produces and the vcpkg DLLs it
# links sit on the same C runtime.
- name: Install MinGW toolchain
if: steps.frida-cache.outputs.cache-hit != 'true' || steps.qemu-cache.outputs.cache-hit != 'true'
id: msys2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.msys2_system }}
install: >-
base-devel
git
${{ matrix.msys2_package }}-toolchain
${{ matrix.msys2_package }}-pkgconf
${{ matrix.msys2_package }}-python
${{ matrix.msys2_package }}-ninja
${{ matrix.msys2_package }}-ntldd
${{ matrix.cgo_package }}
- name: Build frida-core (shared)
if: steps.frida-cache.outputs.cache-hit != 'true'
shell: pwsh
env:
MSYS2_LOCATION: ${{ steps.msys2.outputs.msys2-location }}
run: >
./LumaGtk/scripts/windows/bootstrap.ps1
-Only frida-core
-Arch ${{ matrix.win_arch == 'arm64' && 'arm64' || 'x64' }}
-VcpkgPrefix C:\vcpkg\installed\${{ matrix.vcpkg_triplet }}
-FridaPrefix $env:RUNNER_TEMP\frida-prefix
- name: Save frida-core cache
if: steps.frida-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: ${{ runner.temp }}\frida-prefix
key: ${{ runner.os }}-${{ matrix.win_arch }}-frida-core-${{ env.FRIDA_CORE_REF }}-v8
- name: Restore radare2 cache
id: r2-cache
uses: actions/cache/restore@v5
with:
path: ${{ runner.temp }}\r2-prefix
key: ${{ runner.os }}-${{ matrix.win_arch }}-radare2-${{ env.RADARE2_REF }}-v4
- name: Build radare2 (shared)
if: steps.r2-cache.outputs.cache-hit != 'true'
shell: pwsh
run: >
./LumaGtk/scripts/windows/bootstrap.ps1
-Only radare2
-Arch ${{ matrix.win_arch == 'arm64' && 'arm64' || 'x64' }}
-VcpkgPrefix C:\vcpkg\installed\${{ matrix.vcpkg_triplet }}
-R2Prefix $env:RUNNER_TEMP\r2-prefix
- name: Save radare2 cache
if: steps.r2-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: ${{ runner.temp }}\r2-prefix
key: ${{ runner.os }}-${{ matrix.win_arch }}-radare2-${{ env.RADARE2_REF }}-v4
- name: Restore Pharo VM cache
id: pharo-cache
uses: actions/cache/restore@v5
with:
path: ${{ runner.temp }}/pharo-prefix
key: ${{ runner.os }}-${{ matrix.win_arch }}-pharo-vm-${{ env.SWIFTY_PHARO_REF }}-v2
- name: Build Pharo VM
if: steps.pharo-cache.outputs.cache-hit != 'true'
shell: pwsh
run: >
./LumaGtk/scripts/windows/bootstrap.ps1
-Only pharo-vm
-Arch ${{ matrix.win_arch == 'arm64' && 'arm64' || 'x64' }}
-VcpkgPrefix C:\vcpkg\installed\${{ matrix.vcpkg_triplet }}
-PharoPrefix $env:RUNNER_TEMP\pharo-prefix
- name: Save Pharo VM cache
if: steps.pharo-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: ${{ runner.temp }}/pharo-prefix
key: ${{ runner.os }}-${{ matrix.win_arch }}-pharo-vm-${{ env.SWIFTY_PHARO_REF }}-v2
- name: Restore GnuWin32 cache
id: gnuwin32-cache
uses: actions/cache/restore@v5
with:
path: C:\Program Files (x86)\GnuWin32
key: ${{ runner.os }}-${{ matrix.win_arch }}-gnuwin32-v1
- name: Install native sed/awk/cat for gir2swift post-processing
shell: pwsh
run: |
# gir2swift shells out to sed, awk and cat to patch generated
# Swift sources. Git for Windows' cygwin-based versions crash
# at fork() time on Actions runners with "add_item (\??\C:\
# Program Files\Git, /, ...) failed, errno 1" — a classic
# cygwin heap-rebase failure. The consequence is missing types
# like SequenceIterRef/SListProtocol in the SwiftGLib output
# and later compile errors. Install GnuWin32's native Win32
# ports and put them first on PATH so they win the PATH lookup.
#
# This step has to run *after* frida-core and radare2 are
# built: gnuwin32-coreutils.install ships its own link.exe
# (a coreutils alias for ln) that gets shimmed into
# %ProgramData%\chocolatey\bin (already on PATH) and shadows
# MSVC's link.exe, breaking meson's linker autodetect for any
# subsequent meson build. Swift's link goes through SDKROOT
# rather than PATH, so the LumaGtk build below is unaffected.
# Chocolatey answers 0 when its feed is down and nothing was
# installed, and a missing sed only shows up as gir2swift output
# with types left out of it.
$gnuBin = 'C:\Program Files (x86)\GnuWin32\bin'
$attempts = if ('${{ steps.gnuwin32-cache.outputs.cache-hit }}' -eq 'true') { @() } else { 1..4 }
foreach ($attempt in $attempts) {
$log = choco install -y --no-progress sed gawk gnuwin32-coreutils.install 2>&1
$log | ForEach-Object { Write-Host $_ }
if ($LASTEXITCODE -eq 0 -and ($log -notmatch 'Unable to find package')) { break }
if ($attempt -eq 4) { throw "chocolatey never served the packages" }
$pause = 20 * $attempt
Write-Host "chocolatey came up short; waiting ${pause}s before attempt $($attempt + 1)"
Start-Sleep -Seconds $pause
}
if (Test-Path (Join-Path $gnuBin 'gawk.exe')) {
Copy-Item (Join-Path $gnuBin 'gawk.exe') (Join-Path $gnuBin 'awk.exe') -Force
}
Add-Content -Path $env:GITHUB_PATH -Value $gnuBin
- name: Save GnuWin32 cache
if: steps.gnuwin32-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: C:\Program Files (x86)\GnuWin32
key: ${{ runner.os }}-${{ matrix.win_arch }}-gnuwin32-v1
- name: Build LumaGtk
shell: pwsh
run: >
./LumaGtk/scripts/windows/build.ps1
-Configuration release
-VcpkgPrefix "C:\vcpkg\installed\${{ matrix.vcpkg_triplet }}"
-FridaPrefix "$env:RUNNER_TEMP\frida-prefix"
-R2Prefix "$env:RUNNER_TEMP\r2-prefix"
-PharoPrefix "$env:RUNNER_TEMP\pharo-prefix"
-BuildPath "$env:RUNNER_TEMP\b"
- name: Build QEMU
if: steps.qemu-cache.outputs.cache-hit != 'true'
shell: pwsh
env:
MSYS2_LOCATION: ${{ steps.msys2.outputs.msys2-location }}
run: >
./LumaGtk/scripts/windows/bootstrap.ps1
-Only qemu
-Arch ${{ matrix.win_arch == 'arm64' && 'arm64' || 'x64' }}
-VcpkgPrefix C:\vcpkg\installed\${{ matrix.vcpkg_triplet }}
-QemuPrefix $env:RUNNER_TEMP\qemu
- name: Save QEMU cache
if: steps.qemu-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: ${{ runner.temp }}\qemu
key: ${{ runner.os }}-${{ matrix.win_arch }}-qemu-${{ env.QEMU_VERSION }}-${{ hashFiles('LumaGtk/scripts/windows/build-qemu.sh') }}-v1
- name: Package MSI
shell: pwsh
run: |
cd LumaGtk
.\scripts\windows\package-msi.ps1 -SkipBuild -Configuration release `
-Version "$env:LUMA_VERSION" `
-Arch "${{ matrix.win_arch }}" `
-BuildPath "$env:RUNNER_TEMP/b" `
-VcpkgPrefix "C:/vcpkg/installed/${{ matrix.vcpkg_triplet }}" `
-FridaPrefix "$env:RUNNER_TEMP/frida-prefix" `
-R2Prefix "$env:RUNNER_TEMP/r2-prefix" `
-PharoPrefix "$env:RUNNER_TEMP/pharo-prefix" `
-QemuPrefix "$env:RUNNER_TEMP/qemu"
- uses: actions/upload-artifact@v7
with:
name: Luma-${{ env.LUMA_VERSION }}-${{ matrix.win_arch }}.msi
path: LumaGtk/build/Luma-${{ env.LUMA_VERSION }}-${{ matrix.win_arch }}.msi
if-no-files-found: error
release:
if: github.ref_type == 'tag'
needs: [macos, ios, fedora, ubuntu, appimage, flatpak, snap, windows]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v8
with:
path: artifacts
merge-multiple: true
- uses: softprops/action-gh-release@v3
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
files: |
artifacts/Luma-*.dmg
artifacts/Luma-*.dmg.sig
artifacts/Luma-*.msi
artifacts/Luma-*.ipa
artifacts/luma-*.deb
artifacts/luma-*.rpm
artifacts/luma-*.snap
artifacts/luma-*.flatpak
artifacts/Luma-*.AppImage
artifacts/Luma-*.AppImage.zsync
fail_on_unmatched_files: true
- name: Check out main for package.nix bump
uses: actions/checkout@v6
with:
ref: main
path: repo
token: ${{ secrets.GITHUB_TOKEN }}
- name: Pin package.nix to ${{ github.ref_name }}
env:
VERSION: ${{ github.ref_name }}
run: |
set -euo pipefail
deb=artifacts/luma-${VERSION}-ubuntu-24.04-x86_64.deb
ubuntu_rel=24.04
hash="sha256-$(openssl dgst -sha256 -binary "$deb" | base64)"
cd repo
sed -i \
-e "s|version = \"[^\"]*\";|version = \"${VERSION}\";|" \
-e "s|ubuntu-[0-9.]*-x86_64\\.deb|ubuntu-${ubuntu_rel}-x86_64.deb|" \
-e "s|hash = \"sha256-[^\"]*\";|hash = \"${hash}\";|" \
package.nix
if git diff --quiet package.nix; then
echo "package.nix already up to date"
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add package.nix
git commit -m "nix: Pin package.nix to ${VERSION}"
git push
- name: Notify luma-website
env:
GH_TOKEN: ${{ secrets.LUMA_WEBSITE_DISPATCH_TOKEN }}
run: |
gh api repos/frida/luma-website/dispatches \
-X POST \
-f event_type=luma-released \
-F client_payload[version]="${{ github.ref_name }}"