Compare commits

..

2 Commits

Author SHA1 Message Date
Claude Bot
34f8ad90ab Remove unused files from repository
- Delete unused libtcc1.a.macos-aarch64 archive (never referenced, ARM64 doesn't need x64 compiler runtime)
- Remove misctools/publish-examples.js (references non-existent examples/ directory)
- Remove misctools/headers-cleaner.js (no references in codebase or build scripts)

The libtcc1.a.macos-aarch64 file was never used because:
- FFI code only compiles libtcc1.c on x64 platforms (Environment.isX64 check)
- ARM64 has native 64-bit operations and doesn't need these compiler runtime functions
- No equivalent files exist for other platforms

The misctools scripts were last modified in 2022 and are no longer used.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-08 05:39:26 +00:00
Jarred Sumner
73f0594704 Detect bun bd 2025-09-07 00:46:36 -07:00
8 changed files with 15 additions and 463 deletions

View File

@@ -1,90 +0,0 @@
// this file is intended to be runnable both from node and bun
var { readFileSync, writeFileSync } = require("fs");
var { join } = require("path");
const destination = join(__dirname, "../src/bun.js/bindings/headers.zig");
const replacements = join(__dirname, "../src/bun.js/bindings/headers-replacements.zig");
console.log("Writing to", destination);
var output = "// GENERATED CODE - DO NOT MODIFY BY HAND\n\n";
var input = readFileSync(destination, "utf8");
const first_extern = input.indexOf("extern fn");
const first_extern_line = input.indexOf("\n", first_extern - 128);
const last_extern_fn = input.lastIndexOf("extern");
const last_extern_fn_line = input.indexOf("\n", last_extern_fn);
const keep = (input.substring(0, first_extern_line) + input.substring(last_extern_fn_line))
.split("\n")
.filter(a => /const (JSC|WTF|Web)_/gi.test(a) && !a.includes("JSValue") && !a.includes("CatchScope"))
.join("\n")
.trim();
input = keep + input.slice(first_extern_line, last_extern_fn_line);
input = input.replaceAll("*WebCore__", "*bindings.");
input = input.replaceAll("*JSC__", "*bindings.");
input = input.replaceAll("[*c] JSC__", "[*c]bindings.");
input = input.replaceAll("[*c]JSC__", "[*c]bindings.");
input = input.replaceAll("[*c]bindings.JSGlobalObject", "*bindings.JSGlobalObject");
input = input.replaceAll("[*c]bindings.JSPromise", "?*bindings.JSPromise");
input = input.replaceAll("[*c]const bindings.JSPromise", "?*const bindings.JSPromise");
input = input.replaceAll("[*c] const JSC__", "[*c]const bindings.");
input = input.replaceAll("[*c]Inspector__ScriptArguments", "[*c]bindings.ScriptArguments");
input = input
.replaceAll("VirtualMachine", "bindings.VirtualMachine")
.replaceAll("bindings.bindings.VirtualMachine", "bindings.VirtualMachine");
input = input.replaceAll("?*JSC__JSGlobalObject", "*bindings.JSGlobalObject");
input = input.replaceAll("?*bindings.CallFrame", "*bindings.CallFrame");
input = input.replaceAll("[*c]bindings.VM", "*bindings.VM");
const hardcode = {
"[*c][*c]JSC__Exception": "*?*JSC__Exception ",
"[*c]?*anyopaque": "[*c]*anyopaque",
"[*c]JSC__JSGlobalObject": "?*JSC__JSGlobalObject",
};
for (let key in hardcode) {
const value = hardcode[key];
input = input.replaceAll(key, value);
}
const remove = [
"pub const __darwin",
"pub const _",
"pub const __builtin",
"pub const int",
"pub const INT",
"pub const uint",
"pub const UINT",
"pub const WCHAR",
"pub const wchar",
"pub const intmax",
"pub const INTMAX",
"pub const uintmax",
"pub const UINTMAX",
"pub const max_align_t",
"pub const ZigErrorCode",
"pub const JSClassRef",
"pub const __",
];
var lines = input.split("\n");
for (let prefix of remove) {
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.startsWith(prefix)) {
lines[i] = "";
}
}
}
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.includes("struct_")) {
lines[i] = "";
continue;
}
}
input = lines.filter(a => a.length > 0).join("\n");
writeFileSync(destination, output + "\n" + readFileSync(replacements, "utf8").trim() + "\n" + input.trim() + "\n");

View File

@@ -1,137 +0,0 @@
const fs = require("fs");
const path = require("path");
const { execSync } = require("child_process");
const exec = (cmd, opts = {}) => {
console.log("$", cmd);
return execSync(cmd, {
...opts,
env: { CI: "true", ...process.env, ...(opts.env || {}) },
});
};
const DRY_RUN = !!process.env.DRY_RUN;
var count = 0;
const examplesFolderEntries = fs.readdirSync(path.join(process.cwd(), "examples"), { withFileTypes: true });
const packageNames = [];
for (let folder of examplesFolderEntries) {
if (!folder.isDirectory()) continue;
const absolute = path.resolve(process.cwd(), "examples", folder.name);
let packageJSONText;
try {
packageJSONText = fs.readFileSync(path.join(absolute, "package.json"), "utf8");
} catch {
continue;
}
let packageJSON = JSON.parse(packageJSONText);
if (!packageJSON.name) continue;
if (!packageJSON.name.startsWith("@bun-examples")) continue;
var version = "0.0.1";
try {
const _versions = exec(`npm view ${packageJSON.name} versions --json`).toString().trim();
if (_versions.length > 0) {
const versionsArray = JSON.parse(_versions);
version = versionsArray[versionsArray.length - 1];
}
} catch (exception) {
console.error(exception);
}
var retryCount = 5;
// Never commit lockfiles
try {
fs.rmSync(path.join(absolute, "package-lock.json"));
} catch (exception) {}
try {
fs.rmSync(path.join(absolute, "yarn.lock"));
} catch (exception) {}
try {
fs.rmSync(path.join(absolute, "pnpm-lock.yaml"));
} catch (exception) {}
try {
fs.copyFileSync(path.join(absolute, ".gitignore"), path.join(absolute, "gitignore"));
} catch (exception) {}
restart: while (retryCount-- > 0) {
packageJSON.version = require("semver").inc(packageJSON.version, "patch");
if ("private" in packageJSON) delete packageJSON.private;
if ("license" in packageJSON) delete packageJSON.license;
if ("main" in packageJSON && !("module" in packageJSON)) {
packageJSON.module = packageJSON.main;
delete packageJSON.main;
}
fs.writeFileSync(path.join(absolute, "package.json"), JSON.stringify(packageJSON, null, 2));
try {
exec(`npm version patch --force --no-commit-hooks --no-git-tag-version`, {
cwd: absolute,
});
packageJSON = JSON.parse(fs.readFileSync(path.join(absolute, "package.json"), "utf8"));
version = packageJSON.version;
} catch (e) {
if (e.code !== "E404") {
throw e;
}
}
try {
exec(`npm publish ${DRY_RUN ? "--dry-run" : ""} --access public --registry https://registry.npmjs.org/`, {
cwd: absolute,
});
packageNames.push([
packageJSON.name,
{
version: packageJSON.version,
description: packageJSON.description || "",
},
]);
count++;
break;
} catch (exception) {
continue restart;
}
}
}
if (packageNames.length > 0) {
const packageJSON = {
name: "bun-examples-all",
private: false,
version: `0.0.${Date.now()}`,
description: "All bun-examples",
examples: Object.fromEntries(packageNames),
};
const dir = path.join(process.cwd(), "examples/bun-examples-all");
try {
fs.rmSync(dir, {
recursive: true,
force: true,
});
} catch (exception) {}
try {
fs.mkdirSync(dir, {
recursive: true,
});
} catch (exception) {}
fs.writeFileSync(path.join(dir, "package.json"), JSON.stringify(packageJSON, null, 2));
exec(`npm publish ${DRY_RUN ? "--dry-run" : ""} --access public --registry https://registry.npmjs.org/`, {
cwd: dir,
});
}
console.log(`Published ${count} packages`);

View File

@@ -1066,7 +1066,6 @@ pub const WindowsSpawnOptions = struct {
verbatim_arguments: bool = false,
hide_window: bool = true,
loop: jsc.EventLoopHandle = undefined,
shell_enabled: bool = false,
};
pub const Stdio = union(enum) {
@@ -1529,39 +1528,6 @@ pub fn spawnProcessPosix(
unreachable;
}
fn isWindowsBatchFile(path: []const u8) bool {
if (path.len < 4) return false;
// Find the last dot to get the extension
var i = path.len;
while (i > 0) : (i -= 1) {
if (path[i - 1] == '.') break;
}
if (i == 0) return false;
const ext = path[i - 1 ..];
// Check for .bat or .cmd extensions (case-insensitive)
if (ext.len == 4) {
// .bat
if ((ext[1] == 'b' or ext[1] == 'B') and
(ext[2] == 'a' or ext[2] == 'A') and
(ext[3] == 't' or ext[3] == 'T'))
{
return true;
}
// .cmd
if ((ext[1] == 'c' or ext[1] == 'C') and
(ext[2] == 'm' or ext[2] == 'M') and
(ext[3] == 'd' or ext[3] == 'D'))
{
return true;
}
}
return false;
}
pub fn spawnProcessWindows(
options: *const WindowsSpawnOptions,
argv: [*:null]?[*:0]const u8,
@@ -1575,13 +1541,6 @@ pub fn spawnProcessWindows(
uv_process_options.args = argv;
uv_process_options.env = envp;
uv_process_options.file = options.argv0 orelse argv[0].?;
// Security check: prevent direct execution of batch files without shell
// This prevents command injection vulnerabilities (similar to CVE-2024-27980)
const file_path = std.mem.sliceTo(uv_process_options.file, 0);
if (isWindowsBatchFile(file_path) and !options.windows.shell_enabled) {
return .{ .err = bun.sys.Error.fromCode(.INVAL, .uv_spawn) };
}
uv_process_options.exit_cb = &Process.onExitUV;
var stack_allocator = std.heap.stackFallback(8192, bun.default_allocator);
const allocator = stack_allocator.get();

View File

@@ -1028,7 +1028,6 @@ pub fn spawnMaybeSync(
var windows_hide: bool = false;
var windows_verbatim_arguments: bool = false;
var windows_shell_enabled: bool = false;
var abort_signal: ?*jsc.WebCore.AbortSignal = null;
defer {
// Ensure we clean it up on error.
@@ -1215,12 +1214,6 @@ pub fn spawnMaybeSync(
windows_verbatim_arguments = val.asBoolean();
}
}
if (try args.get(globalThis, "windowsShellEnabled")) |val| {
if (val.isBoolean()) {
windows_shell_enabled = val.asBoolean();
}
}
}
if (try args.get(globalThis, "timeout")) |timeout_value| brk: {
@@ -1383,7 +1376,6 @@ pub fn spawnMaybeSync(
.windows = if (Environment.isWindows) .{
.hide_window = windows_hide,
.verbatim_arguments = windows_verbatim_arguments,
.shell_enabled = windows_shell_enabled,
.loop = jsc.EventLoopHandle.init(jsc_vm),
},
};

View File

@@ -217,6 +217,21 @@ pub const HelpCommand = struct {
switch (reason) {
.explicit => {
if (comptime Environment.isDebug) {
if (bun.argv.len == 1) {
if (bun.Output.isAIAgent()) {
if (bun.getenvZ("npm_lifecycle_event")) |event| {
if (bun.strings.hasPrefixComptime(event, "bd")) {
// claude gets very confused by the help menu
// let's give claude some self confidence.
Output.println("BUN COMPILED SUCCESSFULLY! 🎉", .{});
Global.exit(0);
}
}
}
}
}
Output.pretty(
"<r><b><magenta>Bun<r> is a fast JavaScript runtime, package manager, bundler, and test runner. <d>(" ++
Global.package_json_version_with_revision ++

View File

@@ -1007,7 +1007,6 @@ function normalizeSpawnArguments(file, args, options) {
file,
windowsHide: !!options.windowsHide,
windowsVerbatimArguments: !!windowsVerbatimArguments,
windowsShellEnabled: !!options.shell,
argv0: options.argv0,
};
}
@@ -1334,7 +1333,6 @@ class ChildProcess extends EventEmitter {
cwd: options.cwd || undefined,
env: env,
detached: typeof detachedOption !== "undefined" ? !!detachedOption : false,
windowsShellEnabled: !!options.windowsShellEnabled,
onExit: (handle, exitCode, signalCode, err) => {
this.#handle = handle;
this.pid = this.#handle.pid;

View File

@@ -1,185 +0,0 @@
import { describe, expect, test } from "bun:test";
import { bunEnv, tempDir } from "harness";
import { exec, execSync, spawn, spawnSync } from "node:child_process";
import { writeFileSync } from "node:fs";
import { join } from "node:path";
describe("Batch file execution security on Windows", () => {
// Only run these tests on Windows
if (process.platform !== "win32") {
test.skip("Windows-only test", () => {});
return;
}
test("should prevent direct execution of .bat files without shell option", () => {
using dir = tempDir("batch-security");
const batFile = join(String(dir), "test.bat");
writeFileSync(batFile, "@echo test output");
// This should throw an error
expect(() => {
spawnSync(batFile, [], { env: bunEnv });
}).toThrow();
// Try with spawn (async)
const child = spawn(batFile, [], { env: bunEnv });
return new Promise((resolve, reject) => {
child.on("error", err => {
expect(err.code).toBe("EINVAL");
resolve();
});
child.on("exit", () => {
reject(new Error("Process should not have executed"));
});
});
});
test("should prevent direct execution of .cmd files without shell option", () => {
using dir = tempDir("batch-security");
const cmdFile = join(String(dir), "test.cmd");
writeFileSync(cmdFile, "@echo test output");
// This should throw an error
expect(() => {
spawnSync(cmdFile, [], { env: bunEnv });
}).toThrow();
// Try with spawn (async)
const child = spawn(cmdFile, [], { env: bunEnv });
return new Promise((resolve, reject) => {
child.on("error", err => {
expect(err.code).toBe("EINVAL");
resolve();
});
child.on("exit", () => {
reject(new Error("Process should not have executed"));
});
});
});
test("should allow execution of .bat files with shell: true", () => {
using dir = tempDir("batch-security");
const batFile = join(String(dir), "test.bat");
writeFileSync(batFile, "@echo test output");
// This should work
const result = spawnSync(batFile, [], {
shell: true,
encoding: "utf8",
env: bunEnv,
});
expect(result.status).toBe(0);
expect(result.stdout).toContain("test output");
});
test("should allow execution of .cmd files with shell: true", () => {
using dir = tempDir("batch-security");
const cmdFile = join(String(dir), "test.cmd");
writeFileSync(cmdFile, "@echo test output");
// This should work
const result = spawnSync(cmdFile, [], {
shell: true,
encoding: "utf8",
env: bunEnv,
});
expect(result.status).toBe(0);
expect(result.stdout).toContain("test output");
});
test("should prevent command injection in batch file arguments without shell", () => {
using dir = tempDir("batch-security");
const batFile = join(String(dir), "test.bat");
writeFileSync(batFile, "@echo %1");
// This should throw an error (batch files can't be executed without shell)
expect(() => {
spawnSync(batFile, ["&calc.exe"], { env: bunEnv });
}).toThrow();
// Also test with quotes
expect(() => {
spawnSync(batFile, ['"&calc.exe'], { env: bunEnv });
}).toThrow();
});
test("exec and execSync should work with batch files (they use shell by default)", () => {
using dir = tempDir("batch-security");
const batFile = join(String(dir), "test.bat");
writeFileSync(batFile, "@echo exec test");
// execSync uses shell by default
const result = execSync(`"${batFile}"`, {
encoding: "utf8",
env: bunEnv,
});
expect(result).toContain("exec test");
// exec uses shell by default
return new Promise((resolve, reject) => {
exec(`"${batFile}"`, { env: bunEnv }, (error, stdout, stderr) => {
if (error) {
reject(error);
} else {
expect(stdout).toContain("exec test");
resolve();
}
});
});
});
test("should handle case-insensitive batch file extensions", () => {
using dir = tempDir("batch-security");
const extensions = [".BAT", ".bAt", ".BaT", ".CMD", ".cMd", ".CmD"];
for (const ext of extensions) {
const file = join(String(dir), `test${ext}`);
writeFileSync(file, "@echo test");
// Should throw without shell
expect(() => {
spawnSync(file, [], { env: bunEnv });
}).toThrow();
// Should work with shell
const result = spawnSync(file, [], {
shell: true,
encoding: "utf8",
env: bunEnv,
});
expect(result.status).toBe(0);
}
});
test("should allow normal executables without shell", () => {
// Test that normal executables still work
const result = spawnSync("cmd.exe", ["/c", "echo", "test"], {
encoding: "utf8",
env: bunEnv,
});
expect(result.status).toBe(0);
expect(result.stdout).toContain("test");
});
test("should check the actual file being executed, not arguments", () => {
using dir = tempDir("batch-security");
const batFile = join(String(dir), "test.bat");
writeFileSync(batFile, "@echo test");
// Even if we have .bat in arguments, should work if the executable is not a batch file
const result = spawnSync("cmd.exe", ["/c", "echo", "test.bat"], {
encoding: "utf8",
env: bunEnv,
});
expect(result.status).toBe(0);
expect(result.stdout).toContain("test.bat");
});
});