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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/cd-swift-lume.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ on:
required: true
DEVELOPER_NAME:
required: true
PROVISIONING_PROFILE_BASE64:
required: true

permissions:
contents: write
Expand All @@ -43,6 +45,7 @@ env:
TEAM_ID: ${{ secrets.TEAM_ID }}
APP_SPECIFIC_PASSWORD: ${{ secrets.APP_SPECIFIC_PASSWORD }}
DEVELOPER_NAME: ${{ secrets.DEVELOPER_NAME }}
PROVISIONING_PROFILE_BASE64: ${{ secrets.PROVISIONING_PROFILE_BASE64 }}

jobs:
notarize:
Expand Down Expand Up @@ -137,6 +140,14 @@ jobs:
# Clean up certificate files
rm application.p12 installer.p12

- name: Install Provisioning Profile
env:
PROVISIONING_PROFILE_BASE64: ${{ secrets.PROVISIONING_PROFILE_BASE64 }}
run: |
echo "Installing provisioning profile..."
echo "$PROVISIONING_PROFILE_BASE64" | base64 --decode > libs/lume/resources/embedded.provisionprofile
echo "Provisioning profile installed successfully"

- name: Build and Notarize
id: build_notarize
env:
Expand Down
25 changes: 25 additions & 0 deletions libs/lume/resources/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?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>CFBundleIdentifier</key>
<string>com.trycua.lume</string>
<key>CFBundleExecutable</key>
<string>lume</string>
<key>CFBundleName</key>
<string>Lume</string>
<key>CFBundleVersion</key>
<string>__VERSION__</string>
<key>CFBundleShortVersionString</key>
<string>__VERSION__</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>LSMinimumSystemVersion</key>
<string>14.0</string>
<key>LSUIElement</key>
<true/>
</dict>
</plist>
2 changes: 2 additions & 0 deletions libs/lume/resources/lume.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
<dict>
<key>com.apple.security.virtualization</key>
<true/>
<key>com.apple.vm.networking</key>
<true/>
</dict>
</plist>
136 changes: 68 additions & 68 deletions libs/lume/scripts/build/build-release-notarized.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,23 +64,61 @@ log "normal" "Ensuring .release directory exists and is accessible"
log "essential" "Building release version..."
swift build -c release --product lume > /dev/null

# Sign the binary with hardened runtime entitlements
log "essential" "Signing binary with entitlements..."
# --- Assemble .app bundle ---
log "essential" "Assembling .app bundle..."

APP_BUNDLE=".release/lume.app"
rm -rf "$APP_BUNDLE"
mkdir -p "$APP_BUNDLE/Contents/MacOS"

# Copy the binary into the bundle
cp -f .build/release/lume "$APP_BUNDLE/Contents/MacOS/lume"

# Copy resource bundle (contains unattended presets) alongside the executable
# so SPM's Bundle.module resolves correctly
BUILD_BUNDLE=".build/release/lume_lume.bundle"
if [ -d "$BUILD_BUNDLE" ]; then
cp -rf "$BUILD_BUNDLE" "$APP_BUNDLE/Contents/MacOS/"
fi

# Stamp and copy Info.plist
sed "s/__VERSION__/$VERSION/g" "./resources/Info.plist" > "$APP_BUNDLE/Contents/Info.plist"

# Embed the provisioning profile
PROVISION_PROFILE="./resources/embedded.provisionprofile"
if [ -f "$PROVISION_PROFILE" ]; then
cp "$PROVISION_PROFILE" "$APP_BUNDLE/Contents/embedded.provisionprofile"
else
log "error" "Error: embedded.provisionprofile not found at $PROVISION_PROFILE"
log "error" "The provisioning profile is required for the com.apple.vm.networking entitlement."
log "error" "Obtain one from the Apple Developer portal tied to bundle ID com.trycua.lume."
exit 1
fi

# --- Sign the .app bundle ---
log "essential" "Signing .app bundle..."

# Sign the binary inside the bundle first (with entitlements)
codesign --force --options runtime \
--entitlement ./resources/lume.entitlements \
--sign "$CERT_APPLICATION_NAME" \
.build/release/lume 2> /dev/null
"$APP_BUNDLE/Contents/MacOS/lume" 2> /dev/null

# Create a temporary directory for packaging
TEMP_ROOT=$(mktemp -d)
mkdir -p "$TEMP_ROOT/usr/local/bin"
cp -f .build/release/lume "$TEMP_ROOT/usr/local/bin/"
# Sign the outer bundle
codesign --force --options runtime \
--sign "$CERT_APPLICATION_NAME" \
"$APP_BUNDLE" 2> /dev/null

# Build the installer package
# --- Package as .pkg installer ---
log "essential" "Building installer package..."

TEMP_ROOT=$(mktemp -d)
mkdir -p "$TEMP_ROOT/usr/local/share/lume"
cp -R "$APP_BUNDLE" "$TEMP_ROOT/usr/local/share/lume/"

if ! pkgbuild --root "$TEMP_ROOT" \
--identifier "com.trycua.lume" \
--version "1.0" \
--version "$VERSION" \
--install-location "/" \
--sign "$CERT_INSTALLER_NAME" \
./.release/lume.pkg; then
Expand All @@ -96,7 +134,7 @@ fi

log "essential" "Package created successfully"

# Submit for notarization using stored credentials
# --- Notarize ---
log "essential" "Submitting for notarization..."
if [ "$LOG_LEVEL" = "minimal" ] || [ "$LOG_LEVEL" = "none" ]; then
# Minimal output - capture ID but hide details
Expand Down Expand Up @@ -127,82 +165,45 @@ else
fi
fi

# Staple the notarization ticket
log "essential" "Stapling notarization ticket..."
# Staple the notarization ticket to the .pkg
log "essential" "Stapling notarization ticket to .pkg..."
if ! xcrun stapler staple ./.release/lume.pkg > /dev/null 2>&1; then
log "error" "Failed to staple notarization ticket"
log "error" "Failed to staple notarization ticket to .pkg"
exit 1
fi

# Create temporary directory for package extraction
EXTRACT_ROOT=$(mktemp -d)
PKG_PATH="$(pwd)/.release/lume.pkg"

# Extract the pkg using xar
cd "$EXTRACT_ROOT"
xar -xf "$PKG_PATH" > /dev/null 2>&1

# Verify Payload exists before proceeding
if [ ! -f "Payload" ]; then
log "error" "Error: Payload file not found after xar extraction"
exit 1
fi

# Create a directory for the extracted contents
mkdir -p extracted
cd extracted

# Extract the Payload
cat ../Payload | gunzip -dc | cpio -i > /dev/null 2>&1

# Verify the binary exists
if [ ! -f "usr/local/bin/lume" ]; then
log "error" "Error: lume binary not found in expected location"
exit 1
# Staple the notarization ticket to the .app bundle
log "essential" "Stapling notarization ticket to .app bundle..."
if ! xcrun stapler staple "$APP_BUNDLE" > /dev/null 2>&1; then
log "normal" "Note: Could not staple .app bundle directly (this is expected when notarizing via .pkg)"
fi

# Get the release directory absolute path
RELEASE_DIR="$(realpath "$(dirname "$PKG_PATH")")"
log "normal" "Using release directory: $RELEASE_DIR"

# Copy extracted lume to the release directory
cp -f usr/local/bin/lume "$RELEASE_DIR/lume"

# Copy the resource bundle (contains unattended presets) from the build directory
BUILD_BUNDLE="$LUME_DIR/.build/release/lume_lume.bundle"
if [ -d "$BUILD_BUNDLE" ]; then
cp -rf "$BUILD_BUNDLE" "$RELEASE_DIR/"
fi

# Install to user-local bin directory (standard location)
USER_BIN="$HOME/.local/bin"
mkdir -p "$USER_BIN"
cp -f "$RELEASE_DIR/lume" "$USER_BIN/lume"

# Advise user to add to PATH if not present
if ! echo "$PATH" | grep -q "$USER_BIN"; then
log "normal" "[lume build] Note: $USER_BIN is not in your PATH. Add 'export PATH=\"$USER_BIN:\$PATH\"' to your shell profile."
fi
# --- Create release archives ---

# Get architecture and create OS identifier
ARCH=$(uname -m)
OS_IDENTIFIER="darwin-${ARCH}"
RELEASE_DIR="$(cd .release && pwd)"

# Create versioned archives of the package with OS identifier in the name
log "essential" "Creating archives in $RELEASE_DIR..."
cd "$RELEASE_DIR"

# Clean up any existing artifacts first to avoid conflicts
rm -f lume-*.tar.gz lume-*.pkg.tar.gz

# Create a backward-compatible wrapper script at the tarball root
cat > lume <<'WRAPPER_EOF'
#!/bin/sh
exec "$(dirname "$0")/lume.app/Contents/MacOS/lume" "$@"
WRAPPER_EOF
chmod +x lume

# Create version-specific archives
log "essential" "Creating version-specific archives (${VERSION})..."
# Package the binary and resource bundle
if [ -d "lume_lume.bundle" ]; then
tar -czf "lume-${VERSION}-${OS_IDENTIFIER}.tar.gz" lume lume_lume.bundle > /dev/null 2>&1
else
tar -czf "lume-${VERSION}-${OS_IDENTIFIER}.tar.gz" lume > /dev/null 2>&1
fi

# Package the .app bundle and wrapper script
tar -czf "lume-${VERSION}-${OS_IDENTIFIER}.tar.gz" lume lume.app > /dev/null 2>&1

# Package the installer
tar -czf "lume-${VERSION}-${OS_IDENTIFIER}.pkg.tar.gz" lume.pkg > /dev/null 2>&1

Expand All @@ -220,6 +221,5 @@ chmod 644 "$RELEASE_DIR"/*.tar.gz "$RELEASE_DIR"/*.pkg.tar.gz "$RELEASE_DIR"/che

# Clean up
rm -rf "$TEMP_ROOT"
rm -rf "$EXTRACT_ROOT"

log "essential" "Build and packaging completed successfully."
51 changes: 41 additions & 10 deletions libs/lume/scripts/build/build-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,56 @@ LUME_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$LUME_DIR"

swift build -c release --product lume
codesign --force --entitlement ./resources/lume.entitlements --sign - .build/release/lume

mkdir -p ./.release
cp -f .build/release/lume ./.release/lume
# Assemble .app bundle
APP_BUNDLE=".release/lume.app"
mkdir -p "$APP_BUNDLE/Contents/MacOS"

# Copy the resource bundle (contains unattended presets)
cp -f .build/release/lume "$APP_BUNDLE/Contents/MacOS/lume"

# Copy resource bundle alongside the executable for Bundle.module resolution
if [ -d ".build/release/lume_lume.bundle" ]; then
cp -rf .build/release/lume_lume.bundle ./.release/
cp -rf .build/release/lume_lume.bundle "$APP_BUNDLE/Contents/MacOS/"
fi

# Stamp Info.plist with version from VERSION file
VERSION=$(cat VERSION 2>/dev/null || echo "0.0.0")
sed "s/__VERSION__/$VERSION/g" "./resources/Info.plist" > "$APP_BUNDLE/Contents/Info.plist"

# Embed provisioning profile if available
if [ -f "./resources/embedded.provisionprofile" ]; then
cp "./resources/embedded.provisionprofile" "$APP_BUNDLE/Contents/embedded.provisionprofile"
fi

# Ad-hoc sign the bundle
codesign --force --entitlement ./resources/lume.entitlements --sign - "$APP_BUNDLE/Contents/MacOS/lume"
codesign --force --sign - "$APP_BUNDLE"

# Create wrapper script
mkdir -p .release
cat > .release/lume <<'WRAPPER_EOF'
#!/bin/sh
exec "$(dirname "$0")/lume.app/Contents/MacOS/lume" "$@"
WRAPPER_EOF
chmod +x .release/lume

# Install to user-local bin directory (standard location)
USER_BIN="$HOME/.local/bin"
APP_INSTALL_DIR="$HOME/.local/share/lume"

mkdir -p "$USER_BIN"
cp -f ./.release/lume "$USER_BIN/lume"
mkdir -p "$APP_INSTALL_DIR"

# Install the resource bundle alongside the binary
if [ -d "./.release/lume_lume.bundle" ]; then
cp -rf ./.release/lume_lume.bundle "$USER_BIN/"
fi
# Install .app bundle
rm -rf "$APP_INSTALL_DIR/lume.app"
cp -R ".release/lume.app" "$APP_INSTALL_DIR/"

# Create wrapper script in bin directory
cat > "$USER_BIN/lume" <<WRAPPER_EOF
#!/bin/sh
exec "$APP_INSTALL_DIR/lume.app/Contents/MacOS/lume" "\$@"
WRAPPER_EOF
chmod +x "$USER_BIN/lume"

# Advise user to add to PATH if not present
if ! echo "$PATH" | grep -q "$USER_BIN"; then
Expand Down
Loading