adds script to generate report for dependency overrides (#13179) (#13731)

Co-authored-by: Jordan Reimer <zofskeez@gmail.com>
This commit is contained in:
Vault Automation 2026-04-07 16:30:08 -06:00 committed by GitHub
parent 6469a5a312
commit 547255b0d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 469 additions and 0 deletions

271
ui/DEP_OVERRIDE_REPORT.md Normal file
View file

@ -0,0 +1,271 @@
# 🛡️ PNPM Override Audit Report
Generated on: 2026-03-19, 10:45:45 a.m.
## `@babel/runtime`
**Target Override:** `7.27.0`
⚠️ **REQUIRED**
> These packages will continue to receive the overridden version until they are updated to naturally resolve to >= 7.27.0.
| Parent Package | Naturally Resolved Version |
| :--- | :--- |
| `ember-cli-babel@7.26.11` | `7.12.18` |
| `ember-cli-babel@8.2.0` | `7.12.18` |
---
## `@embroider/macros`
**Target Override:** `1.15.0`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 1.15.0 without the override.
---
## `@messageformat/runtime`
**Target Override:** `3.0.2`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 3.0.2 without the override.
---
## `ajv@6.12.6`
**Target Override:** `6.14.0`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 6.14.0 without the override.
---
## `ajv@8.17.1`
**Target Override:** `8.18.0`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 8.18.0 without the override.
---
## `ansi-html`
**Target Override:** `0.0.8`
⚠️ **REQUIRED**
> These packages will continue to receive the overridden version until they are updated to naturally resolve to >= 0.0.8.
| Parent Package | Naturally Resolved Version |
| :--- | :--- |
| `broccoli-middleware@2.1.1` | `0.0.7` |
| `broccoli@3.5.2` | `0.0.7` |
---
## `async`
**Target Override:** `2.6.4`
⚠️ **REQUIRED**
> These packages will continue to receive the overridden version until they are updated to naturally resolve to >= 2.6.4.
| Parent Package | Naturally Resolved Version |
| :--- | :--- |
| `fireworm@0.7.2` | `0.2.10` |
---
## `braces`
**Target Override:** `3.0.3`
⚠️ **REQUIRED**
> These packages will continue to receive the overridden version until they are updated to naturally resolve to >= 3.0.3.
| Parent Package | Naturally Resolved Version |
| :--- | :--- |
| `micromatch@3.1.10` | `2.3.2` |
---
## `eslint-utils`
**Target Override:** `1.4.3`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 1.4.3 without the override.
---
## `express`
**Target Override:** `4.22.1`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 4.22.1 without the override.
---
## `https-proxy-agent`
**Target Override:** `2.2.4`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 2.2.4 without the override.
---
## `ini`
**Target Override:** `1.3.8`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 1.3.8 without the override.
---
## `json5`
**Target Override:** `1.0.2`
❓ **UNKNOWN (Error)**
> The script encountered an error resolving this package:
> `Command failed: pnpm list "json5" --recursive --depth Infinity --json`
---
## `kind-of`
**Target Override:** `6.0.3`
⚠️ **REQUIRED**
> These packages will continue to receive the overridden version until they are updated to naturally resolve to >= 6.0.3.
| Parent Package | Naturally Resolved Version |
| :--- | :--- |
| `has-values@1.0.0` | `4.0.0` |
| `is-number@3.0.0` | `3.2.2` |
| `object-copy@0.1.0` | `3.2.2` |
| `snapdragon-util@3.0.1` | `3.2.2` |
| `to-object-path@0.3.0` | `3.2.2` |
---
## `markdown-it`
**Target Override:** `14.1.1`
⚠️ **REQUIRED**
> These packages will continue to receive the overridden version until they are updated to naturally resolve to >= 14.1.1.
| Parent Package | Naturally Resolved Version |
| :--- | :--- |
| `ember-cli@5.8.1` | `13.0.2` |
| `markdown-it-terminal@0.4.0` | `13.0.2` |
---
## `micromatch`
**Target Override:** `4.0.8`
⚠️ **REQUIRED**
> These packages will continue to receive the overridden version until they are updated to naturally resolve to >= 4.0.8.
| Parent Package | Naturally Resolved Version |
| :--- | :--- |
| `anymatch@2.0.0` | `3.1.10` |
| `findup-sync@2.0.0` | `3.1.10` |
| `sane@4.1.0` | `3.1.10` |
---
## `minimatch@<3.1.3`
**Target Override:** `3.1.5`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 3.1.5 without the override.
---
## `minimatch@>=5.0.0 <5.1.7`
**Target Override:** `5.1.9`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 5.1.9 without the override.
---
## `minimatch@>=7.0.0 <7.4.7`
**Target Override:** `7.4.9`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 7.4.9 without the override.
---
## `minimatch@>=8.0.0 <8.0.5`
**Target Override:** `8.0.7`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 8.0.7 without the override.
---
## `minimatch@>=9.0.0 <9.0.6`
**Target Override:** `9.0.9`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 9.0.9 without the override.
---
## `prismjs`
**Target Override:** `1.30.0`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 1.30.0 without the override.
---
## `qs`
**Target Override:** `6.14.1`
⚠️ **REQUIRED**
> These packages will continue to receive the overridden version until they are updated to naturally resolve to >= 6.14.1.
| Parent Package | Naturally Resolved Version |
| :--- | :--- |
| `body-parser@1.20.3` | `6.13.0` |
---
## `rollup`
**Target Override:** `2.80.0`
⚠️ **REQUIRED**
> These packages will continue to receive the overridden version until they are updated to naturally resolve to >= 2.80.0.
| Parent Package | Naturally Resolved Version |
| :--- | :--- |
| `@rollup/plugin-replace@2.3.0` | `1.32.1` |
| `broccoli-rollup@4.0.0` | `1.32.1` |
---
## `serialize-javascript`
**Target Override:** `3.1.0`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 3.1.0 without the override.
---
## `socket.io`
**Target Override:** `4.8.1`
✅ **SAFE TO REMOVE**
> All packages naturally resolve to >= 4.8.1 without the override.
---
## `underscore`
**Target Override:** `1.13.7`
⚠️ **REQUIRED**
> These packages will continue to receive the overridden version until they are updated to naturally resolve to >= 1.13.7.
| Parent Package | Naturally Resolved Version |
| :--- | :--- |
| `nomnom@1.8.1` | `1.6.0` |
---

View file

@ -0,0 +1,198 @@
/**
* Copyright IBM Corp. 2016, 2025
* SPDX-License-Identifier: BUSL-1.1
*/
/* eslint-env node */
/* eslint-disable no-console */
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const ROOT_DIR = path.join(__dirname, '..');
const PKG_PATH = path.join(ROOT_DIR, 'package.json');
const LOCK_PATH = path.join(ROOT_DIR, 'pnpm-lock.yaml');
/**
* Simple exact-version comparison.
* Returns true if the resolved version is older than the target override.
*/
function isOlder(found, target) {
if (!found || !target) return false;
const f = found
.replace(/[^0-9.]/g, '')
.split('.')
.map((n) => parseInt(n || 0));
const t = target
.replace(/[^0-9.]/g, '')
.split('.')
.map((n) => parseInt(n || 0));
for (let i = 0; i < Math.max(f.length, t.length); i++) {
if ((f[i] || 0) < (t[i] || 0)) return true;
if ((f[i] || 0) > (t[i] || 0)) return false;
}
return false;
}
function writeReport(report, error) {
const outPath = path.join(ROOT_DIR, 'DEP_OVERRIDE_REPORT.md');
fs.writeFileSync(outPath, report);
const message =
error || '✅ Dependency override audit complete! Project has been restored to its original state.';
console.log(message);
console.log('📄 See DEP_OVERRIDE_REPORT.md for details.');
}
function genOverrideReport() {
console.log('🚀 Starting Dependency Override Audit. Backing up package.json...');
let report = '# 🛡️ PNPM Override Audit Report\n\n';
report += `Generated on: ${new Date().toLocaleString()}\n\n`;
if (!fs.existsSync(PKG_PATH)) {
report += `❌ **Error:** package.json not found at ${PKG_PATH}\n`;
writeReport(report, '❌ package.json not found.');
return;
}
// 1. Read and backup the original state
const originalPkgStr = fs.readFileSync(PKG_PATH, 'utf8');
const originalLockStr = fs.existsSync(LOCK_PATH) ? fs.readFileSync(LOCK_PATH, 'utf8') : null;
const pkgJson = JSON.parse(originalPkgStr);
const overrides = pkgJson.pnpm?.overrides || {};
if (Object.keys(overrides).length === 0) {
report += '✅ **No overrides found in package.json.**\n';
writeReport(report);
return;
}
try {
// 2. Strip overrides and save the modified package.json
const tempPkgJson = JSON.parse(originalPkgStr);
delete tempPkgJson.pnpm.overrides;
fs.writeFileSync(PKG_PATH, JSON.stringify(tempPkgJson, null, 2));
// 3. Reinstall dependencies to recalculate lockfile AND physically update node_modules
console.log('⏳ Relinking node_modules to their natural state (this may take a minute)...');
execSync('pnpm install --no-frozen-lockfile --ignore-scripts', {
cwd: ROOT_DIR,
stdio: 'ignore',
});
// 4. Audit each removed override using pnpm list
for (const [overrideName, targetVersion] of Object.entries(overrides)) {
console.log(`🔎 Auditing natural resolution for ${overrideName}...`);
const culprits = new Map();
let rawJson;
try {
rawJson = execSync(`pnpm list "${overrideName}" --recursive --depth Infinity --json`, {
cwd: ROOT_DIR,
maxBuffer: 1024 * 1024 * 100,
}).toString();
} catch (e) {
console.error(`└──⚠️ Could not fetch tree for ${overrideName}.`);
// execSync attaches stdout and stderr to the error object when a command fails
const stdout = e.stdout ? e.stdout.toString().trim() : '';
const stderr = e.stderr ? e.stderr.toString().trim() : '';
report += `## \`${overrideName}\`\n**Target Override:** \`${targetVersion}\`\n\n`;
// If pnpm exited with 1 but output an empty JSON array, it means "Not Found"
if (stdout === '[]') {
report += `✅ **SAFE TO REMOVE (Orphaned)**\n\n`;
report += `> This package does not exist anywhere in the naturally resolved dependency tree. It was likely removed by an upstream dependency update.\n`;
} else if (e.code === 'ENOBUFS') {
report += `❓ **UNKNOWN (Buffer Overflow)**\n\n`;
report += `> The dependency tree is too large for the allocated memory.\n`;
} else {
const errorMsg = stderr || e.message;
report += `❓ **UNKNOWN (Error)**\n\n`;
report += `> The script encountered an error resolving this package:\n> \`${errorMsg}\`\n`;
}
report += `\n---\n`;
continue; // Immediately jump to the next override in the loop
}
const data = JSON.parse(rawJson);
const scanTree = (parentName, parentVersion, depsObject) => {
if (!depsObject) return;
for (const [depName, depInfo] of Object.entries(depsObject)) {
if (!depInfo) continue;
if (depName === overrideName && depInfo.version) {
const resolvedVersion = depInfo.version;
if (isOlder(resolvedVersion, targetVersion)) {
culprits.set(`${parentName}@${parentVersion}`, resolvedVersion);
}
}
// If this dependency has its own dependencies, it becomes the new parent
if (depInfo.dependencies) {
scanTree(depName, depInfo.version, depInfo.dependencies);
}
}
};
// Start the scan from the top-level workspaces/projects
data.forEach((project) => {
const projectName = project.name || 'Root Project';
const projectVersion = project.version || 'unknown';
const allDeps = {
...project.dependencies,
...project.devDependencies,
...project.optionalDependencies,
};
scanTree(projectName, projectVersion, allDeps);
});
// Generate markdown segment
report += `## \`${overrideName}\`\n**Target Override:** \`${targetVersion}\`\n\n`;
if (culprits.size > 0) {
report += `⚠️ **REQUIRED**\n\n`;
report += `> These packages will continue to receive the overridden version until they are updated to naturally resolve to >= ${targetVersion}.\n\n`;
report += `| Parent Package | Naturally Resolved Version |\n| :--- | :--- |\n`;
const sortedCulprits = Array.from(culprits.entries()).sort();
for (const [parent, resolved] of sortedCulprits) {
report += `| \`${parent}\` | \`${resolved}\` |\n`;
}
} else {
report += `✅ **SAFE TO REMOVE**\n\n`;
report += `> All packages naturally resolve to >= ${targetVersion} without the override.\n`;
}
report += `\n---\n`;
}
} finally {
// 5. Restore original package.json, lockfile, and node_modules
console.log('🧹 Cleaning up: Restoring package.json, lockfile, and node_modules...');
// Put the files back
fs.writeFileSync(PKG_PATH, originalPkgStr);
if (originalLockStr) {
fs.writeFileSync(LOCK_PATH, originalLockStr);
}
// Run a full install again to force pnpm to re-apply overrides to node_modules
try {
execSync('pnpm install --no-frozen-lockfile --ignore-scripts', {
cwd: ROOT_DIR,
stdio: 'ignore',
});
} catch (e) {
console.error("⚠️ Cleanup failed, you may need to run 'pnpm install' manually.");
}
// Write the report
writeReport(report);
}
}
genOverrideReport();