Try to fix Safari extension breakage after app updates
Some checks failed
CI / Test () (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Utilities Tests (push) Has been cancelled
CI / Build, Upload (push) Has been cancelled
CI / Test (macOS NFS) (push) Has been cancelled

Forcing a Gatekeeper assessment seems to fix the extension when it's
broken. General theory: the system does an assessment while the app is
doing an in-place update, calculates a signature mismatch between the
parent app and the appex (or within one of the bundles?), and caches
that forever, so forcing a reassessment fixes it.

(cherry picked from commit e29d8f151e)
This commit is contained in:
Dan Stillman 2026-08-27 11:35:10 -04:00
parent 79ead9105c
commit c7010a65ae
2 changed files with 56 additions and 1 deletions

View file

@ -314,12 +314,22 @@ Zotero.Schema = new function () {
}
// Reset sync queue tries if new version
await _checkClientVersion();
var clientVersionChanged = await _checkClientVersion();
// See above
(!Zotero.test ? Zotero.uiReadyPromise : Zotero.initializationPromise)
.then(() => {
setTimeout(async function () {
// Keep Safari from blocking the bundled extension after an update
if (clientVersionChanged) {
try {
await Zotero.Utilities.Internal.assessAppBundle();
}
catch (e) {
Zotero.logError(e);
}
}
try {
await this.updateBundledFiles();
if (Zotero.Prefs.get('automaticScraperUpdates')) {

View file

@ -725,6 +725,51 @@ Zotero.Utilities.Internal = {
return result;
},
/**
* Run a Gatekeeper assessment of the running app bundle
*
* Safari computes a code signing dictionary for the bundled Safari extension each time it
* launches, and blocks the extension if that fails, which leaves the connector missing from
* Safari's extensions list. The computation can start failing when the app is updated, and it
* keeps failing on every subsequent launch. An assessment refreshes the system state that the
* computation depends on, and Safari loads the extension again the next time it starts.
*
* macOS only. Does nothing for source builds, which don't bundle the extension.
*
* @return {Promise}
*/
assessAppBundle: async function () {
if (!Zotero.isMac || Zotero.isSourceBuild) {
return;
}
let bundle = Services.dirsvc.get("XREExeF", Ci.nsIFile).parent.parent.parent;
Zotero.debug("Running Gatekeeper assessment of " + bundle.path);
let proc = await Subprocess.call({
command: '/usr/sbin/spctl',
arguments: ['-a', '-vv', bundle.path],
stderr: 'pipe'
});
// spctl writes its verdict to stderr
let output = "";
let str;
while ((str = await proc.stderr.readString())) {
output += str;
}
let { exitCode } = await proc.wait();
let message = "Gatekeeper assessment returned " + exitCode + "\n\n" + output.trim();
if (exitCode) {
Zotero.warn(message);
}
else {
Zotero.debug(message);
}
},
/**
* Get string data from the clipboard
* @param {String[]} mimeType MIME type of data to get