Tim commited on
Commit
7d2f50f
Β·
verified Β·
1 Parent(s): b51b530

Upload diagnostic.sh

Browse files
Files changed (1) hide show
  1. diagnostic.sh +563 -152
diagnostic.sh CHANGED
@@ -1,190 +1,601 @@
1
  #!/bin/bash
2
- # BSKL AIColorMatch Diagnostic Script
3
- # Collects system info and logs for troubleshooting
4
-
5
- OUTPUT_DIR="$HOME/Desktop/BSKL_Diagnostic_$(date +%Y%m%d_%H%M%S)"
6
- mkdir -p "$OUTPUT_DIR"
7
-
8
- echo "=== BSKL AIColorMatch Diagnostic Tool ===" | tee "$OUTPUT_DIR/diagnostic.txt"
9
- echo "Date: $(date)" | tee -a "$OUTPUT_DIR/diagnostic.txt"
10
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
11
-
12
- # 1. macOS Version
13
- echo "=== macOS Version ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
14
- sw_vers | tee -a "$OUTPUT_DIR/diagnostic.txt"
15
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
16
-
17
- # 2. Mac Architecture
18
- echo "=== Mac Architecture ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
19
- uname -m | tee -a "$OUTPUT_DIR/diagnostic.txt"
20
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
21
-
22
- # 3. Render Engine Version
23
- echo "=== Render Engine Version ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
24
- RE_VERSION_FILE="/Library/Application Support/BSKL/Render Engine/Python 3.10/version.txt"
25
- if [ -f "$RE_VERSION_FILE" ]; then
26
- echo "Version: $(cat "$RE_VERSION_FILE")" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  else
28
- echo "❌ Render Engine not found" | tee -a "$OUTPUT_DIR/diagnostic.txt"
29
  fi
30
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
31
 
32
- # 4. AIM Server Process Status
33
- echo "=== AIM Server Process ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
34
- AIM_PROCESS=$(ps aux | grep -i "AI MACHINE Server" | grep -v grep)
35
- if [ -n "$AIM_PROCESS" ]; then
36
- echo "βœ… AIM Server is running" | tee -a "$OUTPUT_DIR/diagnostic.txt"
37
- echo "$AIM_PROCESS" | tee -a "$OUTPUT_DIR/diagnostic.txt"
38
- else
39
- echo "❌ AIM Server is NOT running" | tee -a "$OUTPUT_DIR/diagnostic.txt"
40
  fi
41
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
42
 
43
- # 5. Check Server Port (7007 is default)
44
- echo "=== Server Port (7007) ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
45
- PORT_CHECK=$(lsof -i :7007 2>/dev/null | head -5)
46
- if [ -n "$PORT_CHECK" ]; then
47
- echo "βœ… Port 7007 is in use:" | tee -a "$OUTPUT_DIR/diagnostic.txt"
48
- echo "$PORT_CHECK" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  else
50
- echo "❌ Port 7007 is not in use (server not running?)" | tee -a "$OUTPUT_DIR/diagnostic.txt"
51
  fi
52
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
53
 
54
- # 6. AIM Server Lock File
55
- echo "=== AIM Server Lock File ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
56
- LOCK_FILE="$HOME/.AI MACHINE Server.lock"
57
- if [ -f "$LOCK_FILE" ]; then
58
- echo "Lock file exists: $LOCK_FILE" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
 
 
 
 
 
 
 
59
  else
60
- echo "No lock file found" | tee -a "$OUTPUT_DIR/diagnostic.txt"
61
  fi
62
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
63
 
64
- # 7. AIM Settings
65
- echo "=== AIM Settings ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
66
- SETTINGS_FILE="$HOME/.aim/settings.json"
67
- if [ -f "$SETTINGS_FILE" ]; then
68
- echo "Settings file:" | tee -a "$OUTPUT_DIR/diagnostic.txt"
69
- cat "$SETTINGS_FILE" | tee -a "$OUTPUT_DIR/diagnostic.txt"
70
- cp "$SETTINGS_FILE" "$OUTPUT_DIR/"
71
  else
72
- echo "No settings file found at $SETTINGS_FILE" | tee -a "$OUTPUT_DIR/diagnostic.txt"
73
  fi
74
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
75
 
76
- # 8. AIM Server Files
77
- echo "=== AIM Server Files ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
78
- AIM_SERVER_DIR="/Library/Application Support/BSKL/AI MACHINE/Server"
79
- if [ -d "$AIM_SERVER_DIR" ]; then
80
- ls -la "$AIM_SERVER_DIR"/*.so 2>/dev/null | tee -a "$OUTPUT_DIR/diagnostic.txt"
81
- else
82
- echo "❌ AIM Server directory not found" | tee -a "$OUTPUT_DIR/diagnostic.txt"
83
- fi
84
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
85
-
86
- # 9. AI MACHINE Plugins
87
- echo "=== AI MACHINE Plugins ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
88
- PLUGINS_DIR="/Library/Application Support/BSKL/AI MACHINE/Plugins"
89
- if [ -d "$PLUGINS_DIR" ]; then
90
- for plugin_dir in "$PLUGINS_DIR"/*/; do
91
- if [ -d "$plugin_dir" ]; then
92
- plugin_name=$(basename "$plugin_dir")
93
- echo "Plugin: $plugin_name" | tee -a "$OUTPUT_DIR/diagnostic.txt"
94
- # List .so files with sizes
95
- for so_file in "$plugin_dir"*.so; do
96
- if [ -f "$so_file" ]; then
97
- size=$(ls -lh "$so_file" | awk '{print $5}')
98
- arch=$(file "$so_file" | grep -o "arm64\|x86_64" | head -1)
99
- echo " $(basename "$so_file") ($size, $arch)" | tee -a "$OUTPUT_DIR/diagnostic.txt"
100
- fi
101
- done
102
- fi
103
- done
104
  else
105
- echo "❌ AI MACHINE Plugins directory not found" | tee -a "$OUTPUT_DIR/diagnostic.txt"
106
- fi
107
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
108
-
109
- # 10. Adobe BSKL Plugins (with version info from plist)
110
- echo "=== Adobe BSKL Plugins ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
111
- ADOBE_PLUGINS_DIR="/Library/Application Support/Adobe/Common/Plug-ins/7.0/MediaCore/BSKL"
112
- if [ -d "$ADOBE_PLUGINS_DIR" ]; then
113
- for plugin in "$ADOBE_PLUGINS_DIR"/*.plugin; do
114
- if [ -d "$plugin" ]; then
115
- plugin_name=$(basename "$plugin" .plugin)
116
- plist="$plugin/Contents/Info.plist"
117
- if [ -f "$plist" ]; then
118
- version=$(defaults read "$plist" CFBundleShortVersionString 2>/dev/null || echo "n/a")
119
- build=$(defaults read "$plist" CFBundleVersion 2>/dev/null || echo "n/a")
120
- sdk=$(defaults read "$plist" DTPlatformVersion 2>/dev/null || echo "n/a")
121
- xcode=$(defaults read "$plist" DTXcode 2>/dev/null || echo "n/a")
122
- echo "Plugin: $plugin_name" | tee -a "$OUTPUT_DIR/diagnostic.txt"
123
- echo " Version: $version (build: $build)" | tee -a "$OUTPUT_DIR/diagnostic.txt"
124
- echo " SDK: macOS $sdk, Xcode: $xcode" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  else
126
- echo "Plugin: $plugin_name (no plist)" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
127
  fi
 
 
 
 
 
 
 
128
  fi
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  done
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  else
131
- echo "❌ Adobe BSKL plugins directory not found" | tee -a "$OUTPUT_DIR/diagnostic.txt"
132
  fi
133
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
134
 
135
- # 11. NumPy Architecture
136
- echo "=== NumPy Architecture ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
137
- NUMPY_FILE="/Library/Application Support/BSKL/Render Engine/Python 3.10/lib/python3.10/site-packages/numpy/core/_multiarray_umath.cpython-310-darwin.so"
138
- if [ -f "$NUMPY_FILE" ]; then
139
- arch=$(file "$NUMPY_FILE" | grep -o "arm64\|x86_64" | head -1)
140
- echo "NumPy architecture: $arch" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  else
142
- echo "❌ NumPy not found" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  fi
144
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
145
 
146
- # 12. Test Server Connection
147
- echo "=== Server Connection Test ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
148
- CURL_RESULT=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 http://127.0.0.1:7007/ 2>/dev/null)
149
- if [ "$CURL_RESULT" = "200" ] || [ "$CURL_RESULT" = "404" ] || [ "$CURL_RESULT" = "422" ]; then
150
- echo "βœ… Server responding (HTTP $CURL_RESULT)" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  else
152
- echo "❌ Server not responding (HTTP $CURL_RESULT)" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
 
 
 
153
  fi
154
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
155
 
156
- # 13. Collect Logs
157
- echo "=== Collecting Logs ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
- # BSKL logs directory
160
- BSKL_LOGS="/Library/Application Support/BSKL/Logs"
161
- if [ -d "$BSKL_LOGS" ]; then
162
- echo "Found logs:" | tee -a "$OUTPUT_DIR/diagnostic.txt"
163
- ls -la "$BSKL_LOGS"/*.log 2>/dev/null | tee -a "$OUTPUT_DIR/diagnostic.txt"
164
- cp "$BSKL_LOGS"/*.log "$OUTPUT_DIR/" 2>/dev/null
165
- echo "βœ… Copied BSKL logs" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  else
167
- echo "❌ BSKL logs directory not found" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  fi
169
 
170
- # 14. Create ZIP archive
171
- echo "" | tee -a "$OUTPUT_DIR/diagnostic.txt"
172
- echo "=== Creating ZIP Archive ===" | tee -a "$OUTPUT_DIR/diagnostic.txt"
 
173
 
174
- ZIP_FILE="$HOME/Desktop/BSKL_Diagnostic_$(date +%Y%m%d_%H%M%S).zip"
175
- cd "$HOME/Desktop"
176
- zip -r "$ZIP_FILE" "$(basename $OUTPUT_DIR)" > /dev/null 2>&1
 
177
 
178
- if [ -f "$ZIP_FILE" ]; then
179
- # Cleanup temp folder
180
- rm -rf "$OUTPUT_DIR"
 
181
 
182
- echo ""
183
- echo "=========================================="
184
- echo "βœ… Done! Please send this file to support:"
185
- echo "$ZIP_FILE"
186
- echo "=========================================="
187
  else
188
- echo "❌ Failed to create ZIP archive" | tee -a "$OUTPUT_DIR/diagnostic.txt"
189
- echo "Diagnostic folder: $OUTPUT_DIR"
 
 
 
 
 
 
 
 
190
  fi
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  #!/bin/bash
2
+ #
3
+ # After Effects Plugin Diagnostic Tool
4
+ # Checks dependencies, code signing, quarantine, and plugin structure
5
+ #
6
+ # Usage: bash check_plugin.sh /path/to/Plugin.plugin
7
+ #
8
+
9
+ # Don't exit on error - we want to continue checking even if some commands fail
10
+ set +e
11
+
12
+ # Output file on Desktop
13
+ REPORT_TIMESTAMP=$(date +%Y%m%d_%H%M%S)
14
+ OUTPUT_FILE="$HOME/Desktop/plugin_diagnostic_$REPORT_TIMESTAMP.txt"
15
+
16
+ # Function to output to both console and file
17
+ log() {
18
+ echo -e "$1"
19
+ # Strip color codes for file output
20
+ echo -e "$1" | sed 's/\x1b\[[0-9;]*m//g' >> "$OUTPUT_FILE"
21
+ }
22
+
23
+ # Initialize output file
24
+ echo "# After Effects Plugin Diagnostic Report" > "$OUTPUT_FILE"
25
+ echo "# Generated: $(date)" >> "$OUTPUT_FILE"
26
+ echo "" >> "$OUTPUT_FILE"
27
+
28
+ # Colors (for console only)
29
+ RED='\033[0;31m'
30
+ GREEN='\033[0;32m'
31
+ YELLOW='\033[1;33m'
32
+ BLUE='\033[0;34m'
33
+ NC='\033[0m' # No Color
34
+
35
+ # Icons
36
+ PASS="βœ…"
37
+ FAIL="❌"
38
+ WARN="⚠️"
39
+ INFO="ℹ️"
40
+
41
+ print_header() {
42
+ log ""
43
+ log "${BLUE}═══════════════════════════════════════════════════════════${NC}"
44
+ log "${BLUE} $1${NC}"
45
+ log "${BLUE}═══════════════════════════════════════════════════════════${NC}"
46
+ }
47
+
48
+ print_section() {
49
+ log ""
50
+ log "${YELLOW}── $1 ──${NC}"
51
+ }
52
+
53
+ # Default plugin path for AIColorMatch
54
+ DEFAULT_PLUGIN="/Library/Application Support/Adobe/Common/Plug-ins/7.0/MediaCore/BSKL/AIColorMatch.plugin"
55
+ MEDIACORE_PATH="/Library/Application Support/Adobe/Common/Plug-ins/7.0/MediaCore"
56
+
57
+ # Check arguments - use default if not provided
58
+ if [ -z "$1" ]; then
59
+ if [ -d "$DEFAULT_PLUGIN" ]; then
60
+ PLUGIN_PATH="$DEFAULT_PLUGIN"
61
+ echo "Using default plugin path: $PLUGIN_PATH"
62
+ else
63
+ echo -e "${RED}Usage: bash check_plugin.sh /path/to/Plugin.plugin${NC}"
64
+ echo ""
65
+ echo "Default plugin not found at:"
66
+ echo " $DEFAULT_PLUGIN"
67
+ echo ""
68
+ echo "Please specify plugin path manually."
69
+ exit 1
70
+ fi
71
  else
72
+ PLUGIN_PATH="$1"
73
  fi
 
74
 
75
+ # Validate plugin exists
76
+ if [ ! -d "$PLUGIN_PATH" ]; then
77
+ log "${FAIL} Plugin not found: $PLUGIN_PATH"
78
+ exit 1
 
 
 
 
79
  fi
 
80
 
81
+ # Get plugin name
82
+ PLUGIN_NAME=$(basename "$PLUGIN_PATH" .plugin)
83
+
84
+ print_header "After Effects Plugin Diagnostic Report"
85
+ log ""
86
+ log "Plugin: ${GREEN}$PLUGIN_NAME${NC}"
87
+ log "Path: $PLUGIN_PATH"
88
+ log "Date: $(date)"
89
+ log "macOS: $(sw_vers -productVersion) ($(sw_vers -buildVersion))"
90
+ log "Machine: $(uname -m)"
91
+
92
+ # ─────────────────────────────────────────────────────────────
93
+ # 0. ALL PLUGINS IN MEDIACORE
94
+ # ─────────────────────────────────────────────────────���───────
95
+ print_section "All Plugins in MediaCore"
96
+
97
+ if [ -d "$MEDIACORE_PATH" ]; then
98
+ log "${BLUE}Scanning: $MEDIACORE_PATH${NC}"
99
+ log ""
100
+
101
+ # Find all .plugin bundles
102
+ PLUGIN_COUNT=0
103
+ while IFS= read -r plugin_bundle; do
104
+ PLUGIN_COUNT=$((PLUGIN_COUNT + 1))
105
+ plugin_name=$(basename "$plugin_bundle" .plugin)
106
+ plugin_modified=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M" "$plugin_bundle" 2>/dev/null || echo "unknown")
107
+ plugin_size=$(du -sh "$plugin_bundle" 2>/dev/null | cut -f1 || echo "?")
108
+
109
+ # Check if binary exists
110
+ binary_path="$plugin_bundle/Contents/MacOS/$plugin_name"
111
+ if [ -f "$binary_path" ]; then
112
+ arch=$(lipo -archs "$binary_path" 2>/dev/null || echo "?")
113
+ log "$PASS $plugin_name"
114
+ log " Modified: $plugin_modified | Size: $plugin_size | Arch: $arch"
115
+ else
116
+ log "$WARN $plugin_name (binary missing)"
117
+ log " Modified: $plugin_modified | Size: $plugin_size"
118
+ fi
119
+ done < <(find "$MEDIACORE_PATH" -maxdepth 2 -name "*.plugin" -type d 2>/dev/null | sort)
120
+
121
+ log ""
122
+ log "Total plugins found: $PLUGIN_COUNT"
123
  else
124
+ log "$WARN MediaCore directory not found: $MEDIACORE_PATH"
125
  fi
 
126
 
127
+ # ─────────────────────────────────────────────────────────────
128
+ # 1. PLUGIN STRUCTURE
129
+ # ─────────────────────────────────────────────────────────────
130
+ print_section "Plugin Structure"
131
+
132
+ BINARY_PATH="$PLUGIN_PATH/Contents/MacOS/$PLUGIN_NAME"
133
+ PLIST_PATH="$PLUGIN_PATH/Contents/Info.plist"
134
+ RSRC_PATH="$PLUGIN_PATH/Contents/Resources/$PLUGIN_NAME.rsrc"
135
+
136
+ if [ -f "$BINARY_PATH" ]; then
137
+ log "$PASS Binary: $BINARY_PATH"
138
+ BINARY_SIZE=$(du -h "$BINARY_PATH" | cut -f1)
139
+ log " Size: $BINARY_SIZE"
140
  else
141
+ log "$FAIL Binary NOT FOUND: $BINARY_PATH"
142
  fi
 
143
 
144
+ if [ -f "$PLIST_PATH" ]; then
145
+ log "$PASS Info.plist: exists"
 
 
 
 
 
146
  else
147
+ log "$FAIL Info.plist NOT FOUND"
148
  fi
 
149
 
150
+ if [ -f "$RSRC_PATH" ]; then
151
+ log "$PASS Resource file: $PLUGIN_NAME.rsrc"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  else
153
+ log "$WARN Resource file not found (may be embedded)"
154
+ fi
155
+
156
+ # ─────────────────────────────────────────────────────────────
157
+ # 2. ARCHITECTURE
158
+ # ─────────────────────────────────────────────────────────────
159
+ print_section "Architecture"
160
+
161
+ if [ -f "$BINARY_PATH" ]; then
162
+ ARCHS=$(lipo -archs "$BINARY_PATH" 2>/dev/null || echo "unknown")
163
+
164
+ if [[ "$ARCHS" == *"arm64"* ]] && [[ "$ARCHS" == *"x86_64"* ]]; then
165
+ log "$PASS Universal Binary: $ARCHS"
166
+ elif [[ "$ARCHS" == *"arm64"* ]]; then
167
+ log "$WARN ARM64 only (no Intel support)"
168
+ elif [[ "$ARCHS" == *"x86_64"* ]]; then
169
+ log "$WARN Intel only (no Apple Silicon native)"
170
+ else
171
+ log "$FAIL Unknown architecture: $ARCHS"
172
+ fi
173
+
174
+ # Current machine
175
+ MACHINE_ARCH=$(uname -m)
176
+ log "$INFO Current machine: $MACHINE_ARCH"
177
+ fi
178
+
179
+ # ─────────────────────────────────────────────────────────────
180
+ # 3. DEPENDENCIES
181
+ # ─────────────────────────────────────────────────────────────
182
+ print_section "Dependencies"
183
+
184
+ if [ -f "$BINARY_PATH" ]; then
185
+ MISSING_DEPS=0
186
+
187
+ # Get unique dependencies (otool shows both archs for universal binary)
188
+ while IFS= read -r line; do
189
+ # Skip empty lines and the binary path itself
190
+ [[ -z "$line" ]] && continue
191
+ [[ "$line" == *"$BINARY_PATH"* ]] && continue
192
+
193
+ # Extract library path
194
+ LIB_PATH=$(echo "$line" | sed 's/^[[:space:]]*//' | cut -d' ' -f1)
195
+
196
+ # Skip if empty
197
+ [[ -z "$LIB_PATH" ]] && continue
198
+
199
+ # Categorize
200
+ # Note: Since macOS Big Sur, /usr/lib libraries are in shared cache
201
+ # and don't exist as physical files, but they still work
202
+ if [[ "$LIB_PATH" == /usr/lib/* ]]; then
203
+ log "$PASS System: $(basename "$LIB_PATH") (shared cache)"
204
+ elif [[ "$LIB_PATH" == /System/Library/* ]]; then
205
+ if [ -d "${LIB_PATH%/*}" ] || [ -f "$LIB_PATH" ]; then
206
+ log "$PASS Framework: $(echo "$LIB_PATH" | grep -o '[^/]*\.framework')"
207
  else
208
+ log "$FAIL MISSING: $LIB_PATH"
209
+ MISSING_DEPS=$((MISSING_DEPS + 1))
210
  fi
211
+ elif [[ "$LIB_PATH" == @rpath/* ]] || [[ "$LIB_PATH" == @loader_path/* ]] || [[ "$LIB_PATH" == @executable_path/* ]]; then
212
+ log "$WARN Relative: $LIB_PATH"
213
+ elif [ -f "$LIB_PATH" ]; then
214
+ log "$PASS External: $LIB_PATH"
215
+ else
216
+ log "$FAIL MISSING: $LIB_PATH"
217
+ MISSING_DEPS=$((MISSING_DEPS + 1))
218
  fi
219
+ done < <(otool -L "$BINARY_PATH" 2>/dev/null | sort -u)
220
+
221
+ if [ $MISSING_DEPS -gt 0 ]; then
222
+ log ""
223
+ log "${RED}$FAIL Found $MISSING_DEPS missing dependencies!${NC}"
224
+ else
225
+ log ""
226
+ log "${GREEN}$PASS All dependencies found${NC}"
227
+ fi
228
+ fi
229
+
230
+ # ─────────────────────────────────────────────────────────────
231
+ # 4. CODE SIGNING & NOTARIZATION
232
+ # ─────────────────────────────────────────────────────────────
233
+ print_section "Code Signing & Notarization"
234
+
235
+ CODESIGN_OUTPUT=$(codesign -dv --verbose=4 "$PLUGIN_PATH" 2>&1)
236
+ SIGNING_ISSUE=0
237
+
238
+ # Check signing status
239
+ if echo "$CODESIGN_OUTPUT" | grep -q "Authority="; then
240
+ # Extract all authorities (certificate chain)
241
+ log "${BLUE}Certificate Chain:${NC}"
242
+ echo "$CODESIGN_OUTPUT" | grep "Authority=" | while read -r line; do
243
+ CERT=$(echo "$line" | cut -d= -f2)
244
+ log " $CERT"
245
  done
246
+
247
+ # Team ID
248
+ TEAM_ID=$(echo "$CODESIGN_OUTPUT" | grep "TeamIdentifier=" | cut -d= -f2)
249
+ if [ -n "$TEAM_ID" ] && [ "$TEAM_ID" != "not set" ]; then
250
+ log "$PASS Team ID: $TEAM_ID"
251
+ else
252
+ log "$WARN Team ID not set"
253
+ fi
254
+
255
+ # Timestamp
256
+ SIGN_TIMESTAMP=$(echo "$CODESIGN_OUTPUT" | grep "Timestamp=" | cut -d= -f2)
257
+ if [ -n "$SIGN_TIMESTAMP" ]; then
258
+ log "$PASS Signed on: $SIGN_TIMESTAMP"
259
+ else
260
+ log "$WARN No timestamp (signature may expire with certificate)"
261
+ fi
262
+
263
+ # Runtime version (hardened runtime)
264
+ RUNTIME=$(echo "$CODESIGN_OUTPUT" | grep "Runtime Version=" | cut -d= -f2)
265
+ if [ -n "$RUNTIME" ]; then
266
+ log "$PASS Hardened Runtime: $RUNTIME"
267
+ else
268
+ log "$WARN Hardened runtime not enabled"
269
+ fi
270
+
271
+ # Notarization check
272
+ if echo "$CODESIGN_OUTPUT" | grep -q "Notarization Ticket"; then
273
+ log "$PASS Notarization ticket stapled"
274
+ else
275
+ log "$WARN Notarization ticket NOT stapled"
276
+ SIGNING_ISSUE=1
277
+ fi
278
+
279
+ elif echo "$CODESIGN_OUTPUT" | grep -q "adhoc"; then
280
+ log "$WARN Ad-hoc signed (development only)"
281
+ SIGNING_ISSUE=1
282
+ else
283
+ log "$FAIL NOT SIGNED"
284
+ SIGNING_ISSUE=1
285
+ fi
286
+
287
+ # Verify signature integrity
288
+ log ""
289
+ log "${BLUE}Signature Verification:${NC}"
290
+ VERIFY_OUTPUT=$(codesign --verify --deep --strict "$PLUGIN_PATH" 2>&1)
291
+ if [ $? -eq 0 ]; then
292
+ log "$PASS Signature integrity: valid"
293
+ else
294
+ log "$FAIL Signature integrity: INVALID"
295
+ log " $VERIFY_OUTPUT"
296
+ SIGNING_ISSUE=1
297
+ fi
298
+
299
+ # Gatekeeper assessment (spctl)
300
+ log ""
301
+ log "${BLUE}Gatekeeper Assessment:${NC}"
302
+ SPCTL_OUTPUT=$(spctl --assess --type execute -v "$PLUGIN_PATH" 2>&1)
303
+ SPCTL_EXIT=$?
304
+ if [ $SPCTL_EXIT -eq 0 ]; then
305
+ log "$PASS Gatekeeper: accepted"
306
+ elif echo "$SPCTL_OUTPUT" | grep -q "rejected"; then
307
+ # Check the reason
308
+ if echo "$SPCTL_OUTPUT" | grep -q "notarized"; then
309
+ log "$WARN Gatekeeper: requires notarization"
310
+ elif echo "$SPCTL_OUTPUT" | grep -q "not.*app"; then
311
+ log "$PASS Gatekeeper: valid code (not an app bundle)"
312
+ else
313
+ log "$FAIL Gatekeeper: rejected"
314
+ log " $SPCTL_OUTPUT"
315
+ fi
316
  else
317
+ log "$INFO Gatekeeper: $SPCTL_OUTPUT"
318
  fi
 
319
 
320
+ # Check if notarization can be verified online
321
+ log ""
322
+ log "${BLUE}Notarization Status (online check):${NC}"
323
+ STAPLER_OUTPUT=$(xcrun stapler validate "$PLUGIN_PATH" 2>&1)
324
+ if echo "$STAPLER_OUTPUT" | grep -q "valid"; then
325
+ log "$PASS Notarization: verified"
326
+ elif echo "$STAPLER_OUTPUT" | grep -q "not valid"; then
327
+ log "$FAIL Notarization: NOT valid or not notarized"
328
+ SIGNING_ISSUE=1
329
+ else
330
+ log "$INFO $STAPLER_OUTPUT"
331
+ fi
332
+
333
+ # ─────────────────────────────────────────────────────────────
334
+ # 5. QUARANTINE
335
+ # ─────────────────────────────────────────────────────────────
336
+ print_section "Quarantine Status"
337
+
338
+ QUARANTINE=$(xattr -p com.apple.quarantine "$PLUGIN_PATH" 2>/dev/null || echo "")
339
+
340
+ if [ -n "$QUARANTINE" ]; then
341
+ log "$WARN Quarantine flag is SET"
342
+ log " Value: $QUARANTINE"
343
+ log ""
344
+ log "${YELLOW}To remove quarantine, run:${NC}"
345
+ log " xattr -cr \"$PLUGIN_PATH\""
346
  else
347
+ log "$PASS No quarantine flag"
348
+ fi
349
+
350
+ # ─────────────────────────────────────────────────────────────
351
+ # 6. INFO.PLIST CHECK
352
+ # ─────────────────────────────────────────────────────────────
353
+ print_section "Info.plist Analysis"
354
+
355
+ if [ -f "$PLIST_PATH" ]; then
356
+ # CFBundleIdentifier
357
+ BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$PLIST_PATH" 2>/dev/null || echo "")
358
+ if [ -n "$BUNDLE_ID" ] && [ "$BUNDLE_ID" != "" ]; then
359
+ log "$PASS CFBundleIdentifier: $BUNDLE_ID"
360
+ else
361
+ log "$FAIL CFBundleIdentifier is EMPTY!"
362
+ log " ${YELLOW}This may cause loading issues on some systems${NC}"
363
+ fi
364
+
365
+ # CFBundleExecutable
366
+ BUNDLE_EXEC=$(/usr/libexec/PlistBuddy -c "Print :CFBundleExecutable" "$PLIST_PATH" 2>/dev/null || echo "")
367
+ if [ "$BUNDLE_EXEC" = "$PLUGIN_NAME" ]; then
368
+ log "$PASS CFBundleExecutable: $BUNDLE_EXEC"
369
+ else
370
+ log "$WARN CFBundleExecutable: $BUNDLE_EXEC (expected: $PLUGIN_NAME)"
371
+ fi
372
+
373
+ # LSMinimumSystemVersion
374
+ MIN_VERSION=$(/usr/libexec/PlistBuddy -c "Print :LSMinimumSystemVersion" "$PLIST_PATH" 2>/dev/null || echo "not set")
375
+ log "$INFO Minimum macOS: $MIN_VERSION"
376
+
377
+ # Current macOS version
378
+ CURRENT_MACOS=$(sw_vers -productVersion)
379
+ log "$INFO Current macOS: $CURRENT_MACOS"
380
  fi
 
381
 
382
+ # ─────────────────────────────────────────────────────────────
383
+ # 7. ENTRY POINT CHECK (via nm)
384
+ # ─────────────────────────────────────────────────────────────
385
+ print_section "Entry Point"
386
+
387
+ if [ -f "$BINARY_PATH" ]; then
388
+ if nm "$BINARY_PATH" 2>/dev/null | grep -q "_EffectMain"; then
389
+ log "$PASS EffectMain symbol exported"
390
+ elif nm "$BINARY_PATH" 2>/dev/null | grep -q "_main"; then
391
+ log "$WARN Found _main but not _EffectMain"
392
+ else
393
+ log "$FAIL No EffectMain symbol found!"
394
+ fi
395
+ fi
396
+
397
+ # ─────────────────────────────────────────────────────────────
398
+ # 8. FILE PERMISSIONS & OWNERSHIP
399
+ # ─────────────────────────────────────────────────────────────
400
+ print_section "File Permissions & Ownership"
401
+
402
+ PERM_ISSUES=0
403
+ CURRENT_USER=$(whoami)
404
+
405
+ log "${BLUE}Expected: owner=root or current user, readable by all${NC}"
406
+ log ""
407
+
408
+ # Check each file and directory
409
+ while IFS= read -r item; do
410
+ # Get permissions, owner, group
411
+ STAT_OUTPUT=$(stat -f "%Sp %Su %Sg" "$item" 2>/dev/null)
412
+ PERMS=$(echo "$STAT_OUTPUT" | cut -d' ' -f1)
413
+ OWNER=$(echo "$STAT_OUTPUT" | cut -d' ' -f2)
414
+ GROUP=$(echo "$STAT_OUTPUT" | cut -d' ' -f3)
415
+
416
+ # Get relative path for display
417
+ REL_PATH="${item#$PLUGIN_PATH}"
418
+ [ -z "$REL_PATH" ] && REL_PATH="/"
419
+
420
+ # Check if it's a directory or file
421
+ if [ -d "$item" ]; then
422
+ ITEM_TYPE="d"
423
+ # Directories should be readable and executable (r-x) by all
424
+ if [[ "$PERMS" != d*r?x*r?x*r?x* ]] && [[ "$PERMS" != d*r?x*r?x* ]]; then
425
+ # Check if at least owner can read/execute
426
+ if [[ "$PERMS" == d*r?x* ]]; then
427
+ # Owner can access, check if current user is owner
428
+ if [ "$OWNER" != "$CURRENT_USER" ] && [ "$OWNER" != "root" ]; then
429
+ log "$WARN $REL_PATH"
430
+ log " Perms: $PERMS Owner: $OWNER:$GROUP"
431
+ log " ${YELLOW}May not be accessible to After Effects${NC}"
432
+ PERM_ISSUES=$((PERM_ISSUES + 1))
433
+ fi
434
+ else
435
+ log "$FAIL $REL_PATH"
436
+ log " Perms: $PERMS Owner: $OWNER:$GROUP"
437
+ log " ${RED}Directory not readable/executable${NC}"
438
+ PERM_ISSUES=$((PERM_ISSUES + 1))
439
+ fi
440
+ fi
441
+ else
442
+ ITEM_TYPE="f"
443
+ # Files should be readable by all, executable if binary
444
+ FILENAME=$(basename "$item")
445
+
446
+ # Check if file is readable
447
+ if [[ "$PERMS" != -*r* ]]; then
448
+ log "$FAIL $REL_PATH"
449
+ log " Perms: $PERMS Owner: $OWNER:$GROUP"
450
+ log " ${RED}File not readable${NC}"
451
+ PERM_ISSUES=$((PERM_ISSUES + 1))
452
+ fi
453
+
454
+ # Binary should be executable
455
+ if [ "$item" = "$BINARY_PATH" ]; then
456
+ if [[ "$PERMS" != -*x* ]]; then
457
+ log "$FAIL $REL_PATH"
458
+ log " Perms: $PERMS Owner: $OWNER:$GROUP"
459
+ log " ${RED}Binary not executable${NC}"
460
+ PERM_ISSUES=$((PERM_ISSUES + 1))
461
+ fi
462
+ fi
463
+ fi
464
+
465
+ # Check for unusual owners (not root, not current user, not wheel/admin)
466
+ if [ "$OWNER" != "root" ] && [ "$OWNER" != "$CURRENT_USER" ] && [ "$OWNER" != "wheel" ]; then
467
+ # Only warn if we haven't already flagged this item
468
+ if [ $PERM_ISSUES -eq 0 ] || ! echo "$item" | grep -q "flagged"; then
469
+ log "$INFO $REL_PATH"
470
+ log " Owner: $OWNER:$GROUP (unusual)"
471
+ fi
472
+ fi
473
+
474
+ done < <(find "$PLUGIN_PATH" -print 2>/dev/null)
475
+
476
+ # Summary of permissions
477
+ log ""
478
+ if [ $PERM_ISSUES -eq 0 ]; then
479
+ log "${GREEN}$PASS All permissions look correct${NC}"
480
  else
481
+ log "${RED}$FAIL Found $PERM_ISSUES permission issue(s)${NC}"
482
+ log ""
483
+ log "${YELLOW}To fix permissions, run:${NC}"
484
+ log " sudo chmod -R a+rX \"$PLUGIN_PATH\""
485
+ log " sudo chmod a+x \"$BINARY_PATH\""
486
  fi
 
487
 
488
+ # Show ownership summary
489
+ log ""
490
+ log "${BLUE}Ownership Summary:${NC}"
491
+ # Get unique owners
492
+ OWNERS=$(find "$PLUGIN_PATH" -print0 2>/dev/null | xargs -0 stat -f "%Su" | sort -u)
493
+ for owner in $OWNERS; do
494
+ COUNT=$(find "$PLUGIN_PATH" -user "$owner" 2>/dev/null | wc -l | tr -d ' ')
495
+ log " $owner: $COUNT items"
496
+ done
497
+
498
+ # ─────────────────────────────────────────────────────────────
499
+ # 9. EXTENDED ATTRIBUTES
500
+ # ─────────────────────────────────────────────────────────────
501
+ print_section "Extended Attributes"
502
 
503
+ # Check for any extended attributes on all files
504
+ XATTR_FILES=0
505
+ log "${BLUE}Checking for extended attributes on all files...${NC}"
506
+ log ""
507
+
508
+ while IFS= read -r item; do
509
+ XATTRS=$(xattr "$item" 2>/dev/null)
510
+ if [ -n "$XATTRS" ]; then
511
+ REL_PATH="${item#$PLUGIN_PATH}"
512
+ [ -z "$REL_PATH" ] && REL_PATH="/"
513
+
514
+ log "$WARN $REL_PATH"
515
+ echo "$XATTRS" | while read -r attr; do
516
+ if [ -n "$attr" ]; then
517
+ log " $attr"
518
+ fi
519
+ done
520
+ XATTR_FILES=$((XATTR_FILES + 1))
521
+ fi
522
+ done < <(find "$PLUGIN_PATH" -print 2>/dev/null)
523
+
524
+ if [ $XATTR_FILES -eq 0 ]; then
525
+ log "${GREEN}$PASS No extended attributes found${NC}"
526
  else
527
+ log ""
528
+ log "${YELLOW}Found extended attributes on $XATTR_FILES file(s)${NC}"
529
+ log "${YELLOW}To remove all extended attributes, run:${NC}"
530
+ log " xattr -cr \"$PLUGIN_PATH\""
531
+ fi
532
+
533
+ # ─────────────────────────────────────────────────────────────
534
+ # SUMMARY
535
+ # ─────────────────────────────────────────────────────────────
536
+ print_header "Summary"
537
+
538
+ ISSUES=0
539
+
540
+ # Check for common issues
541
+ if [ -z "$BUNDLE_ID" ] || [ "$BUNDLE_ID" = "" ]; then
542
+ log "$FAIL Empty CFBundleIdentifier - may cause 'entry point' errors"
543
+ ISSUES=$((ISSUES + 1))
544
+ fi
545
+
546
+ if [ -n "$QUARANTINE" ]; then
547
+ log "$WARN Quarantine flag set - may block plugin loading"
548
+ ISSUES=$((ISSUES + 1))
549
  fi
550
 
551
+ if [ $MISSING_DEPS -gt 0 ]; then
552
+ log "$FAIL Missing dependencies detected"
553
+ ISSUES=$((ISSUES + 1))
554
+ fi
555
 
556
+ if [ $SIGNING_ISSUE -gt 0 ]; then
557
+ log "$WARN Code signing or notarization issues detected"
558
+ ISSUES=$((ISSUES + 1))
559
+ fi
560
 
561
+ if [ $PERM_ISSUES -gt 0 ]; then
562
+ log "$FAIL Permission issues detected"
563
+ ISSUES=$((ISSUES + 1))
564
+ fi
565
 
566
+ if [ $ISSUES -eq 0 ]; then
567
+ log "${GREEN}$PASS No issues detected${NC}"
 
 
 
568
  else
569
+ log ""
570
+ log "${YELLOW}Found $ISSUES potential issue(s)${NC}"
571
+ log ""
572
+ log "${BLUE}Quick fixes:${NC}"
573
+ if [ -n "$QUARANTINE" ]; then
574
+ log " Remove quarantine: xattr -cr \"$PLUGIN_PATH\""
575
+ fi
576
+ if [ $PERM_ISSUES -gt 0 ]; then
577
+ log " Fix permissions: sudo chmod -R a+rX \"$PLUGIN_PATH\""
578
+ fi
579
  fi
580
+
581
+ # ─────────────────────────────────────────────────────────────
582
+ # OUTPUT FILE INFO
583
+ # ────────────────────────���────────────────────────────────────
584
+ log ""
585
+ log "═══════════════════════════════════════════════════════════"
586
+ log ""
587
+ log "${GREEN}πŸ“„ Report saved to:${NC}"
588
+ log " $OUTPUT_FILE"
589
+ log ""
590
+ log "${YELLOW}Please send this file to support for analysis.${NC}"
591
+ log ""
592
+
593
+ # Also print to console without colors for clarity
594
+ echo ""
595
+ echo "════════════════════════════════════════════════════════════"
596
+ echo ""
597
+ echo "πŸ“„ Report saved to Desktop:"
598
+ echo " $OUTPUT_FILE"
599
+ echo ""
600
+ echo "πŸ‘‰ Please send this file to BSKL support for analysis."
601
+ echo ""