Class: SkillBench::Execution::Sandbox

Inherits:
Object
  • Object
show all
Defined in:
lib/skill_bench/execution/sandbox.rb

Overview

Manages isolated sandbox environments for running agent evaluations. Handles copying files, initializing git, and capturing diffs.

NOTE: Container isolation is not yet shipped. No Docker build context is packaged, so docker_available? always returns false and start_container is never reached — container_id stays nil and commands run on the host (gated by the allowlist and Config.allow_host_execution). The container code below is the planned isolation model, retained but currently inactive.

Constant Summary collapse

GIT_HARDENING =

Global git options applied to every host-side invocation. They strip the repository's and user's ability to launch external programs during routine git operations on untrusted source:

- core.attributesFile=/dev/null  no user-level .gitattributes drivers
- core.fsmonitor=false           no fsmonitor hook program
- core.hooksPath=/dev/null       no git hooks (pre-commit, etc.)
- core.symlinks=false            symlinks treated as plain files

Combined with not copying the source .git, this neutralizes the .gitattributes/config diff & filter driver code-execution vector.

[
  '-c', 'core.attributesFile=/dev/null',
  '-c', 'core.fsmonitor=false',
  '-c', 'core.hooksPath=/dev/null',
  '-c', 'core.symlinks=false'
].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source_dir) ⇒ Sandbox

Returns a new instance of Sandbox.

Parameters:

  • source_dir (String, Pathname)

    The directory to copy into the sandbox.



60
61
62
63
64
# File 'lib/skill_bench/execution/sandbox.rb', line 60

def initialize(source_dir)
  @source_dir = source_dir
  @path = nil
  @container_id = nil
end

Instance Attribute Details

#container_idObject (readonly)

Returns the value of attribute container_id.



19
20
21
# File 'lib/skill_bench/execution/sandbox.rb', line 19

def container_id
  @container_id
end

#pathObject (readonly)

Returns the value of attribute path.



19
20
21
# File 'lib/skill_bench/execution/sandbox.rb', line 19

def path
  @path
end

Class Method Details

.capture_diff(sandbox_dir) ⇒ String

Captures the git diff of changes made within the sandbox.

Parameters:

  • sandbox_dir (String)

    The path to the sandbox directory.

Returns:

  • (String)

    The git diff, or a message indicating no changes.

Raises:

  • (SystemCallError)

    when git commands fail.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/skill_bench/execution/sandbox.rb', line 93

def self.capture_diff(sandbox_dir)
  sandbox_path = File.realpath(sandbox_dir)
  tmp_prefix = File.realpath(Dir.tmpdir) + File::SEPARATOR
  raise "Sandbox directory #{sandbox_dir} is outside temp directory" unless sandbox_path.start_with?(tmp_prefix)

  return 'No code changes made.' unless File.directory?(File.join(sandbox_path, '.git'))

  raise "Failed to stage changes in #{sandbox_path}" unless system(*git_command('add', '.'), chdir: sandbox_path)

  diff, status = Open3.capture2(*git_command('diff', '--cached'), chdir: sandbox_path)
  raise "Failed to capture diff in #{sandbox_path}" unless status.success?

  diff.strip.empty? ? 'No code changes made.' : diff
end

.git_command(*args) ⇒ Array<String>

Builds a hardened git argv: the binary, the hardening flags, then the given subcommand and arguments. Single source of truth so every git call in this file is invoked with the same protections.

Parameters:

  • args (Array<String>)

    git subcommand and its arguments.

Returns:

  • (Array<String>)

    full argv beginning with git and the flags.



43
44
45
# File 'lib/skill_bench/execution/sandbox.rb', line 43

def self.git_command(*args)
  ['git', *GIT_HARDENING, *args]
end

.run(source_dir) {|sandbox| ... } ⇒ Object

Runs a block of code within a temporary, isolated sandbox directory. The sandbox is initialized as a git repository and optionally wrapped in a Docker container.

Parameters:

  • source_dir (String, Pathname)

    The directory to copy into the sandbox.

Yield Parameters:

Returns:

  • (Object)

    The result of the yielded block.

Raises:

  • (SystemCallError)

    when file operations or directory creation fails.

  • (RuntimeError)

    when Docker commands fail.



55
56
57
# File 'lib/skill_bench/execution/sandbox.rb', line 55

def self.run(source_dir, &)
  new(source_dir).run(&)
end

Instance Method Details

#run {|sandbox| ... } ⇒ Object

Executes the sandbox environment setup and yields the sandbox instance.

Yield Parameters:

Returns:

  • (Object)

    The result of the yielded block.

Raises:

  • (SystemCallError)

    when file operations or directory creation fails.

  • (RuntimeError)

    when Docker commands fail.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/skill_bench/execution/sandbox.rb', line 72

def run
  Dir.mktmpdir('evaluator_sandbox_') do |sandbox_dir|
    @path = sandbox_dir
    copy_source_files(sandbox_dir)

    setup_git

    start_container if docker_available?
    begin
      yield self
    ensure
      stop_container
    end
  end
end