From e1c479dc3187545dd77caad2ba2cb77e8148eb8c Mon Sep 17 00:00:00 2001 From: Brian Hudson Date: Mon, 22 Jan 2024 22:46:06 -0500 Subject: [PATCH] Require --no-node-snapshot in node 20+ When started using node 20+ checks if the --no-node-snapshot option was provided and throws an error if not. Signed-off-by: Brian Hudson --- .changeset/unlucky-pens-search.md | 6 +++ .../scaffolder-backend/src/service/helpers.ts | 40 +++++++++++++++++++ .../scaffolder-backend/src/service/router.ts | 16 +++++++- 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 .changeset/unlucky-pens-search.md diff --git a/.changeset/unlucky-pens-search.md b/.changeset/unlucky-pens-search.md new file mode 100644 index 0000000000..4786c14691 --- /dev/null +++ b/.changeset/unlucky-pens-search.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +When using node 20+ the `scaffolder-backend` will now throw an error at startup if the `--no-node-snapshot` option was +not provided to node. diff --git a/plugins/scaffolder-backend/src/service/helpers.ts b/plugins/scaffolder-backend/src/service/helpers.ts index 3412fec2d3..62f8d78810 100644 --- a/plugins/scaffolder-backend/src/service/helpers.ts +++ b/plugins/scaffolder-backend/src/service/helpers.ts @@ -107,3 +107,43 @@ export async function findTemplate(options: { return template as TemplateEntityV1beta3; } + +/** + * Checks if the '--no-node-snapshot' option is included in the NODE_OPTIONS environment variable + * or not included in the command line arguments. + * + * @remarks + * This function checks whether the '--no-node-snapshot' option is part of the NODE_OPTIONS environment + * variable or is missing from the command line arguments. If either condition is met, the function returns `true`. + * This check is especially important when using the "isolated-vm" package with Node.js version 20.x or later. + * + * According to the "isolated-vm" documentation on GitHub (https://github.com/laverdet/isolated-vm), + * if you are using a version of Node.js 20.x or later and you don't pass the '--no-node-snapshot' option, + * it can cause the process to crash. This function helps prevent such crashes by ensuring that the option + * is correctly provided. + * + * @returns {boolean} Returns `true` if the '--no-node-snapshot' option is included in the NODE_OPTIONS + * environment variable or not included in the command line arguments. Otherwise, it returns `false`. + */ +export function isNoNodeSnapshotOptionProvided(): boolean { + return ( + process.env.NODE_OPTIONS?.includes('--no-node-snapshot') || + process.argv.includes('--no-node-snapshot') + ); +} + +/** + * Gets the major version of the currently running Node.js process. + * + * @remarks + * This function extracts the major version from `process.versions.node` (a string representing the Node.js version), + * which includes the major, minor, and patch versions. It splits this string by the `.` character to get an array + * of these versions, and then parses the first element of this array (the major version) to a number. + * + * @returns {number} The major version of the currently running Node.js process. + */ +export function getMajorNodeVersion(): number { + const version = process.versions.node; + return parseInt(version.split('.')[0], 10); +} + diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index de0087e7de..5f27154c5b 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -61,7 +61,13 @@ import { } from '../scaffolder'; import { createDryRunner } from '../scaffolder/dryrun'; import { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker'; -import { findTemplate, getEntityBaseUrl, getWorkingDirectory } from './helpers'; +import { + findTemplate, + getEntityBaseUrl, + getMajorNodeVersion, + getWorkingDirectory, + isNoNodeSnapshotOptionProvided +} from './helpers'; import { IdentityApi, IdentityApiGetIdentityRequest, @@ -258,6 +264,14 @@ export async function createRouter( const logger = parentLogger.child({ plugin: 'scaffolder' }); + const nodeVersion = getMajorNodeVersion(); + if (nodeVersion >= 20 && !isNoNodeSnapshotOptionProvided()) { + throw new Error( + 'When using node v20+ Scaffolder requires that node be started with the --no-node-snapshot option. Please restart ' + + 'Backstage providing the node --no-node-snapshot option.', + ); + } + const identity: IdentityApi = options.identity || buildDefaultIdentityClient(options); const workingDirectory = await getWorkingDirectory(config, logger);