From ccc8a240812bcd957570ff9840ce545dc239e3e4 Mon Sep 17 00:00:00 2001 From: Alistair Smith Date: Wed, 30 Jul 2025 13:42:56 -0700 Subject: [PATCH] tests --- .../PackageManager/install_with_manager.zig | 25 +++++--- .../bun-install-security-provider.test.ts | 64 ++++++++++--------- 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/src/install/PackageManager/install_with_manager.zig b/src/install/PackageManager/install_with_manager.zig index b26f0005ab..8acf7c549d 100644 --- a/src/install/PackageManager/install_with_manager.zig +++ b/src/install/PackageManager/install_with_manager.zig @@ -1042,8 +1042,8 @@ fn performSecurityScanAfterResolution( if (manager.update_requests.len == 0) return; var json_buf = std.ArrayList(u8).init(manager.allocator); - defer json_buf.deinit(); var writer = json_buf.writer(); + defer json_buf.deinit(); const string_buf = manager.lockfile.buffers.string_bytes.items; const packages = manager.lockfile.packages.slice(); @@ -1061,13 +1061,22 @@ fn performSecurityScanAfterResolution( const resolution = resolutions[package_id]; const name = names[package_id].slice(string_buf); + var version_buf: [256]u8 = undefined; const version = switch (resolution.tag) { - .npm => resolution.value.npm.version.slice(string_buf), + .npm => std.fmt.bufPrint(&version_buf, "{}", .{resolution.value.npm.version.fmt(string_buf)}) catch "", .local_tarball => resolution.value.local_tarball.slice(string_buf), .remote_tarball => resolution.value.remote_tarball.slice(string_buf), .folder => resolution.value.folder.slice(string_buf), - .git => resolution.value.git.url.slice(string_buf), - .github => resolution.value.github.url.slice(string_buf), + .git => blk: { + var stream = std.io.fixedBufferStream(&version_buf); + resolution.value.git.formatAs("git+", string_buf, "", .{}, stream.writer()) catch break :blk ""; + break :blk stream.getWritten(); + }, + .github => blk: { + var stream = std.io.fixedBufferStream(&version_buf); + resolution.value.github.formatAs("github:", string_buf, "", .{}, stream.writer()) catch break :blk ""; + break :blk stream.getWritten(); + }, .workspace => "workspace", .symlink => "link", else => continue, @@ -1242,16 +1251,16 @@ fn performSecurityScanAfterResolution( const item_obj = item.data.e_object; - const name_expr = item_obj.get("name") orelse { - Output.errGeneric("Security advisory at index {d} missing required 'name' field", .{i}); + const name_expr = item_obj.get("package") orelse { + Output.errGeneric("Security advisory at index {d} missing required 'package' field", .{i}); Global.exit(1); }; const name_str = name_expr.asString(manager.allocator) orelse { - Output.errGeneric("Security advisory at index {d} 'name' field must be a string", .{i}); + Output.errGeneric("Security advisory at index {d} 'package' field must be a string", .{i}); Global.exit(1); }; if (name_str.len == 0) { - Output.errGeneric("Security advisory at index {d} 'name' field cannot be empty", .{i}); + Output.errGeneric("Security advisory at index {d} 'package' field cannot be empty", .{i}); Global.exit(1); } diff --git a/test/cli/install/bun-install-security-provider.test.ts b/test/cli/install/bun-install-security-provider.test.ts index 1cb099704c..a5434cc3ff 100644 --- a/test/cli/install/bun-install-security-provider.test.ts +++ b/test/cli/install/bun-install-security-provider.test.ts @@ -7,6 +7,7 @@ import { dummyRegistry, package_dir, read, + root_url, setHandler, write, } from "./dummy.registry.js"; @@ -19,24 +20,25 @@ afterEach(dummyAfterEach); function run( name: string, options: { - scanner: Bun.Install.Security.Provider["onInstall"]; + scanner: Bun.Install.Security.Provider["onInstall"] | string; fails: boolean; expect?: (std: { out: string; err: string }) => void | Promise; }, ) { test(name, async () => { const urls: string[] = []; - setHandler(dummyRegistry(urls, { "0.0.5": { as: "0.0.5" } })); + setHandler(dummyRegistry(urls)); - await write( - "./scanner.ts", - ` - export default { - version: "1", - onInstall: ${options.scanner.toString()}, - } satisfies Bun.Install.Security.Provider; - `, - ); + if (typeof options.scanner === "string") { + await write("./scanner.ts", options.scanner); + } else { + const s = `export const provider = { + version: "1", + onInstall: ${options.scanner.toString()}, +};`; + + await write("./scanner.ts", s); + } const bunfig = await read("./bunfig.toml").text(); await write("./bunfig.toml", bunfig + "\n" + "[install.security]" + "\n" + 'provider = "./scanner.ts"'); @@ -47,24 +49,20 @@ function run( dependencies: {}, }); - const pkg = "pkg"; - const { out, err } = await runBunInstall(bunEnv, package_dir, { - packages: [pkg], + packages: ["bar"], allowErrors: true, allowWarnings: false, savesLockfile: false, expectedExitCode: 1, }); - expect(urls).toEqual([]); - - expect(out).toContain(`Security scanner is checking packages: ${pkg}`); - if (options.fails) { - expect(err).toContain("Installation cancelled due to fatal security advisories"); + expect(out).toContain("Installation cancelled due to fatal security issues"); } + expect(urls).toEqual([root_url + "/bar", root_url + "/bar-0.0.2.tgz"]); + await options.expect?.({ out, err }); }); } @@ -98,18 +96,22 @@ run("expect output to contain the advisory", { run("stdout contains all input package metadata", { fails: true, - scanner: async ({ packages }) => [ - { - package: packages[0].name, - description: "Advisory 1 description", - level: "fatal", - url: "https://example.com/advisory-1", - }, - ], + scanner: async ({ packages }) => { + console.log(JSON.stringify(packages)); + + return [ + { + package: packages[0].name, + description: "Advisory 1 description", + level: "fatal", + url: "https://example.com/advisory-1", + }, + ]; + }, expect: ({ out }) => { - expect(out).toContain('"version": "1.0.0"'); - expect(out).toContain('"name": "pkg"'); - expect(out).toContain('"requestedRange": "latest"'); - expect(out).toContain('"registryUrl": "https://registry.npmjs.org"'); + expect(out).toContain('\"version\":\"0.0.2\"'); + expect(out).toContain('\"name\":\"bar\"'); + expect(out).toContain('\"requestedRange\":\"^0.0.2\"'); + expect(out).toContain(`\"registryUrl\":\"${root_url}/\"`); }, });