
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
ruby-wasm-wasi
Advanced tools
WebAssembly port of CRuby with WASI.
The CRuby source code is available at a working branch.
For instaling ruby-wasm-wasi, just run this command in your shell:
$ npm install --save ruby-head-wasm-wasi
See the example project for more details.
import fs from "fs/promises";
import { WASI } from "wasi";
import { RubyVM } from "ruby-head-wasm-wasi";
const main = async () => {
const wasi = new WASI();
const binary = await fs.readFile(
"./node_modules/ruby-head-wasm-wasi/ruby.wasm"
);
const vm = new RubyVM();
const imports = {
wasi_snapshot_preview1: wasi.wasiImport,
};
// Add imports for WebAssembly instantiation
vm.addToImports(imports);
// Instantiate the WebAssembly module
const { instance } = await WebAssembly.instantiate(binary.buffer, imports);
// Set instance to vm
await vm.setInstance(instance);
// Initialize WASI application
wasi.initialize(instance);
// Initialize Ruby VM
vm.initialize();
vm.eval(`
luckiness = ["Lucky", "Unlucky"].sample
puts "You are #{luckiness}"
`);
};
main();
Then you can run the example project in your terminal:
$ node --experimental-wasi-unstable-preview1 index.node.js
In browser, you need a WASI polyfill See the example project for more details.
import { WASI } from "@wasmer/wasi";
import { WasmFs } from "@wasmer/wasmfs";
import { RubyVM } from "ruby-head-wasm-wasi";
const main = async () => {
// Setup WASI and FileSystem emulation
const wasmFs = new WasmFs();
const wasi = new WASI({
bindings: {
...WASI.defaultBindings,
fs: wasmFs.fs,
},
});
// (Optional) Forward stdout/stderr to console
const originalWriteSync = wasmFs.fs.writeSync.bind(wasmFs.fs);
wasmFs.fs.writeSync = (fd, buffer, offset, length, position) => {
const text = new TextDecoder("utf-8").decode(buffer);
const handlers = {
1: (line) => console.log(line),
2: (line) => console.warn(line),
};
if (handlers[fd]) handlers[fd](text);
return originalWriteSync(fd, buffer, offset, length, position);
};
// Fetch and instantiate WebAssembly binary
const response = await fetch(
"./node_modules/ruby-head-wasm-wasi/dist/ruby.wasm"
);
const buffer = await response.arrayBuffer();
const vm = new RubyVM();
const imports = {
wasi_snapshot_preview1: wasi.wasiImport,
};
// Add imports for WebAssembly instantiation
vm.addToImports(imports);
// Instantiate the WebAssembly module
const { instance } = await WebAssembly.instantiate(buffer, imports);
// Set instance to vm
await vm.setInstance(instance);
// Initialize WASI application
wasi.setMemory(instance.exports.memory);
// Initialize Ruby VM
vm.initialize();
vm.eval(`
require "js"
luckiness = ["Lucky", "Unlucky"].sample
JS::eval("document.body.innerText = '#{luckiness}'")
`);
};
main();
A Ruby VM instance
const wasi = new WASI();
const vm = new RubyVM();
const imports = {
wasi_snapshot_preview1: wasi.wasiImport,
};
vm.addToImports(imports);
const instance = await WebAssembly.instantiate(rubyModule, imports);
await vm.setInstance(instance);
wasi.initialize(instance);
Initialize the Ruby VM with the given command line arguments
args The command line arguments to pass to Ruby. Must be
an array of strings starting with the Ruby program name. (optional, default ["ruby.wasm","--disable-gems","-e_=0"])Set a given instance to interact JavaScript and Ruby's WebAssembly instance. This method must be called before calling Ruby API.
instance The WebAssembly instance to interact with. Must
be instantiated from a Ruby built with JS extension, and built
with Reactor ABI instead of command line.Add intrinsic import entries, which is necessary to interact JavaScript and Ruby's WebAssembly instance.
imports The import object to add to the WebAssembly instancePrint the Ruby version to stdout
Runs a string of Ruby code from JavaScript
code The Ruby code to runvm.eval("puts 'hello world'");
const result = vm.eval("1 + 2");
console.log(result.toString()); // 3
Returns any the result of the last expression
A RbValue is an object that represents a value in Ruby
innervmexporterCall a given method with given arguments
callee name of the Ruby method to callargs ...any arguments to pass to the method. Must be an array of RbValueconst ary = vm.eval("[1, 2, 3]");
ary.call("push", 4);
console.log(ary.call("sample").toString());
hintReturns a string representation of the value by calling to_s
Returns a JavaScript object representation of the value
by calling to_js.
Returns null if the value is not convertible to a JavaScript object.
Extends Error
Error class thrown by Ruby execution
messageFor building the package from source, you need to prepare a Ruby build produced by WASI SDK, and you need wit-bindgen and wasm-opt in your PATH.
The instructions for building a Ruby targeting WebAssembly are available at: TODO.
Then, you can run the following command in your shell:
# Check the directory structure of your Ruby build
$ tree -L 3 path/to/wasm32-unknown-wasi-full-js/
path/to/wasm32-unknown-wasi-full-js/
├── usr
│ └── local
│ ├── bin
│ ├── include
│ ├── lib
│ └── share
└── var
└── lib
└── gems
$ ./build-package.sh path/to/wasm32-unknown-wasi-full-js/
Generating "/Users/katei/.ghq/github.com/kateinoigakukun/ruby.wasm/packages/ruby-wasm-wasi/src/bindgen/intrinsics.js"
Generating "/Users/katei/.ghq/github.com/kateinoigakukun/ruby.wasm/packages/ruby-wasm-wasi/src/bindgen/rb-abi-guest.d.ts"
Generating "/Users/katei/.ghq/github.com/kateinoigakukun/ruby.wasm/packages/ruby-wasm-wasi/src/bindgen/rb-abi-guest.js"
Generating "/Users/katei/.ghq/github.com/kateinoigakukun/ruby.wasm/packages/ruby-wasm-wasi/src/bindgen/rb-js-abi-host.d.ts"
Generating "/Users/katei/.ghq/github.com/kateinoigakukun/ruby.wasm/packages/ruby-wasm-wasi/src/bindgen/rb-js-abi-host.js"
src/index.ts → dist/index.umd.js, dist/index.esm.js, dist/index.cjs.js...
created dist/index.umd.js, dist/index.esm.js, dist/index.cjs.js in 682ms
FAQs
WebAssembly port of CRuby with WASI
We found that ruby-wasm-wasi demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.