chore: Bump vulnerable dependencies (#44428)

This PR bumps various dependencies to fix vulnerabilities. 

The logic for bumping packages has been taken out of
`fix-audit-vulnerability` into a `bump-package` script.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Chores**
  * Removed unused development dependency from generator package
* Updated package version overrides and vulnerability management
configuration to address security concerns
* Enhanced internal package dependency maintenance tooling for improved
operational efficiency

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Ivan Vasilov
2026-04-01 13:10:37 +02:00
committed by GitHub
parent 97130a76e1
commit 83edf14a23
5 changed files with 523 additions and 1359 deletions
-1
View File
@@ -22,7 +22,6 @@
},
"dependencies": {},
"devDependencies": {
"@redocly/cli": "^1.28.0",
"@types/json-stringify-safe": "^5.0.0",
"@types/lodash": "^4.14.202",
"json-stringify-safe": "^5.0.1",
+274 -1225
View File
File diff suppressed because it is too large Load Diff
+7 -9
View File
@@ -46,12 +46,9 @@ minimumReleaseAgeExclude:
- '@supabase/*'
- '@supabase-labs/*'
# The following deps were added due to vulnerabilities. You can remove them after the minimum time has passed.
- undici
- next
- '@next/*'
- h3
- typescript
- stripe-experiment-sync
- path-to-regexp
- brace-expansion
- serialize-javascript
onlyBuiltDependencies:
- node-pty
@@ -59,11 +56,12 @@ onlyBuiltDependencies:
overrides:
'@ardatan/relay-compiler>immutable': ^3.8.3
'@aws-sdk/core>fast-xml-parser': ^4.5.4
'@aws-sdk/core>fast-xml-parser': ^4.5.5
'@mapbox/node-pre-gyp>tar': ^7.5.11
'@redocly/respect-core>form-data': ^4.0.4
'@redocly/respect-core>js-yaml': ^4.1.1
'@rollup/plugin-terser>serialize-javascript': ^7.0.3
'@rollup/plugin-terser>serialize-javascript': ^7.0.5
'@tanstack/start-server-core': ^1.159.0
cacache>tar: ^7.5.11
dompurify: ^3.3.2
esbuild: ^0.25.2
@@ -75,7 +73,7 @@ overrides:
'pgsql-parser>libpg-query': ^15.2.0
refractor>prismjs: ^1.30.0
supabase>tar: ^7.5.11
'terser-webpack-plugin>serialize-javascript': ^7.0.3
'terser-webpack-plugin>serialize-javascript': ^7.0.5
tmp: ^0.2.4
webpack: ^5.104.1
+234
View File
@@ -0,0 +1,234 @@
import { execSync } from 'node:child_process'
import * as fs from 'node:fs'
import * as path from 'node:path'
const WORKSPACE_YAML_PATH = path.join(process.cwd(), 'pnpm-workspace.yaml')
export const LOCKFILE_PATH = path.join(process.cwd(), 'pnpm-lock.yaml')
export function compareSemver(a: string, b: string): number {
const pa = a.split('.').map(Number)
const pb = b.split('.').map(Number)
for (let i = 0; i < 3; i++) {
if (pa[i] !== pb[i]) return pa[i] - pb[i]
}
return 0
}
function escapeRegex(str: string): string {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
function formatOverrideLine(moduleName: string, version: string): string {
const key = moduleName.includes('@') ? `'${moduleName}'` : moduleName
return ` ${key}: ${version}`
}
function addOverride(yamlContent: string, moduleName: string, version: string): string {
const lines = yamlContent.split('\n')
const overridesIdx = lines.findIndex((line) => /^overrides:\s*$/.test(line))
if (overridesIdx === -1) {
throw new Error('Could not find "overrides:" section in pnpm-workspace.yaml')
}
let blockEnd = overridesIdx + 1
while (blockEnd < lines.length) {
const line = lines[blockEnd]
if (line === '' || /^\s+/.test(line)) {
blockEnd++
} else {
break
}
}
const existingPattern = new RegExp(`^\\s+['"]?${escapeRegex(moduleName)}['"]?\\s*:`)
const existingIdx = lines.findIndex(
(line, idx) => idx > overridesIdx && idx < blockEnd && existingPattern.test(line)
)
if (existingIdx !== -1) {
console.log(`\nWARNING: Override for "${moduleName}" already exists:`)
console.log(` ${lines[existingIdx].trim()}`)
console.log(` Replacing with: ${moduleName}: ${version}`)
lines[existingIdx] = formatOverrideLine(moduleName, version)
return lines.join('\n')
}
const newLine = formatOverrideLine(moduleName, version)
lines.splice(blockEnd, 0, newLine)
return lines.join('\n')
}
function findHighestVersionInLockfile(packageName: string): string | null {
const lockfileContent = fs.readFileSync(LOCKFILE_PATH, 'utf-8')
const escaped = escapeRegex(packageName)
// pnpm lockfile v9 format:
// scoped: ` '@org/pkg@x.y.z':`
// unscoped: ` pkg@x.y.z:`
const pattern = packageName.startsWith('@')
? new RegExp(`^ '${escaped}@(\\d+\\.\\d+\\.\\d+)':`, 'gm')
: new RegExp(`^ ${escaped}@(\\d+\\.\\d+\\.\\d+):`, 'gm')
const versions: string[] = []
let match: RegExpExecArray | null
while ((match = pattern.exec(lockfileContent)) !== null) {
versions.push(match[1])
}
if (versions.length === 0) return null
return versions.sort(compareSemver).at(-1)!
}
function handleMinimumReleaseAgeError(output: string): void {
const blocks = output.split('ERR_PNPM_NO_MATCHING_VERSION')
for (const block of blocks.slice(1)) {
const versionMatch = block.match(
/No matching version found for (\S+) published by .+?\. Version (\S+) satisfies the specs but was released at (.+)/
)
const chainLines = block
.split('\n')
.filter((line: string) => /^\s+at /.test(line))
.map((line: string) => line.trim().replace(/^at /, ''))
if (versionMatch) {
const [, spec, version, releaseDate] = versionMatch
console.error(`\n Blocked package: ${spec} (v${version} released ${releaseDate.trim()})`)
if (chainLines.length > 0) {
console.error(` Dependency chain: ${chainLines.join(' -> ')}`)
}
const pkgName = spec.replace(/@[^/]*$/, '')
console.error(
` To unblock, add "${pkgName}" to the minimumReleaseAgeExclude setting in pnpm-workspace.yaml`
)
}
}
}
interface BumpResult {
previousVersion: string | null
finalVersion: string | null
}
/**
* Bumps a package to the given override version (or patch+1 of the current highest if omitted).
* First tries a plain `pnpm install`; if that doesn't move the version, falls back to adding
* a temporary override in pnpm-workspace.yaml. Reverts and throws on failure.
*/
export async function bumpPackage(
packageName: string,
overrideVersion?: string
): Promise<BumpResult> {
const currentHighest = findHighestVersionInLockfile(packageName)
let targetVersion: string
if (overrideVersion) {
targetVersion = overrideVersion
console.log(`Package: ${packageName}`)
if (currentHighest) console.log(`Current highest in lockfile: ${currentHighest}`)
console.log(`Target version (explicit): ${targetVersion}`)
} else {
if (!currentHighest) {
throw new Error(`Package "${packageName}" not found in pnpm-lock.yaml`)
}
const [major, minor, patch] = currentHighest.split('.').map(Number)
targetVersion = `^${major}.${minor}.${patch + 1}`
console.log(`Package: ${packageName}`)
console.log(`Current highest in lockfile: ${currentHighest}`)
console.log(`Target version (minimal bump): ${targetVersion}`)
}
// Attempt 1: plain pnpm install, no override
console.log('\nAttempt 1: pnpm install (no override)...')
execSync('pnpm install --silent', { stdio: 'pipe', encoding: 'utf-8' })
const afterPlainInstall = findHighestVersionInLockfile(packageName)
if (currentHighest && afterPlainInstall && compareSemver(afterPlainInstall, currentHighest) > 0) {
console.log(
`\n${packageName} bumped to ${afterPlainInstall} via plain install (no override needed).`
)
return { previousVersion: currentHighest, finalVersion: afterPlainInstall }
}
console.log('No change from plain install. Proceeding with override...')
// Snapshot for revert
const originalYaml = fs.readFileSync(WORKSPACE_YAML_PATH, 'utf-8')
const originalLockfile = fs.readFileSync(LOCKFILE_PATH, 'utf-8')
function revert(): void {
console.log('\nReverting pnpm-workspace.yaml and pnpm-lock.yaml...')
fs.writeFileSync(WORKSPACE_YAML_PATH, originalYaml, 'utf-8')
fs.writeFileSync(LOCKFILE_PATH, originalLockfile, 'utf-8')
console.log('Reverted to original state.')
}
// Attempt 2: add override
console.log(`\nAttempt 2: adding override ${packageName}: ${targetVersion}`)
const updatedYaml = addOverride(originalYaml, packageName, targetVersion)
fs.writeFileSync(WORKSPACE_YAML_PATH, updatedYaml, 'utf-8')
console.log('Updated pnpm-workspace.yaml')
console.log('\nRunning pnpm install (with override)...')
try {
execSync('pnpm install', { stdio: 'pipe', encoding: 'utf-8' })
} catch (error: any) {
const output = (error.stdout ?? '') + (error.stderr ?? '')
if (output.includes('ERR_PNPM_NO_MATCHING_VERSION')) {
console.error(
`\nNo matching version found for "${packageName}@${targetVersion}" — blocked by minimumReleaseAge.`
)
handleMinimumReleaseAgeError(output)
revert()
throw new Error(`Blocked by minimumReleaseAge`)
}
revert()
throw error
}
// Remove override and re-install to let the lockfile bump stick on its own
console.log('\nRemoving override and running pnpm install again...')
fs.writeFileSync(WORKSPACE_YAML_PATH, originalYaml, 'utf-8')
execSync('pnpm install --silent', { stdio: 'pipe', encoding: 'utf-8' })
return {
previousVersion: currentHighest,
finalVersion: findHighestVersionInLockfile(packageName),
}
}
async function main(): Promise<void> {
const [packageName, versionArg] = process.argv.slice(2)
if (!packageName) {
console.error('Usage: ts-node scripts/bump-package.ts <package-name> [version]')
process.exit(1)
}
const overrideVersion = versionArg ? `^${versionArg}` : undefined
let result: BumpResult
try {
result = await bumpPackage(packageName, overrideVersion)
} catch (error: any) {
console.error(error.message ?? error)
process.exit(1)
}
const { previousVersion, finalVersion } = result
if (!finalVersion || (previousVersion && compareSemver(finalVersion, previousVersion) <= 0)) {
console.error(
`\nERROR: "${packageName}" was not bumped after removing override. ` +
`Consider using scoped overrides or updating the parent dependency.`
)
process.exit(1)
}
console.log(`\nSUCCESS: ${packageName} bumped from ${previousVersion} to ${finalVersion}.`)
}
if (require.main === module) {
main().catch((error) => {
console.error('Fatal error:', error)
process.exit(1)
})
}
+8 -124
View File
@@ -1,7 +1,7 @@
import { execSync } from 'node:child_process'
import * as fs from 'node:fs'
import * as path from 'node:path'
import * as readline from 'node:readline'
import { bumpPackage, compareSemver, LOCKFILE_PATH } from './bump-package'
interface Advisory {
id: number
@@ -33,9 +33,6 @@ interface VulnerableModule {
allPaths: string[]
}
const WORKSPACE_YAML_PATH = path.join(process.cwd(), 'pnpm-workspace.yaml')
const LOCKFILE_PATH = path.join(process.cwd(), 'pnpm-lock.yaml')
const SEVERITY_ORDER = ['critical', 'high', 'moderate', 'low']
function runAudit(): AuditOutput {
@@ -60,15 +57,6 @@ function parseMinVersion(patchedVersions: string): string | null {
return match ? match[1] : null
}
function compareSemver(a: string, b: string): number {
const pa = a.split('.').map(Number)
const pb = b.split('.').map(Number)
for (let i = 0; i < 3; i++) {
if (pa[i] !== pb[i]) return pa[i] - pb[i]
}
return 0
}
function groupAdvisories(advisories: Record<string, Advisory>): VulnerableModule[] {
const byModule = new Map<string, Advisory[]>()
@@ -167,54 +155,6 @@ function promptSelection(modules: VulnerableModule[]): Promise<VulnerableModule>
})
}
function escapeRegex(str: string): string {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
function formatOverrideLine(moduleName: string, version: string): string {
const key = moduleName.includes('@') ? `'${moduleName}'` : moduleName
return ` ${key}: ${version}`
}
function addOverride(yamlContent: string, moduleName: string, version: string): string {
const lines = yamlContent.split('\n')
const overridesIdx = lines.findIndex((line) => /^overrides:\s*$/.test(line))
if (overridesIdx === -1) {
throw new Error('Could not find "overrides:" section in pnpm-workspace.yaml')
}
// Find the end of the overrides block (next non-indented, non-empty line)
let blockEnd = overridesIdx + 1
while (blockEnd < lines.length) {
const line = lines[blockEnd]
if (line === '' || /^\s+/.test(line)) {
blockEnd++
} else {
break
}
}
// Check if this module already has an override
const existingPattern = new RegExp(`^\\s+['"]?${escapeRegex(moduleName)}['"]?\\s*:`)
const existingIdx = lines.findIndex(
(line, idx) => idx > overridesIdx && idx < blockEnd && existingPattern.test(line)
)
if (existingIdx !== -1) {
console.log(`\nWARNING: Override for "${moduleName}" already exists:`)
console.log(` ${lines[existingIdx].trim()}`)
console.log(` Replacing with: ${moduleName}: ${version}`)
lines[existingIdx] = formatOverrideLine(moduleName, version)
return lines.join('\n')
}
// Insert new override at the end of the overrides block
const newLine = formatOverrideLine(moduleName, version)
lines.splice(blockEnd, 0, newLine)
return lines.join('\n')
}
async function main(): Promise<void> {
console.log('Running pnpm audit...')
const auditResult = runAudit()
@@ -230,74 +170,16 @@ async function main(): Promise<void> {
const selected = await promptSelection(modules)
// Snapshot original files for revert on failure
const originalYaml = fs.readFileSync(WORKSPACE_YAML_PATH, 'utf-8')
// Snapshot lockfile to revert if the audit verify step fails
const originalLockfile = fs.readFileSync(LOCKFILE_PATH, 'utf-8')
function revert(): void {
console.log('\nReverting pnpm-workspace.yaml and pnpm-lock.yaml...')
fs.writeFileSync(WORKSPACE_YAML_PATH, originalYaml, 'utf-8')
fs.writeFileSync(LOCKFILE_PATH, originalLockfile, 'utf-8')
console.log('Reverted to original state.')
}
console.log(`\nAdding override: ${selected.module_name}: ${selected.overrideVersion}`)
const updatedYaml = addOverride(originalYaml, selected.module_name, selected.overrideVersion)
fs.writeFileSync(WORKSPACE_YAML_PATH, updatedYaml, 'utf-8')
console.log('Updated pnpm-workspace.yaml')
console.log('\nRunning pnpm install (with override)...')
try {
execSync('pnpm install', {
stdio: 'pipe',
encoding: 'utf-8',
})
await bumpPackage(selected.module_name, selected.overrideVersion)
} catch (error: any) {
const output = (error.stdout ?? '') + (error.stderr ?? '')
if (output.includes('ERR_PNPM_NO_MATCHING_VERSION')) {
console.error(
`\nNo matching version found for "${selected.module_name}@${selected.overrideVersion}", the minimumReleaseAge option forbids it from installing.`
)
// Extract and display dependency chains that failed due to minimumReleaseAge
const blocks = output.split('ERR_PNPM_NO_MATCHING_VERSION')
for (const block of blocks.slice(1)) {
const versionMatch = block.match(
/No matching version found for (\S+) published by .+?\. Version (\S+) satisfies the specs but was released at (.+)/
)
const chainLines = block
.split('\n')
.filter((line: string) => /^\s+at /.test(line))
.map((line: string) => line.trim().replace(/^at /, ''))
if (versionMatch) {
const [, spec, version, releaseDate] = versionMatch
console.error(`\n Blocked package: ${spec} (v${version} released ${releaseDate.trim()})`)
if (chainLines.length > 0) {
console.error(` Dependency chain: ${chainLines.join(' -> ')}`)
}
// Handle scoped (@org/pkg) and unscoped packages: strip the version range suffix
const pkgName = spec.replace(/@[^/]*$/, '')
console.error(
` To unblock, add "${pkgName}" to the minimumReleaseAgeExclude setting in pnpm-workspace.yaml`
)
}
}
revert()
process.exit(1)
}
throw error
console.error(error.message ?? error)
process.exit(1)
}
// Remove the override and re-install to see if the lockfile update alone fixes it
console.log('\nRemoving override and running pnpm install again...')
fs.writeFileSync(WORKSPACE_YAML_PATH, originalYaml, 'utf-8')
execSync('pnpm install --silent', {
stdio: 'pipe',
encoding: 'utf-8',
})
console.log('\nRunning pnpm audit to verify fix without override...')
const verifyResult = runAudit()
@@ -306,7 +188,9 @@ async function main(): Promise<void> {
)
if (stillVulnerable) {
revert()
console.log('\nReverting pnpm-lock.yaml...')
fs.writeFileSync(LOCKFILE_PATH, originalLockfile, 'utf-8')
console.log('Reverted to original state.')
console.error(
`\nERROR: Vulnerability for "${selected.module_name}" still present even with override.`
)