Skip to content

Node 22 and Azure Functions v4 migration#13

Open
MarcAstr0 wants to merge 8 commits intoboostercloud:mainfrom
Optum:node_22
Open

Node 22 and Azure Functions v4 migration#13
MarcAstr0 wants to merge 8 commits intoboostercloud:mainfrom
Optum:node_22

Conversation

@MarcAstr0
Copy link
Collaborator

## Description

This PR adds Node 22 support to the Webhook Rocket. The changes in this PR are similar to those introduced in #1593 of the framework. This PR also addresses several vulnerabilities found in the dependencies.

This version of the rocket is compatible with 4.x versions of the main framework.

Changes

  • Updated rocket-webhook-azure-infrastructure package to generate v4-compatible Azure Functions
  • Updated rocket-webhook-azure to work with the v4 @azure/functions SDK
  • Added overrides to package.json to address several vulnerabilities across dependencies
  • Updated .nvmrc file
  • Updated dependencies across all packages to support Node 22

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the Azure Webhook Rocket to Node 22 and Azure Functions v4 compatibility (Booster Framework v4.x), while also updating dependency constraints and applying dependency overrides to address vulnerabilities.

Changes:

  • Bump peer dependency compatibility across packages from Booster Framework v3.x to v4.x.
  • Update Azure infrastructure generation for Functions v4 (including Node 22 runtime in the Function App stack and new V4 function mounting path).
  • Update tooling/dependencies (Lerna 9, cdktf/provider versions, Node typings) and add root overrides for vulnerability mitigation.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/rocket-webhook-types/package.json Update peer dependency minimums to Booster Framework v4.
packages/rocket-webhook-core/package.json Update peer dependency minimums to Booster Framework v4.
packages/rocket-webhook-local-infrastructure/package.json Update peer deps to v4, bump express, update local infra provider + Node typings for Node 22.
packages/rocket-webhook-azure-infrastructure/package.json Update peer deps/dev deps to Booster v4 ecosystem, bump cdktf/provider + Node typings.
packages/rocket-webhook-azure-infrastructure/src/synth/terraform-function-app.ts Set Azure Function App Node runtime to ~22 and Functions extension ~4.
packages/rocket-webhook-azure-infrastructure/src/synth/synth.ts Minor refactor/formatting; continues wiring gateway overrides to the Function App.
packages/rocket-webhook-azure-infrastructure/src/index.ts Switch infra rocket entrypoint to expose mountFunctionsV4.
packages/rocket-webhook-azure-infrastructure/src/functions/functions.ts Implement mountFunctionsV4 returning v4 function app definitions and generated code.
packages/rocket-webhook-azure-infrastructure/src/functions/webhook-function.ts Replace v3 function.json-style definition with generated @azure/functions v4 registration code.
package.json Update peer deps to v4, bump lerna, add overrides to mitigate vulnerabilities.
lerna.json Remove legacy command config (bootstrap/hoist settings).
.nvmrc Update Node LTS to Node 22 (lts/jod).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +8 to +11
app.http('${name}', {
methods: ['POST', 'GET'],
authLevel: 'anonymous',
route: '${endpoint}',
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

endpoint is embedded verbatim into generated JS (app.http(... route: '...')). If a route contains quotes/newlines/backticks, it will generate invalid JS (and can allow code injection during generation). Escape/sanitize endpoint (and the derived name) when embedding, e.g. by using JSON.stringify to emit a safe string literal.

Suggested change
app.http('${name}', {
methods: ['POST', 'GET'],
authLevel: 'anonymous',
route: '${endpoint}',
app.http(${JSON.stringify(name)}, {
methods: ['POST', 'GET'],
authLevel: 'anonymous',
route: ${JSON.stringify(endpoint)},

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +8 to +15
static generateFunctionsCode(endpoint: string): string {
const name = endpoint.replace(/\//g, '_')
return {
name: name,
config: {
bindings: [
{
type: 'httpTrigger',
direction: 'in',
name: 'rawRequest',
authLevel: 'anonymous',
methods: ['post', 'get'],
route: `${endpoint}`,
},
{
type: 'http',
direction: 'out',
name: '$return',
},
],
scriptFile: config.functionRelativePath,
entryPoint: config.rocketDispatcherHandler.split('.')[1],
return `
app.http('${name}', {
methods: ['POST', 'GET'],
authLevel: 'anonymous',
route: '${endpoint}',
handler: async (request, context) => {
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generateFunctionsCode() interpolates name and endpoint directly into single-quoted JS string literals. If a route contains quotes, backslashes, or newlines (or even {}/: etc depending on conventions), the generated module can become invalid JS or allow unintended code injection during synthesis. Generate these literals using a safe escaping strategy (e.g., serialize with JSON.stringify(...) and embed the resulting string literal) and ensure the derived function name is sanitized to a valid Azure Functions identifier.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +44
const webhookRequest = {
ROCKET_FUNCTION_ID: process.env.ROCKET_FUNCTION_ID,
req: {
method: request.method,
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated request object hardcodes the function id key as ROCKET_FUNCTION_ID. Elsewhere in this repo the key comes from rocketFunctionIDEnvVar (local controller, terraform app settings), so hardcoding it here risks subtle breakage if the constant ever changes and makes the code inconsistent across providers. Consider importing rocketFunctionIDEnvVar in sharedImports() and using it as a computed property key when building webhookRequest.

Copilot uses AI. Check for mistakes.
mountStack: Synth.mountStack.bind(Synth, params),
mountFunctions: Functions.mountFunctions.bind(Synth, params),
mountFunctionsV4: Functions.mountFunctionsV4.bind(Functions, params),
getFunctionAppName: Functions.getFunctionAppName.bind(Synth, params),
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getFunctionAppName is bound with thisArg set to Synth, but the function is a static on Functions. While it may work today (because it doesn’t use this), this is an easy copy/paste footgun and makes the binding inconsistent with mountFunctionsV4. Bind it to Functions for clarity and to avoid future refactors accidentally depending on this.

Suggested change
getFunctionAppName: Functions.getFunctionAppName.bind(Synth, params),
getFunctionAppName: Functions.getFunctionAppName.bind(Functions, params),

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants