Module: SecurityBox::ModuleCache

Defined in:
lib/security_box/module_cache.rb

Overview

Content-addressed disk cache for compiled wasm modules.

Compiling the ruby.wasm image costs ~15s per process. This cache stores the compiled artifact (Module#serialize) so later processes pay only a fast deserialize. Files live at <cache_dir>/modules/.cwasm, where the key combines the image content digest with the wasmtime precompile compatibility key — a stored module is only reused when the running engine can consume it.

Everything here is best effort: on any I/O or deserialization failure the caller falls back to a regular compile and the cache self-heals on the next successful store. Set SECURITY_BOX_CACHE_DIR to relocate the cache; the default is ~/.cache/security_box.

Constant Summary collapse

CACHE_DIR_ENV_VAR =
"SECURITY_BOX_CACHE_DIR"

Class Method Summary collapse

Class Method Details

.cache_path(engine, image_path) ⇒ Object

Nil when no usable cache directory exists (cache disabled).



58
59
60
61
62
63
# File 'lib/security_box/module_cache.rb', line 58

def cache_path(engine, image_path)
  dir = modules_dir
  return nil unless dir

  File.join(dir, "#{cache_key(engine, image_path)}.cwasm")
end

.compile_and_store(engine, image_path) ⇒ Object

Compiles the image and stores the serialized artifact in the cache (best effort). Returns the compiled module in all cases.



37
38
39
40
41
# File 'lib/security_box/module_cache.rb', line 37

def compile_and_store(engine, image_path)
  module_ = Wasmtime::Module.from_file(engine, image_path)
  store(engine, image_path, module_)
  module_
end

.load_module(engine, image_path) ⇒ Object

Returns the cached module for this engine+image, or nil on cache miss, corrupted cache file or any cache error.



26
27
28
29
30
31
32
33
# File 'lib/security_box/module_cache.rb', line 26

def load_module(engine, image_path)
  path = cache_path(engine, image_path)
  return nil unless path && File.file?(path)

  Wasmtime::Module.deserialize_file(engine, path)
rescue Wasmtime::Error, TypeError, SystemCallError
  nil
end

.modules_dir ⇒ Object



65
66
67
68
69
70
# File 'lib/security_box/module_cache.rb', line 65

def modules_dir
  base = ENV[CACHE_DIR_ENV_VAR] || default_base_dir
  return nil unless base

  File.expand_path("modules", base)
end

.store(engine, image_path, module_) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/security_box/module_cache.rb', line 43

def store(engine, image_path, module_)
  path = cache_path(engine, image_path)
  return if path.nil?

  dir = File.dirname(path)
  FileUtils.mkdir_p(dir)
  tmp = File.join(dir, ".#{File.basename(path)}.#{Process.pid}.tmp")
  File.binwrite(tmp, module_.serialize)
  File.rename(tmp, path)
rescue Wasmtime::Error, SystemCallError
  File.delete(tmp) if defined?(tmp) && tmp && File.exist?(tmp)
  nil
end