mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-07-09 17:28:35 +00:00
fix notarize
This commit is contained in:
parent
b5849338ab
commit
233c8ac085
3 changed files with 373 additions and 2 deletions
|
|
@ -18,7 +18,7 @@ exports.default = async function afterPack(context) {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log('🧹 Cleaning invalid symlinks before signing...');
|
||||
console.log('🧹 Cleaning invalid symlinks and cache directories before signing...');
|
||||
|
||||
const resourcesPath = path.join(appPath, 'Contents', 'Resources');
|
||||
const prebuiltPath = path.join(resourcesPath, 'prebuilt');
|
||||
|
|
@ -27,6 +27,59 @@ exports.default = async function afterPack(context) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Remove .npm-cache directories (should not be packaged)
|
||||
function removeNpmCache(dir) {
|
||||
if (!fs.existsSync(dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
|
||||
try {
|
||||
if (entry.name === '.npm-cache' && entry.isDirectory()) {
|
||||
console.log(`Removing .npm-cache directory: ${fullPath}`);
|
||||
fs.rmSync(fullPath, { recursive: true, force: true });
|
||||
} else if (entry.isDirectory()) {
|
||||
removeNpmCache(fullPath);
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore errors
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore errors
|
||||
}
|
||||
}
|
||||
|
||||
removeNpmCache(prebuiltPath);
|
||||
|
||||
// Remove flac-mac binary (uses outdated SDK, causes notarization issues)
|
||||
const venvLibPath = path.join(prebuiltPath, 'venv', 'lib');
|
||||
if (fs.existsSync(venvLibPath)) {
|
||||
try {
|
||||
const entries = fs.readdirSync(venvLibPath, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory() && entry.name.startsWith('python')) {
|
||||
const flacMacPath = path.join(venvLibPath, entry.name, 'site-packages', 'speech_recognition', 'flac-mac');
|
||||
if (fs.existsSync(flacMacPath)) {
|
||||
console.log(`Removing flac-mac binary (outdated SDK): ${flacMacPath}`);
|
||||
try {
|
||||
fs.unlinkSync(flacMacPath);
|
||||
} catch (error) {
|
||||
console.warn(`Warning: Could not remove flac-mac: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore errors
|
||||
}
|
||||
}
|
||||
|
||||
// Clean Python symlinks in venv/bin
|
||||
const venvBinDir = path.join(prebuiltPath, 'venv', 'bin');
|
||||
if (fs.existsSync(venvBinDir)) {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
{
|
||||
"from": "resources/prebuilt",
|
||||
"to": "prebuilt",
|
||||
"filter": ["**/*", "!cache/**/*"]
|
||||
"filter": ["**/*", "!cache/**/*", "!**/.npm-cache/**/*"]
|
||||
}
|
||||
],
|
||||
"protocols": [
|
||||
|
|
|
|||
318
scripts/test-signing.js
Normal file
318
scripts/test-signing.js
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* Test script for macOS code signing
|
||||
* This script helps debug signing issues by:
|
||||
* 1. Checking for invalid symlinks
|
||||
* 2. Verifying bundle structure
|
||||
* 3. Testing codesign verification (without actual signing)
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { execSync } from 'child_process';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const projectRoot = path.resolve(__dirname, '..');
|
||||
|
||||
const RELEASE_DIR = path.join(projectRoot, 'release');
|
||||
const APP_BUNDLE_PATTERN = /Eigent\.app$/;
|
||||
|
||||
/**
|
||||
* Find the app bundle in release directory
|
||||
*/
|
||||
function findAppBundle() {
|
||||
if (!fs.existsSync(RELEASE_DIR)) {
|
||||
console.log('❌ Release directory does not exist. Please build the app first.');
|
||||
console.log(' Run: npm run build:mac');
|
||||
return null;
|
||||
}
|
||||
|
||||
const entries = fs.readdirSync(RELEASE_DIR, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory() && entry.name.match(APP_BUNDLE_PATTERN)) {
|
||||
return path.join(RELEASE_DIR, entry.name);
|
||||
}
|
||||
|
||||
// Check subdirectories (e.g., mac-arm64/Eigent.app)
|
||||
if (entry.isDirectory()) {
|
||||
const subDir = path.join(RELEASE_DIR, entry.name);
|
||||
const subEntries = fs.readdirSync(subDir, { withFileTypes: true });
|
||||
for (const subEntry of subEntries) {
|
||||
if (subEntry.isDirectory() && subEntry.name.match(APP_BUNDLE_PATTERN)) {
|
||||
return path.join(subDir, subEntry.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for invalid symlinks in the app bundle
|
||||
*/
|
||||
function checkSymlinks(bundlePath) {
|
||||
console.log('\n🔍 Checking for invalid symlinks...');
|
||||
|
||||
const invalidSymlinks = [];
|
||||
|
||||
function checkDir(dir) {
|
||||
if (!fs.existsSync(dir)) return;
|
||||
|
||||
try {
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
|
||||
try {
|
||||
if (entry.isSymbolicLink()) {
|
||||
const target = fs.readlinkSync(fullPath);
|
||||
const resolvedPath = path.resolve(path.dirname(fullPath), target);
|
||||
const bundlePathResolved = path.resolve(bundlePath);
|
||||
|
||||
if (!fs.existsSync(resolvedPath)) {
|
||||
invalidSymlinks.push({
|
||||
path: fullPath,
|
||||
target: target,
|
||||
reason: 'Target does not exist'
|
||||
});
|
||||
} else if (!resolvedPath.startsWith(bundlePathResolved)) {
|
||||
invalidSymlinks.push({
|
||||
path: fullPath,
|
||||
target: target,
|
||||
reason: 'Target is outside bundle'
|
||||
});
|
||||
}
|
||||
} else if (entry.isDirectory()) {
|
||||
// Skip certain directories
|
||||
if (entry.name === 'node_modules' || entry.name === '__pycache__') {
|
||||
continue;
|
||||
}
|
||||
checkDir(fullPath);
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore errors for individual files
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore errors for directories
|
||||
}
|
||||
}
|
||||
|
||||
checkDir(bundlePath);
|
||||
|
||||
if (invalidSymlinks.length > 0) {
|
||||
console.log(`❌ Found ${invalidSymlinks.length} invalid symlink(s):`);
|
||||
invalidSymlinks.forEach(symlink => {
|
||||
console.log(` - ${symlink.path}`);
|
||||
console.log(` → ${symlink.target}`);
|
||||
console.log(` Reason: ${symlink.reason}`);
|
||||
});
|
||||
return false;
|
||||
} else {
|
||||
console.log('✅ No invalid symlinks found');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check bundle structure
|
||||
*/
|
||||
function checkBundleStructure(bundlePath) {
|
||||
console.log('\n🔍 Checking bundle structure...');
|
||||
|
||||
const requiredPaths = [
|
||||
'Contents/Info.plist',
|
||||
'Contents/MacOS',
|
||||
'Contents/Resources'
|
||||
];
|
||||
|
||||
let allValid = true;
|
||||
|
||||
for (const requiredPath of requiredPaths) {
|
||||
const fullPath = path.join(bundlePath, requiredPath);
|
||||
if (!fs.existsSync(fullPath)) {
|
||||
console.log(`❌ Missing: ${requiredPath}`);
|
||||
allValid = false;
|
||||
} else {
|
||||
console.log(`✅ Found: ${requiredPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
return allValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check entitlements file
|
||||
*/
|
||||
function checkEntitlements() {
|
||||
console.log('\n🔍 Checking entitlements...');
|
||||
|
||||
const entitlementsPath = path.join(projectRoot, 'entitlements.mac.plist');
|
||||
|
||||
if (!fs.existsSync(entitlementsPath)) {
|
||||
console.log('❌ entitlements.mac.plist not found');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('✅ entitlements.mac.plist exists');
|
||||
|
||||
// Try to validate plist format
|
||||
try {
|
||||
execSync(`plutil -lint "${entitlementsPath}"`, { stdio: 'pipe' });
|
||||
console.log('✅ Entitlements file is valid');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log('⚠️ Could not validate entitlements file format');
|
||||
return true; // Don't fail on this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test codesign verification (if app is already signed)
|
||||
*/
|
||||
function testCodesignVerification(bundlePath) {
|
||||
console.log('\n🔍 Testing codesign verification...');
|
||||
|
||||
try {
|
||||
// First check if app is signed at all
|
||||
const signCheck = execSync(
|
||||
`codesign -dv "${bundlePath}" 2>&1 || true`,
|
||||
{ encoding: 'utf-8' }
|
||||
);
|
||||
|
||||
if (signCheck.includes('code object is not signed')) {
|
||||
console.log('ℹ️ App is not signed (this is expected for local testing without certificates)');
|
||||
return true;
|
||||
}
|
||||
|
||||
// If signed, verify it
|
||||
const output = execSync(
|
||||
`codesign --verify --deep --strict --verbose=2 "${bundlePath}" 2>&1 || true`,
|
||||
{ encoding: 'utf-8' }
|
||||
);
|
||||
|
||||
if (output.includes('valid on disk') || output.includes('satisfies its Designated Requirement')) {
|
||||
console.log('✅ App is properly signed');
|
||||
return true;
|
||||
} else if (output.includes('code has no resources but signature indicates they must be present')) {
|
||||
// This error often means the app was signed incorrectly or needs to be re-signed
|
||||
console.log('⚠️ Codesign verification issue detected:');
|
||||
console.log(' This usually means the app needs to be re-signed.');
|
||||
console.log(' In CI/CD, this should be fixed by electron-builder during signing.');
|
||||
console.log(' For local testing, you can ignore this if you don\'t have signing certificates.');
|
||||
return true; // Don't fail local testing
|
||||
} else {
|
||||
console.log('⚠️ Codesign verification issues:');
|
||||
console.log(output);
|
||||
return true; // Don't fail local testing
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('ℹ️ Could not verify signature (app may not be signed - expected for local testing)');
|
||||
return true; // Don't fail on this for local testing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for common signing issues
|
||||
*/
|
||||
function checkCommonIssues(bundlePath) {
|
||||
console.log('\n🔍 Checking for common signing issues...');
|
||||
|
||||
const issues = [];
|
||||
|
||||
// Check for files that might cause issues
|
||||
const problematicPatterns = [
|
||||
/\.DS_Store$/,
|
||||
/\.git$/,
|
||||
/node_modules/,
|
||||
];
|
||||
|
||||
function scanDir(dir, depth = 0) {
|
||||
if (depth > 10) return; // Prevent infinite recursion
|
||||
|
||||
try {
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
const relativePath = path.relative(bundlePath, fullPath);
|
||||
|
||||
// Check for problematic files
|
||||
for (const pattern of problematicPatterns) {
|
||||
if (pattern.test(relativePath)) {
|
||||
issues.push(`Found ${relativePath} (may cause signing issues)`);
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.isDirectory() && !entry.isSymbolicLink()) {
|
||||
scanDir(fullPath, depth + 1);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore errors
|
||||
}
|
||||
}
|
||||
|
||||
scanDir(bundlePath);
|
||||
|
||||
if (issues.length > 0) {
|
||||
console.log('⚠️ Potential issues found:');
|
||||
issues.forEach(issue => console.log(` - ${issue}`));
|
||||
} else {
|
||||
console.log('✅ No obvious issues found');
|
||||
}
|
||||
|
||||
return issues.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
function main() {
|
||||
console.log('🧪 macOS Code Signing Test Script\n');
|
||||
|
||||
const appBundle = findAppBundle();
|
||||
|
||||
if (!appBundle) {
|
||||
console.log('\n💡 To build the app for testing:');
|
||||
console.log(' npm run build:mac');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`📦 Found app bundle: ${appBundle}\n`);
|
||||
|
||||
const results = {
|
||||
symlinks: checkSymlinks(appBundle),
|
||||
structure: checkBundleStructure(appBundle),
|
||||
entitlements: checkEntitlements(),
|
||||
codesign: testCodesignVerification(appBundle),
|
||||
commonIssues: checkCommonIssues(appBundle),
|
||||
};
|
||||
|
||||
console.log('\n📊 Summary:');
|
||||
console.log(` Symlinks: ${results.symlinks ? '✅' : '❌'}`);
|
||||
console.log(` Structure: ${results.structure ? '✅' : '❌'}`);
|
||||
console.log(` Entitlements: ${results.entitlements ? '✅' : '❌'}`);
|
||||
console.log(` Codesign: ${results.codesign ? '✅' : '⚠️'}`);
|
||||
console.log(` Common Issues: ${results.commonIssues ? '✅' : '⚠️'}`);
|
||||
|
||||
// For local testing, only fail on critical issues (symlinks, structure, entitlements)
|
||||
const criticalChecks = [results.symlinks, results.structure, results.entitlements];
|
||||
const allCriticalPassed = criticalChecks.every(r => r);
|
||||
|
||||
if (allCriticalPassed) {
|
||||
console.log('\n✅ Critical checks passed! The app should be ready for signing.');
|
||||
console.log(' Note: Codesign warnings are expected for local testing without certificates.');
|
||||
console.log(' The app will be properly signed in CI/CD with the provided certificates.');
|
||||
} else {
|
||||
console.log('\n❌ Critical checks failed. Please fix the issues above before signing.');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Loading…
Add table
Add a link
Reference in a new issue