mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-03-25 09:25:50 +00:00
Fix Homebrew library dependencies in release builds (#269)
This commit is contained in:
parent
32caa7ac4f
commit
6b93fdbf41
15 changed files with 677 additions and 31 deletions
48
.github/scripts/verify-release.sh
vendored
Executable file
48
.github/scripts/verify-release.sh
vendored
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
#!/bin/bash
|
||||
|
||||
# GitHub Actions script to verify release builds
|
||||
# This should be run after building the DMG but before creating the release
|
||||
|
||||
set -e
|
||||
|
||||
echo "::group::Release Build Verification"
|
||||
|
||||
# Find the built app (adjust path as needed for your CI)
|
||||
APP_PATH="$1"
|
||||
if [ -z "$APP_PATH" ]; then
|
||||
# Try to find it in common locations
|
||||
if [ -f "build/VibeTunnel.app" ]; then
|
||||
APP_PATH="build/VibeTunnel.app"
|
||||
elif [ -f "mac/build/Release/VibeTunnel.app" ]; then
|
||||
APP_PATH="mac/build/Release/VibeTunnel.app"
|
||||
else
|
||||
echo "::error::Could not find VibeTunnel.app. Please provide path as argument."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run the verification script
|
||||
if ./verify-release-build.sh "$APP_PATH"; then
|
||||
echo "::notice::✅ Release build verification passed!"
|
||||
else
|
||||
echo "::error::❌ Release build verification failed! Check the logs above."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "::endgroup::"
|
||||
|
||||
# Additional CI-specific checks
|
||||
echo "::group::Additional CI Checks"
|
||||
|
||||
# Check that we're not on a debug branch
|
||||
if [[ "$GITHUB_REF" == *"debug"* ]] || [[ "$GITHUB_REF" == *"test"* ]]; then
|
||||
echo "::warning::Building from a branch that contains 'debug' or 'test' in the name"
|
||||
fi
|
||||
|
||||
# Verify build configuration from environment
|
||||
if [ "$CONFIGURATION" == "Debug" ]; then
|
||||
echo "::error::Building with Debug configuration! Use Release for production builds."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "::endgroup::"
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -129,3 +129,4 @@ playwright-report/
|
|||
buildServer.json
|
||||
/temp
|
||||
/temp/webrtc-check
|
||||
/web/release-check/
|
||||
|
|
|
|||
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -1,5 +1,15 @@
|
|||
# Changelog
|
||||
|
||||
## [1.0.0-beta.8] - 2025-07-08
|
||||
|
||||
#### **Homebrew Library Dependencies**
|
||||
- **FIXED**: Release builds now correctly bundle all Homebrew library dependencies
|
||||
- **FIXED**: App launches reliably on systems without developer tools installed
|
||||
- Updated build scripts to handle dynamic library dependencies properly
|
||||
|
||||
#### **File Browser Enhancements**
|
||||
- **FIXED**: File browser going dark due to event bubbling issues with modal handling
|
||||
|
||||
## [1.0.0-beta.7] - 2025-07-08
|
||||
|
||||
### 🎯 Major Features
|
||||
|
|
|
|||
185
docs/homebrew-issue.md
Normal file
185
docs/homebrew-issue.md
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
# Homebrew Library Dependencies Issue
|
||||
|
||||
## Summary
|
||||
|
||||
VibeTunnel beta 7 shipped with Homebrew library dependencies, causing the app to fail on systems without Homebrew installed. This document explains the issue, how to identify it, and how to prevent it in future releases.
|
||||
|
||||
## The Problem
|
||||
|
||||
When users without Homebrew installed tried to run VibeTunnel beta 7, they received errors like:
|
||||
|
||||
```
|
||||
dyld: Library not loaded: /opt/homebrew/opt/brotli/lib/libbrotlidec.1.dylib
|
||||
Referenced from: /Applications/VibeTunnel.app/Contents/Resources/vibetunnel
|
||||
Reason: image not found
|
||||
```
|
||||
|
||||
## Binary Dependencies Comparison
|
||||
|
||||
### Beta 6 (Working) vs Beta 7 (Broken)
|
||||
|
||||
| Component | Beta 6 | Beta 7 |
|
||||
|-----------|--------|--------|
|
||||
| **Main App Binary** | System frameworks only | System frameworks + Thread Sanitizer |
|
||||
| **vibetunnel Server** | System libraries only (106MB) | System + 10 Homebrew libraries (63MB) |
|
||||
| **Frameworks Directory** | Clean | Contains `libclang_rt.tsan_osx_dynamic.dylib` |
|
||||
|
||||
### Beta 7 Homebrew Dependencies
|
||||
|
||||
The `vibetunnel` server binary in beta 7 linked to these Homebrew libraries:
|
||||
|
||||
```
|
||||
/opt/homebrew/opt/libuv/lib/libuv.1.dylib
|
||||
/opt/homebrew/opt/brotli/lib/libbrotlidec.1.dylib
|
||||
/opt/homebrew/opt/brotli/lib/libbrotlienc.1.dylib
|
||||
/opt/homebrew/opt/c-ares/lib/libcares.2.dylib
|
||||
/opt/homebrew/opt/libnghttp2/lib/libnghttp2.14.dylib
|
||||
/opt/homebrew/opt/openssl@3/lib/libcrypto.3.dylib
|
||||
/opt/homebrew/opt/openssl@3/lib/libssl.3.dylib
|
||||
/opt/homebrew/opt/icu4c@77/lib/libicui18n.77.dylib
|
||||
/opt/homebrew/opt/icu4c@77/lib/libicuuc.77.dylib
|
||||
```
|
||||
|
||||
## Root Cause
|
||||
|
||||
The issue was introduced by commit `826d8de4` which added `node-path-setup.sh` with:
|
||||
|
||||
```bash
|
||||
export PATH="/opt/homebrew/bin:/usr/local/bin:..."
|
||||
```
|
||||
|
||||
This prioritized Homebrew in PATH during the build process, causing:
|
||||
1. Node.js to be built linking against Homebrew libraries
|
||||
2. Native modules (node-pty, authenticate-pam) to link against Homebrew
|
||||
3. The final vibetunnel binary to inherit these dependencies
|
||||
|
||||
## How to Test for Homebrew Dependencies
|
||||
|
||||
### Quick Check with otool
|
||||
|
||||
Check any binary for Homebrew dependencies:
|
||||
|
||||
```bash
|
||||
# Check for Homebrew paths
|
||||
otool -L /path/to/binary | grep -E "/opt/homebrew|/usr/local/Cellar"
|
||||
|
||||
# Show all dependencies
|
||||
otool -L /path/to/binary
|
||||
```
|
||||
|
||||
### Automated Verification Script
|
||||
|
||||
Use the provided verification script:
|
||||
|
||||
```bash
|
||||
./verify-release-build.sh /Applications/VibeTunnel.app
|
||||
```
|
||||
|
||||
This script checks for:
|
||||
- Homebrew dependencies in all binaries
|
||||
- Thread/Address/UB Sanitizer libraries
|
||||
- Debug symbols and settings
|
||||
- Code signing status
|
||||
|
||||
### Manual Testing Process
|
||||
|
||||
1. **Check the main app binary:**
|
||||
```bash
|
||||
otool -L /Applications/VibeTunnel.app/Contents/MacOS/VibeTunnel
|
||||
```
|
||||
|
||||
2. **Check the server binary:**
|
||||
```bash
|
||||
otool -L /Applications/VibeTunnel.app/Contents/Resources/vibetunnel
|
||||
```
|
||||
|
||||
3. **Check native modules:**
|
||||
```bash
|
||||
otool -L /Applications/VibeTunnel.app/Contents/Resources/pty.node
|
||||
otool -L /Applications/VibeTunnel.app/Contents/Resources/authenticate_pam.node
|
||||
```
|
||||
|
||||
4. **Check for sanitizer libraries:**
|
||||
```bash
|
||||
ls -la /Applications/VibeTunnel.app/Contents/Frameworks/ | grep -i "clang\|san"
|
||||
```
|
||||
|
||||
## What Dependencies Are Acceptable?
|
||||
|
||||
### ✅ Good (System Libraries Only)
|
||||
|
||||
```
|
||||
/usr/lib/libz.1.dylib
|
||||
/System/Library/Frameworks/CoreFoundation.framework/...
|
||||
/System/Library/Frameworks/Security.framework/...
|
||||
/usr/lib/libc++.1.dylib
|
||||
/usr/lib/libSystem.B.dylib
|
||||
```
|
||||
|
||||
### ❌ Bad (Homebrew/External)
|
||||
|
||||
Any path containing:
|
||||
- `/opt/homebrew/`
|
||||
- `/usr/local/Cellar/`
|
||||
- `/usr/local/opt/`
|
||||
- `libclang_rt.*san*` (sanitizer libraries)
|
||||
|
||||
## Prevention
|
||||
|
||||
### Build Environment
|
||||
|
||||
The fix involves using a clean PATH during builds:
|
||||
|
||||
```bash
|
||||
# Set this before building
|
||||
export VIBETUNNEL_BUILD_CLEAN_ENV=true
|
||||
```
|
||||
|
||||
This modifies `node-path-setup.sh` to put Homebrew at the END of PATH instead of the beginning.
|
||||
|
||||
### Xcode Settings
|
||||
|
||||
Ensure these are disabled in the scheme:
|
||||
- Thread Sanitizer (`enableThreadSanitizer`)
|
||||
- Address Sanitizer (`enableAddressSanitizer`)
|
||||
- ASan Stack Use After Return (`enableASanStackUseAfterReturn`)
|
||||
- NSZombieEnabled
|
||||
|
||||
Check with:
|
||||
```bash
|
||||
./mac/scripts/check-xcode-settings.sh
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
Add to your release workflow:
|
||||
```yaml
|
||||
- name: Verify Release Build
|
||||
run: ./.github/scripts/verify-release.sh "${{ steps.build.outputs.app-path }}"
|
||||
```
|
||||
|
||||
## Testing on a Clean System
|
||||
|
||||
To properly test a release:
|
||||
|
||||
1. **Find a Mac without Homebrew** (or temporarily rename `/opt/homebrew`)
|
||||
2. **Install the app** from the DMG
|
||||
3. **Run the app** and verify it starts without library errors
|
||||
4. **Check Console.app** for any dlopen or library loading errors
|
||||
|
||||
## The Fix
|
||||
|
||||
The solution involved:
|
||||
|
||||
1. **Modifying PATH priority** - Homebrew paths moved to end during builds
|
||||
2. **Clean environment** - Removing LDFLAGS, LIBRARY_PATH, etc. during compilation
|
||||
3. **Configure flags** - Using `--shared-zlib` to prefer system libraries
|
||||
4. **Verification tools** - Scripts to catch these issues before release
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
- Always check library dependencies before releasing
|
||||
- Homebrew should never be required for the release build
|
||||
- Build environments can contaminate the final binary
|
||||
- Automated verification prevents these issues
|
||||
- The size difference (106MB → 63MB) wasn't from optimization alone - it included external libraries
|
||||
|
|
@ -1,5 +1,15 @@
|
|||
# Changelog
|
||||
|
||||
## [1.0.0-beta.8] - 2025-07-08
|
||||
|
||||
#### **Homebrew Library Dependencies**
|
||||
- **FIXED**: Release builds now correctly bundle all Homebrew library dependencies
|
||||
- **FIXED**: App launches reliably on systems without developer tools installed
|
||||
- Updated build scripts to handle dynamic library dependencies properly
|
||||
|
||||
#### **File Browser Enhancements**
|
||||
- **FIXED**: File browser going dark due to event bubbling issues with modal handling
|
||||
|
||||
## [1.0.0-beta.7] - 2025-07-08
|
||||
|
||||
### 🎯 Major Features
|
||||
|
|
|
|||
|
|
@ -39,8 +39,7 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
enableThreadSanitizer = "YES"
|
||||
enableASanStackUseAfterReturn = "NO"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
|
@ -64,13 +63,6 @@
|
|||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<AdditionalOptions>
|
||||
<AdditionalOption
|
||||
key = "NSZombieEnabled"
|
||||
value = "YES"
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// VibeTunnel Version Configuration
|
||||
// This file contains the version and build number for the app
|
||||
|
||||
MARKETING_VERSION = 1.0.0-beta.7
|
||||
CURRENT_PROJECT_VERSION = 170
|
||||
MARKETING_VERSION = 1.0.0-beta.8
|
||||
CURRENT_PROJECT_VERSION = 171
|
||||
|
||||
// Domain and GitHub configuration
|
||||
APP_DOMAIN = vibetunnel.sh
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ echo "Building web frontend..."
|
|||
|
||||
# Setup Node.js PATH (Homebrew, nvm, Volta, fnm)
|
||||
SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )"
|
||||
# Set environment variable to use clean build environment
|
||||
export VIBETUNNEL_BUILD_CLEAN_ENV=true
|
||||
source "${SCRIPT_DIR}/node-path-setup.sh"
|
||||
|
||||
# Export CI to prevent interactive prompts
|
||||
|
|
|
|||
109
mac/scripts/check-xcode-settings.sh
Executable file
109
mac/scripts/check-xcode-settings.sh
Executable file
|
|
@ -0,0 +1,109 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Script to check Xcode project settings for potential release issues
|
||||
|
||||
echo "Checking Xcode Project Settings"
|
||||
echo "==============================="
|
||||
|
||||
ERRORS=0
|
||||
PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
|
||||
# Check for Thread Sanitizer in xcscheme files
|
||||
echo "1. Checking for Thread Sanitizer..."
|
||||
SCHEME_FILES=$(find "$PROJECT_DIR" -name "*.xcscheme" 2>/dev/null)
|
||||
|
||||
for scheme in $SCHEME_FILES; do
|
||||
if grep -q "enableThreadSanitizer.*YES" "$scheme" 2>/dev/null; then
|
||||
echo "❌ ERROR: Thread Sanitizer is enabled in $(basename "$scheme")"
|
||||
echo " File: $scheme"
|
||||
((ERRORS++))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $ERRORS -eq 0 ]; then
|
||||
echo "✅ Thread Sanitizer is not enabled"
|
||||
fi
|
||||
|
||||
# Check for Address Sanitizer
|
||||
echo ""
|
||||
echo "2. Checking for Address Sanitizer..."
|
||||
ASAN_ERRORS=0
|
||||
for scheme in $SCHEME_FILES; do
|
||||
if grep -q "enableAddressSanitizer.*YES" "$scheme" 2>/dev/null; then
|
||||
echo "❌ ERROR: Address Sanitizer is enabled in $(basename "$scheme")"
|
||||
echo " File: $scheme"
|
||||
((ASAN_ERRORS++))
|
||||
fi
|
||||
if grep -q "enableASanStackUseAfterReturn.*YES" "$scheme" 2>/dev/null; then
|
||||
echo "❌ ERROR: ASan Stack Use After Return is enabled in $(basename "$scheme")"
|
||||
echo " File: $scheme"
|
||||
((ASAN_ERRORS++))
|
||||
fi
|
||||
done
|
||||
|
||||
ERRORS=$((ERRORS + ASAN_ERRORS))
|
||||
if [ $ASAN_ERRORS -eq 0 ]; then
|
||||
echo "✅ Address Sanitizer is not enabled"
|
||||
fi
|
||||
|
||||
# Check for UB Sanitizer
|
||||
echo ""
|
||||
echo "3. Checking for Undefined Behavior Sanitizer..."
|
||||
UBSAN_ERRORS=0
|
||||
for scheme in $SCHEME_FILES; do
|
||||
if grep -q "enableUBSanitizer.*YES" "$scheme" 2>/dev/null; then
|
||||
echo "❌ ERROR: Undefined Behavior Sanitizer is enabled in $(basename "$scheme")"
|
||||
echo " File: $scheme"
|
||||
((UBSAN_ERRORS++))
|
||||
fi
|
||||
done
|
||||
|
||||
ERRORS=$((ERRORS + UBSAN_ERRORS))
|
||||
if [ $UBSAN_ERRORS -eq 0 ]; then
|
||||
echo "✅ Undefined Behavior Sanitizer is not enabled"
|
||||
fi
|
||||
|
||||
# Check for NSZombie
|
||||
echo ""
|
||||
echo "4. Checking for NSZombieEnabled..."
|
||||
ZOMBIE_ERRORS=0
|
||||
for scheme in $SCHEME_FILES; do
|
||||
if grep -q "NSZombieEnabled.*YES" "$scheme" 2>/dev/null; then
|
||||
echo "❌ ERROR: NSZombieEnabled is set in $(basename "$scheme")"
|
||||
echo " File: $scheme"
|
||||
((ZOMBIE_ERRORS++))
|
||||
fi
|
||||
done
|
||||
|
||||
ERRORS=$((ERRORS + ZOMBIE_ERRORS))
|
||||
if [ $ZOMBIE_ERRORS -eq 0 ]; then
|
||||
echo "✅ NSZombieEnabled is not set"
|
||||
fi
|
||||
|
||||
# Check build configuration in project.pbxproj
|
||||
echo ""
|
||||
echo "5. Checking Release configuration..."
|
||||
PBXPROJ="$PROJECT_DIR/VibeTunnel-Mac.xcodeproj/project.pbxproj"
|
||||
|
||||
if [ -f "$PBXPROJ" ]; then
|
||||
# This is a simple check - a more thorough check would parse the file properly
|
||||
if grep -q "ENABLE_TESTABILITY.*YES.*Release" "$PBXPROJ" 2>/dev/null; then
|
||||
echo "⚠️ WARNING: Testability might be enabled in Release configuration"
|
||||
else
|
||||
echo "✅ Release configuration looks OK"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ WARNING: Could not find project.pbxproj"
|
||||
fi
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
echo "==============================="
|
||||
if [ $ERRORS -eq 0 ]; then
|
||||
echo "✅ All Xcode settings checks passed!"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ Found $ERRORS error(s) in Xcode settings!"
|
||||
echo "These settings must be disabled for release builds."
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -11,8 +11,16 @@ if [ -s "$HOME/.nvm/nvm.sh" ]; then
|
|||
source "$NVM_DIR/nvm.sh" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Set final PATH with Homebrew priority
|
||||
export PATH="/opt/homebrew/bin:/usr/local/bin:$HOME/.volta/bin:$HOME/Library/pnpm:$HOME/.bun/bin:$PATH"
|
||||
# Check if we're in a build context that needs to avoid Homebrew library contamination
|
||||
# This is set by build scripts that compile native code
|
||||
if [ "${VIBETUNNEL_BUILD_CLEAN_ENV}" = "true" ]; then
|
||||
# For builds, add Homebrew at the END of PATH to avoid library contamination
|
||||
# This ensures system libraries are preferred during compilation
|
||||
export PATH="$HOME/.volta/bin:$HOME/Library/pnpm:$HOME/.bun/bin:$PATH:/opt/homebrew/bin:/usr/local/bin"
|
||||
else
|
||||
# For normal usage, Homebrew can be at the beginning for convenience
|
||||
export PATH="/opt/homebrew/bin:/usr/local/bin:$HOME/.volta/bin:$HOME/Library/pnpm:$HOME/.bun/bin:$PATH"
|
||||
fi
|
||||
|
||||
# Verify Node.js is available
|
||||
if ! command -v node >/dev/null 2>&1; then
|
||||
|
|
|
|||
64
test-homebrew-fix.sh
Executable file
64
test-homebrew-fix.sh
Executable file
|
|
@ -0,0 +1,64 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
echo "Testing Homebrew dependency fix..."
|
||||
echo "================================"
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Clean up existing builds
|
||||
echo "1. Cleaning existing Node.js builds..."
|
||||
rm -rf web/.node-builds
|
||||
|
||||
echo "2. Cleaning existing native builds..."
|
||||
rm -rf web/native
|
||||
rm -rf web/build
|
||||
|
||||
echo "3. Building custom Node.js without Homebrew dependencies..."
|
||||
cd web
|
||||
# Set clean build environment to avoid Homebrew contamination
|
||||
export VIBETUNNEL_BUILD_CLEAN_ENV=true
|
||||
node build-custom-node.js
|
||||
|
||||
echo ""
|
||||
echo "4. Checking custom Node.js dependencies..."
|
||||
CUSTOM_NODE=$(find .node-builds -name "node-v*-minimal" -type d -exec test -f {}/out/Release/node \; -print | sort -V | tail -n1)
|
||||
if [ -n "$CUSTOM_NODE" ]; then
|
||||
echo "Custom Node.js found at: $CUSTOM_NODE"
|
||||
echo "Dependencies:"
|
||||
otool -L "$CUSTOM_NODE/out/Release/node" | grep -v "/usr/lib\|/System"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "5. Building vibetunnel with custom Node.js..."
|
||||
node build-native.js --custom-node
|
||||
|
||||
echo ""
|
||||
echo "6. Checking vibetunnel dependencies..."
|
||||
if [ -f native/vibetunnel ]; then
|
||||
echo "Dependencies of native/vibetunnel:"
|
||||
otool -L native/vibetunnel | grep -v "/usr/lib\|/System"
|
||||
|
||||
# Check for Homebrew dependencies
|
||||
if otool -L native/vibetunnel | grep -q "/opt/homebrew\|/usr/local/Cellar"; then
|
||||
echo ""
|
||||
echo "❌ ERROR: Homebrew dependencies found!"
|
||||
otool -L native/vibetunnel | grep -E "/opt/homebrew|/usr/local/Cellar"
|
||||
exit 1
|
||||
else
|
||||
echo ""
|
||||
echo "✅ SUCCESS: No Homebrew dependencies found!"
|
||||
fi
|
||||
else
|
||||
echo "❌ ERROR: native/vibetunnel not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "7. Testing the binary..."
|
||||
cd native
|
||||
./vibetunnel --version
|
||||
|
||||
echo ""
|
||||
echo "Test complete!"
|
||||
197
verify-release-build.sh
Executable file
197
verify-release-build.sh
Executable file
|
|
@ -0,0 +1,197 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo "VibeTunnel Release Build Verification"
|
||||
echo "====================================="
|
||||
|
||||
# Check if an app path was provided
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: $0 /path/to/VibeTunnel.app"
|
||||
echo "Example: $0 /Applications/VibeTunnel.app"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
APP_PATH="$1"
|
||||
ERRORS=0
|
||||
WARNINGS=0
|
||||
|
||||
# Verify the app exists
|
||||
if [ ! -d "$APP_PATH" ]; then
|
||||
echo -e "${RED}❌ ERROR: App not found at $APP_PATH${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Checking: $APP_PATH"
|
||||
echo ""
|
||||
|
||||
# Function to check a binary for issues
|
||||
check_binary() {
|
||||
local binary_path="$1"
|
||||
local binary_name=$(basename "$binary_path")
|
||||
|
||||
echo "Checking $binary_name..."
|
||||
|
||||
# Check for Thread Sanitizer
|
||||
if otool -L "$binary_path" 2>/dev/null | grep -q "libclang_rt.tsan"; then
|
||||
echo -e "${RED}❌ ERROR: Thread Sanitizer library found in $binary_name${NC}"
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
# Check for Address Sanitizer
|
||||
if otool -L "$binary_path" 2>/dev/null | grep -q "libclang_rt.asan"; then
|
||||
echo -e "${RED}❌ ERROR: Address Sanitizer library found in $binary_name${NC}"
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
# Check for Undefined Behavior Sanitizer
|
||||
if otool -L "$binary_path" 2>/dev/null | grep -q "libclang_rt.ubsan"; then
|
||||
echo -e "${RED}❌ ERROR: Undefined Behavior Sanitizer library found in $binary_name${NC}"
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
# Check for Homebrew dependencies
|
||||
local homebrew_deps=$(otool -L "$binary_path" 2>/dev/null | grep -E "/opt/homebrew|/usr/local/Cellar" || true)
|
||||
if [ -n "$homebrew_deps" ]; then
|
||||
echo -e "${RED}❌ ERROR: Homebrew dependencies found in $binary_name:${NC}"
|
||||
echo "$homebrew_deps"
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
# Check for debug symbols (for main app binary)
|
||||
if [[ "$binary_name" == "VibeTunnel" ]]; then
|
||||
# Check if binary was built with debug configuration
|
||||
if nm -a "$binary_path" 2>/dev/null | grep -q "_NSZombieEnabled"; then
|
||||
echo -e "${YELLOW}⚠️ WARNING: Binary may contain debug code (NSZombie references found)${NC}"
|
||||
((WARNINGS++))
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 1. Check main app binary
|
||||
echo "1. Main App Binary"
|
||||
echo "------------------"
|
||||
MAIN_BINARY="$APP_PATH/Contents/MacOS/VibeTunnel"
|
||||
if [ -f "$MAIN_BINARY" ]; then
|
||||
check_binary "$MAIN_BINARY"
|
||||
else
|
||||
echo -e "${RED}❌ ERROR: Main binary not found${NC}"
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
# 2. Check for sanitizer libraries in Frameworks
|
||||
echo ""
|
||||
echo "2. Checking Frameworks"
|
||||
echo "---------------------"
|
||||
FRAMEWORKS_DIR="$APP_PATH/Contents/Frameworks"
|
||||
if [ -d "$FRAMEWORKS_DIR" ]; then
|
||||
SANITIZER_LIBS=$(find "$FRAMEWORKS_DIR" -name "*clang_rt*san*" -o -name "*asan*" -o -name "*tsan*" -o -name "*ubsan*" 2>/dev/null || true)
|
||||
if [ -n "$SANITIZER_LIBS" ]; then
|
||||
echo -e "${RED}❌ ERROR: Sanitizer libraries found in Frameworks:${NC}"
|
||||
echo "$SANITIZER_LIBS"
|
||||
((ERRORS++))
|
||||
else
|
||||
echo -e "${GREEN}✅ No sanitizer libraries in Frameworks${NC}"
|
||||
fi
|
||||
else
|
||||
echo "No Frameworks directory found"
|
||||
fi
|
||||
|
||||
# 3. Check vibetunnel server binary
|
||||
echo ""
|
||||
echo "3. VibeTunnel Server Binary"
|
||||
echo "--------------------------"
|
||||
SERVER_BINARY="$APP_PATH/Contents/Resources/vibetunnel"
|
||||
if [ -f "$SERVER_BINARY" ]; then
|
||||
check_binary "$SERVER_BINARY"
|
||||
|
||||
# Check size (debug builds are often larger)
|
||||
SIZE_MB=$(ls -lh "$SERVER_BINARY" | awk '{print $5}')
|
||||
echo "Binary size: $SIZE_MB"
|
||||
|
||||
# Get size in bytes for comparison
|
||||
SIZE_BYTES=$(stat -f%z "$SERVER_BINARY" 2>/dev/null || stat -c%s "$SERVER_BINARY" 2>/dev/null)
|
||||
if [ "$SIZE_BYTES" -gt 157286400 ]; then # 150 MB
|
||||
echo -e "${YELLOW}⚠️ WARNING: Binary size exceeds 150MB, might be a debug build${NC}"
|
||||
((WARNINGS++))
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}❌ ERROR: Server binary not found${NC}"
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
# 4. Check native modules
|
||||
echo ""
|
||||
echo "4. Native Modules"
|
||||
echo "----------------"
|
||||
for module in pty.node authenticate_pam.node spawn-helper; do
|
||||
MODULE_PATH="$APP_PATH/Contents/Resources/$module"
|
||||
if [ -f "$MODULE_PATH" ]; then
|
||||
check_binary "$MODULE_PATH"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ WARNING: $module not found${NC}"
|
||||
((WARNINGS++))
|
||||
fi
|
||||
done
|
||||
|
||||
# 5. Check build configuration (if Info.plist contains debug info)
|
||||
echo ""
|
||||
echo "5. Build Configuration"
|
||||
echo "--------------------"
|
||||
INFO_PLIST="$APP_PATH/Contents/Info.plist"
|
||||
if [ -f "$INFO_PLIST" ]; then
|
||||
# Check for common debug keys
|
||||
if plutil -p "$INFO_PLIST" 2>/dev/null | grep -qi "debug"; then
|
||||
echo -e "${YELLOW}⚠️ WARNING: Info.plist may contain debug configuration${NC}"
|
||||
((WARNINGS++))
|
||||
else
|
||||
echo -e "${GREEN}✅ No obvious debug configuration in Info.plist${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ WARNING: Info.plist not found${NC}"
|
||||
((WARNINGS++))
|
||||
fi
|
||||
|
||||
# 6. Check code signature
|
||||
echo ""
|
||||
echo "6. Code Signature"
|
||||
echo "----------------"
|
||||
CODESIGN_INFO=$(codesign -dvvv "$APP_PATH" 2>&1 || true)
|
||||
if echo "$CODESIGN_INFO" | grep -q "Authority="; then
|
||||
echo -e "${GREEN}✅ App is signed${NC}"
|
||||
# Check if it's a development certificate
|
||||
if echo "$CODESIGN_INFO" | grep -q "Developer ID"; then
|
||||
echo -e "${GREEN}✅ Signed with Developer ID (release)${NC}"
|
||||
elif echo "$CODESIGN_INFO" | grep -q "Apple Development"; then
|
||||
echo -e "${YELLOW}⚠️ WARNING: Signed with development certificate${NC}"
|
||||
((WARNINGS++))
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ WARNING: App is not signed${NC}"
|
||||
((WARNINGS++))
|
||||
fi
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
echo "====================================="
|
||||
echo "Verification Summary"
|
||||
echo "====================================="
|
||||
|
||||
if [ $ERRORS -eq 0 ] && [ $WARNINGS -eq 0 ]; then
|
||||
echo -e "${GREEN}✅ All checks passed! This appears to be a valid release build.${NC}"
|
||||
exit 0
|
||||
elif [ $ERRORS -eq 0 ]; then
|
||||
echo -e "${YELLOW}⚠️ Build has $WARNINGS warning(s) but no critical errors.${NC}"
|
||||
echo "Review the warnings above to ensure they're acceptable."
|
||||
exit 0
|
||||
else
|
||||
echo -e "${RED}❌ Build has $ERRORS error(s) and $WARNINGS warning(s).${NC}"
|
||||
echo "This build should NOT be released!"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -98,8 +98,8 @@ async function buildCustomNode() {
|
|||
// Support CI environment variable
|
||||
nodeSourceVersion = process.env.NODE_VERSION;
|
||||
} else {
|
||||
// Default to Node.js 24.2.0 (recommended version)
|
||||
nodeSourceVersion = '24.2.0';
|
||||
// Default to Node.js 24.3.0 (recommended version)
|
||||
nodeSourceVersion = '24.3.0';
|
||||
}
|
||||
|
||||
const platform = process.platform;
|
||||
|
|
@ -177,6 +177,7 @@ async function buildCustomNode() {
|
|||
'--without-inspector', // Remove debugging/profiling features
|
||||
'--without-node-code-cache', // Disable code cache
|
||||
'--without-node-snapshot', // Don't create/use startup snapshot
|
||||
'--shared-zlib', // Use system zlib instead of building custom
|
||||
];
|
||||
|
||||
// Check if ninja is available
|
||||
|
|
@ -188,7 +189,8 @@ async function buildCustomNode() {
|
|||
console.log('Ninja not found, using Make...');
|
||||
}
|
||||
|
||||
// Enable ccache if available
|
||||
|
||||
// Enable ccache if available in system paths
|
||||
try {
|
||||
execSync('which ccache', { stdio: 'ignore' });
|
||||
process.env.CC = 'ccache gcc';
|
||||
|
|
@ -201,8 +203,6 @@ async function buildCustomNode() {
|
|||
// Use -Os optimization which is proven to be safe
|
||||
process.env.CFLAGS = '-Os';
|
||||
process.env.CXXFLAGS = '-Os';
|
||||
// Clear LDFLAGS to avoid any issues
|
||||
delete process.env.LDFLAGS;
|
||||
|
||||
execSync(`./configure ${configureArgs.join(' ')}`, { stdio: 'inherit' });
|
||||
|
||||
|
|
@ -277,6 +277,7 @@ Path: ${customNodePath}
|
|||
`;
|
||||
fs.writeFileSync(summaryPath, summary);
|
||||
|
||||
|
||||
// Change back to original directory
|
||||
process.chdir(originalCwd);
|
||||
|
||||
|
|
|
|||
|
|
@ -321,21 +321,40 @@ async function main() {
|
|||
const customVersion = execSync(`"${nodeExe}" --version`, { encoding: 'utf8' }).trim();
|
||||
console.log(`Custom Node.js version: ${customVersion}`);
|
||||
|
||||
// Save original PATH and use clean environment
|
||||
const originalPath = process.env.PATH;
|
||||
const cleanEnv = {
|
||||
...process.env,
|
||||
// Use only system paths to avoid Homebrew contamination
|
||||
PATH: '/usr/bin:/bin:/usr/sbin:/sbin',
|
||||
npm_config_runtime: 'node',
|
||||
npm_config_target: customVersion.substring(1), // Remove 'v' prefix
|
||||
npm_config_arch: process.arch,
|
||||
npm_config_target_arch: process.arch,
|
||||
npm_config_disturl: 'https://nodejs.org/dist',
|
||||
npm_config_build_from_source: 'true',
|
||||
// Node.js 24 requires C++20
|
||||
CXXFLAGS: '-std=c++20',
|
||||
npm_config_cxxflags: '-std=c++20'
|
||||
};
|
||||
|
||||
// Remove any Homebrew-related environment variables
|
||||
delete cleanEnv.LDFLAGS;
|
||||
delete cleanEnv.LIBRARY_PATH;
|
||||
delete cleanEnv.CPATH;
|
||||
delete cleanEnv.C_INCLUDE_PATH;
|
||||
delete cleanEnv.CPLUS_INCLUDE_PATH;
|
||||
delete cleanEnv.PKG_CONFIG_PATH;
|
||||
|
||||
console.log('Using clean PATH to avoid Homebrew dependencies during native module rebuild...');
|
||||
|
||||
execSync(`pnpm rebuild node-pty authenticate-pam`, {
|
||||
stdio: 'inherit',
|
||||
env: {
|
||||
...process.env,
|
||||
npm_config_runtime: 'node',
|
||||
npm_config_target: customVersion.substring(1), // Remove 'v' prefix
|
||||
npm_config_arch: process.arch,
|
||||
npm_config_target_arch: process.arch,
|
||||
npm_config_disturl: 'https://nodejs.org/dist',
|
||||
npm_config_build_from_source: 'true',
|
||||
// Node.js 24 requires C++20
|
||||
CXXFLAGS: '-std=c++20',
|
||||
npm_config_cxxflags: '-std=c++20'
|
||||
}
|
||||
env: cleanEnv
|
||||
});
|
||||
|
||||
// Restore original PATH
|
||||
process.env.PATH = originalPath;
|
||||
}
|
||||
|
||||
// 2. Bundle TypeScript with esbuild
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vibetunnel/vibetunnel-cli",
|
||||
"version": "1.0.0-beta.7",
|
||||
"version": "1.0.0-beta.8",
|
||||
"description": "Web frontend for terminal multiplexer",
|
||||
"main": "dist/server.js",
|
||||
"bin": {
|
||||
|
|
|
|||
Loading…
Reference in a new issue