Skip to content

Commit ef7f763

Browse files
committed
dynamic greet on dashboard, desktop ci/cd
1 parent f4d47ff commit ef7f763

File tree

26 files changed

+446
-174
lines changed

26 files changed

+446
-174
lines changed

.github/workflows/desktop-build.yml

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,70 @@ jobs:
4444
working-directory: apps/desktop
4545
run: npm ci
4646

47+
- name: Import Apple Code Signing Certificate
48+
if: ${{ env.APPLE_CERTIFICATE_P12 != '' }}
49+
env:
50+
APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
51+
run: |
52+
# Create temporary keychain
53+
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
54+
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
55+
56+
# Create keychain
57+
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
58+
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
59+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
60+
61+
# Import certificate
62+
echo "${{ secrets.APPLE_CERTIFICATE_P12 }}" | base64 --decode > certificate.p12
63+
security import certificate.p12 \
64+
-k "$KEYCHAIN_PATH" \
65+
-P "${{ secrets.APPLE_CERTIFICATE_PASSWORD }}" \
66+
-T /usr/bin/codesign \
67+
-T /usr/bin/productsign
68+
69+
# Set keychain for codesign
70+
security list-keychain -d user -s "$KEYCHAIN_PATH"
71+
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
72+
73+
# Clean up
74+
rm certificate.p12
75+
76+
echo "✅ Certificate imported successfully"
77+
4778
- name: Build macOS app (${{ matrix.arch }})
4879
working-directory: apps/desktop
4980
run: npm run build:mac -- --${{ matrix.arch }}
5081
env:
51-
# Skip notarization in CI (requires Apple Developer credentials)
52-
CSC_IDENTITY_AUTO_DISCOVERY: false
82+
# Use proper signing if certificate is available
83+
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE_P12 }}
84+
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
85+
APPLE_ID: ${{ secrets.APPLE_ID }}
86+
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
87+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
5388

54-
- name: Ad-hoc code sign the app
89+
- name: Notarize app (if credentials available)
90+
if: ${{ env.APPLE_ID != '' }}
5591
working-directory: apps/desktop
92+
env:
93+
APPLE_ID: ${{ secrets.APPLE_ID }}
5694
run: |
95+
echo "🔔 Notarizing app with Apple..."
96+
97+
# electron-builder handles notarization automatically if credentials are set
98+
# The build step above already notarized it
99+
100+
echo "✅ Notarization complete (if credentials were valid)"
101+
102+
- name: Ad-hoc code sign (fallback if no certificate)
103+
if: ${{ env.APPLE_CERTIFICATE_P12 == '' }}
104+
working-directory: apps/desktop
105+
env:
106+
APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
107+
run: |
108+
echo "⚠️ No Apple certificate found, using ad-hoc signing"
109+
echo " Users will need to right-click > Open on first launch"
110+
57111
# Find the .app bundle
58112
APP_PATH=$(find dist/mac*/ -name "*.app" -type d | head -1)
59113
@@ -66,26 +120,12 @@ jobs:
66120
# Ad-hoc sign with hardened runtime
67121
codesign --force --deep --sign - \
68122
--options runtime \
69-
--entitlements <(cat <<EOF
70-
<?xml version="1.0" encoding="UTF-8"?>
71-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
72-
<plist version="1.0">
73-
<dict>
74-
<key>com.apple.security.cs.allow-jit</key>
75-
<true/>
76-
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
77-
<true/>
78-
<key>com.apple.security.cs.disable-library-validation</key>
79-
<true/>
80-
</dict>
81-
</plist>
82-
EOF
83-
) "$APP_PATH"
123+
"$APP_PATH"
84124
85125
# Verify signature
86126
codesign --verify --verbose "$APP_PATH"
87127
88-
echo "✅ App signed successfully"
128+
echo "✅ App signed successfully (ad-hoc)"
89129
else
90130
echo "⚠️ Warning: Could not find .app bundle"
91131
ls -R dist/

apps/desktop/.env.example

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Apple Code Signing & Notarization
2+
# Copy this file to .env and fill in your values
3+
4+
# Path to your exported P12 certificate file
5+
CSC_LINK="./certs/Kortix-Signing.p12"
6+
7+
# Password for the P12 certificate
8+
CSC_KEY_PASSWORD="your_p12_password_here"
9+
10+
# Your Apple ID email
11+
APPLE_ID="you@example.com"
12+
13+
# App-specific password from appleid.apple.com
14+
APPLE_APP_SPECIFIC_PASSWORD="abcd-efgh-ijkl-mnop"
15+
16+
# Your Apple Team ID (10 characters)
17+
APPLE_TEAM_ID="AB12CD34EF"
18+
19+
# Optional: Build for specific architecture
20+
# ARCH=arm64 # or x64 or universal

apps/desktop/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@ node_modules/
22
dist/
33
*.log
44
.DS_Store
5+
.env
6+
*.p12
7+
*.pem
8+
*.cer

apps/desktop/README.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ npm start
2121
Build for your platform:
2222

2323
```bash
24-
npm run build:mac # macOS
25-
npm run build:win # Windows
26-
npm run build:linux # Linux
24+
npm run build:mac # macOS (with signing if .env exists)
25+
npm run build:mac:unsigned # macOS (quick, no signing)
26+
npm run build:win # Windows
27+
npm run build:linux # Linux
2728
```
2829

2930
Or build for all platforms:
@@ -32,6 +33,8 @@ Or build for all platforms:
3233
npm run build
3334
```
3435

36+
**Note:** For signed macOS builds, create a `.env` file with Apple credentials (see `LOCAL-BUILD.md`).
37+
3538
## Configuration
3639

3740
Set `APP_URL` environment variable to load a different URL:
@@ -42,6 +45,10 @@ APP_URL=http://localhost:3000 npm start
4245

4346
By default, it loads `https://kortix.com/`.
4447

48+
## Installation
49+
50+
For end users, see [INSTALLATION.md](./INSTALLATION.md) for detailed installation instructions including how to bypass macOS Gatekeeper on first launch.
51+
4552
## Deep Linking
4653

4754
The app registers the `kortix://` protocol for magic link authentication:
@@ -53,3 +60,12 @@ The app registers the `kortix://` protocol for magic link authentication:
5360
5. App handles auth callback and logs user in
5461

5562
The protocol is automatically registered when the app is installed.
63+
64+
## Code Signing Status
65+
66+
The CI/CD builds use **ad-hoc code signing** which means:
67+
- ✅ App is properly signed and not "damaged"
68+
- ⚠️ Not notarized with Apple (requires paid developer account)
69+
- 📝 Users must right-click → Open on first launch (macOS only)
70+
71+
For production notarization, add Apple Developer credentials to GitHub Secrets.

apps/desktop/assets/AppIcon.png

41.4 KB
Loading

apps/desktop/assets/icon.icns

22 KB
Binary file not shown.

apps/desktop/assets/icon.png

27.1 KB
Loading

apps/desktop/assets/logo.png

-1.34 MB
Binary file not shown.

apps/desktop/build-signed.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Local build script with code signing
5+
* Loads credentials from .env file
6+
*/
7+
8+
require('dotenv').config();
9+
const { execSync } = require('child_process');
10+
const fs = require('fs');
11+
const path = require('path');
12+
13+
console.log('🔨 Starting signed build...\n');
14+
15+
// Check if .env exists
16+
if (!fs.existsSync('.env')) {
17+
console.log('⚠️ No .env file found');
18+
console.log('📝 Copy .env.example to .env and fill in your Apple credentials');
19+
console.log(' Or run: npm run build:mac:unsigned (for quick testing)\n');
20+
process.exit(1);
21+
}
22+
23+
// Check required environment variables
24+
const required = [
25+
'CSC_LINK',
26+
'CSC_KEY_PASSWORD',
27+
'APPLE_ID',
28+
'APPLE_APP_SPECIFIC_PASSWORD',
29+
'APPLE_TEAM_ID'
30+
];
31+
32+
const missing = required.filter(key => !process.env[key]);
33+
34+
if (missing.length > 0) {
35+
console.log('❌ Missing required environment variables:');
36+
missing.forEach(key => console.log(` - ${key}`));
37+
console.log('\n📝 Please add them to your .env file\n');
38+
process.exit(1);
39+
}
40+
41+
// Check if certificate file exists
42+
const certPath = process.env.CSC_LINK;
43+
if (!certPath) {
44+
console.log('❌ CSC_LINK environment variable is not set');
45+
process.exit(1);
46+
}
47+
48+
if (certPath.startsWith('./') || certPath.startsWith('../')) {
49+
const fullPath = path.resolve(__dirname, certPath);
50+
if (!fs.existsSync(fullPath)) {
51+
console.log(`❌ Certificate file not found: ${fullPath}`);
52+
console.log('📝 Make sure CSC_LINK points to your .p12 file\n');
53+
process.exit(1);
54+
}
55+
}
56+
57+
console.log('✅ Environment variables loaded');
58+
console.log('✅ Certificate found');
59+
console.log('\n🔨 Building with code signing and notarization...');
60+
console.log(' This may take 5-10 minutes (notarization is slow)\n');
61+
62+
// Determine architecture
63+
const arch = process.env.ARCH || 'universal';
64+
const archFlag = arch === 'universal' ? '' : `--${arch}`;
65+
66+
try {
67+
// Resolve certificate path to absolute if relative
68+
const resolvedCertPath = certPath.startsWith('./') || certPath.startsWith('../')
69+
? path.resolve(__dirname, certPath)
70+
: certPath;
71+
72+
// Run electron-builder with signing
73+
execSync(`electron-builder --mac ${archFlag}`, {
74+
stdio: 'inherit',
75+
env: {
76+
...process.env,
77+
// Ensure certificate path is absolute
78+
CSC_LINK: resolvedCertPath
79+
}
80+
});
81+
82+
console.log('\n✅ Build complete!');
83+
console.log('📦 Output: dist/\n');
84+
85+
// List output files
86+
const distPath = path.join(__dirname, 'dist');
87+
if (fs.existsSync(distPath)) {
88+
const files = fs.readdirSync(distPath)
89+
.filter(f => f.endsWith('.dmg') || f.endsWith('.zip'))
90+
.map(f => ` ${f}`)
91+
.join('\n');
92+
93+
if (files) {
94+
console.log('📦 Built files:');
95+
console.log(files);
96+
console.log('');
97+
}
98+
}
99+
100+
} catch (error) {
101+
console.error('\n❌ Build failed:', error.message);
102+
process.exit(1);
103+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>com.apple.security.cs.allow-jit</key>
6+
<true/>
7+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
8+
<true/>
9+
<key>com.apple.security.cs.disable-library-validation</key>
10+
<true/>
11+
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
12+
<true/>
13+
</dict>
14+
</plist>
15+

0 commit comments

Comments
 (0)