Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to allow localhost and allowlist #27

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/grpc_mock/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ def request_including(values)
GrpcMock::Matchers::RequestIncludingMatcher.new(values)
end

def disable_net_connect!
def disable_net_connect!(allow_localhost: false, allow: nil)
GrpcMock.config.allow_net_connect = false
GrpcMock.config.allow_localhost = allow_localhost
GrpcMock.config.allow = allow
end

def allow_net_connect!
Expand Down
4 changes: 3 additions & 1 deletion lib/grpc_mock/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

module GrpcMock
class Configuration
attr_accessor :allow_net_connect
attr_accessor :allow_net_connect, :allow_localhost, :allow

def initialize
@allow_net_connect = true
@allow_localhost = false
@allow = nil
end
end
end
44 changes: 40 additions & 4 deletions lib/grpc_mock/grpc_stub_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def request_response(method, request, *args, metadata: {}, return_op: false, **k
else
mock.evaluate(request, call.single_req_view)
end
elsif GrpcMock.config.allow_net_connect
elsif connection_allowed?
super
else
raise NetConnectNotAllowedError, method
Expand All @@ -52,7 +52,7 @@ def client_streamer(method, requests, *args, metadata: {}, return_op: false, **k
else
mock.evaluate(r, call.multi_req_view)
end
elsif GrpcMock.config.allow_net_connect
elsif connection_allowed?
super
else
raise NetConnectNotAllowedError, method
Expand All @@ -76,7 +76,7 @@ def server_streamer(method, request, *args, metadata: {}, return_op: false, **kw
else
mock.evaluate(request, call.single_req_view)
end
elsif GrpcMock.config.allow_net_connect
elsif connection_allowed?
super
else
raise NetConnectNotAllowedError, method
Expand All @@ -100,12 +100,48 @@ def bidi_streamer(method, requests, *args, metadata: {}, return_op: false, **kwa
else
mock.evaluate(r, nil) # FIXME: provide BidiCall equivalent
end
elsif GrpcMock.config.allow_net_connect
elsif connection_allowed?
super
else
raise NetConnectNotAllowedError, method
end
end

def connection_allowed?
return true if GrpcMock.config.allow_net_connect

uri = @host.include?("://") ? URI.parse(@host) : URI.parse("http://#{@host}")
return true if GrpcMock.config.allow_localhost && localhost_allowed?(uri)

net_connection_explicitly_allowed?(GrpcMock.config.allow, uri)
end

def localhost_allowed?(uri)
return false unless GrpcMock.config.allow_localhost
%w(localhost 127.0.0.1 0.0.0.0 [::1]).include?(uri.host)
end

def net_connection_explicitly_allowed?(allowed, uri)
return false unless GrpcMock.config.allow

case allowed
when Array
allowed.any? { |allowed_item| net_connection_explicitly_allowed?(allowed_item, uri) }
when Regexp
(uri.to_s =~ allowed) != nil ||
("#{uri.scheme}://#{uri.host}" =~ allowed) != nil && uri.port == uri.default_port
when String
allowed == uri.to_s ||
allowed == uri.host ||
allowed == "#{uri.host}:#{uri.port}" ||
allowed == "#{uri.scheme}://#{uri.host}:#{uri.port}" ||
allowed == "#{uri.scheme}://#{uri.host}" && uri.port == uri.default_port
else
if allowed.respond_to?(:call)
allowed.call(uri)
end
end
end
end

def self.disable!
Expand Down
17 changes: 10 additions & 7 deletions spec/examples/hello/hello_client.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
require_relative './hello_services_pb'

class HelloClient
def initialize
@client = Hello::Hello::Stub.new('localhost:8000', :this_channel_is_insecure)
def initialize(host = 'localhost:8000')
@client = Hello::Hello::Stub.new(host, :this_channel_is_insecure)
Copy link
Author

@niborg niborg Oct 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change makes it easier for specs to make request to external endpoints so we can test that gRPC requests are bypassing GrpcMock.

end

def send_message(msg, client_stream: false, server_stream: false, metadata: {})
def send_message(msg, client_stream: false, server_stream: false, metadata: {}, timeout: 0.1)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spec requests to localhost fail immediately, but when the tests try to hit a fake outside service we need a timeout to keep things fast.

options = { metadata: metadata }
options[:deadline] = Time.now + timeout if timeout

if client_stream && server_stream
m = Hello::HelloStreamRequest.new(msg: msg)
@client.hello_stream([m].to_enum, metadata: metadata)
@client.hello_stream([m].to_enum, **options)
elsif client_stream
m = Hello::HelloStreamRequest.new(msg: msg)
@client.hello_client_stream([m].to_enum, metadata: metadata)
@client.hello_client_stream([m].to_enum, **options)
elsif server_stream
m = Hello::HelloRequest.new(msg: msg)
@client.hello_server_stream(m, metadata: metadata)
@client.hello_server_stream(m, **options)
else
m = Hello::HelloRequest.new(msg: msg)
@client.hello(m, metadata: metadata)
@client.hello(m, **options)
end
end
end
Loading