2026-05-01 18:42:05 +00:00
2026-02-08 21:47:33 +00:00
2026-05-01 18:42:05 +00:00

@push.rocks/smartvm

Boot and control Firecracker microVMs from TypeScript without rebuilding the same host plumbing every time. @push.rocks/smartvm handles Firecracker binaries, Unix-socket API calls, per-VM runtime directories, base-image bundles, TAP/bridge networking, optional egress firewalling, host-side WireGuard routing, and cleanup so you can focus on the VM workload.

Issue Reporting and Security

For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.

Why It Rocks

smartvm is for programmers who want real microVM isolation with a TypeScript control plane and sane defaults:

  • 🚀 Boot Firecracker VMs with a few typed calls.
  • 🧊 Keep runtime state ephemeral by default with tmpfs-backed sockets and staged writable drives.
  • 🧰 Use known-good Firecracker CI images for quick starts, or ship your own hosted image manifest with SHA256 verification.
  • 🌐 Create Linux TAP devices, bridges, deterministic guest MACs, static guest IP data, and NAT without custom scripts.
  • 🔒 Apply VM-subnet egress policy with ordered IPv4 firewall rules.
  • 🕳️ Route all VM traffic through a host WireGuard interface without installing WireGuard in the guest.
  • 🧹 Tear down processes, sockets, TAP devices, bridge/NAT/firewall/WireGuard state, and staged drive copies.

What It Does

smartvm wraps the operational parts of Amazon Firecracker:

  • Downloads and caches Firecracker binaries.
  • Resolves bootable Firecracker CI base-image bundles with latest and lts presets.
  • Supports project-owned hosted base-image manifests with SHA256 verification.
  • Creates and controls microVMs through Firecracker's HTTP-over-Unix-socket API.
  • Converts TypeScript camelCase config into Firecracker's snake_case payloads.
  • Creates TAP devices, a Linux bridge, static guest network assignments, and NAT rules.
  • Applies optional global VM egress firewall rules for the managed subnet.
  • Routes VM egress through host-side WireGuard when configured.
  • Defaults VM runtime artifacts to tmpfs via /dev/shm/.smartvm/runtime when available.
  • Stages writable drives into per-VM ephemeral storage by default so guest writes do not touch cached rootfs files.
  • Cleans up Firecracker processes, sockets, TAPs, bridges, NAT/firewall/WireGuard rules, and staged drive copies.

The default mental model is: immutable base image, explicit writable scratch, no accidental persistent state, and persistence only when you opt in.

Install

pnpm add @push.rocks/smartvm

Runtime Requirements

Firecracker is a Linux/KVM technology. The package is TypeScript, but the runtime host must provide the VM substrate.

Requirement Why it matters
Linux with /dev/kvm Firecracker needs KVM acceleration.
Firecracker binary Downloaded by ensureBinary() or supplied through firecrackerBinaryPath.
Root privileges for networking TAP devices, bridges, IP forwarding, iptables NAT, firewalling, and WireGuard policy routing require elevated privileges.
Host tools: curl, tar, ip, sysctl, iptables, wg when WireGuard is used Used for binary/image downloads and network setup. dd and mkfs.ext4 are only needed for ImageManager.createBlankRootfs().
Enough tmpfs memory Writable VM drives are copied into /dev/shm by default when available.

If you only use VMConfig, SocketClient, or custom low-level flows without creating host networking, those pieces do not need root. Actual Firecracker boot still needs a Linux/KVM-capable host.

Quick Start

This is the happy path: let smartvm download Firecracker, resolve a known-good base image, boot it, and clean everything up. Run it on a Linux host with KVM access.

import { SmartVM } from '@push.rocks/smartvm';

const smartvm = new SmartVM({
  // Optional. Defaults are intentionally disk-light.
  dataDir: '/tmp/.smartvm',
  runtimeDir: '/dev/shm/.smartvm/runtime',
});

const baseImage = await smartvm.ensureBaseImage({ preset: 'latest' });

const vm = await smartvm.createVM({
  id: 'hello-firecracker',
  bootSource: {
    kernelImagePath: baseImage.kernelImagePath,
    bootArgs: baseImage.bootArgs,
  },
  machineConfig: {
    vcpuCount: 1,
    memSizeMib: 256,
  },
  drives: [
    {
      driveId: 'rootfs',
      pathOnHost: baseImage.rootfsPath,
      isRootDevice: true,
      isReadOnly: baseImage.rootfsIsReadOnly,
    },
  ],
});

try {
  await vm.start();
  console.log(vm.state); // "running"
  console.log(await vm.getVersion());
  console.log(await vm.getInfo());
} finally {
  if (vm.state === 'running' || vm.state === 'paused') {
    await vm.stop();
  }
  await vm.cleanup();
  await smartvm.cleanup();
}

What happened:

  • Firecracker was downloaded or reused from /tmp/.smartvm/bin.
  • A base image bundle was resolved and cached under /tmp/.smartvm/base-images.
  • A per-VM socket directory was created under /dev/shm/.smartvm/runtime/<vmId> when /dev/shm exists.
  • Writable drives would be staged into that runtime directory before boot; read-only drives stay in place.
  • cleanup() removed VM runtime files and networking resources owned by this SmartVM instance.

Disk-Light Runtime Model

By default, smartvm treats VMs as ephemeral execution units.

Path Default Persistence model
Firecracker binaries /tmp/.smartvm/bin Cached for reuse.
Base images /tmp/.smartvm/base-images Cached, retention-limited, verified before reuse.
VM sockets /dev/shm/.smartvm/runtime/<vmId>/firecracker.sock Per-VM tmpfs, deleted on cleanup.
Writable drives /dev/shm/.smartvm/runtime/<vmId>/drives/* Per-VM tmpfs copy, deleted on cleanup.
Read-only drives Original path Not copied unless ephemeral: true.

Writable drives are staged into the VM runtime directory before boot. Firecracker receives the staged path, so guest writes do not modify cached base images or source rootfs files.

const vm = await smartvm.createVM({
  bootSource: { kernelImagePath: baseImage.kernelImagePath, bootArgs: baseImage.bootArgs },
  machineConfig: { vcpuCount: 1, memSizeMib: 256 },
  drives: [
    {
      driveId: 'rootfs',
      pathOnHost: baseImage.rootfsPath,
      isRootDevice: true,
      isReadOnly: false,
      // Default for writable drives: true
      ephemeral: true,
    },
  ],
});

Opt into persistence only when that is the point:

const persistentVm = await smartvm.createVM({
  bootSource: { kernelImagePath: '/images/vmlinux', bootArgs: 'console=ttyS0 reboot=k panic=1 pci=off' },
  machineConfig: { vcpuCount: 2, memSizeMib: 512 },
  drives: [
    {
      driveId: 'state',
      pathOnHost: '/var/lib/my-vm/state.ext4',
      isRootDevice: true,
      isReadOnly: false,
      ephemeral: false,
    },
  ],
});

You can also disable writable-drive staging globally:

const smartvm = new SmartVM({
  ephemeralWritableDrives: false,
});

Best practice for high-volume VM starts:

  • Prefer squashfs or another read-only root filesystem.
  • Put mutable scratch data on tmpfs-backed writable drives.
  • Keep shared assets read-only by default.
  • Use external services, object storage, databases, or explicit persistent drives for durable state.
  • Use a dedicated runtimeDir on a real tmpfs if /dev/shm is too small or unavailable.

Architecture

SmartVM
  ImageManager          downloads/caches Firecracker binaries and manual images
  BaseImageManager      resolves known-good base-image bundles
  NetworkManager        creates TAP devices, bridge, NAT, firewall/WireGuard egress, and static guest network data
  MicroVM
    FirecrackerProcess  starts/stops the VMM process
    SocketClient        talks HTTP over the Firecracker Unix socket
    VMConfig            validates and transforms TypeScript config

Firecracker exposes a REST API over a Unix domain socket. smartvm starts the child process, waits for readiness, sends pre-boot config in the right order, starts the instance, and tears down host resources when you are done.

SmartVM

SmartVM is the top-level orchestrator.

import { SmartVM } from '@push.rocks/smartvm';
import type { ISmartVMOptions } from '@push.rocks/smartvm';

const options: ISmartVMOptions = {
  dataDir: '/tmp/.smartvm',
  runtimeDir: '/dev/shm/.smartvm/runtime',
  ephemeralWritableDrives: true,
  firecrackerVersion: 'v1.7.0',
  arch: 'x86_64',
  firecrackerBinaryPath: '/usr/bin/firecracker',
  bridgeName: 'svbr0',
  subnet: '172.30.0.0/24',
  firewall: {
    egress: {
      defaultAction: 'allow',
      rules: [],
    },
  },
  wireguard: {
    existingInterface: 'wg0',
    failClosed: true,
  },
  baseImageCacheDir: '/tmp/.smartvm/base-images',
  maxStoredBaseImages: 2,
  baseImageManifestUrl: 'https://assets.example.com/smartvm/manifest.json',
  baseImageManifestPath: './assets/base-images/local.manifest.json',
};

const smartvm = new SmartVM(options);
API Description
ensureBinary() Ensures the Firecracker binary exists and returns its path.
ensureBaseImage(options) Resolves/downloads a base-image bundle and returns kernel/rootfs paths plus boot args.
createVM(config) Creates a MicroVM instance. It does not boot until vm.start().
getRuntimeDir() Returns the active runtime directory used for per-VM tmpfs artifacts.
getVM(id) Looks up an active VM by ID.
listVMs() Lists active VM IDs.
vmCount Number of tracked VMs.
removeVM(id) Removes a VM from the internal tracking map.
stopAll() Stops every running or paused VM.
cleanup() Cleans up all tracked VMs and networking resources.

Base Images

BaseImageManager gives you fast bootable image discovery without committing giant rootfs files to git. The latest and lts presets use Firecracker CI artifacts, which are excellent for tests, demos, and bring-up. For product workloads, prefer the hosted manifest path so you control the kernel/rootfs pair and verify artifacts with SHA256.

const baseImage = await smartvm.ensureBaseImage(); // preset: "latest"
const ltsBaseImage = await smartvm.ensureBaseImage({ preset: 'lts' });
const freshBaseImage = await smartvm.ensureBaseImage({ preset: 'latest', forceDownload: true });

Presets:

Preset Behavior
latest Resolves the latest Firecracker release and matching CI demo artifacts.
lts Uses the pinned Firecracker CI train v1.7 / Firecracker v1.7.0.
hosted Uses a project-owned manifest. Requires manifestUrl, manifestPath, or manager-level hosted manifest options.

The resolver prefers read-only squashfs rootfs artifacts when Firecracker CI exposes them, falling back to ext4 when needed.

import { BaseImageManager } from '@push.rocks/smartvm';

const baseImageManager = new BaseImageManager({
  arch: 'x86_64',
  cacheDir: '/tmp/.smartvm/base-images',
  maxStoredBaseImages: 4,
  hostedManifestPath: './assets/base-images/smartvm-minimal.manifest.json',
});

console.log(baseImageManager.getCacheDir());
console.log(baseImageManager.getMaxStoredBaseImages());

const hosted = await baseImageManager.ensureBaseImage({ preset: 'hosted' });
const evictedBundleIds = await baseImageManager.pruneBaseImageCache(hosted.bundleId);

IBaseImageBundle contains:

  • kernelImagePath
  • rootfsPath
  • rootfsType
  • rootfsIsReadOnly
  • bootArgs
  • firecrackerVersion
  • checksums
  • sizes
  • source metadata

Cache behavior:

  • Default cache directory: /tmp/.smartvm/base-images
  • Default retention: 2 bundles
  • Older bundles are evicted with a console.warn when retention is exceeded
  • Cached artifacts are checked for size and SHA256 before reuse
  • Hosted URL artifacts require SHA256 hashes
  • Hosted local-path artifacts may omit SHA256, but hashes are still recorded in the cached manifest

Hosted manifests are the clean way to ship a project-owned minimal image. Keep big binaries in object storage or release assets, keep only the manifest in git, and let smartvm verify the exact bytes before boot.

Hosted manifest example:

The repository ships an example at assets/base-images/smartvm-minimal.manifest.example.json.

{
  "schemaVersion": 1,
  "bundleId": "smartvm-minimal-v1-x86_64",
  "name": "SmartVM minimal x86_64 bundle",
  "arch": "x86_64",
  "firecrackerVersion": "v1.15.1",
  "rootfsType": "squashfs",
  "rootfsIsReadOnly": true,
  "bootArgs": "console=ttyS0 reboot=k panic=1 pci=off ro rootfstype=squashfs",
  "kernel": {
    "url": "https://assets.example.com/smartvm/vmlinux",
    "fileName": "vmlinux",
    "sha256": "0000000000000000000000000000000000000000000000000000000000000000",
    "sizeBytes": 12345678
  },
  "rootfs": {
    "url": "https://assets.example.com/smartvm/rootfs.squashfs",
    "fileName": "rootfs.squashfs",
    "sha256": "0000000000000000000000000000000000000000000000000000000000000000",
    "sizeBytes": 12345678
  }
}

MicroVM Lifecycle

MicroVM is a single Firecracker instance with a strict state machine:

created -> configuring -> running -> paused -> stopped
                         \-> error
const vm = await smartvm.createVM({
  id: 'api-worker-1',
  bootSource: {
    kernelImagePath: baseImage.kernelImagePath,
    bootArgs: baseImage.bootArgs,
  },
  machineConfig: {
    vcpuCount: 2,
    memSizeMib: 512,
    smt: false,
    cpuTemplate: 'T2',
    trackDirtyPages: true,
  },
  drives: [
    {
      driveId: 'rootfs',
      pathOnHost: baseImage.rootfsPath,
      isRootDevice: true,
      isReadOnly: baseImage.rootfsIsReadOnly,
      cacheType: 'Unsafe',
      ephemeral: true,
      rateLimiter: {
        bandwidth: { size: 100_000_000, refillTime: 1_000_000_000 },
        ops: { size: 1000, refillTime: 1_000_000_000 },
      },
    },
  ],
  networkInterfaces: [{ ifaceId: 'eth0' }],
  vsock: {
    guestCid: 3,
    udsPath: '/dev/shm/api-worker-1.vsock',
  },
  balloon: {
    amountMib: 128,
    deflateOnOom: true,
    statsPollingIntervalS: 5,
  },
  mmds: {
    version: 'V2',
    networkInterfaces: ['eth0'],
  },
});

await vm.start();
await vm.pause();
await vm.resume();
await vm.stop();
await vm.cleanup();
API Valid state Description
start() created Stages ephemeral drives, starts Firecracker, applies config, boots the VM.
pause() running Pauses execution.
resume() paused Resumes execution.
stop() running, paused Sends Ctrl+Alt+Del, waits briefly, then stops the process.
cleanup() any Stops process, deletes sockets/runtime dir, removes auto-created TAPs.
getInfo() after start Returns Firecracker instance info.
getVersion() after start Returns Firecracker version info.
setMetadata(data) running, paused Writes MMDS metadata.
getMetadata() running, paused Reads MMDS metadata.
updateDrive(id, path) running, paused Hot-updates a drive path.
updateNetworkInterface(id, update) running, paused Updates network interface config such as rate limiters.
updateBalloon(mib) running, paused Resizes the balloon device.
createSnapshot(params) paused Creates a Firecracker snapshot.
loadSnapshot(params) created, configuring Low-level Firecracker snapshot-load call; requires an initialized socket client.
getTapDevices() any Returns TAP devices created automatically by this VM.
getVMConfig() any Returns the internal VMConfig instance.
getRuntimeDir() any Returns the per-VM runtime directory after it has been created.

Snapshot caveat: diff snapshots require dirty-page tracking to be enabled before boot through machineConfig.trackDirtyPages. Snapshot restore is currently exposed as a low-level API; full restore orchestration should be built around the Firecracker process/config lifecycle intentionally.

Networking

NetworkManager creates host-side networking primitives. It does not run DHCP inside the guest. Your guest image must configure its interface itself, or you must pass static ip= kernel boot arguments.

Automatic mode:

const vm = await smartvm.createVM({
  bootSource: { kernelImagePath: baseImage.kernelImagePath, bootArgs: baseImage.bootArgs },
  machineConfig: { vcpuCount: 1, memSizeMib: 256 },
  drives: [{ driveId: 'rootfs', pathOnHost: baseImage.rootfsPath, isRootDevice: true, isReadOnly: baseImage.rootfsIsReadOnly }],
  networkInterfaces: [{ ifaceId: 'eth0' }],
});

Static-kernel-args mode:

const tap = await smartvm.networkManager.createTapDevice('net-vm', 'eth0');

const vm = await smartvm.createVM({
  id: 'net-vm',
  bootSource: {
    kernelImagePath: baseImage.kernelImagePath,
    bootArgs: `${baseImage.bootArgs} ${smartvm.networkManager.getGuestNetworkBootArgs(tap)}`,
  },
  machineConfig: { vcpuCount: 1, memSizeMib: 256 },
  drives: [{ driveId: 'rootfs', pathOnHost: baseImage.rootfsPath, isRootDevice: true, isReadOnly: baseImage.rootfsIsReadOnly }],
  networkInterfaces: [
    {
      ifaceId: 'eth0',
      hostDevName: tap.tapName,
      guestMac: tap.mac,
    },
  ],
});

Networking behavior:

  • Default bridge: svbr0
  • Default subnet: 172.30.0.0/24
  • Subnet input is normalized to the network address
  • Prefix length must be 1-30
  • Gateway uses the first usable address
  • Guest IP allocation starts at the second usable address
  • Allocation is sequential and not reused within the same NetworkManager instance
  • MAC addresses are deterministic and locally administered (02:xx:xx:xx:xx:xx)
  • TAP names are capped to Linux's 15-character IFNAMSIZ limit
  • NAT masquerade uses the host default route interface unless WireGuard egress is configured
  • Use a dedicated bridge name; cleanup() tears down the bridge configured by this manager

Egress Firewall

Configure firewall.egress on SmartVM to apply one ordered policy to all VMs using that manager's subnet. The default action is allow, so existing behavior is preserved unless you opt into a stricter policy.

const smartvm = new SmartVM({
  firewall: {
    egress: {
      defaultAction: 'deny',
      rules: [
        { action: 'allow', to: '1.1.1.1', protocol: 'udp', ports: 53, comment: 'DNS' },
        { action: 'allow', to: '203.0.113.0/24', protocol: 'tcp', ports: [443] },
      ],
    },
  },
});

Firewall behavior:

  • Rules are evaluated in order before the final defaultAction.
  • to accepts IPv4 addresses or CIDR ranges only.
  • protocol can be all, tcp, udp, or icmp.
  • ports are destination ports and require protocol: 'tcp' or protocol: 'udp'.
  • The implementation uses an owned iptables chain jumped from FORWARD for traffic from the VM subnet.

WireGuard Egress

WireGuard routing is host-side. The guest does not need WireGuard installed; smartvm policy-routes packets from the VM subnet through a WireGuard interface and leaves normal host traffic on the host default route.

Managed interface mode creates and removes the WireGuard interface:

const smartvm = new SmartVM({
  wireguard: {
    interfaceName: 'svwg0',
    routeTable: 51820,
    failClosed: true,
    config: `
[Interface]
PrivateKey = <private-key>
Address = 10.70.0.2/32
MTU = 1420

[Peer]
PublicKey = <public-key>
AllowedIPs = 0.0.0.0/0
Endpoint = vpn.example.com:51820
PersistentKeepalive = 25
`,
  },
});

Existing interface mode uses an interface you manage outside smartvm:

const smartvm = new SmartVM({
  wireguard: {
    existingInterface: 'wg0',
    routeTable: 51820,
    failClosed: true,
  },
});

WireGuard behavior:

  • routeAllVmTraffic defaults to true; set it to false to keep normal default-route NAT.
  • failClosed defaults to true; VM forwarding to non-WireGuard egress interfaces is dropped when WireGuard routing is active.
  • Managed configs accept wg-quick-style Address and MTU, but reject PreUp, PostUp, PreDown, PostDown, and SaveConfig.
  • DNS and Table in managed configs are ignored; use host DNS and the routeTable option instead.
  • IPv4 addresses and IPv4 AllowedIPs are supported in this release.
  • cleanup() removes owned policy routes, iptables rules, NAT rules, and managed WireGuard interfaces. Existing WireGuard interfaces are not deleted.

ImageManager

ImageManager is the lower-level helper for Firecracker binaries and manually managed kernel/rootfs files.

const imageManager = smartvm.imageManager;

await imageManager.ensureDirectories();

const latest = await imageManager.getLatestVersion();
const firecrackerPath = await imageManager.downloadFirecracker(latest);

const kernelPath = await imageManager.downloadKernel(
  'https://example.com/vmlinux',
  'vmlinux',
);

const rootfsPath = await imageManager.downloadRootfs(
  'https://example.com/rootfs.ext4',
  'rootfs.ext4',
);

const blankRootfs = await imageManager.createBlankRootfs('scratch.ext4', 1024);
const clonedRootfs = await imageManager.cloneRootfs(rootfsPath, 'vm-rootfs.ext4');

Useful path helpers:

  • getBinDir()
  • getKernelsDir()
  • getRootfsDir()
  • getSocketsDir()
  • getFirecrackerPath(version)
  • getJailerPath(version)
  • getSocketPath(vmId)

Note: SmartVM.createVM() uses runtimeDir/<vmId>/firecracker.sock for new VM sockets by default. ImageManager.getSocketPath() remains available for lower-level/custom flows.

VMConfig

VMConfig validates IMicroVMConfig and transforms it into Firecracker API payloads.

import { VMConfig } from '@push.rocks/smartvm';

const vmConfig = new VMConfig({
  bootSource: { kernelImagePath: '/images/vmlinux', bootArgs: 'console=ttyS0 reboot=k panic=1 pci=off' },
  machineConfig: { vcpuCount: 2, memSizeMib: 256 },
  drives: [{ driveId: 'rootfs', pathOnHost: '/images/rootfs.ext4', isRootDevice: true }],
});

const validation = vmConfig.validate();
if (!validation.valid) {
  throw new Error(validation.errors.join('; '));
}

console.log(vmConfig.toBootSourcePayload());
console.log(vmConfig.toMachineConfigPayload());
console.log(vmConfig.toDrivePayload(vmConfig.config.drives![0]));

The constructor clones caller-provided config, so internal normalization does not mutate your original object.

SocketClient

SocketClient is the raw Firecracker API client. Most users should go through MicroVM, but the low-level client is exported for tooling and diagnostics.

import { SocketClient } from '@push.rocks/smartvm';

const client = new SocketClient({ socketPath: '/dev/shm/.smartvm/runtime/vm/firecracker.sock' });

const version = await client.get('/version');
const machineConfig = await client.put('/machine-config', {
  vcpu_count: 1,
  mem_size_mib: 256,
});
const paused = await client.patch('/vm', { state: 'Paused' });

console.log(version.ok, version.statusCode, version.body);
console.log(machineConfig.ok, machineConfig.statusCode, machineConfig.body);
console.log(paused.ok, paused.statusCode, paused.body);

SocketClient returns { ok, statusCode, body }. Non-2xx responses do not become API_ERROR until higher-level MicroVM helpers validate them.

Metadata Service

Firecracker MMDS lets the host pass structured metadata to a running VM.

const vm = await smartvm.createVM({
  bootSource: { kernelImagePath: baseImage.kernelImagePath, bootArgs: baseImage.bootArgs },
  machineConfig: { vcpuCount: 1, memSizeMib: 256 },
  drives: [{ driveId: 'rootfs', pathOnHost: baseImage.rootfsPath, isRootDevice: true, isReadOnly: baseImage.rootfsIsReadOnly }],
  networkInterfaces: [{ ifaceId: 'eth0' }],
  mmds: {
    version: 'V2',
    networkInterfaces: ['eth0'],
  },
});

await vm.start();

await vm.setMetadata({
  instance: { id: 'api-worker-1', region: 'local' },
  config: { mode: 'ephemeral' },
});

console.log(await vm.getMetadata());

Error Handling

All package-level failures use SmartVMError with structured codes.

import { SmartVMError } from '@push.rocks/smartvm';

try {
  await vm.start();
} catch (err) {
  if (err instanceof SmartVMError) {
    console.error(err.code);
    console.error(err.statusCode);
    console.error(err.details);
  }
  throw err;
}
Code Meaning
INVALID_STATE Operation is invalid for the current VM state.
INVALID_CONFIG VM configuration failed validation.
SOCKET_TIMEOUT Firecracker did not create its socket in time.
API_TIMEOUT Firecracker API readiness check timed out.
SOCKET_REQUEST_FAILED Unix-socket HTTP request failed.
API_ERROR Firecracker returned a non-2xx response through a high-level VM call.
BINARY_NOT_FOUND Custom Firecracker binary path does not exist.
DOWNLOAD_FAILED Binary, kernel, or rootfs download failed.
VERSION_FETCH_FAILED Latest Firecracker version lookup failed.
BASE_IMAGE_RESOLVE_FAILED Firecracker CI base-image artifact resolution failed.
BASE_IMAGE_MANIFEST_FAILED Hosted manifest could not be loaded or used.
BASE_IMAGE_PREPARE_FAILED Base-image download/copy/verification failed.
INVALID_BASE_IMAGE_MANIFEST Hosted manifest schema or artifact metadata is invalid.
INVALID_BASE_IMAGE_CACHE_LIMIT Base-image retention limit is invalid.
INVALID_SUBNET Subnet is not a supported IPv4 CIDR.
INVALID_INTERFACE_NAME Bridge or TAP name is invalid.
INVALID_FIREWALL_CONFIG VM egress firewall config is invalid.
INVALID_WIREGUARD_CONFIG WireGuard egress config is invalid.
IP_EXHAUSTED No guest IPs remain in the configured subnet.
BRIDGE_SETUP_FAILED Bridge/NAT setup failed.
WIREGUARD_SETUP_FAILED WireGuard interface or policy-route setup failed.
TAP_CREATE_FAILED TAP creation failed.
ROOTFS_CREATE_FAILED Blank rootfs creation failed.
ROOTFS_CLONE_FAILED Rootfs clone failed.
START_FAILED VM start sequence failed.
NO_CLIENT Socket client is not initialized.

Testing

Default tests are safe on machines without KVM or root privileges:

pnpm test
pnpm run build

The default suite covers config validation, payload generation, lifecycle guards, base-image cache behavior, hosted manifest validation, VM tracking, ephemeral drive staging, subnet/IP behavior, and firewall/WireGuard option validation.

Opt into real Firecracker boot tests on a Linux/KVM host:

SMARTVM_RUN_INTEGRATION=true pnpm test

Accepted truthy values for SMARTVM_RUN_INTEGRATION: 1, true, yes.

Useful integration-test environment variables:

Variable Purpose
SMARTVM_BASE_IMAGE_PRESET latest or lts; default is latest.
SMARTVM_BASE_IMAGE_MANIFEST_URL Hosted/project-owned base-image manifest URL.
SMARTVM_BASE_IMAGE_MANIFEST_PATH Local hosted manifest path.
SMARTVM_BASE_IMAGE_CACHE_DIR Override /tmp/.smartvm/base-images.
SMARTVM_MAX_STORED_BASE_IMAGES Override default retention of 2.
SMARTVM_FIRECRACKER_VERSION Override the Firecracker binary version.
SMARTVM_ARCH x86_64 or aarch64; defaults from host architecture.
SMARTVM_INTEGRATION_DATA_DIR Override the Firecracker binary data directory used by integration tests.

TypeScript Surface

Main exports:

export {
  SmartVM,
  MicroVM,
  NetworkManager,
  FirecrackerProcess,
  BaseImageManager,
  ImageManager,
  SocketClient,
  VMConfig,
};

Important exported types:

import type {
  ISmartVMOptions,
  IMicroVMRuntimeOptions,
  IMicroVMConfig,
  IBootSource,
  IMachineConfig,
  IDriveConfig,
  INetworkInterfaceConfig,
  IVsockConfig,
  IBalloonConfig,
  IMmdsConfig,
  ILoggerConfig,
  IMetricsConfig,
  IBaseImageManagerOptions,
  IEnsureBaseImageOptions,
  IBaseImageBundle,
  IBaseImageHostedManifest,
  IBaseImageArtifactManifest,
  ISnapshotCreateParams,
  ISnapshotLoadParams,
  IRateLimiter,
  INetworkManagerOptions,
  ITapDevice,
  IFirewallConfig,
  IFirewallEgressConfig,
  IFirewallRule,
  TFirewallAction,
  TFirewallProtocol,
  TWireGuardConfig,
  IWireGuardManagedConfig,
  IWireGuardExistingInterfaceConfig,
  ISocketClientOptions,
  IApiResponse,
  TVMState,
  TFirecrackerArch,
  TCacheType,
  TSnapshotType,
  TLogLevel,
  TBaseImagePreset,
  TBaseImageRootfsType,
} from '@push.rocks/smartvm';

This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the LICENSE file.

Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.

Trademarks

This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.

Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.

Company Information

Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany

For any legal inquiries or further information, please contact us via email at hello@task.vc.

By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

S
Description
fast vms
Readme 402 KiB
Languages
TypeScript 100%