Skip to content
Kward Search API index

Class: Kward::Sandbox::MacOSSeatbeltRunner

Inherits:
CommandRunner show all
Defined in:
lib/kward/sandbox/macos_seatbelt_runner.rb

Overview

Runs a command under macOS Seatbelt. This backend deliberately constrains writes and child networking first; host-process and plugin access remain outside the command worker boundary.

Constant Summary collapse

EXECUTABLE =
"/usr/bin/sandbox-exec".freeze
PROTECTED_READ_DIRECTORIES =
%w[.aws .gnupg .kward .ssh .config/gcloud .config/gh].freeze

Instance Attribute Summary

Attributes inherited from CommandRunner

#capabilities, #policy

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(policy:, capabilities: self.class.capabilities) ⇒ MacOSSeatbeltRunner

Returns a new instance of MacOSSeatbeltRunner.

Raises:

  • (ArgumentError)


29
30
31
32
33
# File 'lib/kward/sandbox/macos_seatbelt_runner.rb', line 29

def initialize(policy:, capabilities: self.class.capabilities)
  raise ArgumentError, "macOS Seatbelt is unavailable: #{capabilities.reason}" unless capabilities.available?

  super
end

Class Method Details

.capabilities(platform: RUBY_PLATFORM) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/kward/sandbox/macos_seatbelt_runner.rb', line 16

def self.capabilities(platform: RUBY_PLATFORM)
  available = platform.to_s.include?("darwin") && File.executable?(EXECUTABLE)
  return Capabilities.new(available: true, filesystem_enforced: true, child_network_enforced: true, backend: "macos_seatbelt") if available

  Capabilities.new(
    available: false,
    filesystem_enforced: false,
    child_network_enforced: false,
    backend: "macos_seatbelt",
    reason: "#{EXECUTABLE} is unavailable"
  )
end

Instance Method Details

#command_argv(command, cwd:, temporary_root: nil) ⇒ Object



54
55
56
57
# File 'lib/kward/sandbox/macos_seatbelt_runner.rb', line 54

def command_argv(command, cwd:, temporary_root: nil)
  temporary_root ||= Dir.tmpdir
  [EXECUTABLE, "-p", profile(temporary_root), "/bin/zsh", "-lc", command.to_s]
end

#run(command, cwd:, timeout_seconds:, max_output_bytes:, cancellation: nil, &block) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/kward/sandbox/macos_seatbelt_runner.rb', line 35

def run(command, cwd:, timeout_seconds:, max_output_bytes:, cancellation: nil, &block)
  temporary_root = Dir.mktmpdir("kward-sandbox")
  environment = Environment.command_worker(temporary_root)

  LocalCommandRunner.new(
    timeout_seconds: timeout_seconds,
    max_output_bytes: max_output_bytes
  ).run(
    *command_argv(command, cwd: cwd, temporary_root: temporary_root),
    env: environment,
    cwd: cwd,
    cancellation: cancellation,
    unsetenv_others: true,
    &block
  )
ensure
  FileUtils.remove_entry(temporary_root) if temporary_root && File.exist?(temporary_root)
end