Skip to content

Commit

Permalink
Add MacOS notarization
Browse files Browse the repository at this point in the history
  • Loading branch information
mbacchi committed Oct 15, 2019
1 parent 46c7da3 commit e8e9103
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 19 deletions.
3 changes: 1 addition & 2 deletions BUILD.gn
Expand Up @@ -188,8 +188,7 @@ group("create_dist") {
]
} else {
deps += [
"build/mac:sign_dmg",
"build/mac:sign_pkg"
"build/mac:notarize_dmg_pkg"
]
}
}
Expand Down
90 changes: 84 additions & 6 deletions build/mac/BUILD.gn
Expand Up @@ -10,6 +10,11 @@ declare_args() {
mac_installer_signing_identifier = ""
mac_signing_keychain = "login"
mac_signing_output_prefix = "signing"
mac_signed_output_prefix = "signed"
notary_user = ""
notary_password = ""
notarize = false
notarize_argument = "False"
}

group("brave") {}
Expand Down Expand Up @@ -103,7 +108,7 @@ if (skip_signing) {
}
}
} else {
packaging_dir = "$root_out_dir/$chrome_product_full_name Packaging"
packaging_dir = "$root_out_dir/" + string_replace("$chrome_product_full_name Packaging", " ", "_")
target_sign_app_path = "$root_out_dir/$mac_signing_output_prefix/" + string_replace("$chrome_product_full_name", " ", "") + "-$chrome_version_full/$brave_exe"
unsigned_pkg_path = "$root_out_dir/unsigned/$brave_pkg"
keychain_db = getenv("HOME") + "/Library/Keychains/${mac_signing_keychain}.keychain-db"
Expand All @@ -130,6 +135,9 @@ if (skip_signing) {
provisioning_profile = "//brave/build/mac/dummy.provisionprofile"
is_development = "True"
}
if (notarize) {
notarize_argument = "True"
}

inputs = [
script,
Expand All @@ -150,6 +158,9 @@ if (skip_signing) {
rebase_path(provisioning_profile, root_out_dir),
keychain_db,
mac_signing_identifier,
notarize_argument,
notary_user,
notary_password
]
}

Expand Down Expand Up @@ -193,11 +204,11 @@ if (skip_signing) {
shell_script,
unsigned_pkg_path,
]
outputs = [ "${root_out_dir}/$mac_signing_output_prefix/$brave_pkg" ]
outputs = [ "${root_out_dir}/$mac_signed_output_prefix/$brave_pkg" ]
args = [
rebase_path(shell_script, root_build_dir),
rebase_path(unsigned_pkg_path),
rebase_path("$root_out_dir/$brave_pkg"),
rebase_path("$root_out_dir/$mac_signed_output_prefix/$brave_pkg"),
keychain_db,
mac_installer_signing_identifier,
]
Expand All @@ -220,7 +231,7 @@ if (skip_signing) {
"--source", "/var/empty",
"--target", "unsigned/$brave_dmg",
"--format", "UDBZ",
"--verbosity", "0",
"--verbosity", "2",
"--volname", "$chrome_product_full_name",
"--copy", rebase_path(target_sign_app_path, root_build_dir),
"--tempdir", "/tmp",
Expand All @@ -242,16 +253,83 @@ if (skip_signing) {
shell_script,
unsigned_dmg,
]
outputs = [ "${root_out_dir}/$mac_signing_output_prefix/$brave_dmg" ]
outputs = [ "${root_out_dir}/$mac_signed_output_prefix/$brave_dmg" ]
args = [
rebase_path(shell_script, root_build_dir),
rebase_path(unsigned_dmg),
rebase_path("$root_out_dir/$brave_dmg"),
rebase_path("$root_out_dir/$mac_signed_output_prefix/$brave_dmg"),
keychain_db,
mac_signing_identifier,
"-r=designated => identifier \"$chrome_product_full_name\" and certificate leaf = H\"$mac_signing_identifier\"",
]

deps = [":create_dmg"]
}

copy("copy_notarize_script") {

sources = [ "notarize_dmg_pkg.py" ]

outputs = [
"$packaging_dir/{{source_file_part}}"
]

}

action("notarize_dmg_pkg") {
if (notarize) {
if (is_official_build) {
development_arg = ""
if (brave_channel == "") {
provisioning_profile = "//brave/build/mac/release.provisionprofile"
} else {
provisioning_profile = "//brave/build/mac/${brave_channel}.provisionprofile"
}
} else {
development_arg = "--development"
provisioning_profile = "//brave/build/mac/dummy.provisionprofile"
}

script = "$packaging_dir/notarize_dmg_pkg.py"
inputs = [
script,
"$root_out_dir/$mac_signed_output_prefix/$brave_dmg",
"$root_out_dir/$mac_signed_output_prefix/$brave_pkg",
]
outputs = [
"$root_out_dir/$brave_dmg",
"$root_out_dir/$brave_pkg",
]
args = [
"--keychain",
keychain_db,
"--identity",
mac_signing_identifier,
"--notary-user",
notary_user,
"--notary-password",
notary_password,
development_arg,
"--dmg",
rebase_path("$root_out_dir/$mac_signed_output_prefix/$brave_dmg"),
"--pkg",
rebase_path("$root_out_dir/$mac_signed_output_prefix/$brave_pkg"),
"--signed",
rebase_path("$root_out_dir/$mac_signed_output_prefix"),
"--outdir",
rebase_path("$root_out_dir"),
"--pkgdir",
rebase_path(packaging_dir),
"--mac_provisioning_profile",
rebase_path(provisioning_profile)
]
deps = [
":sign_dmg",
":sign_pkg",
":copy_notarize_script"
]
} else {
print("Notarization of .dmg and .pkg not requested.")
}
}
}
184 changes: 184 additions & 0 deletions build/mac/notarize_dmg_pkg.py
@@ -0,0 +1,184 @@
#!/usr/bin/env python

# Copyright (c) 2019 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/. */

import argparse
import os
import subprocess
import sys

"""
The sign_chrome.py script does notarization of the app, but we don't use it to
create our .dmg and .pkg files. Instead we do our own signing and packaging,
but must perform notarization after those processes are complete. This script
performs notarizing and stapling of those files.
"""

# Our CWD is the packaging directory (i.e.
# src/out/Release/Brave_Browser_CHANNEL_Packaging), the signing directory is
# relative to that
packaging_signing_path = os.path.realpath(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(packaging_signing_path)

# Import the entire module to avoid circular dependencies in the functions
from signing import config, commands, model, notarize, pipeline, signing


def run_command(args, **kwargs):
print('Running command: {}'.format(args))
subprocess.check_call(args, **kwargs)


def create_config(config_args, development, mac_provisioning_profile):
"""Creates the |model.CodeSignConfig| for the signing operations.
If |development| is True, the config will be modified to not require
restricted internal assets, nor will the products be required to match
specific certificate hashes.
Args:
config_args: List of args to expand to the config class's constructor.
development: Boolean indicating whether or not to modify the chosen
config for development testing.
Returns:
An instance of |model.CodeSignConfig|.
"""
config_class = config.CodeSignConfig
"""
try:
import signing.internal_config
config_class = signing.internal_config.InternalCodeSignConfig
except ImportError as e:
# If the build specified Google Chrome as the product, then the
# internal config has to be available.
if config_class(identity, keychain).product == 'Google Chrome':
raise e
"""

if development:

class DevelopmentCodeSignConfig(config_class):

@property
def codesign_requirements_basic(self):
return ''

@property
def provisioning_profile_basename(self):
return None

@property
def run_spctl_assess(self):
return False

config_class = DevelopmentCodeSignConfig

config_class = GetBraveSigningConfig(config_class, development, mac_provisioning_profile)
return config_class(*config_args)


def GetBraveSigningConfig(config_class, development, mac_provisioning_profile):
if development:
return config_class

if mac_provisioning_profile:
provisioning_profile = mac_provisioning_profile
assert len(provisioning_profile), 'Argument mac_provisioning_profile not provided!'

class ProvisioningProfileCodeSignConfig(config_class):

@property
def provisioning_profile_basename(self):
return os.path.splitext(os.path.basename(
provisioning_profile))[0]

@property
def run_spctl_assess(self):
return True

return ProvisioningProfileCodeSignConfig


def NotarizeBraveDmgPkg(paths, config, dmg, pkg, outdir, signed, do_notarization=True):
"""
Notarize Brave .dmg and .pkg files.
"""
if do_notarization:
uuids_to_path_map = {}
for dist in config.distributions:
dist_config = dist.to_config(config)
uuid = notarize.submit(dmg, dist_config)
uuids_to_path_map[uuid] = dmg
uuid1 = notarize.submit(pkg, dist_config)
uuids_to_path_map[uuid1] = pkg
for result in notarize.wait_for_results(
uuids_to_path_map.keys(), config):
brave_path = uuids_to_path_map[result]
notarize.staple(brave_path)
for item in uuids_to_path_map.values():
commands.copy_files(os.path.join(signed, item), outdir)
return 0

def main():

args = parse_args()

if args.mac_provisioning_profile and args.development is not True:
config = create_config((args.identity, args.keychain, args.notary_user,
args.notary_password, args.notary_asc_provider),
args.development, args.mac_provisioning_profile)
else:
config = create_config((args.identity, args.keychain, args.notary_user,
args.notary_password, args.notary_asc_provider),
args.development)
paths = model.Paths(args.pkgdir, args.outdir, None)

rc = NotarizeBraveDmgPkg(paths, config, args.dmg, args.pkg, args.outdir, args.signed)
return rc

def parse_args():
parser = argparse.ArgumentParser(description='Notarize Mac DMG and PKG')
parser.add_argument(
'--keychain', help='The keychain to load the identity from.')
parser.add_argument(
'--identity', required=True, help='The identity to sign with.')
parser.add_argument(
'--notary-user',
help='The username used to authenticate to the Apple notary service.')
parser.add_argument(
'--notary-password',
help='The password or password reference (e.g. @keychain, see '
'`xcrun altool -h`) used to authenticate to the Apple notary service.')
parser.add_argument(
'--notary-asc-provider',
help='The ASC provider string to be used as the `--asc-provider` '
'argument to `xcrun altool`, to be used when --notary-user is '
'associated with multiple Apple developer teams. See `xcrun altool -h. '
'Run `iTMSTransporter -m provider -account_type itunes_connect -v off '
'-u USERNAME -p PASSWORD` to list valid providers.')
parser.add_argument(
'--development',
action='store_true',
help='The specified identity is for development. Certain codesign '
'requirements will be omitted.')
parser.add_argument('-d', '--dmg', help='Path to the dmg to notarize',
required=True)
parser.add_argument('-o', '--outdir', help='Output directory',
required=True)
parser.add_argument('--pkgdir', help='Packaging directory',
required=True)
parser.add_argument('-s', '--signed', help='Directory with signed DMG and PKG',
required=True)
parser.add_argument('-p', '--pkg', help='Path to the pkg to notarize',
required=True)
parser.add_argument('--mac_provisioning_profile', help='Provisioning profile(optional)')
return parser.parse_args()


if __name__ == '__main__':
import sys
sys.exit(main())

0 comments on commit e8e9103

Please sign in to comment.