fix: limit the number of globals defined due to the v8 snapshot (#25051)

This commit is contained in:
Ryan Manuel
2022-12-08 09:35:58 -06:00
committed by GitHub
parent c540284f50
commit f9541aff10
7 changed files with 121 additions and 110 deletions

View File

@@ -28,7 +28,7 @@ mainBuildFilters: &mainBuildFilters
only:
- develop
- /^release\/\d+\.\d+\.\d+$/
- 'ryanm/fix/cy-in-cy-and-v8-snapshots'
- 'ryanm/fix/issue-with-integrity-check'
# 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
@@ -37,7 +37,7 @@ macWorkflowFilters: &darwin-workflow-filters
when:
or:
- equal: [ develop, << pipeline.git.branch >> ]
- equal: [ 'ryanm/fix/cy-in-cy-and-v8-snapshots', << pipeline.git.branch >> ]
- equal: [ 'ryanm/fix/issue-with-integrity-check', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
@@ -45,7 +45,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
when:
or:
- equal: [ develop, << pipeline.git.branch >> ]
- equal: [ 'ryanm/fix/cy-in-cy-and-v8-snapshots', << pipeline.git.branch >> ]
- equal: [ 'ryanm/fix/issue-with-integrity-check', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
@@ -63,7 +63,7 @@ windowsWorkflowFilters: &windows-workflow-filters
when:
or:
- equal: [ develop, << pipeline.git.branch >> ]
- equal: [ 'ryanm/fix/cy-in-cy-and-v8-snapshots', << pipeline.git.branch >> ]
- equal: [ 'ryanm/fix/issue-with-integrity-check', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
@@ -129,7 +129,7 @@ commands:
- run:
name: Check current branch to persist artifacts
command: |
if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "ryanm/fix/cy-in-cy-and-v8-snapshots" ]]; then
if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "ryanm/fix/issue-with-integrity-check" ]]; then
echo "Not uploading artifacts or posting install comment for this branch."
circleci-agent step halt
fi

View File

@@ -47,9 +47,9 @@ chai.use(chaiSubset)
chai.use(sinonChai)
export async function e2ePluginSetup (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) {
// @ts-ignore snapshotAuxiliaryData is injected by the snapshot script
if (typeof global.snapshotAuxiliaryData === 'undefined') {
throw new Error('snapshotAuxiliaryData is undefined. v8 snapshots are not being used in Cypress in Cypress')
// @ts-ignore getSnapshotResult is injected by the snapshot script
if (typeof global.getSnapshotResult === 'undefined') {
throw new Error('getSnapshotResult is undefined. v8 snapshots are not being used in Cypress in Cypress')
}
process.env.CYPRESS_INTERNAL_E2E_TESTING_SELF = 'true'

View File

@@ -207,20 +207,16 @@ export function snapshotRequire (
let moduleNeedsReload: ModuleNeedsReload | undefined
// @ts-ignore global snapshotAuxiliaryData
if (typeof snapshotAuxiliaryData !== 'undefined') {
// @ts-ignore global snapshotAuxiliaryData
resolverMap = snapshotAuxiliaryData.resolverMap
const dependencyMapArray: DependencyMapArray =
// @ts-ignore global snapshotAuxiliaryData
snapshotAuxiliaryData.dependencyMapArray
resolverMap = sr.snapshotAuxiliaryData.resolverMap
// @ts-ignore global snapshotAuxiliaryData
const dependencyMapArray: DependencyMapArray = sr.snapshotAuxiliaryData.dependencyMapArray
// 5. Setup the module needs reload predicate with the dependency map
if (dependencyMapArray != null) {
moduleNeedsReload = createModuleNeedsReload(
dependencyMapArray,
projectBaseDir,
)
}
// 5. Setup the module needs reload predicate with the dependency map
if (dependencyMapArray != null) {
moduleNeedsReload = createModuleNeedsReload(
dependencyMapArray,
projectBaseDir,
)
}
// 6. Setup the module key resolver with the resolver map

View File

@@ -287,6 +287,21 @@ const runIntegrityTest = async function (buildAppExecutable, buildAppDir, e2e) {
await testAlteringEntryPoint('console.log("simple alteration")', 'Integrity check failed with expected stack length 9 but got 10')
await testAlteringEntryPoint('console.log("accessing " + global.getSnapshotResult())', 'getSnapshotResult can only be called once')
function compareGlobals () {
const childProcess = require('child_process')
const nodeGlobalKeys = JSON.parse(childProcess.spawnSync('node -p "const x = Object.getOwnPropertyNames(global);JSON.stringify(x)"', { shell: true, encoding: 'utf8' }).stdout)
const extraKeys = Object.getOwnPropertyNames(global).filter((key) => {
return !nodeGlobalKeys.includes(key)
})
console.error(`extra keys in electron process: ${extraKeys}`)
}
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 test = async function (buildAppExecutable, buildAppDir) {

View File

@@ -1,6 +1,6 @@
describe('simple v8 snapshot spec', () => {
it('passes', () => {
// Snapshot result needs to be undefined in the renderer process
expect(window.snapshotResult).to.be.undefined
expect(window.getSnapshotResult).to.be.undefined
})
})

View File

@@ -109,101 +109,110 @@ export function scriptFromBlueprint (config: BlueprintConfig): {
const wrapperOpen = Buffer.from(
`
const PATH_SEP = '${pathSep}'
var snapshotAuxiliaryData = ${auxiliaryData}
(function () {
const PATH_SEP = '${pathSep}'
${integrityCheckSource || ''}
${integrityCheckSource || ''}
function generateSnapshot() {
//
// <process>
//
function cannotAccess(proto, prop) {
return function () {
throw 'Cannot access ' + proto + '.' + prop + ' during snapshot creation'
function generateSnapshot() {
//
// <process>
//
function cannotAccess(proto, prop) {
return function () {
throw 'Cannot access ' + proto + '.' + prop + ' during snapshot creation'
}
}
}
function getPrevent(proto, prop) {
return {
get: cannotAccess(proto, prop)
function getPrevent(proto, prop) {
return {
get: cannotAccess(proto, prop)
}
}
}
let process = {}
Object.defineProperties(process, {
platform: {
value: '${processPlatform}',
enumerable: false,
},
argv: {
value: [],
enumerable: false,
},
env: {
value: {
NODE_ENV: '${nodeEnv}',
let process = {}
Object.defineProperties(process, {
platform: {
value: '${processPlatform}',
enumerable: false,
},
enumerable: false,
},
version: {
value: '${processNodeVersion}',
enumerable: false,
},
versions: {
value: { node: '${processNodeVersion}' },
enumerable: false,
},
nextTick: getPrevent('process', 'nextTick')
})
argv: {
value: [],
enumerable: false,
},
env: {
value: {
NODE_ENV: '${nodeEnv}',
},
enumerable: false,
},
version: {
value: '${processNodeVersion}',
enumerable: false,
},
versions: {
value: { node: '${processNodeVersion}' },
enumerable: false,
},
nextTick: getPrevent('process', 'nextTick')
})
function get_process() {
return process
}
//
// </process>
//
function get_process() {
return process
}
//
// </process>
//
${globals}
${includeStrictVerifiers ? strictGlobals : ''}
${globals}
${includeStrictVerifiers ? strictGlobals : ''}
`,
'utf8',
)
const wrapperClose = Buffer.from(
`
${customRequire}
${includeStrictVerifiers ? 'require.isStrict = true' : ''}
`
${customRequire}
${includeStrictVerifiers ? 'require.isStrict = true' : ''}
customRequire(${normalizedMainModuleRequirePath}, ${normalizedMainModuleRequirePath})
const result = {}
Object.defineProperties(result, {
customRequire: {
customRequire(${normalizedMainModuleRequirePath}, ${normalizedMainModuleRequirePath})
const result = {}
Object.defineProperties(result, {
customRequire: {
writable: false,
value: customRequire
},
setGlobals: {
writable: false,
value: ${setGlobals}
},
snapshotAuxiliaryData: {
writable: false,
value: ${auxiliaryData},
},
})
return result
}
let numberOfGetSnapshotResultCalls = 0
const snapshotResult = generateSnapshot.call({})
Object.defineProperties(this, {
getSnapshotResult: {
writable: false,
value: customRequire
value: function () {
if (numberOfGetSnapshotResultCalls > 0) {
throw new Error('getSnapshotResult can only be called once')
}
numberOfGetSnapshotResultCalls++
return snapshotResult
},
},
setGlobals: {
supportTypeScript: {
writable: false,
value: ${setGlobals}
}
value: ${supportTypeScript},
},
})
return result
}
let numberOfGetSnapshotResultCalls = 0
const snapshotResult = generateSnapshot.call({})
Object.defineProperty(this, 'getSnapshotResult', {
writable: false,
value: function () {
if (numberOfGetSnapshotResultCalls > 0) {
throw new Error('getSnapshotResult can only be called once')
}
numberOfGetSnapshotResultCalls++
return snapshotResult
},
})
var supportTypeScript = ${supportTypeScript}
generateSnapshot = null
generateSnapshot = null
}).call(this)
`,
'utf8',
'utf8',
)
const buffers = [wrapperOpen, customRequireDefinitions, wrapperClose]

View File

@@ -14,14 +14,5 @@ export function readSnapshotResult (cacheDir: string) {
const metaFile = path.join(cacheDir, 'snapshot-meta.json')
const meta = fs.readJSONSync(metaFile)
const snapshotFile = path.join(cacheDir, 'snapshot.js')
const snapshotFileContent = fs.readFileSync(snapshotFile, 'utf8')
const sourcemapComment = snapshotFileContent.split('\n').pop()
const { snapshotResult, snapshotAuxiliaryData } = eval(
`(function () {\n${snapshotFileContent};\n return { snapshotResult, snapshotAuxiliaryData };}).bind({})()`,
)
return { meta, snapshotResult, snapshotAuxiliaryData, sourcemapComment }
return { meta }
}