Add codesigning script for macOS (#42912)

This script automates the signing, packaging and notarization of
servoshell on macOS.
This is a first step towards: #40031 and #12532. While we could let a
maintainer code-sign and upload the signed release, probably this should
be integrated into CI, which would require additional work.

This script started out quite simple as part of `./mach package`.
However, since the script has access to secrets, it shouldn't be part of
mach (to minimize the amout of code that needs to be trusted).
We also needed to save state and be able to resume operations, since
notarizing can take quite long and the stapling needs to wait until
notarization has completed.
Since notarizing can take long (up to a day has been observed during
first tests), we save artifacts and the notarization ID, and add a
`--check-status` command that can be used to poll if notarization has
been finished.

Testing: Manually testing required. A signed and notarized `.dmg`
artifact has [been
uploaded](https://servo.zulipchat.com/#narrow/channel/500774-tsc/topic/Signing.20macos.20Servoshell/near/576256648)
to zulip, allowing others to verify the notarization worked.

---------

Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This commit is contained in:
Jonathan Schwender
2026-03-06 04:43:20 +01:00
committed by GitHub
parent cab4416d4c
commit a2bd2ab09b
4 changed files with 502 additions and 1 deletions

View File

@@ -75,10 +75,15 @@ class PackageCommands(CommandBase):
@CommandArgument("--android", default=None, action="store_true", help="Package Android")
@CommandArgument("--ohos", default=None, action="store_true", help="Package OpenHarmony")
@CommandArgument("--target", "-t", default=None, help="Package for given target platform")
@CommandArgument("--preserve-app", action="store_true", help="On macOS, keep the .app bundle after packaging")
@CommandBase.common_command_arguments(build_configuration=False, build_type=True, package_configuration=True)
@CommandBase.allow_target_configuration
def package(
self, build_type: BuildType, flavor: str | None = None, sanitizer: SanitizerKind = SanitizerKind.NONE
self,
build_type: BuildType,
flavor: str | None = None,
sanitizer: SanitizerKind = SanitizerKind.NONE,
preserve_app: bool = False,
) -> int | None:
env = self.build_env()
binary_path = self.get_binary_path(build_type, sanitizer=sanitizer)
@@ -268,6 +273,13 @@ class PackageCommands(CommandBase):
print("Packaging MacOS dmg exited with return value %d" % e.returncode)
return e.returncode
if preserve_app:
preserved_app = path.join(target_dir, "Servo.app")
if path.exists(preserved_app):
delete(preserved_app)
shutil.copytree(dir_to_app, preserved_app)
print("Preserved app bundle at " + preserved_app)
print("Cleaning up")
delete(dir_to_dmg)
print("Packaged Servo into " + dmg_path)