mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
fix(audit): exclude workspace devDependencies in --prod mode (#26675)
When running `bun audit --prod` from a monorepo root, devDependencies of workspace packages were incorrectly being included in the audit. The bug was in the BFS traversal of buildProductionPackageSet(), which didn't check isDev() for transitive dependencies. This fix adds the missing isDev() check so workspace package devDependencies are properly excluded when auditing production deps. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -220,7 +220,9 @@ fn buildProductionPackageSet(allocator: std.mem.Allocator, pm: *PackageManager,
|
||||
const current_dep_slice = current_deps.get(dependencies);
|
||||
const current_res_slice = current_resolutions.get(resolutions);
|
||||
|
||||
for (current_dep_slice, current_res_slice) |_, resolved_pkg_id| {
|
||||
for (current_dep_slice, current_res_slice) |dep, resolved_pkg_id| {
|
||||
// Skip devDependencies - they should not be included in production audit
|
||||
if (dep.behavior.isDev()) continue;
|
||||
if (resolved_pkg_id >= pkg_names.len) continue;
|
||||
|
||||
const pkg_name = pkg_names[resolved_pkg_id].slice(buf);
|
||||
|
||||
171
test/regression/issue/26675.test.ts
Normal file
171
test/regression/issue/26675.test.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
import { spawn } from "bun";
|
||||
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe, gunzipJsonRequest, tempDir } from "harness";
|
||||
|
||||
// Test for GitHub issue #26675:
|
||||
// `bun audit --prod` should not include devDependencies of workspace packages
|
||||
|
||||
let server: Bun.Server;
|
||||
|
||||
beforeAll(() => {
|
||||
server = Bun.serve({
|
||||
port: 0,
|
||||
fetch: async req => {
|
||||
const body = await gunzipJsonRequest(req);
|
||||
|
||||
// Return vulnerabilities for ms@0.7.0, empty for everything else
|
||||
if (body && body.ms && body.ms.includes("0.7.0")) {
|
||||
return Response.json({
|
||||
ms: [
|
||||
{
|
||||
id: 1094419,
|
||||
url: "https://github.com/advisories/GHSA-w9mr-4mfr-499f",
|
||||
title: "Vercel ms Inefficient Regular Expression Complexity vulnerability",
|
||||
severity: "moderate",
|
||||
vulnerable_versions: "<2.0.0",
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
return Response.json({});
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
server.stop();
|
||||
});
|
||||
|
||||
const fakeIntegrity = "sha512-V8E0l1jyyeSSS9R+J9oljx5eq2rqzClInuwaPcyuv0Mm3ViI/3/rcc4rCEO8i4eQ4I0O0FAGYDA2i5xWHHPhzg==";
|
||||
|
||||
describe("issue #26675 - bun audit --prod with workspace devDependencies", () => {
|
||||
test("--prod flag should exclude devDependencies of workspace packages", async () => {
|
||||
using dir = tempDir("bun-test-audit-workspace-prod", {
|
||||
"package.json": JSON.stringify({
|
||||
name: "test-monorepo",
|
||||
private: true,
|
||||
workspaces: ["packages/*"],
|
||||
}),
|
||||
"packages/frontend/package.json": JSON.stringify({
|
||||
name: "test-frontend",
|
||||
devDependencies: {
|
||||
ms: "0.7.0",
|
||||
},
|
||||
}),
|
||||
"bun.lock": JSON.stringify({
|
||||
lockfileVersion: 1,
|
||||
workspaces: {
|
||||
"": {
|
||||
name: "test-monorepo",
|
||||
},
|
||||
"packages/frontend": {
|
||||
name: "test-frontend",
|
||||
devDependencies: {
|
||||
ms: "0.7.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
packages: {
|
||||
"test-frontend": ["test-frontend@workspace:packages/frontend"],
|
||||
ms: ["ms@0.7.0", "", {}, fakeIntegrity],
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const url = server.url.toString().slice(0, -1);
|
||||
|
||||
// First, verify that without --prod, the vulnerability is reported
|
||||
{
|
||||
await using proc = spawn({
|
||||
cmd: [bunExe(), "audit"],
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
cwd: String(dir),
|
||||
env: {
|
||||
...bunEnv,
|
||||
NPM_CONFIG_REGISTRY: url,
|
||||
},
|
||||
});
|
||||
|
||||
const [stdout, exitCode] = await Promise.all([proc.stdout.text(), proc.exited]);
|
||||
|
||||
expect(stdout).toContain("ms");
|
||||
expect(stdout).toContain("vulnerabilities");
|
||||
expect(exitCode).toBe(1);
|
||||
}
|
||||
|
||||
// Now verify that with --prod, the devDependency vulnerability is NOT reported
|
||||
{
|
||||
await using proc = spawn({
|
||||
cmd: [bunExe(), "audit", "--prod"],
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
cwd: String(dir),
|
||||
env: {
|
||||
...bunEnv,
|
||||
NPM_CONFIG_REGISTRY: url,
|
||||
},
|
||||
});
|
||||
|
||||
const [stdout, exitCode] = await Promise.all([proc.stdout.text(), proc.exited]);
|
||||
|
||||
expect(stdout).toContain("No vulnerabilities found");
|
||||
expect(exitCode).toBe(0);
|
||||
}
|
||||
});
|
||||
|
||||
test("--prod flag should still report production dependencies of workspace packages", async () => {
|
||||
using dir = tempDir("bun-test-audit-workspace-prod-deps", {
|
||||
"package.json": JSON.stringify({
|
||||
name: "test-monorepo",
|
||||
private: true,
|
||||
workspaces: ["packages/*"],
|
||||
}),
|
||||
"packages/frontend/package.json": JSON.stringify({
|
||||
name: "test-frontend",
|
||||
dependencies: {
|
||||
ms: "0.7.0",
|
||||
},
|
||||
}),
|
||||
"bun.lock": JSON.stringify({
|
||||
lockfileVersion: 1,
|
||||
workspaces: {
|
||||
"": {
|
||||
name: "test-monorepo",
|
||||
},
|
||||
"packages/frontend": {
|
||||
name: "test-frontend",
|
||||
dependencies: {
|
||||
ms: "0.7.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
packages: {
|
||||
"test-frontend": ["test-frontend@workspace:packages/frontend"],
|
||||
ms: ["ms@0.7.0", "", {}, fakeIntegrity],
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const url = server.url.toString().slice(0, -1);
|
||||
|
||||
// With --prod, production dependency vulnerabilities should still be reported
|
||||
await using proc = spawn({
|
||||
cmd: [bunExe(), "audit", "--prod"],
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
cwd: String(dir),
|
||||
env: {
|
||||
...bunEnv,
|
||||
NPM_CONFIG_REGISTRY: url,
|
||||
},
|
||||
});
|
||||
|
||||
const [stdout, exitCode] = await Promise.all([proc.stdout.text(), proc.exited]);
|
||||
|
||||
expect(stdout).toContain("ms");
|
||||
expect(stdout).toContain("vulnerabilities");
|
||||
expect(exitCode).toBe(1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user