diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt
index 9553b571c5..ac23264aeb 100644
--- a/interface/CMakeLists.txt
+++ b/interface/CMakeLists.txt
@@ -142,6 +142,22 @@ endif()
if (APPLE)
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
+ set_from_env(XCODE_DEVELOPMENT_TEAM XCODE_DEVELOPMENT_TEAM "")
+ if ("${XCODE_DEVELOPMENT_TEAM}" STREQUAL "")
+ message(WARNING "XCODE_DEVELOPMENT_TEAM environment variable is not set. Not signing build.")
+ else()
+ set_target_properties(${TARGET_NAME} PROPERTIES
+ XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/interface.entitlements"
+ XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Developer ID Application"
+ XCODE_ATTRIBUTE_CODE_SIGN_INJECT_BASE_ENTITLEMENTS NO
+ XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Manual"
+ XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${XCODE_DEVELOPMENT_TEAM}"
+ XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES
+ XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "--timestamp --deep"
+ XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER ""
+ )
+ endif()
+
# make sure the output name for the .app bundle is correct
# Fix up the rpath so macdeployqt works
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
diff --git a/interface/interface.entitlements b/interface/interface.entitlements
new file mode 100644
index 0000000000..22747cbc32
--- /dev/null
+++ b/interface/interface.entitlements
@@ -0,0 +1,16 @@
+
+
+
+
+ com.apple.security.app-sandbox
+
+ com.apple.security.network.client
+
+ com.apple.security.network.server
+
+ com.apple.security.application-groups
+
+ high-fidelity.hifi
+
+
+
diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt
index 0a7ef70461..88ac666a93 100644
--- a/launchers/darwin/CMakeLists.txt
+++ b/launchers/darwin/CMakeLists.txt
@@ -69,8 +69,27 @@ function(set_from_env _RESULT_NAME _ENV_VAR_NAME _DEFAULT_VALUE)
endfunction()
add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${src_files})
-set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME}
- MACOSX_BUNDLE_BUNDLE_NAME ${APP_NAME})
+
+set_from_env(XCODE_DEVELOPMENT_TEAM XCODE_DEVELOPMENT_TEAM "")
+if ("${XCODE_DEVELOPMENT_TEAM}" STREQUAL "")
+ message(WARNING "XCODE_DEVELOPMENT_TEAM environmental variable is not set. Not signing build.")
+ set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME}
+ MACOSX_BUNDLE_BUNDLE_NAME ${APP_NAME}
+ )
+else()
+ set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME}
+ MACOSX_BUNDLE_BUNDLE_NAME ${APP_NAME}
+ XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "HQ Launcher.entitlements"
+ XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Developer ID Application"
+ XCODE_ATTRIBUTE_CODE_SIGN_INJECT_BASE_ENTITLEMENTS NO
+ XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Manual"
+ XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${XCODE_DEVELOPMENT_TEAM}"
+ XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES
+ XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "--timestamp"
+ XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER ""
+ )
+endif()
+
set_from_env(LAUNCHER_HMAC_SECRET LAUNCHER_HMAC_SECRET "")
if ("${LAUNCHER_HMAC_SECRET}" STREQUAL "")
message(FATAL_ERROR "LAUNCHER_HMAC_SECRET is not set")
diff --git a/launchers/darwin/HQ Launcher.entitlements b/launchers/darwin/HQ Launcher.entitlements
new file mode 100644
index 0000000000..0f41736b78
--- /dev/null
+++ b/launchers/darwin/HQ Launcher.entitlements
@@ -0,0 +1,14 @@
+
+
+
+
+ com.apple.security.app-sandbox
+
+ com.apple.security.network.client
+
+ com.apple.security.application-groups
+
+ high-fideilty.hifi
+
+
+
diff --git a/tools/ci-scripts/postbuild.py b/tools/ci-scripts/postbuild.py
index 00b3007104..949c40b0f2 100644
--- a/tools/ci-scripts/postbuild.py
+++ b/tools/ci-scripts/postbuild.py
@@ -2,6 +2,9 @@
import os
import sys
import shutil
+import subprocess
+import tempfile
+import uuid
import zipfile
import base64
@@ -11,6 +14,33 @@ sys.path.append(SOURCE_PATH)
import hifi_utils
+
+class ZipAttrs:
+ """ A readable wrapper for ZipInfo's external attributes bit field """
+
+ S_IFREG = 0x8
+ S_IFLNK = 0xa
+ S_IFDIR = 0x4
+ MODE_MASK = 0xfff0000
+
+ def __init__(self, zip_info):
+ # File stats are the 4 high bits of external_attr, a 32 bit field.
+ self._stat = zip_info.external_attr >> 28
+ self.mode = (zip_info.external_attr & self.MODE_MASK) >> 16
+
+ @property
+ def is_symlink(self):
+ return self._stat == self.S_IFLNK
+
+ @property
+ def is_dir(self):
+ return self._stat == self.S_IFDIR
+
+ @property
+ def is_regular(self):
+ return self._stat == self.S_IFREG
+
+
BUILD_PATH = os.path.join(SOURCE_PATH, 'build')
INTERFACE_BUILD_PATH = os.path.join(BUILD_PATH, 'interface', 'Release')
WIPE_PATHS = []
@@ -65,8 +95,12 @@ def fixupMacZip(filename):
fullPath = os.path.join(BUILD_PATH, "{}.zip".format(filename))
outFullPath = "{}.zip".format(fullPath)
print("Fixup mac ZIP file {}".format(fullPath))
- with zipfile.ZipFile(fullPath) as inzip:
- with zipfile.ZipFile(outFullPath, 'w') as outzip:
+ tmpDir = os.path.join(tempfile.gettempdir(),
+ 'com.highfidelity.launcher.postbuild',
+ str(uuid.uuid4()))
+
+ try:
+ with zipfile.ZipFile(fullPath) as inzip:
rootPath = inzip.infolist()[0].filename
for entry in inzip.infolist():
if entry.filename == rootPath:
@@ -86,11 +120,51 @@ def fixupMacZip(filename):
continue
# if we made it here, include the file in the output
buffer = inzip.read(entry.filename)
- entry.filename = newFilename
- outzip.writestr(entry, buffer)
- outzip.close()
- print("Replacing {} with fixed {}".format(fullPath, outFullPath))
- shutil.move(outFullPath, fullPath)
+ newFilename = os.path.join(tmpDir, newFilename)
+
+ attrs = ZipAttrs(entry)
+ if attrs.is_dir:
+ os.makedirs(newFilename)
+ elif attrs.is_regular:
+ with open(newFilename, mode='wb') as _file:
+ _file.write(buffer)
+ os.chmod(newFilename, mode=attrs.mode)
+ elif attrs.is_symlink:
+ os.symlink(buffer, newFilename)
+ else:
+ raise IOError('Invalid file stat')
+
+ if 'XCODE_DEVELOPMENT_TEAM' in os.environ:
+ print('XCODE_DEVELOPMENT_TEAM environment variable is not set. '
+ 'Not signing build.', file=sys.stderr)
+ else:
+ # The interface.app bundle must be signed again after being
+ # stripped.
+ print('Signing interface.app bundle')
+ entitlementsPath = os.path.join(
+ os.path.dirname(__file__),
+ '../../interface/interface.entitlements')
+ subprocess.run([
+ 'codesign', '-s', 'Developer ID Application', '--deep',
+ '--timestamp', '--force', '--entitlements', entitlementsPath,
+ os.path.join(tmpDir, 'interface.app')
+ ], check=True)
+
+ # Repackage the zip including the signed version of interface.app
+ print('Replacing {} with fixed {}'.format(fullPath, outFullPath))
+ if os.path.exists(outFullPath):
+ print('fixed zip already exists, deleting it', file=sys.stderr)
+ os.unlink(outFullPath)
+ previous_cwd = os.getcwd()
+ os.chdir(tmpDir)
+ try:
+ subprocess.run(['zip', '--symlink', '-r', outFullPath, './.'],
+ stdout=subprocess.DEVNULL, check=True)
+ finally:
+ os.chdir(previous_cwd)
+
+ finally:
+ shutil.rmtree(tmpDir)
def fixupWinZip(filename):
fullPath = os.path.join(BUILD_PATH, "{}.zip".format(filename))