Class: LittleGhost::Network::ExternalGateway

Inherits:
Gateway
  • Object
show all
Defined in:
lib/little_ghost/network/external_gateway.rb

Overview

Exposes an application-managed proxy to an isolated sandbox without claiming ownership of its lifecycle or attesting what it enforces. The application owns proxy policy, credentials, readiness, logging, and cleanup.

Instance Attribute Summary collapse

Attributes inherited from Gateway

#policy

Instance Method Summary collapse

Methods inherited from Gateway

#client_network, #close, #mounts

Constructor Details

#initialize(policy:, workspace:, runtime_paths:, proxy_mount_path:, environment: {}, validate: nil) ⇒ ExternalGateway

Builds a gateway around existing process-only workspace paths and a physical proxy socket path. No path remapping is performed.

Raises:



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/little_ghost/network/external_gateway.rb', line 13

def initialize(policy:, workspace:, runtime_paths:, proxy_mount_path:, environment: {}, validate: nil)
  super(policy:)
  @runtime_paths = Array(runtime_paths).map(&:to_sym).freeze
  raise PolicyError, "external gateway runtime_paths must not be empty" if @runtime_paths.empty?
  @roots = @runtime_paths.map { |name| (name == :root) ? workspace.root : workspace.path(name) }.freeze
  @proxy_mount_path = File.expand_path(proxy_mount_path).freeze
  unless @roots.any? { |root| @proxy_mount_path == root || @proxy_mount_path.start_with?("#{root}#{File::SEPARATOR}") }
    raise PolicyError, "external gateway proxy path must be inside a runtime path"
  end
  unless validate.nil? || validate.respond_to?(:call)
    raise PolicyError, "external gateway validator must be callable"
  end

  @environment = Sandbox::EnvironmentPolicy.coerce(environment).to_h
  @validator = validate
end

Instance Attribute Details

#environmentObject (readonly)

Returns child-scoped proxy and trust variables.



31
32
33
# File 'lib/little_ghost/network/external_gateway.rb', line 31

def environment
  @environment
end

#proxy_mount_pathObject (readonly)

Returns the proxy socket path visible inside the sandbox.



35
36
37
# File 'lib/little_ghost/network/external_gateway.rb', line 35

def proxy_mount_path
  @proxy_mount_path
end

#runtime_pathsObject (readonly)

Named process-only workspace paths used by the gateway.



33
34
35
# File 'lib/little_ghost/network/external_gateway.rb', line 33

def runtime_paths
  @runtime_paths
end

Instance Method Details

#open(run: nil) ⇒ Object

Pins application-managed mount roots without taking lifecycle ownership.



38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/little_ghost/network/external_gateway.rb', line 38

def open(run: nil)
  @path_identities = @roots.to_h do |path|
    root = File.realpath(path)
    stat = File.stat(root)
    raise PolicyError, "external gateway runtime path must be a directory" unless stat.directory?

    [path, [root, stat.dev, stat.ino]]
  end.freeze
  self
rescue Errno::ENOENT, Errno::EACCES
  raise DependencyError, "external gateway mount source is unavailable"
end

#validate!Object

Runs the application's readiness assertion before each child process.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/little_ghost/network/external_gateway.rb', line 52

def validate!
  open unless @path_identities
  @roots.each do |path|
    root = File.realpath(path)
    stat = File.stat(root)
    unless [root, stat.dev, stat.ino] == @path_identities.fetch(path)
      raise DependencyError, "external gateway runtime path changed after opening"
    end
  end
  @validator&.call
  self
rescue Errno::ENOENT, Errno::EACCES
  raise DependencyError, "external gateway runtime path changed after opening"
end