Module: ZeroMcp::Sandbox

Defined in:
lib/zeromcp/sandbox.rb

Class Method Summary collapse

Class Method Details

.allowed?(hostname, allowlist) ⇒ Boolean

Returns:

  • (Boolean)


60
61
62
63
64
65
66
67
68
69
70
# File 'lib/zeromcp/sandbox.rb', line 60

def allowed?(hostname, allowlist)
  allowlist.any? do |pattern|
    if pattern.start_with?('*.')
      suffix = pattern[1..] # e.g. ".example.com"
      base = pattern[2..]   # e.g. "example.com"
      hostname.end_with?(suffix) || hostname == base
    else
      hostname == pattern
    end
  end
end

.check_network_access(tool_name, hostname, permissions, bypass: false, logging: false) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/zeromcp/sandbox.rb', line 7

def check_network_access(tool_name, hostname, permissions, bypass: false, logging: false)
  network = permissions.key?(:network) ? permissions[:network] : permissions['network']

  # No permissions or network not specified = full access
  if network.nil?
    log("#{tool_name} -> #{hostname}") if logging
    return true
  end

  # network: true = full access
  if network == true
    log("#{tool_name} -> #{hostname}") if logging
    return true
  end

  # network: false = denied
  if network == false
    if bypass
      log("! #{tool_name} -> #{hostname} (network disabled -- bypassed)") if logging
      return true
    end
    log("#{tool_name} x #{hostname} (network disabled)") if logging
    return false
  end

  # network: [] (empty array) = denied
  if network.is_a?(Array) && network.empty?
    if bypass
      log("! #{tool_name} -> #{hostname} (network disabled -- bypassed)") if logging
      return true
    end
    log("#{tool_name} x #{hostname} (network disabled)") if logging
    return false
  end

  # network: ["host1", "*.host2"] = allowlist
  if network.is_a?(Array)
    if allowed?(hostname, network)
      log("#{tool_name} -> #{hostname}") if logging
      return true
    end
    if bypass
      log("! #{tool_name} -> #{hostname} (not in allowlist -- bypassed)") if logging
      return true
    end
    log("#{tool_name} x #{hostname} (not in allowlist)") if logging
    return false
  end

  # Unknown type — allow by default
  true
end

.extract_hostname(url) ⇒ Object



72
73
74
75
76
# File 'lib/zeromcp/sandbox.rb', line 72

def extract_hostname(url)
  after_scheme = url.sub(%r{^[a-z]+://}, '')
  host_port = after_scheme.split('/').first || after_scheme
  host_port.split(':').first || host_port
end

.log(msg) ⇒ Object



78
79
80
# File 'lib/zeromcp/sandbox.rb', line 78

def log(msg)
  $stderr.puts "[zeromcp] #{msg}"
end