mirror of
https://github.com/cypress-io/cypress.git
synced 2025-12-31 11:39:48 -06:00
* chore: add logic to dynamically load new studio functionality * fix types * fix tests * fix * fix tests * fix tests * additional changes to lock things down * clean up code * Update guides/studio-development.md Co-authored-by: Jennifer Shehane <jennifer@cypress.io> * Update protocol-development.md * additional headers * PR comments * Update packages/server/lib/cloud/api/get_app_studio.ts Co-authored-by: Matt Schile <mschile@cypress.io> * Update packages/app/vite.config.mjs * update studio/protocol development guides --------- Co-authored-by: Jennifer Shehane <jennifer@cypress.io> Co-authored-by: Matt Schile <mschile@cypress.io>
153 lines
5.2 KiB
JavaScript
153 lines
5.2 KiB
JavaScript
const fs = require('fs-extra')
|
|
const crypto = require('crypto')
|
|
const path = require('path')
|
|
const esbuild = require('esbuild')
|
|
|
|
const escapeString = (string) => string.replaceAll(`\``, `\\\``).replaceAll(`$`, `\\$`)
|
|
const secret = require('crypto').randomBytes(48).toString('hex')
|
|
const DUMMY_INDEX_JSC_HASH = 'abcddcbaabcddcbaabcddcbaabcddcba'
|
|
|
|
function read (file) {
|
|
const pathToFile = require.resolve(`./${file}`)
|
|
|
|
return fs.readFileSync(pathToFile, 'utf8')
|
|
}
|
|
|
|
const getBinaryEntryPointSource = async () => {
|
|
const esbuildResult = await esbuild.build({
|
|
entryPoints: [require.resolve('./binary-entry-point-source.js')],
|
|
bundle: true,
|
|
platform: 'node',
|
|
write: false,
|
|
minify: true,
|
|
treeShaking: true,
|
|
})
|
|
|
|
return esbuildResult.outputFiles[0].text
|
|
}
|
|
|
|
const getBinaryByteNodeEntryPointSource = async () => {
|
|
const esbuildResult = await esbuild.build({
|
|
entryPoints: [require.resolve('./binary-byte-node-entry-point-source.js')],
|
|
bundle: true,
|
|
platform: 'node',
|
|
write: false,
|
|
minify: true,
|
|
treeShaking: true,
|
|
})
|
|
|
|
return esbuildResult.outputFiles[0].text
|
|
}
|
|
|
|
const getIntegrityCheckSource = (baseDirectory) => {
|
|
const fileSource = read('binary-integrity-check-source.js')
|
|
|
|
const mainIndexHash = crypto.createHmac('md5', secret).update(fs.readFileSync(path.join(baseDirectory, './index.js'), 'utf8')).digest('hex')
|
|
|
|
return fileSource.split('\n').join(`\n `)
|
|
.replaceAll('MAIN_INDEX_HASH', mainIndexHash)
|
|
.replaceAll('INDEX_JSC_HASH', DUMMY_INDEX_JSC_HASH)
|
|
.replaceAll('HMAC_SECRET', secret)
|
|
.replaceAll('CRYPTO_CREATE_HMAC_TO_STRING', escapeString(crypto.createHmac.toString()))
|
|
.replaceAll('CRYPTO_HMAC_UPDATE_TO_STRING', escapeString(crypto.Hmac.prototype.update.toString()))
|
|
.replaceAll('CRYPTO_HMAC_DIGEST_TO_STRING', escapeString(crypto.Hmac.prototype.digest.toString()))
|
|
}
|
|
|
|
const getIndexJscHash = (baseDirectory) => {
|
|
return crypto.createHmac('md5', secret).update(fs.readFileSync(path.join(baseDirectory, './packages/server/index.jsc'), 'utf8')).digest('hex')
|
|
}
|
|
|
|
const getEncryptionFileSource = async (encryptionFilePath) => {
|
|
const fileContents = await fs.readFile(encryptionFilePath, 'utf8')
|
|
|
|
if (!fileContents.includes(`test: CY_TEST,`)) {
|
|
throw new Error(`Expected to find test key in cloud encryption file`)
|
|
}
|
|
|
|
return fileContents.replace(`test: CY_TEST,`, '').replace(/const CY_TEST = `(.*?)`/, '')
|
|
}
|
|
|
|
const validateEncryptionFile = async (encryptionFilePath) => {
|
|
const afterReplaceEncryption = await fs.readFile(encryptionFilePath, 'utf8')
|
|
|
|
if (afterReplaceEncryption.includes('CY_TEST')) {
|
|
throw new Error(`Expected test key to be stripped from cloud encryption file`)
|
|
}
|
|
}
|
|
|
|
const getCloudEnvironmentFileSource = async (cloudApiFilePath) => {
|
|
const fileContents = await fs.readFile(cloudApiFilePath, 'utf8')
|
|
|
|
if (!fileContents.includes('process.env.CYPRESS_ENV_DEPENDENCIES')) {
|
|
throw new Error(`Expected to find CYPRESS_ENV_DEPENDENCIES in cloud api file`)
|
|
}
|
|
|
|
if (process.env.CYPRESS_ENV_DEPENDENCIES) {
|
|
return fileContents.replace('process.env.CYPRESS_ENV_DEPENDENCIES', `'${process.env.CYPRESS_ENV_DEPENDENCIES}'`)
|
|
}
|
|
|
|
return fileContents
|
|
}
|
|
|
|
const validateCloudEnvironmentFile = async (cloudApiFilePath) => {
|
|
if (process.env.CYPRESS_ENV_DEPENDENCIES) {
|
|
const afterReplaceCloudApi = await fs.readFile(cloudApiFilePath, 'utf8')
|
|
|
|
if (afterReplaceCloudApi.includes('process.env.CYPRESS_ENV_DEPENDENCIES')) {
|
|
throw new Error(`Expected process.env.CYPRESS_ENV_DEPENDENCIES to be stripped from cloud api file`)
|
|
}
|
|
}
|
|
}
|
|
|
|
const getProtocolFileSource = async (protocolFilePath) => {
|
|
const fileContents = await fs.readFile(protocolFilePath, 'utf8')
|
|
|
|
if (!fileContents.includes('process.env.CYPRESS_LOCAL_PROTOCOL_PATH')) {
|
|
throw new Error(`Expected to find CYPRESS_LOCAL_PROTOCOL_PATH in protocol file`)
|
|
}
|
|
|
|
return fileContents.replaceAll('process.env.CYPRESS_LOCAL_PROTOCOL_PATH', 'undefined')
|
|
}
|
|
|
|
const getStudioFileSource = async (studioFilePath) => {
|
|
const fileContents = await fs.readFile(studioFilePath, 'utf8')
|
|
|
|
if (!fileContents.includes('process.env.CYPRESS_LOCAL_STUDIO_PATH')) {
|
|
throw new Error(`Expected to find CYPRESS_LOCAL_STUDIO_PATH in studio file`)
|
|
}
|
|
|
|
return fileContents.replaceAll('process.env.CYPRESS_LOCAL_STUDIO_PATH', 'undefined')
|
|
}
|
|
|
|
const validateProtocolFile = async (protocolFilePath) => {
|
|
const afterReplaceProtocol = await fs.readFile(protocolFilePath, 'utf8')
|
|
|
|
if (afterReplaceProtocol.includes('process.env.CYPRESS_LOCAL_PROTOCOL_PATH')) {
|
|
throw new Error(`Expected process.env.CYPRESS_LOCAL_PROTOCOL_PATH to be stripped from protocol file`)
|
|
}
|
|
}
|
|
|
|
const validateStudioFile = async (studioFilePath) => {
|
|
const afterReplaceStudio = await fs.readFile(studioFilePath, 'utf8')
|
|
|
|
if (afterReplaceStudio.includes('process.env.CYPRESS_LOCAL_STUDIO_PATH')) {
|
|
throw new Error(`Expected process.env.CYPRESS_LOCAL_STUDIO_PATH to be stripped from studio file`)
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
getBinaryEntryPointSource,
|
|
getBinaryByteNodeEntryPointSource,
|
|
getIntegrityCheckSource,
|
|
getEncryptionFileSource,
|
|
validateEncryptionFile,
|
|
getCloudEnvironmentFileSource,
|
|
validateCloudEnvironmentFile,
|
|
getProtocolFileSource,
|
|
validateProtocolFile,
|
|
getStudioFileSource,
|
|
validateStudioFile,
|
|
getIndexJscHash,
|
|
DUMMY_INDEX_JSC_HASH,
|
|
}
|