Project

runbox

0.0
No release in over 3 years
Official Ruby client for Runbox, a fast and secure API for running code in isolated containers.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 5.21
~> 13.0
~> 1.60
~> 3.19

Runtime

~> 2.9
 Project Readme

README.md

Runbox Ruby Client

Official Ruby client for Runbox - a fast, secure API for running code in isolated containers.

Gem Version CI License: MIT

Installation

Add to your Gemfile:

gem "runbox"

Or install directly:

gem install runbox

Quick Start

require "runbox"

# Configure (or use environment variables)
Runbox.configure do |config|
  config.url = "http://localhost:8080"
  config.api_key = "your-api-key"
end

# Create a client
client = Runbox::Client.new

# Step 1: Set up a container and get environment info
setup = client.setup(
  identifier: "my-session",
  language: "python"
)

puts setup.container_id  # => "runbox-my-session-python"
puts setup.environment_snapshot.runtime_version  # => "3.11.6"
puts setup.environment_snapshot.packages["requests"]  # => "2.31.0"

# Step 2: Run code in the container
result = client.run(
  container_id: setup.container_id,
  files: [{ path: "main.py", content: "print('Hello!')" }],
  run_command: "python main.py"
)

puts result.stdout  # => "Hello!\n"
puts result.success?  # => true

Configuration

Using Environment Variables

export RUNBOX_URL=http://localhost:8080
export RUNBOX_API_KEY=your-api-key

Using Configuration Block

Runbox.configure do |config|
  config.url = "http://localhost:8080"
  config.api_key = "your-api-key"
  config.timeout = 60  # HTTP timeout
end

Per-Client Configuration

client = Runbox::Client.new(
  url: "http://localhost:8080",
  api_key: "your-api-key"
)

Usage

Setting Up a Container

setup = client.setup(
  identifier: "session-123",
  language: "python",
  env: { "API_KEY" => "secret" },  # Optional: set environment variables
  memory: "512m",                   # Optional: memory limit
  network_allow: ["api.stripe.com"] # Optional: allowed network destinations
)

# Access environment information
puts setup.container_id  # => "runbox-session-123-python"
puts setup.cached?       # => false (true if container was reused)

env = setup.environment_snapshot
puts env.os_name          # => "debian"
puts env.os_version       # => "12"
puts env.runtime_name     # => "python"
puts env.runtime_version  # => "3.11.6"
puts env.packages         # => {"pip" => "23.0.1", "requests" => "2.31.0", ...}

Running Code

result = client.run(
  container_id: "runbox-session-123-python",
  files: [{ path: "main.py", content: "print('Hello!')" }],
  run_command: "python main.py",
  env: { "DEBUG" => "true" },  # Optional: runtime environment variables
  timeout: 30                   # Optional: execution timeout in seconds
)

puts result.success?          # => true
puts result.exit_code         # => 0
puts result.stdout            # => "Hello!\n"
puts result.stderr            # => ""
puts result.execution_time_ms # => 42
puts result.timeout?          # => false

Installing Dependencies On-The-Fly

Install new dependencies before running code:

# Python example
result = client.run(
  container_id: container_id,
  files: [{ path: "main.py", content: "import requests; print(requests.__version__)" }],
  run_command: "python main.py",
  new_dependencies: ["requests==2.31.0", "pytest"]
)

puts result.packages  # => {"pip"=>"23.0.1", "requests"=>"2.31.0", "pytest"=>"7.4.0", ...}

# Ruby example
result = client.run(
  container_id: container_id,
  files: [{ path: "main.rb", content: "require 'rake'; puts Rake::VERSION" }],
  run_command: "ruby main.rb",
  new_dependencies: ["rake", "rspec"]
)

# Shell example (uses apk)
result = client.run(
  container_id: container_id,
  files: [{ path: "script.sh", content: "#!/bin/sh\ncurl --version" }],
  run_command: "sh script.sh",
  new_dependencies: ["curl", "jq", "git"]
)

Note: The packages field is only included in the result when new_dependencies are provided.

Cleanup Containers

deleted = client.delete_containers("session-123")
puts deleted  # => ["runbox-session-123-python"]

Check Health

health = client.health
puts health[:status]  # => "healthy"
puts health[:version] # => "1.0.0"

API Reference

client.setup(identifier:, language:, **options)

Set up a container and get environment information.

Parameters:

  • identifier (String, required): Unique identifier for container reuse
  • language (String, required): Programming language ("python", "ruby", "shell")
  • env (Hash, optional): Environment variables to set
  • timeout (Integer, optional): Default timeout in seconds
  • memory (String, optional): Memory limit (e.g., "256m", "1g")
  • network_allow (Array, optional): Allowed network destinations

Returns: SetupResult with:

  • container_id: Container ID to use in run() calls
  • cached?: Whether container was reused
  • environment_snapshot: Environment information (OS, runtime, packages)

client.run(container_id:, files:, run_command:, **options)

Run code in a container that was set up via setup().

Parameters:

  • container_id (String, required): Container ID from setup() response
  • files (Array, required): Files to write before running
  • run_command (String, required): Command to run
  • env (Hash, optional): Runtime environment variables
  • timeout (Integer, optional): Execution timeout in seconds

Returns: Result with:

  • success?: Whether run succeeded (exit code 0)
  • exit_code: Process exit code
  • stdout: Standard output
  • stderr: Standard error
  • execution_time_ms: Execution time in milliseconds
  • timeout?: Whether run timed out

Error Handling

begin
  setup = client.setup(identifier: "test", language: "python")
  result = client.run(
    container_id: setup.container_id,
    files: [{ path: "main.py", content: "print('hi')" }],
    run_command: "python main.py"
  )
rescue Runbox::AuthenticationError => e
  puts "Invalid API key"
rescue Runbox::NotFoundError => e
  puts "Container not found (did you call setup first?)"
rescue Runbox::ValidationError => e
  puts "Invalid request: #{e.message}"
rescue Runbox::RunError => e
  puts "Run failed: #{e.message}"
rescue Runbox::ConnectionError => e
  puts "Could not connect to Runbox"
end

Development

Running Tests

bundle install
bundle exec rake test

Running Integration Tests

Integration tests require a running Runbox server:

# Start Runbox server (in another terminal)
cd ../runbox
docker-compose up

# Run integration tests
export RUNBOX_URL=http://localhost:8080
export RUNBOX_API_KEY=your-api-key
ruby examples/integration_test.rb

Linting

bundle exec rubocop

CI/CD

  • CI: Runs on every push and PR

    • Tests on Ruby 3.1, 3.2, 3.3
    • Linting with RuboCop
    • Integration tests against live Runbox server
  • CD: Publishes to RubyGems on version tags

    • Create a tag: git tag v1.0.0 && git push --tags
    • Requires RUBYGEMS_API_KEY secret in GitHub

License

MIT License - see LICENSE for details.