1
0
mirror of https://github.com/laurent22/joplin.git synced 2026-02-01 07:49:31 +02:00

Compare commits

...

11 Commits

Author SHA1 Message Date
Laurent Cozic
ec69097cec update 2026-01-20 18:17:07 +00:00
Laurent Cozic
6b1f2c946e update 2026-01-20 15:50:33 +00:00
Laurent Cozic
c6c1a9a888 update 2026-01-20 15:32:06 +00:00
Laurent Cozic
e95e84edeb update 2026-01-20 15:13:40 +00:00
Laurent Cozic
4e5895e53f update 2026-01-20 14:26:49 +00:00
Laurent Cozic
0bf92c2cdd update 2026-01-20 13:49:37 +00:00
Laurent Cozic
2a9dfe7cf9 update 2026-01-20 13:19:46 +00:00
Laurent Cozic
66388acfbe update 2026-01-20 12:17:32 +00:00
Laurent Cozic
dd12f4df64 update 2026-01-20 11:14:41 +00:00
Laurent Cozic
7209948ded trying signing 2026-01-20 10:15:37 +00:00
Laurent Cozic
cdf104f650 update 2026-01-20 10:12:22 +00:00
8 changed files with 172 additions and 84 deletions

View File

@@ -611,6 +611,7 @@ packages/app-desktop/tools/copy7Zip.js
packages/app-desktop/tools/generateLatestArm64Yml.js
packages/app-desktop/tools/githubReleasesUtils.js
packages/app-desktop/tools/modifyReleaseAssets.js
packages/app-desktop/tools/notarizeFile.js
packages/app-desktop/tools/notarizeMacApp.js
packages/app-desktop/tools/resolveSourceMap.js
packages/app-desktop/utils/7zip/getPathToExecutable7Zip.js

View File

@@ -46,6 +46,8 @@ jobs:
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
CSC_INSTALLER_KEY_PASSWORD: ${{ secrets.CSC_INSTALLER_KEY_PASSWORD }}
CSC_INSTALLER_LINK: ${{ secrets.CSC_INSTALLER_LINK }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
@@ -72,6 +74,39 @@ jobs:
npm pkg set 'build.mac.target[2].arch[0]'='arm64'
fi
curl -L -o installer.p12 "$CSC_INSTALLER_LINK"
# Create an explicit keychain file path (avoid temp dirs / weird defaults)
KEYCHAIN="$RUNNER_TEMP/build.keychain-db"
KEYCHAIN_PW=""
security create-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN"
security set-keychain-settings -lut 21600 "$KEYCHAIN"
security unlock-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN"
# Make sure this keychain is the one security uses
security list-keychains -d user -s "$KEYCHAIN"
security default-keychain -d user -s "$KEYCHAIN"
# Import with -A to avoid access-control prompts in CI
security import installer.p12 \
-k "$KEYCHAIN" \
-P "$CSC_INSTALLER_KEY_PASSWORD" \
-A
# Sanity: confirm identity is now present
security find-identity -p codesigning -v "$KEYCHAIN"
build_dist() {
if [[ "$PUBLISH_ENABLED" == "true" ]]; then
echo "Building and publishing desktop application..."

View File

@@ -75,6 +75,8 @@ jobs:
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
CSC_INSTALLER_KEY_PASSWORD: ${{ secrets.CSC_INSTALLER_KEY_PASSWORD }}
CSC_INSTALLER_LINK: ${{ secrets.CSC_INSTALLER_LINK }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
IS_CONTINUOUS_INTEGRATION: 1
BUILD_SEQUENCIAL: 1

1
.gitignore vendored
View File

@@ -585,6 +585,7 @@ packages/app-desktop/tools/copy7Zip.js
packages/app-desktop/tools/generateLatestArm64Yml.js
packages/app-desktop/tools/githubReleasesUtils.js
packages/app-desktop/tools/modifyReleaseAssets.js
packages/app-desktop/tools/notarizeFile.js
packages/app-desktop/tools/notarizeMacApp.js
packages/app-desktop/tools/resolveSourceMap.js
packages/app-desktop/utils/7zip/getPathToExecutable7Zip.js

View File

@@ -2,6 +2,7 @@ const fs = require('fs');
const path = require('path');
const os = require('os');
const sha512 = require('js-sha512');
const notarizeFile = require('./tools/notarizeFile').default;
const distDirName = 'dist';
const distPath = path.join(__dirname, distDirName);
@@ -31,7 +32,24 @@ const generateChecksumFile = () => {
return sha512FilePath;
};
const mainHook = () => {
const notarizePkg = async () => {
if (os.platform() !== 'darwin') {
return;
}
const files = fs.readdirSync(distPath);
for (const filename of files) {
if (filename.endsWith('.pkg')) {
const pkgPath = path.join(distPath, filename);
await notarizeFile(pkgPath);
return;
}
}
};
const mainHook = async () => {
await notarizePkg();
const sha512FilePath = generateChecksumFile();
const outputFiles = [sha512FilePath].filter(item => item);
return outputFiles;

View File

@@ -0,0 +1,109 @@
import { existsSync } from 'fs';
import { notarize } from '@electron/notarize';
const execCommand = require('./execCommand');
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
// Same appId in electron-builder.
const appId = 'net.cozic.joplin-desktop';
function isDesktopAppTag(tagName: string) {
if (!tagName) return false;
return tagName[0] === 'v';
}
export default async function notarizeFile(filePath: string) {
if (process.platform !== 'darwin') return;
console.info(`Checking if notarization should be done on: ${filePath}`);
if (!process.env.IS_CONTINUOUS_INTEGRATION || !isDesktopAppTag(process.env.GIT_TAG_NAME)) {
console.info(`Either not running in CI or not processing a desktop app tag - skipping notarization. process.env.IS_CONTINUOUS_INTEGRATION = ${process.env.IS_CONTINUOUS_INTEGRATION}; process.env.GIT_TAG_NAME = ${process.env.GIT_TAG_NAME}`);
return;
}
if (!process.env.APPLE_ID || !process.env.APPLE_ID_PASSWORD) {
console.warn('Environment variables APPLE_ID and APPLE_ID_PASSWORD not found - notarization will NOT be done.');
return;
}
if (!existsSync(filePath)) {
throw new Error(`Cannot find file at: ${filePath}`);
}
// Every x seconds we print something to stdout, otherwise CI may timeout
// the task after 10 minutes, and Apple notarization can take more time.
const waitingIntervalId = setInterval(() => {
console.info('.');
}, 60000);
const isPkg = filePath.endsWith('.pkg');
console.info(`Notarizing ${filePath}`);
try {
if (isPkg) {
await execAsync(
`xcrun notarytool submit "${filePath}" ` +
`--apple-id "${process.env.APPLE_ID}" ` +
`--password "${process.env.APPLE_ID_PASSWORD}" ` +
`--team-id "${process.env.APPLE_ASC_PROVIDER}" ` +
'--wait',
{ maxBuffer: 1024 * 1024 },
);
} else {
await notarize({
appBundleId: appId,
appPath: filePath,
// Apple Developer email address
appleId: process.env.APPLE_ID,
// App-specific password: https://support.apple.com/en-us/HT204397
appleIdPassword: process.env.APPLE_ID_PASSWORD,
// When Apple ID is attached to multiple providers (eg if the
// account has been used to build multiple apps for different
// companies), in that case the provider "Team Short Name" (also
// known as "ProviderShortname") must be provided.
//
// Use this to get it:
//
// xcrun altool --list-providers -u APPLE_ID -p APPLE_ID_PASSWORD
// ascProvider: process.env.APPLE_ASC_PROVIDER,
// In our case, the team ID is the same as the legacy ASC_PROVIDER
teamId: process.env.APPLE_ASC_PROVIDER,
tool: 'notarytool',
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
} as any);
}
} catch (error) {
console.error(error);
process.exit(1);
}
clearInterval(waitingIntervalId);
// It appears that electron-notarize doesn't staple the app, but without
// this we were still getting the malware warning when launching the app.
// Stapling the app means attaching the notarization ticket to it, so that
// if the user is offline, macOS can still check if the app was notarized.
// So it seems to be more or less optional, but at least in our case it
// wasn't.
console.info('Stapling notarization ticket to the file...');
const staplerCmd = `xcrun stapler staple "${filePath}"`;
console.info(`> ${staplerCmd}`);
console.info(await execCommand(staplerCmd));
console.info(`Validating stapled file: ${filePath}`);
try {
await execAsync(`spctl -a -vv -t install "${filePath}"`);
} catch (error) {
console.error(`Failed validating stapled file: ${filePath}:`, error);
}
console.info(`Done notarizing ${filePath}`);
}

View File

@@ -1,12 +1,5 @@
import { existsSync } from 'fs';
import { join } from 'path';
import { notarize } from '@electron/notarize';
const execCommand = require('./execCommand');
function isDesktopAppTag(tagName: string) {
if (!tagName) return false;
return tagName[0] === 'v';
}
import notarizeFile from './notarizeFile';
interface Params {
appOutDir: string;
@@ -18,80 +11,6 @@ interface Params {
}
export default async (params: Params) => {
if (process.platform !== 'darwin') return;
console.info('Checking if notarization should be done...');
if (!process.env.IS_CONTINUOUS_INTEGRATION || !isDesktopAppTag(process.env.GIT_TAG_NAME)) {
console.info(`Either not running in CI or not processing a desktop app tag - skipping notarization. process.env.IS_CONTINUOUS_INTEGRATION = ${process.env.IS_CONTINUOUS_INTEGRATION}; process.env.GIT_TAG_NAME = ${process.env.GIT_TAG_NAME}`);
return;
}
if (!process.env.APPLE_ID || !process.env.APPLE_ID_PASSWORD) {
console.warn('Environment variables APPLE_ID and APPLE_ID_PASSWORD not found - notarization will NOT be done.');
return;
}
// Same appId in electron-builder.
const appId = 'net.cozic.joplin-desktop';
const appPath = join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);
if (!existsSync(appPath)) {
throw new Error(`Cannot find application at: ${appPath}`);
}
console.log(`Notarizing ${appId} found at ${appPath}`);
// Every x seconds we print something to stdout, otherwise CI may timeout
// the task after 10 minutes, and Apple notarization can take more time.
const waitingIntervalId = setInterval(() => {
console.log('.');
}, 60000);
try {
await notarize({
appBundleId: appId,
appPath: appPath,
// Apple Developer email address
appleId: process.env.APPLE_ID,
// App-specific password: https://support.apple.com/en-us/HT204397
appleIdPassword: process.env.APPLE_ID_PASSWORD,
// When Apple ID is attached to multiple providers (eg if the
// account has been used to build multiple apps for different
// companies), in that case the provider "Team Short Name" (also
// known as "ProviderShortname") must be provided.
//
// Use this to get it:
//
// xcrun altool --list-providers -u APPLE_ID -p APPLE_ID_PASSWORD
// ascProvider: process.env.APPLE_ASC_PROVIDER,
// In our case, the team ID is the same as the legacy ASC_PROVIDER
teamId: process.env.APPLE_ASC_PROVIDER,
tool: 'notarytool',
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
} as any);
} catch (error) {
console.error(error);
process.exit(1);
}
clearInterval(waitingIntervalId);
// It appears that electron-notarize doesn't staple the app, but without
// this we were still getting the malware warning when launching the app.
// Stapling the app means attaching the notarization ticket to it, so that
// if the user is offline, macOS can still check if the app was notarized.
// So it seems to be more or less optional, but at least in our case it
// wasn't.
console.log('Staple notarization ticket to the app...');
const staplerCmd = `xcrun stapler staple "${appPath}"`;
console.log(`> ${staplerCmd}`);
console.log(await execCommand(staplerCmd));
console.log(`Done notarizing ${appId}`);
await notarizeFile(appPath);
};

View File

@@ -246,3 +246,6 @@ youtu
nocookie
fgag
mrjo
spctl
codesign
productbuild