From c534ac4872611c1b2498cfd812e619548d766e80 Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Fri, 9 Dec 2022 20:32:24 -0600 Subject: [PATCH 01/13] fix: add column, line, and method check to integrity check --- .../binary/binary-integrity-check-source.js | 51 +++++++++++++++++-- scripts/binary/binary-sources.js | 1 + 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/scripts/binary/binary-integrity-check-source.js b/scripts/binary/binary-integrity-check-source.js index 59f4a89cf98b..857405d0da0d 100644 --- a/scripts/binary/binary-integrity-check-source.js +++ b/scripts/binary/binary-integrity-check-source.js @@ -2,6 +2,8 @@ const OrigError = Error const captureStackTrace = Error.captureStackTrace const toString = Function.prototype.toString const callFn = Function.call +const filter = Array.prototype.filter +const startsWith = String.prototype.startsWith const integrityErrorMessage = ` We detected an issue with the integrity of the Cypress binary. It may have been modified and cannot run. We recommend re-installing the Cypress binary with: @@ -22,7 +24,7 @@ const stackIntegrityCheck = function stackIntegrityCheck (options) { const tempError = new OrigError captureStackTrace(tempError, arguments.callee) - const stack = tempError.stack.filter((frame) => !frame.getFileName().startsWith('node:internal') && !frame.getFileName().startsWith('node:electron')) + const stack = filter.call(tempError.stack, (frame) => !startsWith.call(frame.getFileName(), 'node:internal') && !startsWith.call(frame.getFileName(), 'node:electron')) OrigError.prepareStackTrace = originalPrepareStackTrace OrigError.stackTraceLimit = originalStackTraceLimit @@ -33,26 +35,58 @@ const stackIntegrityCheck = function stackIntegrityCheck (options) { } for (let index = 0; index < options.stackToMatch.length; index++) { - const { functionName: expectedFunctionName, fileName: expectedFileName } = options.stackToMatch[index] + const { functionName: expectedFunctionName, methodName: expectedMethodName, fileName: expectedFileName, line: expectedLineNumber, column: expectedColumnNumber } = options.stackToMatch[index] const actualFunctionName = stack[index].getFunctionName() const actualFileName = stack[index].getFileName() + const actualColumnNumber = stack[index].getColumnNumber() + const actualLineNumber = stack[index].getLineNumber() + const actualMethodName = stack[index].getMethodName() if (expectedFunctionName && actualFunctionName !== expectedFunctionName) { console.error(`Integrity check failed with expected function name ${expectedFunctionName} but got ${actualFunctionName}`) throw new Error(integrityErrorMessage) } + if (expectedMethodName && actualMethodName !== expectedMethodName) { + console.error(`Integrity check failed with expected method name ${expectedMethodName} but got ${actualMethodName}`) + throw new Error(integrityErrorMessage) + } + if (expectedFileName && actualFileName !== expectedFileName) { console.error(`Integrity check failed with expected file name ${expectedFileName} but got ${actualFileName}`) throw new Error(integrityErrorMessage) } + + if (expectedLineNumber && actualLineNumber !== expectedLineNumber) { + console.error(`Integrity check failed with expected line number ${expectedLineNumber} but got ${actualLineNumber}`) + throw new Error(integrityErrorMessage) + } + + if (expectedColumnNumber && actualColumnNumber !== expectedColumnNumber) { + console.error(`Integrity check failed with expected column number ${expectedColumnNumber} but got ${actualColumnNumber}`) + throw new Error(integrityErrorMessage) + } + } +} + +function validateStartsWith () { + if (startsWith.call !== callFn) { + console.error(`Integrity check failed for startsWith.call`) + throw new Error(integrityErrorMessage) + } +} + +function validateFilter () { + if (filter.call !== callFn) { + console.error(`Integrity check failed for filter.call`) + throw new Error(integrityErrorMessage) } } function validateToString () { if (toString.call !== callFn) { console.error(`Integrity check failed for toString.call`) - throw new Error('Integrity check failed for toString.call') + throw new Error(integrityErrorMessage) } } @@ -60,7 +94,7 @@ function validateElectron (electron) { // Hard coded function as this is electron code and there's not an easy way to get the function string at package time. If this fails on an updated version of electron, we'll need to update this. if (toString.call(electron.app.getAppPath) !== 'function getAppPath() { [native code] }') { console.error(`Integrity check failed for toString.call(electron.app.getAppPath)`) - throw new Error(`Integrity check failed for toString.call(electron.app.getAppPath)`) + throw new Error(integrityErrorMessage) } } @@ -106,6 +140,8 @@ function integrityCheck (options) { const crypto = require('crypto') // 1. Validate that the native functions we are using haven't been tampered with + validateStartsWith() + validateFilter() validateToString() validateElectron(electron) validateFs(fs) @@ -143,13 +179,18 @@ function integrityCheck (options) { fileName: 'evalmachine.', }, { - functionName: 'Module2._extensions.', + functionName: 'p._extensions.', + methodName: '.jsc', // eslint-disable-next-line no-undef fileName: [appPath, 'index.js'].join(PATH_SEP), + line: 1, + column: 4364, }, { // eslint-disable-next-line no-undef fileName: [appPath, 'index.js'].join(PATH_SEP), + line: 4, + column: 385, }, ], }) diff --git a/scripts/binary/binary-sources.js b/scripts/binary/binary-sources.js index 2e9d1ade817a..63293369115c 100644 --- a/scripts/binary/binary-sources.js +++ b/scripts/binary/binary-sources.js @@ -17,6 +17,7 @@ const getBinaryEntryPointSource = async () => { bundle: true, platform: 'node', write: false, + minify: true, }) return esbuildResult.outputFiles[0].text From ca01c3ebdeef5a71ebdf5ddcb023632207bbcac3 Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Fri, 9 Dec 2022 20:38:54 -0600 Subject: [PATCH 02/13] run ci --- .circleci/workflows.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.circleci/workflows.yml b/.circleci/workflows.yml index 1f72027568cf..a2de66d3c6ef 100644 --- a/.circleci/workflows.yml +++ b/.circleci/workflows.yml @@ -28,6 +28,7 @@ mainBuildFilters: &mainBuildFilters only: - develop - /^release\/\d+\.\d+\.\d+$/ + - 'ryanm/fix/column-line' # usually we don't build Mac app - it takes a long time # but sometimes we want to really confirm we are doing the right thing @@ -36,6 +37,7 @@ macWorkflowFilters: &darwin-workflow-filters when: or: - equal: [ develop, << pipeline.git.branch >> ] + - equal: [ 'ryanm/fix/column-line', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -43,6 +45,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters when: or: - equal: [ develop, << pipeline.git.branch >> ] + - equal: [ 'ryanm/fix/column-line', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -60,7 +63,7 @@ windowsWorkflowFilters: &windows-workflow-filters when: or: - equal: [ develop, << pipeline.git.branch >> ] - - equal: [ 'mschile/fix_windows_flake', << pipeline.git.branch >> ] + - equal: [ 'ryanm/fix/column-line', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -126,7 +129,7 @@ commands: - run: name: Check current branch to persist artifacts command: | - if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "ryanm/fix/issue-with-integrity-check" ]]; then + if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "ryanm/fix/column-line" ]]; then echo "Not uploading artifacts or posting install comment for this branch." circleci-agent step halt fi From 6efb3ae82afb6e09466458cb1bc41729052fb7c5 Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Fri, 9 Dec 2022 21:21:27 -0600 Subject: [PATCH 03/13] add test --- scripts/binary/smoke.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/scripts/binary/smoke.js b/scripts/binary/smoke.js index 063ad600ea24..bd1560ebacec 100644 --- a/scripts/binary/smoke.js +++ b/scripts/binary/smoke.js @@ -302,6 +302,24 @@ const runIntegrityTest = async function (buildAppExecutable, buildAppDir, e2e) { const allowList = ['regeneratorRuntime', '__core-js_shared__', 'getSnapshotResult', 'supportTypeScript'] await testAlteringEntryPoint(`(${compareGlobals.toString()})()`, `extra keys in electron process: ${allowList}\nIntegrity check failed with expected stack length 9 but got 10`) + + const testTemporarilyRewritingEntryPoint = async () => { + const file = path.join(buildAppDir, 'index.js') + const backupFile = path.join(buildAppDir, 'index.js.bak') + const contents = await fs.readFile(file) + + // Backup state + await fs.move(file, backupFile) + + // Modify app + await fs.writeFile(file, `console.log("rewritten code");const fs=require('fs');fs.writeFileSync('${file}',fs.readFileSync('${backupFile}'));${contents}`) + await runErroringProjectTest(buildAppExecutable, e2e, 'temporarily rewriting index.js', 'Integrity check failed with expected column number 4364 but got 4708') + + // Restore original state + await fs.move(backupFile, file, { overwrite: true }) + } + + await testTemporarilyRewritingEntryPoint() } const test = async function (buildAppExecutable, buildAppDir) { From 1c59a4cc58f89667e259f6af82da2f8119347af7 Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Fri, 9 Dec 2022 21:22:30 -0600 Subject: [PATCH 04/13] run ci From ab85363811aa7ac3f1a1c91f352651dd5ae75ee8 Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Fri, 9 Dec 2022 21:47:33 -0600 Subject: [PATCH 05/13] run ci --- scripts/binary/smoke.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/binary/smoke.js b/scripts/binary/smoke.js index bd1560ebacec..fe9661035128 100644 --- a/scripts/binary/smoke.js +++ b/scripts/binary/smoke.js @@ -313,7 +313,7 @@ const runIntegrityTest = async function (buildAppExecutable, buildAppDir, e2e) { // Modify app await fs.writeFile(file, `console.log("rewritten code");const fs=require('fs');fs.writeFileSync('${file}',fs.readFileSync('${backupFile}'));${contents}`) - await runErroringProjectTest(buildAppExecutable, e2e, 'temporarily rewriting index.js', 'Integrity check failed with expected column number 4364 but got 4708') + await runErroringProjectTest(buildAppExecutable, e2e, 'temporarily rewriting index.js', 'Integrity check failed with expected column number 4364 but got') // Restore original state await fs.move(backupFile, file, { overwrite: true }) From b71ec81ce325cfeb23063e085199b131376c4f13 Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Fri, 9 Dec 2022 23:36:19 -0600 Subject: [PATCH 06/13] fix test --- scripts/binary/smoke.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/binary/smoke.js b/scripts/binary/smoke.js index fe9661035128..0a41aced014a 100644 --- a/scripts/binary/smoke.js +++ b/scripts/binary/smoke.js @@ -312,7 +312,7 @@ const runIntegrityTest = async function (buildAppExecutable, buildAppDir, e2e) { await fs.move(file, backupFile) // Modify app - await fs.writeFile(file, `console.log("rewritten code");const fs=require('fs');fs.writeFileSync('${file}',fs.readFileSync('${backupFile}'));${contents}`) + await fs.writeFile(file, `console.log("rewritten code");const fs=require('fs');const { join } = require('path');fs.writeFileSync(join(__dirname,'index.js'),fs.readFileSync(join(__dirname,'index.js.bak')));${contents}`) await runErroringProjectTest(buildAppExecutable, e2e, 'temporarily rewriting index.js', 'Integrity check failed with expected column number 4364 but got') // Restore original state From 4a9bcc018bd458817ac5fad46a2a1eaa61a434ec Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Sat, 10 Dec 2022 16:56:53 -0600 Subject: [PATCH 07/13] harden logic --- patches/bytenode+1.3.7.patch | 16 ++++++++++++++++ scripts/binary/binary-integrity-check-source.js | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 patches/bytenode+1.3.7.patch diff --git a/patches/bytenode+1.3.7.patch b/patches/bytenode+1.3.7.patch new file mode 100644 index 000000000000..0149649e8849 --- /dev/null +++ b/patches/bytenode+1.3.7.patch @@ -0,0 +1,16 @@ +diff --git a/node_modules/bytenode/lib/index.js b/node_modules/bytenode/lib/index.js +index cdd98cc..cc6b8fa 100644 +--- a/node_modules/bytenode/lib/index.js ++++ b/node_modules/bytenode/lib/index.js +@@ -327,10 +327,7 @@ const addLoaderFile = function (fileToLoad, loaderFilename) { + }; + + const loaderCode = function (targetPath) { +- return ` +- require('bytenode'); +- require('${targetPath}'); +- `; ++ return `require('bytenode');require('${targetPath}');`; + }; + + global.bytenode = { diff --git a/scripts/binary/binary-integrity-check-source.js b/scripts/binary/binary-integrity-check-source.js index 857405d0da0d..289e5351a16f 100644 --- a/scripts/binary/binary-integrity-check-source.js +++ b/scripts/binary/binary-integrity-check-source.js @@ -189,8 +189,8 @@ function integrityCheck (options) { { // eslint-disable-next-line no-undef fileName: [appPath, 'index.js'].join(PATH_SEP), - line: 4, - column: 385, + line: 1, + column: 5049, }, ], }) From 8aafe385c4376d95f306a4e6c04c41fa376130d7 Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Sat, 10 Dec 2022 20:11:45 -0600 Subject: [PATCH 08/13] trim down what is used from bytenode --- patches/bytenode+1.3.7.dev.patch | 381 ++++++++++++++++++ patches/bytenode+1.3.7.patch | 16 - scripts/binary/binary-cleanup.js | 2 +- .../binary/binary-integrity-check-source.js | 6 +- scripts/binary/smoke.js | 2 +- 5 files changed, 386 insertions(+), 21 deletions(-) create mode 100644 patches/bytenode+1.3.7.dev.patch delete mode 100644 patches/bytenode+1.3.7.patch diff --git a/patches/bytenode+1.3.7.dev.patch b/patches/bytenode+1.3.7.dev.patch new file mode 100644 index 000000000000..2ac48f754980 --- /dev/null +++ b/patches/bytenode+1.3.7.dev.patch @@ -0,0 +1,381 @@ +diff --git a/node_modules/bytenode/lib/compileFile.js b/node_modules/bytenode/lib/compileFile.js +new file mode 100644 +index 0000000..314eeee +--- /dev/null ++++ b/node_modules/bytenode/lib/compileFile.js +@@ -0,0 +1,138 @@ ++'use strict'; ++ ++const fs = require('fs'); ++const path = require('path'); ++const Module = require('module'); ++const fork = require('child_process').fork; ++const { compileCode } = require('./index'); ++ ++const COMPILED_EXTNAME = '.jsc'; ++ ++/** ++ * This function runs the compileCode() function (above) ++ * via a child process usine Electron as Node ++ * @param {string} javascriptCode ++ * @returns {Promise} - returns a Promise which resolves in the generated bytecode. ++ */ ++const compileElectronCode = function (javascriptCode) { ++ return new Promise((resolve, reject) => { ++ let data = Buffer.from([]); ++ ++ const electronPath = path.join(path.dirname(require.resolve('electron')), 'cli.js'); ++ if (!fs.existsSync(electronPath)) { ++ throw new Error('Electron not installed'); ++ } ++ const bytenodePath = path.join(__dirname, 'cli.js'); ++ ++ // create a subprocess in which we run Electron as our Node and V8 engine ++ // running Bytenode to compile our code through stdin/stdout ++ const proc = fork(electronPath, [bytenodePath, '--compile', '--no-module', '-'], { ++ env: { ELECTRON_RUN_AS_NODE: '1' }, ++ stdio: ['pipe', 'pipe', 'pipe', 'ipc'] ++ }); ++ ++ if (proc.stdin) { ++ proc.stdin.write(javascriptCode); ++ proc.stdin.end(); ++ } ++ ++ if (proc.stdout) { ++ proc.stdout.on('data', (chunk) => { ++ data = Buffer.concat([data, chunk]); ++ }); ++ proc.stdout.on('error', (err) => { ++ console.error(err); ++ }); ++ proc.stdout.on('end', () => { ++ resolve(data); ++ }); ++ } ++ ++ if (proc.stderr) { ++ proc.stderr.on('data', (chunk) => { ++ console.error('Error: ', chunk.toString()); ++ }); ++ proc.stderr.on('error', (err) => { ++ console.error('Error: ', err); ++ }); ++ } ++ ++ proc.addListener('message', (message) => console.log(message)); ++ proc.addListener('error', err => console.error(err)); ++ ++ proc.on('error', (err) => reject(err)); ++ proc.on('exit', () => { resolve(data); }); ++ }); ++}; ++ ++/** ++ * Compiles JavaScript file to .jsc file. ++ * @param {object|string} args ++ * @param {string} args.filename The JavaScript source file that will be compiled ++ * @param {boolean} [args.compileAsModule=true] If true, the output will be a commonjs module ++ * @param {string} [args.output=filename.jsc] The output filename. Defaults to the same path and name of the original file, but with `.jsc` extension. ++ * @param {boolean} [args.electron=false] If true, compile code for Electron (which needs to be installed) ++ * @param {boolean} [args.createLoader=false] If true, create a loader file. ++ * @param {boolean} [args.loaderFilename='%.loader.js'] Filename or pattern for generated loader files. Defaults to originalFilename.loader.js. Use % as a substitute for originalFilename. ++ * @param {string} [output] The output filename. (Deprecated: use args.output instead) ++ * @returns {Promise} A Promise which returns the compiled filename ++ */ ++ const compileFile = async function (args, output) { ++ let filename, compileAsModule, electron, createLoader, loaderFilename; ++ ++ if (typeof args === 'string') { ++ filename = args; ++ compileAsModule = true; ++ electron = false; ++ createLoader = false; ++ } else if (typeof args === 'object') { ++ filename = args.filename; ++ compileAsModule = args.compileAsModule !== false; ++ electron = args.electron; ++ createLoader = args.createLoader; ++ loaderFilename = args.loaderFilename; ++ if (loaderFilename) createLoader = true; ++ } ++ ++ if (typeof filename !== 'string') { ++ throw new Error(`filename must be a string. ${typeof filename} was given.`); ++ } ++ ++ // @ts-ignore ++ const compiledFilename = args.output || output || filename.slice(0, -3) + COMPILED_EXTNAME; ++ ++ if (typeof compiledFilename !== 'string') { ++ throw new Error(`output must be a string. ${typeof compiledFilename} was given.`); ++ } ++ ++ const javascriptCode = fs.readFileSync(filename, 'utf-8'); ++ ++ let code; ++ ++ if (compileAsModule) { ++ code = Module.wrap(javascriptCode.replace(/^#!.*/, '')); ++ } else { ++ code = javascriptCode.replace(/^#!.*/, ''); ++ } ++ ++ let bytecodeBuffer; ++ ++ if (electron) { ++ bytecodeBuffer = await compileElectronCode(code); ++ } else { ++ bytecodeBuffer = compileCode(code); ++ } ++ ++ fs.writeFileSync(compiledFilename, bytecodeBuffer); ++ ++ if (createLoader) { ++ addLoaderFile(compiledFilename, loaderFilename); ++ } ++ ++ return compiledFilename; ++}; ++ ++module.exports = { ++ compileFile, ++ compileElectronCode, ++}; +diff --git a/node_modules/bytenode/lib/index.js b/node_modules/bytenode/lib/index.js +index cdd98cc..3f451d8 100644 +--- a/node_modules/bytenode/lib/index.js ++++ b/node_modules/bytenode/lib/index.js +@@ -5,7 +5,6 @@ const vm = require('vm'); + const v8 = require('v8'); + const path = require('path'); + const Module = require('module'); +-const fork = require('child_process').fork; + + v8.setFlagsFromString('--no-lazy'); + +@@ -36,63 +35,6 @@ const compileCode = function (javascriptCode) { + return bytecodeBuffer; + }; + +-/** +- * This function runs the compileCode() function (above) +- * via a child process usine Electron as Node +- * @param {string} javascriptCode +- * @returns {Promise} - returns a Promise which resolves in the generated bytecode. +- */ +-const compileElectronCode = function (javascriptCode) { +- return new Promise((resolve, reject) => { +- let data = Buffer.from([]); +- +- const electronPath = path.join(path.dirname(require.resolve('electron')), 'cli.js'); +- if (!fs.existsSync(electronPath)) { +- throw new Error('Electron not installed'); +- } +- const bytenodePath = path.join(__dirname, 'cli.js'); +- +- // create a subprocess in which we run Electron as our Node and V8 engine +- // running Bytenode to compile our code through stdin/stdout +- const proc = fork(electronPath, [bytenodePath, '--compile', '--no-module', '-'], { +- env: { ELECTRON_RUN_AS_NODE: '1' }, +- stdio: ['pipe', 'pipe', 'pipe', 'ipc'] +- }); +- +- if (proc.stdin) { +- proc.stdin.write(javascriptCode); +- proc.stdin.end(); +- } +- +- if (proc.stdout) { +- proc.stdout.on('data', (chunk) => { +- data = Buffer.concat([data, chunk]); +- }); +- proc.stdout.on('error', (err) => { +- console.error(err); +- }); +- proc.stdout.on('end', () => { +- resolve(data); +- }); +- } +- +- if (proc.stderr) { +- proc.stderr.on('data', (chunk) => { +- console.error('Error: ', chunk.toString()); +- }); +- proc.stderr.on('error', (err) => { +- console.error('Error: ', err); +- }); +- } +- +- proc.addListener('message', (message) => console.log(message)); +- proc.addListener('error', err => console.error(err)); +- +- proc.on('error', (err) => reject(err)); +- proc.on('exit', () => { resolve(data); }); +- }); +-}; +- + // TODO: rewrite this function + const fixBytecode = function (bytecodeBuffer) { + if (!Buffer.isBuffer(bytecodeBuffer)) { +@@ -136,119 +78,6 @@ const readSourceHash = function (bytecodeBuffer) { + } + }; + +-/** +- * Runs v8 bytecode buffer and returns the result. +- * @param {Buffer} bytecodeBuffer The buffer object that was created using compileCode function. +- * @returns {any} The result of the very last statement executed in the script. +- */ +-const runBytecode = function (bytecodeBuffer) { +- if (!Buffer.isBuffer(bytecodeBuffer)) { +- throw new Error('bytecodeBuffer must be a buffer object.'); +- } +- +- fixBytecode(bytecodeBuffer); +- +- const length = readSourceHash(bytecodeBuffer); +- +- let dummyCode = ''; +- +- if (length > 1) { +- dummyCode = '"' + '\u200b'.repeat(length - 2) + '"'; // "\u200b" Zero width space +- } +- +- const script = new vm.Script(dummyCode, { +- cachedData: bytecodeBuffer +- }); +- +- if (script.cachedDataRejected) { +- throw new Error('Invalid or incompatible cached data (cachedDataRejected)'); +- } +- +- return script.runInThisContext(); +-}; +- +-/** +- * Compiles JavaScript file to .jsc file. +- * @param {object|string} args +- * @param {string} args.filename The JavaScript source file that will be compiled +- * @param {boolean} [args.compileAsModule=true] If true, the output will be a commonjs module +- * @param {string} [args.output=filename.jsc] The output filename. Defaults to the same path and name of the original file, but with `.jsc` extension. +- * @param {boolean} [args.electron=false] If true, compile code for Electron (which needs to be installed) +- * @param {boolean} [args.createLoader=false] If true, create a loader file. +- * @param {boolean} [args.loaderFilename='%.loader.js'] Filename or pattern for generated loader files. Defaults to originalFilename.loader.js. Use % as a substitute for originalFilename. +- * @param {string} [output] The output filename. (Deprecated: use args.output instead) +- * @returns {Promise} A Promise which returns the compiled filename +- */ +-const compileFile = async function (args, output) { +- let filename, compileAsModule, electron, createLoader, loaderFilename; +- +- if (typeof args === 'string') { +- filename = args; +- compileAsModule = true; +- electron = false; +- createLoader = false; +- } else if (typeof args === 'object') { +- filename = args.filename; +- compileAsModule = args.compileAsModule !== false; +- electron = args.electron; +- createLoader = args.createLoader; +- loaderFilename = args.loaderFilename; +- if (loaderFilename) createLoader = true; +- } +- +- if (typeof filename !== 'string') { +- throw new Error(`filename must be a string. ${typeof filename} was given.`); +- } +- +- // @ts-ignore +- const compiledFilename = args.output || output || filename.slice(0, -3) + COMPILED_EXTNAME; +- +- if (typeof compiledFilename !== 'string') { +- throw new Error(`output must be a string. ${typeof compiledFilename} was given.`); +- } +- +- const javascriptCode = fs.readFileSync(filename, 'utf-8'); +- +- let code; +- +- if (compileAsModule) { +- code = Module.wrap(javascriptCode.replace(/^#!.*/, '')); +- } else { +- code = javascriptCode.replace(/^#!.*/, ''); +- } +- +- let bytecodeBuffer; +- +- if (electron) { +- bytecodeBuffer = await compileElectronCode(code); +- } else { +- bytecodeBuffer = compileCode(code); +- } +- +- fs.writeFileSync(compiledFilename, bytecodeBuffer); +- +- if (createLoader) { +- addLoaderFile(compiledFilename, loaderFilename); +- } +- +- return compiledFilename; +-}; +- +-/** +- * Runs .jsc file and returns the result. +- * @param {string} filename +- * @returns {any} The result of the very last statement executed in the script. +- */ +-const runBytecodeFile = function (filename) { +- if (typeof filename !== 'string') { +- throw new Error(`filename must be a string. ${typeof filename} was given.`); +- } +- +- const bytecodeBuffer = fs.readFileSync(filename); +- +- return runBytecode(bytecodeBuffer); +-}; +- + Module._extensions[COMPILED_EXTNAME] = function (fileModule, filename) { + const bytecodeBuffer = fs.readFileSync(filename); + +@@ -308,39 +137,6 @@ Module._extensions[COMPILED_EXTNAME] = function (fileModule, filename) { + return compiledWrapper.apply(fileModule.exports, args); + }; + +-/** +- * Add a loader file for a given .jsc file +- * @param {String} fileToLoad path of the .jsc file we're loading +- * @param {String} loaderFilename - optional pattern or name of the file to write - defaults to filename.loader.js. Patterns: "%" represents the root name of .jsc file. +- */ +-const addLoaderFile = function (fileToLoad, loaderFilename) { +- let loaderFilePath; +- if (typeof loaderFilename === 'boolean' || loaderFilename === undefined || loaderFilename === '') { +- loaderFilePath = fileToLoad.replace('.jsc', '.loader.js'); +- } else { +- loaderFilename = loaderFilename.replace('%', path.parse(fileToLoad).name); +- loaderFilePath = path.join(path.dirname(fileToLoad), loaderFilename); +- } +- const relativePath = path.relative(path.dirname(loaderFilePath), fileToLoad); +- const code = loaderCode('./' + relativePath); +- fs.writeFileSync(loaderFilePath, code); +-}; +- +-const loaderCode = function (targetPath) { +- return ` +- require('bytenode'); +- require('${targetPath}'); +- `; +-}; +- +-global.bytenode = { ++module.exports = { + compileCode, +- compileFile, +- compileElectronCode, +- runBytecode, +- runBytecodeFile, +- addLoaderFile, +- loaderCode + }; +- +-module.exports = global.bytenode; diff --git a/patches/bytenode+1.3.7.patch b/patches/bytenode+1.3.7.patch deleted file mode 100644 index 0149649e8849..000000000000 --- a/patches/bytenode+1.3.7.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/node_modules/bytenode/lib/index.js b/node_modules/bytenode/lib/index.js -index cdd98cc..cc6b8fa 100644 ---- a/node_modules/bytenode/lib/index.js -+++ b/node_modules/bytenode/lib/index.js -@@ -327,10 +327,7 @@ const addLoaderFile = function (fileToLoad, loaderFilename) { - }; - - const loaderCode = function (targetPath) { -- return ` -- require('bytenode'); -- require('${targetPath}'); -- `; -+ return `require('bytenode');require('${targetPath}');`; - }; - - global.bytenode = { diff --git a/scripts/binary/binary-cleanup.js b/scripts/binary/binary-cleanup.js index 0b985fe1de9e..5bbf24cec7c4 100644 --- a/scripts/binary/binary-cleanup.js +++ b/scripts/binary/binary-cleanup.js @@ -6,7 +6,7 @@ const esbuild = require('esbuild') const snapshotMetadata = require('@tooling/v8-snapshot/cache/prod-darwin/snapshot-meta.cache.json') const tempDir = require('temp-dir') const workingDir = path.join(tempDir, 'binary-cleanup-workdir') -const bytenode = require('bytenode') +const bytenode = require('bytenode/lib/compileFile') fs.ensureDirSync(workingDir) diff --git a/scripts/binary/binary-integrity-check-source.js b/scripts/binary/binary-integrity-check-source.js index 289e5351a16f..3f1a890a073c 100644 --- a/scripts/binary/binary-integrity-check-source.js +++ b/scripts/binary/binary-integrity-check-source.js @@ -179,18 +179,18 @@ function integrityCheck (options) { fileName: 'evalmachine.', }, { - functionName: 'p._extensions.', + functionName: 'c._extensions.', methodName: '.jsc', // eslint-disable-next-line no-undef fileName: [appPath, 'index.js'].join(PATH_SEP), line: 1, - column: 4364, + column: 2076, }, { // eslint-disable-next-line no-undef fileName: [appPath, 'index.js'].join(PATH_SEP), line: 1, - column: 5049, + column: 2346, }, ], }) diff --git a/scripts/binary/smoke.js b/scripts/binary/smoke.js index 0a41aced014a..5f7d45ac6757 100644 --- a/scripts/binary/smoke.js +++ b/scripts/binary/smoke.js @@ -313,7 +313,7 @@ const runIntegrityTest = async function (buildAppExecutable, buildAppDir, e2e) { // Modify app await fs.writeFile(file, `console.log("rewritten code");const fs=require('fs');const { join } = require('path');fs.writeFileSync(join(__dirname,'index.js'),fs.readFileSync(join(__dirname,'index.js.bak')));${contents}`) - await runErroringProjectTest(buildAppExecutable, e2e, 'temporarily rewriting index.js', 'Integrity check failed with expected column number 4364 but got') + await runErroringProjectTest(buildAppExecutable, e2e, 'temporarily rewriting index.js', 'Integrity check failed with expected column number 2076 but got') // Restore original state await fs.move(backupFile, file, { overwrite: true }) From fe282492d48926a38390207a21d2f354ddb6bfa6 Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Mon, 12 Dec 2022 11:01:10 -0600 Subject: [PATCH 09/13] pr comments --- patches/bytenode+1.3.7.dev.patch | 453 ++++-------------- scripts/binary/binary-cleanup.js | 3 +- scripts/binary/binary-entry-point-source.js | 8 +- .../binary/binary-integrity-check-source.js | 16 +- scripts/binary/binary-sources.js | 1 + 5 files changed, 104 insertions(+), 377 deletions(-) diff --git a/patches/bytenode+1.3.7.dev.patch b/patches/bytenode+1.3.7.dev.patch index 2ac48f754980..8b7093470d6b 100644 --- a/patches/bytenode+1.3.7.dev.patch +++ b/patches/bytenode+1.3.7.dev.patch @@ -1,381 +1,112 @@ -diff --git a/node_modules/bytenode/lib/compileFile.js b/node_modules/bytenode/lib/compileFile.js -new file mode 100644 -index 0000000..314eeee ---- /dev/null -+++ b/node_modules/bytenode/lib/compileFile.js -@@ -0,0 +1,138 @@ -+'use strict'; -+ -+const fs = require('fs'); -+const path = require('path'); -+const Module = require('module'); -+const fork = require('child_process').fork; -+const { compileCode } = require('./index'); -+ -+const COMPILED_EXTNAME = '.jsc'; -+ -+/** -+ * This function runs the compileCode() function (above) -+ * via a child process usine Electron as Node -+ * @param {string} javascriptCode -+ * @returns {Promise} - returns a Promise which resolves in the generated bytecode. -+ */ -+const compileElectronCode = function (javascriptCode) { -+ return new Promise((resolve, reject) => { -+ let data = Buffer.from([]); -+ -+ const electronPath = path.join(path.dirname(require.resolve('electron')), 'cli.js'); -+ if (!fs.existsSync(electronPath)) { -+ throw new Error('Electron not installed'); -+ } -+ const bytenodePath = path.join(__dirname, 'cli.js'); -+ -+ // create a subprocess in which we run Electron as our Node and V8 engine -+ // running Bytenode to compile our code through stdin/stdout -+ const proc = fork(electronPath, [bytenodePath, '--compile', '--no-module', '-'], { -+ env: { ELECTRON_RUN_AS_NODE: '1' }, -+ stdio: ['pipe', 'pipe', 'pipe', 'ipc'] -+ }); -+ -+ if (proc.stdin) { -+ proc.stdin.write(javascriptCode); -+ proc.stdin.end(); -+ } -+ -+ if (proc.stdout) { -+ proc.stdout.on('data', (chunk) => { -+ data = Buffer.concat([data, chunk]); -+ }); -+ proc.stdout.on('error', (err) => { -+ console.error(err); -+ }); -+ proc.stdout.on('end', () => { -+ resolve(data); -+ }); -+ } -+ -+ if (proc.stderr) { -+ proc.stderr.on('data', (chunk) => { -+ console.error('Error: ', chunk.toString()); -+ }); -+ proc.stderr.on('error', (err) => { -+ console.error('Error: ', err); -+ }); -+ } -+ -+ proc.addListener('message', (message) => console.log(message)); -+ proc.addListener('error', err => console.error(err)); -+ -+ proc.on('error', (err) => reject(err)); -+ proc.on('exit', () => { resolve(data); }); -+ }); -+}; -+ -+/** -+ * Compiles JavaScript file to .jsc file. -+ * @param {object|string} args -+ * @param {string} args.filename The JavaScript source file that will be compiled -+ * @param {boolean} [args.compileAsModule=true] If true, the output will be a commonjs module -+ * @param {string} [args.output=filename.jsc] The output filename. Defaults to the same path and name of the original file, but with `.jsc` extension. -+ * @param {boolean} [args.electron=false] If true, compile code for Electron (which needs to be installed) -+ * @param {boolean} [args.createLoader=false] If true, create a loader file. -+ * @param {boolean} [args.loaderFilename='%.loader.js'] Filename or pattern for generated loader files. Defaults to originalFilename.loader.js. Use % as a substitute for originalFilename. -+ * @param {string} [output] The output filename. (Deprecated: use args.output instead) -+ * @returns {Promise} A Promise which returns the compiled filename -+ */ -+ const compileFile = async function (args, output) { -+ let filename, compileAsModule, electron, createLoader, loaderFilename; -+ -+ if (typeof args === 'string') { -+ filename = args; -+ compileAsModule = true; -+ electron = false; -+ createLoader = false; -+ } else if (typeof args === 'object') { -+ filename = args.filename; -+ compileAsModule = args.compileAsModule !== false; -+ electron = args.electron; -+ createLoader = args.createLoader; -+ loaderFilename = args.loaderFilename; -+ if (loaderFilename) createLoader = true; -+ } -+ -+ if (typeof filename !== 'string') { -+ throw new Error(`filename must be a string. ${typeof filename} was given.`); -+ } -+ -+ // @ts-ignore -+ const compiledFilename = args.output || output || filename.slice(0, -3) + COMPILED_EXTNAME; -+ -+ if (typeof compiledFilename !== 'string') { -+ throw new Error(`output must be a string. ${typeof compiledFilename} was given.`); -+ } -+ -+ const javascriptCode = fs.readFileSync(filename, 'utf-8'); -+ -+ let code; -+ -+ if (compileAsModule) { -+ code = Module.wrap(javascriptCode.replace(/^#!.*/, '')); -+ } else { -+ code = javascriptCode.replace(/^#!.*/, ''); -+ } -+ -+ let bytecodeBuffer; -+ -+ if (electron) { -+ bytecodeBuffer = await compileElectronCode(code); -+ } else { -+ bytecodeBuffer = compileCode(code); -+ } -+ -+ fs.writeFileSync(compiledFilename, bytecodeBuffer); -+ -+ if (createLoader) { -+ addLoaderFile(compiledFilename, loaderFilename); -+ } -+ -+ return compiledFilename; -+}; -+ -+module.exports = { -+ compileFile, -+ compileElectronCode, -+}; +diff --git a/node_modules/bytenode/lib/cli.js b/node_modules/bytenode/lib/cli.js +index 9f57493..3ba173e 100755 +--- a/node_modules/bytenode/lib/cli.js ++++ b/node_modules/bytenode/lib/cli.js +@@ -2,11 +2,15 @@ + + 'use strict'; + +-const fs = require('fs'); +-const path = require('path'); +-const wrap = require('module').wrap; +-const spawnSync = require('child_process').spawnSync; +-const bytenode = require('./index.js'); ++import fs from 'fs'; ++import path from 'path'; ++import * as mod from 'module'; ++import { spawnSync } from 'child_process'; ++import * as bytenode from './index.js'; ++import * as url from 'url'; ++ ++const __filename = url.fileURLToPath(import.meta.url); ++const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); + + const args = process.argv.slice(2); + +@@ -100,7 +104,7 @@ if (program.flags.includes('--compile')) { + if (program.flags.includes('--no-module')) { + process.stdout.write(bytenode.compileCode(script)); + } else { +- process.stdout.write(bytenode.compileCode(wrap(script))); ++ process.stdout.write(bytenode.compileCode(mod.wrap(script))); + } + } catch (error) { + console.error(error); +@@ -136,13 +140,6 @@ if (program.flags.includes('--compile')) { + $ echo 'console.log("Hello");' | bytenode --compile - > hello.jsc + compile from stdin and save to \`hello.jsc\` + `); +-} else if (program.flags.includes('--version') && program.flags.length === 1 && program.files.length === 0) { +- const pkg = require('../package.json'); +- console.log(pkg.name, pkg.version); +- console.log('Node', process.versions.node); +- if (process.versions.electron) { +- console.log('Electron', process.versions.electron); +- } + } else { + try { + spawnSync(program.nodeBin, [ diff --git a/node_modules/bytenode/lib/index.js b/node_modules/bytenode/lib/index.js -index cdd98cc..3f451d8 100644 +index cdd98cc..635bc27 100644 --- a/node_modules/bytenode/lib/index.js +++ b/node_modules/bytenode/lib/index.js -@@ -5,7 +5,6 @@ const vm = require('vm'); - const v8 = require('v8'); - const path = require('path'); - const Module = require('module'); +@@ -1,11 +1,13 @@ + 'use strict'; + +-const fs = require('fs'); +-const vm = require('vm'); +-const v8 = require('v8'); +-const path = require('path'); +-const Module = require('module'); -const fork = require('child_process').fork; ++import fs from 'fs'; ++import vm from 'vm'; ++import v8 from 'v8'; ++import path from 'path'; ++import Module from 'module'; ++import { fork } from 'child_process'; ++import { createRequire } from 'module'; ++import * as url from 'url'; v8.setFlagsFromString('--no-lazy'); -@@ -36,63 +35,6 @@ const compileCode = function (javascriptCode) { - return bytecodeBuffer; - }; +@@ -46,10 +48,12 @@ const compileElectronCode = function (javascriptCode) { + return new Promise((resolve, reject) => { + let data = Buffer.from([]); --/** -- * This function runs the compileCode() function (above) -- * via a child process usine Electron as Node -- * @param {string} javascriptCode -- * @returns {Promise} - returns a Promise which resolves in the generated bytecode. -- */ --const compileElectronCode = function (javascriptCode) { -- return new Promise((resolve, reject) => { -- let data = Buffer.from([]); -- -- const electronPath = path.join(path.dirname(require.resolve('electron')), 'cli.js'); -- if (!fs.existsSync(electronPath)) { -- throw new Error('Electron not installed'); -- } -- const bytenodePath = path.join(__dirname, 'cli.js'); -- -- // create a subprocess in which we run Electron as our Node and V8 engine -- // running Bytenode to compile our code through stdin/stdout -- const proc = fork(electronPath, [bytenodePath, '--compile', '--no-module', '-'], { -- env: { ELECTRON_RUN_AS_NODE: '1' }, -- stdio: ['pipe', 'pipe', 'pipe', 'ipc'] -- }); -- -- if (proc.stdin) { -- proc.stdin.write(javascriptCode); -- proc.stdin.end(); -- } -- -- if (proc.stdout) { -- proc.stdout.on('data', (chunk) => { -- data = Buffer.concat([data, chunk]); -- }); -- proc.stdout.on('error', (err) => { -- console.error(err); -- }); -- proc.stdout.on('end', () => { -- resolve(data); -- }); -- } -- -- if (proc.stderr) { -- proc.stderr.on('data', (chunk) => { -- console.error('Error: ', chunk.toString()); -- }); -- proc.stderr.on('error', (err) => { -- console.error('Error: ', err); -- }); -- } -- -- proc.addListener('message', (message) => console.log(message)); -- proc.addListener('error', err => console.error(err)); -- -- proc.on('error', (err) => reject(err)); -- proc.on('exit', () => { resolve(data); }); -- }); --}; -- - // TODO: rewrite this function - const fixBytecode = function (bytecodeBuffer) { - if (!Buffer.isBuffer(bytecodeBuffer)) { -@@ -136,119 +78,6 @@ const readSourceHash = function (bytecodeBuffer) { - } ++ const require = createRequire(import.meta.url) + const electronPath = path.join(path.dirname(require.resolve('electron')), 'cli.js'); + if (!fs.existsSync(electronPath)) { + throw new Error('Electron not installed'); + } ++ const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); + const bytenodePath = path.join(__dirname, 'cli.js'); + + // create a subprocess in which we run Electron as our Node and V8 engine +@@ -249,7 +253,7 @@ const runBytecodeFile = function (filename) { + return runBytecode(bytecodeBuffer); }; --/** -- * Runs v8 bytecode buffer and returns the result. -- * @param {Buffer} bytecodeBuffer The buffer object that was created using compileCode function. -- * @returns {any} The result of the very last statement executed in the script. -- */ --const runBytecode = function (bytecodeBuffer) { -- if (!Buffer.isBuffer(bytecodeBuffer)) { -- throw new Error('bytecodeBuffer must be a buffer object.'); -- } -- -- fixBytecode(bytecodeBuffer); -- -- const length = readSourceHash(bytecodeBuffer); -- -- let dummyCode = ''; -- -- if (length > 1) { -- dummyCode = '"' + '\u200b'.repeat(length - 2) + '"'; // "\u200b" Zero width space -- } -- -- const script = new vm.Script(dummyCode, { -- cachedData: bytecodeBuffer -- }); -- -- if (script.cachedDataRejected) { -- throw new Error('Invalid or incompatible cached data (cachedDataRejected)'); -- } -- -- return script.runInThisContext(); --}; -- --/** -- * Compiles JavaScript file to .jsc file. -- * @param {object|string} args -- * @param {string} args.filename The JavaScript source file that will be compiled -- * @param {boolean} [args.compileAsModule=true] If true, the output will be a commonjs module -- * @param {string} [args.output=filename.jsc] The output filename. Defaults to the same path and name of the original file, but with `.jsc` extension. -- * @param {boolean} [args.electron=false] If true, compile code for Electron (which needs to be installed) -- * @param {boolean} [args.createLoader=false] If true, create a loader file. -- * @param {boolean} [args.loaderFilename='%.loader.js'] Filename or pattern for generated loader files. Defaults to originalFilename.loader.js. Use % as a substitute for originalFilename. -- * @param {string} [output] The output filename. (Deprecated: use args.output instead) -- * @returns {Promise} A Promise which returns the compiled filename -- */ --const compileFile = async function (args, output) { -- let filename, compileAsModule, electron, createLoader, loaderFilename; -- -- if (typeof args === 'string') { -- filename = args; -- compileAsModule = true; -- electron = false; -- createLoader = false; -- } else if (typeof args === 'object') { -- filename = args.filename; -- compileAsModule = args.compileAsModule !== false; -- electron = args.electron; -- createLoader = args.createLoader; -- loaderFilename = args.loaderFilename; -- if (loaderFilename) createLoader = true; -- } -- -- if (typeof filename !== 'string') { -- throw new Error(`filename must be a string. ${typeof filename} was given.`); -- } -- -- // @ts-ignore -- const compiledFilename = args.output || output || filename.slice(0, -3) + COMPILED_EXTNAME; -- -- if (typeof compiledFilename !== 'string') { -- throw new Error(`output must be a string. ${typeof compiledFilename} was given.`); -- } -- -- const javascriptCode = fs.readFileSync(filename, 'utf-8'); -- -- let code; -- -- if (compileAsModule) { -- code = Module.wrap(javascriptCode.replace(/^#!.*/, '')); -- } else { -- code = javascriptCode.replace(/^#!.*/, ''); -- } -- -- let bytecodeBuffer; -- -- if (electron) { -- bytecodeBuffer = await compileElectronCode(code); -- } else { -- bytecodeBuffer = compileCode(code); -- } -- -- fs.writeFileSync(compiledFilename, bytecodeBuffer); -- -- if (createLoader) { -- addLoaderFile(compiledFilename, loaderFilename); -- } -- -- return compiledFilename; --}; -- --/** -- * Runs .jsc file and returns the result. -- * @param {string} filename -- * @returns {any} The result of the very last statement executed in the script. -- */ --const runBytecodeFile = function (filename) { -- if (typeof filename !== 'string') { -- throw new Error(`filename must be a string. ${typeof filename} was given.`); -- } -- -- const bytecodeBuffer = fs.readFileSync(filename); -- -- return runBytecode(bytecodeBuffer); --}; -- - Module._extensions[COMPILED_EXTNAME] = function (fileModule, filename) { +-Module._extensions[COMPILED_EXTNAME] = function (fileModule, filename) { ++const runBytecodeAsModule = function (fileModule, filename) { const bytecodeBuffer = fs.readFileSync(filename); -@@ -308,39 +137,6 @@ Module._extensions[COMPILED_EXTNAME] = function (fileModule, filename) { - return compiledWrapper.apply(fileModule.exports, args); + fixBytecode(bytecodeBuffer); +@@ -333,14 +337,13 @@ const loaderCode = function (targetPath) { + `; }; --/** -- * Add a loader file for a given .jsc file -- * @param {String} fileToLoad path of the .jsc file we're loading -- * @param {String} loaderFilename - optional pattern or name of the file to write - defaults to filename.loader.js. Patterns: "%" represents the root name of .jsc file. -- */ --const addLoaderFile = function (fileToLoad, loaderFilename) { -- let loaderFilePath; -- if (typeof loaderFilename === 'boolean' || loaderFilename === undefined || loaderFilename === '') { -- loaderFilePath = fileToLoad.replace('.jsc', '.loader.js'); -- } else { -- loaderFilename = loaderFilename.replace('%', path.parse(fileToLoad).name); -- loaderFilePath = path.join(path.dirname(fileToLoad), loaderFilename); -- } -- const relativePath = path.relative(path.dirname(loaderFilePath), fileToLoad); -- const code = loaderCode('./' + relativePath); -- fs.writeFileSync(loaderFilePath, code); --}; -- --const loaderCode = function (targetPath) { -- return ` -- require('bytenode'); -- require('${targetPath}'); -- `; --}; -- -global.bytenode = { -+module.exports = { ++export { compileCode, -- compileFile, -- compileElectronCode, -- runBytecode, -- runBytecodeFile, -- addLoaderFile, + compileFile, + compileElectronCode, + runBytecode, + runBytecodeFile, + addLoaderFile, - loaderCode ++ loaderCode, ++ runBytecodeAsModule, }; - -module.exports = global.bytenode; diff --git a/scripts/binary/binary-cleanup.js b/scripts/binary/binary-cleanup.js index 5bbf24cec7c4..7df26766fdce 100644 --- a/scripts/binary/binary-cleanup.js +++ b/scripts/binary/binary-cleanup.js @@ -6,7 +6,6 @@ const esbuild = require('esbuild') const snapshotMetadata = require('@tooling/v8-snapshot/cache/prod-darwin/snapshot-meta.cache.json') const tempDir = require('temp-dir') const workingDir = path.join(tempDir, 'binary-cleanup-workdir') -const bytenode = require('bytenode/lib/compileFile') fs.ensureDirSync(workingDir) @@ -137,6 +136,8 @@ const createServerEntryPointBundle = async (buildAppDir) => { console.log(`compiling server entry point bundle to ${path.join(buildAppDir, 'packages', 'server', 'index.jsc')}`) // Use bytenode to compile the entry point bundle. This will save time on the v8 compile step and ensure the integrity of the entry point + const bytenode = await import('bytenode') + await bytenode.compileFile({ filename: path.join(buildAppDir, 'packages', 'server', 'index.js'), output: path.join(buildAppDir, 'packages', 'server', 'index.jsc'), diff --git a/scripts/binary/binary-entry-point-source.js b/scripts/binary/binary-entry-point-source.js index fcab4c31418c..4bccda2d553b 100644 --- a/scripts/binary/binary-entry-point-source.js +++ b/scripts/binary/binary-entry-point-source.js @@ -1,13 +1,13 @@ -const Module = require('module') -const path = require('path') +import Module from 'module' +import path from 'path' +import { runBytecodeAsModule } from 'bytenode' process.env.CYPRESS_INTERNAL_ENV = process.env.CYPRESS_INTERNAL_ENV || 'production' try { - require('bytenode') const filename = path.join(__dirname, 'packages', 'server', 'index.jsc') const dirname = path.dirname(filename) - Module._extensions['.jsc']({ + runBytecodeAsModule({ require: module.require, id: filename, filename, diff --git a/scripts/binary/binary-integrity-check-source.js b/scripts/binary/binary-integrity-check-source.js index 3f1a890a073c..7d5e1ab66880 100644 --- a/scripts/binary/binary-integrity-check-source.js +++ b/scripts/binary/binary-integrity-check-source.js @@ -35,23 +35,17 @@ const stackIntegrityCheck = function stackIntegrityCheck (options) { } for (let index = 0; index < options.stackToMatch.length; index++) { - const { functionName: expectedFunctionName, methodName: expectedMethodName, fileName: expectedFileName, line: expectedLineNumber, column: expectedColumnNumber } = options.stackToMatch[index] + const { functionName: expectedFunctionName, fileName: expectedFileName, line: expectedLineNumber, column: expectedColumnNumber } = options.stackToMatch[index] const actualFunctionName = stack[index].getFunctionName() const actualFileName = stack[index].getFileName() const actualColumnNumber = stack[index].getColumnNumber() const actualLineNumber = stack[index].getLineNumber() - const actualMethodName = stack[index].getMethodName() if (expectedFunctionName && actualFunctionName !== expectedFunctionName) { console.error(`Integrity check failed with expected function name ${expectedFunctionName} but got ${actualFunctionName}`) throw new Error(integrityErrorMessage) } - if (expectedMethodName && actualMethodName !== expectedMethodName) { - console.error(`Integrity check failed with expected method name ${expectedMethodName} but got ${actualMethodName}`) - throw new Error(integrityErrorMessage) - } - if (expectedFileName && actualFileName !== expectedFileName) { console.error(`Integrity check failed with expected file name ${expectedFileName} but got ${actualFileName}`) throw new Error(integrityErrorMessage) @@ -157,6 +151,7 @@ function integrityCheck (options) { fileName: '', }, { + functionName: 'setGlobals', fileName: '', }, { @@ -179,18 +174,17 @@ function integrityCheck (options) { fileName: 'evalmachine.', }, { - functionName: 'c._extensions.', - methodName: '.jsc', + functionName: 'v', // eslint-disable-next-line no-undef fileName: [appPath, 'index.js'].join(PATH_SEP), line: 1, - column: 2076, + column: 2573, }, { // eslint-disable-next-line no-undef fileName: [appPath, 'index.js'].join(PATH_SEP), line: 1, - column: 2346, + column: 2764, }, ], }) diff --git a/scripts/binary/binary-sources.js b/scripts/binary/binary-sources.js index 63293369115c..e754ca050922 100644 --- a/scripts/binary/binary-sources.js +++ b/scripts/binary/binary-sources.js @@ -18,6 +18,7 @@ const getBinaryEntryPointSource = async () => { platform: 'node', write: false, minify: true, + treeShaking: true, }) return esbuildResult.outputFiles[0].text From ea697f63f214a8f3c71675719d6f4d14fe4958e2 Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Mon, 12 Dec 2022 11:08:58 -0600 Subject: [PATCH 10/13] fix smoke test --- scripts/binary/smoke.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/binary/smoke.js b/scripts/binary/smoke.js index 5f7d45ac6757..879c5e68e5b9 100644 --- a/scripts/binary/smoke.js +++ b/scripts/binary/smoke.js @@ -313,7 +313,7 @@ const runIntegrityTest = async function (buildAppExecutable, buildAppDir, e2e) { // Modify app await fs.writeFile(file, `console.log("rewritten code");const fs=require('fs');const { join } = require('path');fs.writeFileSync(join(__dirname,'index.js'),fs.readFileSync(join(__dirname,'index.js.bak')));${contents}`) - await runErroringProjectTest(buildAppExecutable, e2e, 'temporarily rewriting index.js', 'Integrity check failed with expected column number 2076 but got') + await runErroringProjectTest(buildAppExecutable, e2e, 'temporarily rewriting index.js', 'Integrity check failed with expected column number 2573 but got') // Restore original state await fs.move(backupFile, file, { overwrite: true }) From 082b495278c99134b9931011ba4cb06e45479c84 Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Mon, 12 Dec 2022 11:45:32 -0600 Subject: [PATCH 11/13] fix build --- patches/bytenode+1.3.7.dev.patch | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/patches/bytenode+1.3.7.dev.patch b/patches/bytenode+1.3.7.dev.patch index 8b7093470d6b..ef1f3800ce8f 100644 --- a/patches/bytenode+1.3.7.dev.patch +++ b/patches/bytenode+1.3.7.dev.patch @@ -110,3 +110,15 @@ index cdd98cc..635bc27 100644 }; - -module.exports = global.bytenode; +diff --git a/node_modules/bytenode/package.json b/node_modules/bytenode/package.json +index 6caff7c..72e2c46 100644 +--- a/node_modules/bytenode/package.json ++++ b/node_modules/bytenode/package.json +@@ -3,6 +3,7 @@ + "version": "1.3.7", + "description": "A minimalist bytecode compiler for Node.js", + "main": "lib/index.js", ++ "type": "module", + "bin": "lib/cli.js", + "types": "lib/index.d.ts", + "files": [ From a833145f8079a860faf949366f8743ac0eab805c Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Mon, 12 Dec 2022 12:18:57 -0600 Subject: [PATCH 12/13] fix build --- scripts/binary/binary-integrity-check-source.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/binary/binary-integrity-check-source.js b/scripts/binary/binary-integrity-check-source.js index 7d5e1ab66880..50a800a37570 100644 --- a/scripts/binary/binary-integrity-check-source.js +++ b/scripts/binary/binary-integrity-check-source.js @@ -151,7 +151,6 @@ function integrityCheck (options) { fileName: '', }, { - functionName: 'setGlobals', fileName: '', }, { From a29c08c264c2e1f7d61b3f93491a3b37052bfcfc Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Mon, 12 Dec 2022 13:15:45 -0600 Subject: [PATCH 13/13] Update cache-version.txt --- .circleci/cache-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/cache-version.txt b/.circleci/cache-version.txt index ac501d1253cf..125dd7e97cdf 100644 --- a/.circleci/cache-version.txt +++ b/.circleci/cache-version.txt @@ -1,3 +1,3 @@ # Bump this version to force CI to re-create the cache from scratch. -12-05-22 +12-12-22