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.
1854 lines
72 KiB
YAML
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 }}"
|