@Arnaud , you’re right — and I was wrong about what it costs to do it properly. So I went and measured it, on macOS 27, with my own package.
Without the flag, nothing runs. An unsigned package carrying no quarantine attribute opens straight into the Installer wizard. No assessment, no prompt, nothing in the log.
With the flag, macOS does exactly what you would want. The same unsigned package, with com.apple.quarantine set by hand: the open is refused outright, and the dialog says Apple could not confirm the package is free of malware. Its buttons are Move to Trash and Done — and on one of my attempts the package was simply gone afterwards.
And on a legitimate package it costs nothing at all. My signed, notarized, stapled .pkg with the flag set opens the Installer with no dialog whatsoever. The log shows the quarantine resolver running and XProtectIsNotarized = 1.
That last line is where you were more right than I had realised. The quarantine path runs XProtect’s malware analysis*; my own check does not. For the signature half, my check isn’t a reimplementation — spctl --assess -t install is the same SecAssessment evaluation Gatekeeper performs, called explicitly instead of being triggered by the flag. But the signature half is all it is. So the two aren’t redundant: mine asks “is this signed and notarized, and by whom it claims”, and the system adds “and does XProtect recognise anything inside”.
So XPackager will set the flag on what it downloads, and keep its own check. The order matters: verify first, so the application can refuse with a reason in the user’s own language and never hand a bad file to the Installer at all — Apple’s dialog tells the user nothing about why, and one of its two buttons bins the download. Then hand it over with the flag on, and let XProtect and Gatekeeper have their say.
@Jared — your objection is real, and it belongs to a different route from mine. I tested both:
- From a quarantined
.pkg, the installed file carries only com.apple.provenance.
The flag does not reach the payload: installd extracts as root and doesn’t copy extended attributes across. Nothing to clear, nothing to break.
- From a quarantined
.zip expanded by Archive Utility, every extracted item is stamped — the folder and the file inside it. That is your scenario exactly, and it is why Sparkle clears the attribute itself, after it has validated the signature.
So the rule seems to be: ship updates as a package, and you can mark the download and let the Installer be checked for free. Ship them as an archive you expand yourself, and you own the verification — clearing the flag afterwards is then the honest thing to do, having actually checked first.
Thanks to you both. This goes into the next version.