diff --git a/.evergreen.yml b/.evergreen.yml index 56a63c66b3..89ff220883 100644 --- a/.evergreen.yml +++ b/.evergreen.yml @@ -30,6 +30,10 @@ variables: -c 'cd /tmp/build && npm run evergreen-release package' else npm run evergreen-release package + if [ `uname` == Darwin ]; then + # Verify signing + spctl -a -vvv -t install dist/mongosh + fi fi RELEASE_MONGOSH diff --git a/config/build.conf.js b/config/build.conf.js index 2fbc2ade90..c601f03f3f 100644 --- a/config/build.conf.js +++ b/config/build.conf.js @@ -64,6 +64,7 @@ module.exports = { appleUser: process.env.APPLE_DEV_USER, applePassword: process.env.APPLE_DEV_PASSWORD, appleAppIdentity: process.env.APPLE_APP_IDENTITY, + entitlementsFile: path.resolve(__dirname, 'macos-entitlements.xml'), isCi: process.env.IS_CI === 'true', isPatch: process.env.IS_PATCH === 'true', platform: os.platform(), diff --git a/config/macos-entitlements.xml b/config/macos-entitlements.xml new file mode 100644 index 0000000000..68fea254f3 --- /dev/null +++ b/config/macos-entitlements.xml @@ -0,0 +1,12 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-executable-page-protection + + + diff --git a/package-lock.json b/package-lock.json index 2e9f291f18..527c35db5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14045,8 +14045,8 @@ "dev": true }, "node-codesign": { - "version": "github:durran/node-codesign#92863a258c2108556c0a33284d26f635729041da", - "from": "github:durran/node-codesign", + "version": "github:addaleax/node-codesign#845437573cd3550f18d2d758009ed946c1c37878", + "from": "github:addaleax/node-codesign", "dev": true, "requires": { "async": "^2.1.2", diff --git a/package.json b/package.json index 1896c27561..f87bc85832 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "mocha": "^7.1.2", "mongodb-js-precommit": "^2.0.0", "mongodb-runner": "^4.7.5", - "node-codesign": "durran/node-codesign", + "node-codesign": "github:addaleax/node-codesign", "parcel-bundler": "^1.12.4", "pkg": "^4.4.3", "pkg-deb": "^1.1.1", diff --git a/packages/build/src/compile-and-zip-executable.ts b/packages/build/src/compile-and-zip-executable.ts index 20168f9aa7..24a3ab7c9d 100644 --- a/packages/build/src/compile-and-zip-executable.ts +++ b/packages/build/src/compile-and-zip-executable.ts @@ -1,6 +1,9 @@ import compileExec from './compile-exec'; import { createTarball, TarballFile } from './tarball'; import Config from './config'; +import Platform from './platform'; +import os from 'os'; +import macOSSignAndNotarize from './macos-sign'; export default async function compileAndZipExecutable(config: Config): Promise { const executable = await compileExec( @@ -12,15 +15,21 @@ export default async function compileAndZipExecutable(config: Config): Promise => { + return await createTarball( + executable, + config.outputDir, + config.buildVariant, + config.version, + config.rootDir + ); + }; - // add artifcats for .rpm and .msi - return artifact; + // Zip the executable, or, on macOS, do it as part of the notarization/signing + // step. + if (os.platform() === Platform.MacOs && !config.dryRun) { + return await macOSSignAndNotarize(executable, config, runCreateTarball); + } else { + return await runCreateTarball(); + } } diff --git a/packages/build/src/config.ts b/packages/build/src/config.ts index 328fe59df2..79d54caafa 100644 --- a/packages/build/src/config.ts +++ b/packages/build/src/config.ts @@ -21,6 +21,7 @@ export default interface Config { appleUser?: string; applePassword?: string; appleAppIdentity?: string; + entitlementsFile?: string; isCi?: boolean; platform?: string; execNodeVersion?: string; diff --git a/packages/build/src/macos-sign.ts b/packages/build/src/macos-sign.ts index 37f18f7116..d2f9da5da4 100644 --- a/packages/build/src/macos-sign.ts +++ b/packages/build/src/macos-sign.ts @@ -3,7 +3,7 @@ import util from 'util'; import codesign from 'node-codesign'; import { notarize as nodeNotarize } from 'electron-notarize'; import Config from './config'; -import { createTarball } from './tarball'; +import { createTarball, TarballFile } from './tarball'; /** * Notarizes the zipped mongosh. Will send the tarball to Apple and poll apple @@ -29,31 +29,29 @@ const notarize = (bundleId: string, artifact: string, user: string, password: st * @param {string} executable - The mongosh executable. * @param {string} identity - The apple developer identity. */ -const sign = (executable: string, identity: string) => { - return new Promise((resolve, reject) => { - codesign({ identity: identity, appPath: executable }, (err, paths) => { - if (err) { - reject(err); - } else { - resolve(err); - } - }); +const sign = (executable: string, identity: string, entitlementsFile: string) => { + return util.promisify(codesign)({ + identity: identity, + appPath: executable, + entitlements: entitlementsFile, }); }; -const publish = async(executable: string, artifact: string, platform: string, config: Config) => { - console.log('mongosh: removing unsigned tarball:', artifact); - await util.promisify(fs.unlink)(artifact); +const macOSSignAndNotarize = async( + executable: string, + config: Config, + runCreateTarball: () => Promise): Promise => { + console.log('mongosh: signing:', executable); - await sign(executable, config.appleAppIdentity). - catch((e) => { console.error(e); throw e; }); + await sign(executable, config.appleAppIdentity, config.entitlementsFile); console.log('mongosh: notarizing and creating tarball:', executable); - await createTarball(executable, config.outputDir, platform, config.version, config.rootDir); + const artifact = await runCreateTarball(); await notarize( config.bundleId, - artifact, + artifact.path, config.appleUser, - config.applePassword).catch((e) => { console.error(e); throw e; }); + config.applePassword); + return artifact; }; -export default publish; +export default macOSSignAndNotarize; diff --git a/scripts/evergreen-release.js b/scripts/evergreen-release.js index 0143018f5f..43bf70e325 100644 --- a/scripts/evergreen-release.js +++ b/scripts/evergreen-release.js @@ -11,7 +11,7 @@ const runRelease = async() => { const command = process.argv[2]; if (!['package', 'publish'].includes(command)) { - throw new Error('USAGE: npm run evergreen-release [--dry]'); + throw new Error('USAGE: npm run evergreen-release -- [--dry]'); } if (process.argv.includes('--dry')) {