From f48cd96a12b9e4bdcb299135099955202924b9ea Mon Sep 17 00:00:00 2001 From: sander boer Date: Fri, 23 Aug 2024 00:20:56 +0200 Subject: [PATCH] Fix/certificate (#6) * add certificate * macOS? * copy pasta * use from docs https://docs.github.com/en/actions/use-cases-and-examples/deploying/installing-an-apple-certificate-on-macos-runners-for-xcode-development * only run om macos * removed setting certificate from blog post * add provisioning profile * uncomment path * move command up for debugging * clean up keychain use actual env value * remove avrgirl-arduino * clean bundle to only include required modules could potentially be even stricter * dont strict verify * debug osx sign for pipeline test * sign in release as well --- .github/workflows/make.yml | 38 ++++++++++++++-- .github/workflows/release.yml | 25 +++++++++- .gitignore | 1 + apps/electron-app/bundler.js | 34 +++++++++++++- apps/electron-app/extraResource.js | 1 - apps/electron-app/forge.config.js | 28 +++++++++++- apps/electron-app/package.json | 1 - apps/electron-app/src/main/ipc.ts | 35 +++++++++++--- apps/electron-app/workers/check.js | 13 +++--- yarn.lock | 73 +----------------------------- 10 files changed, 155 insertions(+), 94 deletions(-) delete mode 100644 apps/electron-app/extraResource.js diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index 1467739..ad44ec9 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -21,10 +21,37 @@ jobs: os: [macos-latest, ubuntu-latest, windows-latest] steps: + - name: Install the Apple certificate + if: runner.os == 'macOS' + env: + MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }} + MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + run: | + # create variables + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + + # import certificate + echo -n "$MACOS_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH + + # create temporary keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + security set-keychain-settings -lut 21600 $KEYCHAIN_PATH + security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$MACOS_CERTIFICATE_PWD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + + - name: Run security find-identity -v + if: runner.os == 'macOS' + run: security find-identity -v + - uses: actions/checkout@v4 - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: '**/node_modules' key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} @@ -48,8 +75,13 @@ jobs: # Required for `distutils` module python-version: '3.10' + # https://localazy.com/blog/how-to-automatically-sign-macos-apps-using-github-actions - name: Make application run: yarn make env: - APPLE_API_KEY: AuthKey_${{ env.APPLE_API_KEY_ID }}.p8 - APPLE_IDENTITY: env.APPLE_IDENTITY + APPLE_IDENTITY: ${{ env.APPLE_IDENTITY }} + + - name: Clean up keychain and provisioning profile + if: runner.os == 'macOS' + run: | + security delete-keychain $RUNNER_TEMP/app-signing.keychain-db diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a9b4c81..5224f58 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,10 +14,33 @@ jobs: os: [macos-latest, ubuntu-latest, windows-latest] steps: + - name: Install the Apple certificate + if: runner.os == 'macOS' + env: + MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }} + MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + run: | + # create variables + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + + # import certificate + echo -n "$MACOS_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH + + # create temporary keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + security set-keychain-settings -lut 21600 $KEYCHAIN_PATH + security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$MACOS_CERTIFICATE_PWD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + - uses: actions/checkout@v4 - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: '**/node_modules' key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} diff --git a/.gitignore b/.gitignore index 51b468a..3bf6eb8 100644 --- a/.gitignore +++ b/.gitignore @@ -122,3 +122,4 @@ dist-ssr # Secrets .env *.p8 +*.provisionprofile diff --git a/apps/electron-app/bundler.js b/apps/electron-app/bundler.js index f533194..e3d3805 100644 --- a/apps/electron-app/bundler.js +++ b/apps/electron-app/bundler.js @@ -51,10 +51,28 @@ const collectProdDeps = node => { while (stack.length > 0) { const currentNode = stack.pop(); + // Ignore types packages + if (currentNode.location.startsWith('node_modules/@types')) { + // console.debug(`IGNORE ${currentNode.location}`); + continue; + } + + // Ignore radix-ui packages + if (currentNode.location.includes('@radix-ui')) { + // console.debug(`IGNORE ${currentNode.location}`); + continue; + } + const depEdges = [...currentNode.edgesOut.values()].filter( depEdge => depEdge.type === 'prod', ); + // Show dependencies + // console.debug( + // currentNode.location, + // depEdges.map(depEdge => depEdge.to.location), + // ); + for (const depEdge of depEdges) { const depNode = resolveLink(depEdge.to); @@ -83,8 +101,20 @@ const bundle = async (source, destination) => { for (const dep of prodDeps) { const dest = path.join(destination, dep.location); - console.log(`Copying ${dep.location} to ${dest}`); - await fs.cp(dep.realpath, dest, { + let bundlePath = dest; + if (dep.location.startsWith('packages')) { + switch (dep.location) { + case 'packages/components': + bundlePath = dest.replace('packages', 'node_modules/@microflow'); + break; + default: + continue; + } + } + + console.log(`${dep.location} --> ${bundlePath}`); + + await fs.cp(dep.realpath, bundlePath, { recursive: true, errorOnExist: false, }); diff --git a/apps/electron-app/extraResource.js b/apps/electron-app/extraResource.js deleted file mode 100644 index e558141..0000000 --- a/apps/electron-app/extraResource.js +++ /dev/null @@ -1 +0,0 @@ -console.log(true); diff --git a/apps/electron-app/forge.config.js b/apps/electron-app/forge.config.js index 565b3f2..f17dc27 100644 --- a/apps/electron-app/forge.config.js +++ b/apps/electron-app/forge.config.js @@ -8,7 +8,34 @@ module.exports = { executableName: 'Microflow studio', icon: 'assets/icon', osxSign: { + strictVerify: false, identity: process.env.APPLE_IDENTITY, // https://github.com/electron/forge/issues/3131#issuecomment-2237818679 + ignore: filePath => { + if (filePath.includes('build/node_gyp_bins/python3')) { + console.log('>> ignore signing', filePath); + return true; + } + return false; + }, + // optionsForFile: filePath => { + // if (!filePath.includes('node_gyp_bins/python3')) { + // return; + // } + + // console.log('>> extra options', filePath); + + // return { + // additionalArguments: ['--deep'], + // }; + // }, + // ignore: filePath => { + // if (!filePath.includes('node_gyp_bins/python3')) { + // return false; + // } + + // console.log('>> ignore', filePath); + // return true; + // }, }, // osxNotarize: { // tool: 'notarytool', @@ -17,7 +44,6 @@ module.exports = { // teamId: process.env.APPLE_TEAM_ID, // }, prune: false, // Requires for monorepo - extraResource: ['./workers', './hex'], protocols: [ { name: 'microflow-studio', diff --git a/apps/electron-app/package.json b/apps/electron-app/package.json index 291c490..4adbe08 100644 --- a/apps/electron-app/package.json +++ b/apps/electron-app/package.json @@ -59,7 +59,6 @@ "@microflow/utils": "workspaces:*", "@xyflow/react": "^12.0.0", "abcjs": "^6.4.2", - "avrgirl-arduino": "https://github.com/xiduzo/avrgirl-arduino.git", "electron-log": "^5.1.5", "firmata": "https://github.com/xiduzo/firmata.js.git", "mqtt": "^5.8.0", diff --git a/apps/electron-app/src/main/ipc.ts b/apps/electron-app/src/main/ipc.ts index b913319..c45fd7b 100644 --- a/apps/electron-app/src/main/ipc.ts +++ b/apps/electron-app/src/main/ipc.ts @@ -23,9 +23,6 @@ import { let childProcess: UtilityProcess | null = null; -const isDev = process.env.NODE_ENV === 'development'; -const resourcesPath = isDev ? __dirname : process.resourcesPath; - // ipcMain.on("shell:open", () => { // const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked') // const pagePath = path.join('file://', pageDirectory, 'index.html') @@ -47,24 +44,41 @@ ipcMain.on('ipc-check-board', async event => { const boardsAndPorts = await getKnownBoardsWithPorts(); - const filePath = join(resourcesPath, 'workers', 'check.js'); + const filePath = join(__dirname, 'workers', 'check.js'); let connectedPort: PortInfo | null = null; const [lastBoard, ports] = boardsAndPorts.at(-1); const lastPort = ports.at(-1); + log.debug('Checking boards and ports', { + boardsAndPorts: JSON.stringify(boardsAndPorts), + }); + // Check board on all ports which match the known product IDs checkBoard: for (const [board, ports] of boardsAndPorts) { for (const port of ports) { - log.debug(`checking board ${board} on path ${port.path}`); + log.debug(`checking board ${board} on path ${port.path}`, { filePath }); const result = await new Promise(resolve => { childProcess = utilityProcess.fork(filePath, [port.path], { serviceName: 'Microflow studio - micro-controller validator', + stdio: 'pipe', + }); + + childProcess.stderr?.on('data', data => { + log.error('board check child process error', { + data: data.toString(), + }); + }); + + log.debug('Child process forked', { + filePath, + port: port.path, }); childProcess.on('message', async (message: BoardCheckResult) => { + log.debug('board check child process process message', { message }); if (message.type !== 'info') { childProcess?.kill(); // Free up the port again resolve(message); @@ -121,7 +135,7 @@ ipcMain.on('ipc-upload-code', (event, code: string, portPath: string) => { } childProcess?.kill(); - const filePath = join(resourcesPath, 'temp.js'); + const filePath = join(__dirname, 'temp.js'); log.debug('Writing code to file', { filePath }); writeFile(filePath, code, error => { if (error) { @@ -135,6 +149,13 @@ ipcMain.on('ipc-upload-code', (event, code: string, portPath: string) => { childProcess = utilityProcess.fork(filePath, [portPath], { serviceName: 'Microflow studio - micro-controller runner', + stdio: 'pipe', + }); + + childProcess.stderr?.on('data', data => { + log.error('board check child process error', { + data: data.toString(), + }); }); childProcess.on( @@ -160,7 +181,7 @@ async function flashBoard(board: BoardName, port: PortInfo): Promise { log.debug(`Try flashing firmata to ${board} on ${port.path}`); const firmataPath = resolve( - resourcesPath, + __dirname, 'hex', board, 'StandardFirmata.cpp.hex', diff --git a/apps/electron-app/workers/check.js b/apps/electron-app/workers/check.js index 4c1c234..aefc7d1 100644 --- a/apps/electron-app/workers/check.js +++ b/apps/electron-app/workers/check.js @@ -1,12 +1,13 @@ const { Board } = require('@microflow/components'); -const log = require('electron-log/node'); const port = process.argv.at(-1); if (!port) { - log.warn( - 'No port provided, johnny five usualy can handle this. This might cause unforseen behavior.', - ); + process.parentPort.postMessage({ + type: 'info', + message: + 'No port provided, johnny five usualy can handle this. This might cause unforseen behavior.', + }); } let board; @@ -18,11 +19,10 @@ try { port, }); - log.debug('Board is being checked', { port: board.port }); - process.parentPort.postMessage({ type: 'info', message: 'checking micro-controller', + port: board.port, }); board.on('info', event => { @@ -85,7 +85,6 @@ try { process.parentPort.postMessage({ type: 'close' }); }); } catch (error) { - log.error('something went wrong', { error }); process.parentPort.postMessage({ type: 'error', message: error.message, diff --git a/yarn.lock b/yarn.lock index a0d2609..8ea7403 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5166,15 +5166,6 @@ __metadata: languageName: node linkType: hard -"async@npm:^2.6.3": - version: 2.6.4 - resolution: "async@npm:2.6.4" - dependencies: - lodash: ^4.17.14 - checksum: a52083fb32e1ebe1d63e5c5624038bb30be68ff07a6c8d7dfe35e47c93fc144bd8652cbec869e0ac07d57dde387aa5f1386be3559cdee799cb1f789678d88e19 - languageName: node - linkType: hard - "async@npm:^3.2.3": version: 3.2.5 resolution: "async@npm:3.2.5" @@ -5223,37 +5214,6 @@ __metadata: languageName: node linkType: hard -"avrgirl-arduino@https://github.com/xiduzo/avrgirl-arduino.git": - version: 5.0.1 - resolution: "avrgirl-arduino@https://github.com/xiduzo/avrgirl-arduino.git#commit=213f5a825cd3e639a1511be0c81addf2282ad960" - dependencies: - async: ^2.6.3 - awty: ^0.1.0 - browser-serialport: "git+https://github.com/noopkat/browser-serialport.git#c8628c41c11890d3058875994c15f83f2df8185b" - chip.avr.avr109: ^1.1.1 - colors: ^1.4.0 - graceful-fs: ^4.2.4 - intel-hex: ^0.1.2 - minimist: ^1.2.5 - process: ^0.11.10 - serialport: ^10.4.0 - stk500: ^2.0.3 - stk500-v2: ^1.0.4 - bin: - avrgirl-arduino: ./bin/cli.js - checksum: 7c489fccb4013187624ac3ca4709aa77861b59b717e34db957f2819a5ed52396c9dd8bf05454cc4d5c0240aeabed2d9f7d6d6aee3c97d4e8306b4ca9c00239f9 - languageName: node - linkType: hard - -"awty@npm:^0.1.0": - version: 0.1.0 - resolution: "awty@npm:0.1.0" - dependencies: - isval: 0.0.2 - checksum: 71ee5cca80e36eeab742b9b570fbdc4b0591c7f73de9abce1d7893706583db63e609a9b813f1b2d821c318f9ddde24ce55604d6f0245ab26683a3ed3a4cd1012 - languageName: node - linkType: hard - "axe-core@npm:^4.9.1": version: 4.10.0 resolution: "axe-core@npm:4.10.0" @@ -5436,13 +5396,6 @@ __metadata: languageName: node linkType: hard -"browser-serialport@git+https://github.com/noopkat/browser-serialport.git#c8628c41c11890d3058875994c15f83f2df8185b": - version: 2.0.3 - resolution: "browser-serialport@https://github.com/noopkat/browser-serialport.git#commit=c8628c41c11890d3058875994c15f83f2df8185b" - checksum: 67a5b14b93ebbf93481f8112b1827ae1f7004ab6c8baf714d840d08a69f4d625f7f5a407c8103a13ef1c5340531c2aa650e79236eaea56580c7978e0e4a5bcf7 - languageName: node - linkType: hard - "browser-serialport@npm:latest": version: 2.1.0 resolution: "browser-serialport@npm:2.1.0" @@ -6006,13 +5959,6 @@ __metadata: languageName: node linkType: hard -"colors@npm:^1.4.0": - version: 1.4.0 - resolution: "colors@npm:1.4.0" - checksum: 98aa2c2418ad87dedf25d781be69dc5fc5908e279d9d30c34d8b702e586a0474605b3a189511482b9d5ed0d20c867515d22749537f7bc546256c6014f3ebdcec - languageName: node - linkType: hard - "commander@npm:7": version: 7.2.0 resolution: "commander@npm:7.2.0" @@ -9130,13 +9076,6 @@ __metadata: languageName: node linkType: hard -"intel-hex@npm:^0.1.2": - version: 0.1.2 - resolution: "intel-hex@npm:0.1.2" - checksum: 55388f6f7e5fc97a4a891b121feaa1e4e3e919793e9a2297f9692f11151e0b51ebe0d60306e4de296712dc2575facafa9f3bf3fd2514501335db1edfe12f1691 - languageName: node - linkType: hard - "internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.7": version: 1.0.7 resolution: "internal-slot@npm:1.0.7" @@ -9592,13 +9531,6 @@ __metadata: languageName: node linkType: hard -"isval@npm:0.0.2": - version: 0.0.2 - resolution: "isval@npm:0.0.2" - checksum: f78e679349d4fefe9a99e5b929578b39860a433ee8a1bfbcbacc0af7dc16ca1d5d1059cdd2e501b73b89b441f97c330df624c428a8696752a0511a5215d5ffb3 - languageName: node - linkType: hard - "iterator.prototype@npm:^1.1.2": version: 1.1.2 resolution: "iterator.prototype@npm:1.1.2" @@ -10136,7 +10068,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4": +"lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -10474,7 +10406,6 @@ __metadata: "@xyflow/react": ^12.0.0 abcjs: ^6.4.2 autoprefixer: ^10.4.19 - avrgirl-arduino: "https://github.com/xiduzo/avrgirl-arduino.git" dotenv: ^16.4.5 electron: 28.0.0 electron-log: ^5.1.5 @@ -10833,7 +10764,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.1.1, minimist@npm:^1.1.3, minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.8": +"minimist@npm:^1.1.1, minimist@npm:^1.1.3, minimist@npm:^1.2.0, minimist@npm:^1.2.6, minimist@npm:^1.2.8": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0