Skip to content
Merged
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
22 changes: 22 additions & 0 deletions app/grpc/health_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

require 'grpc/health/v1/health_services_pb'

class HealthHandler < Grpc::Health::V1::Health::Service
include GrpcHandler

def check(req, _call)
return Grpc::Health::V1::HealthCheckResponse.new(status: :SERVING) if req.service == 'liveness'

if req.service == 'readiness'
ActiveRecord::Base.connection_pool.with_connection do |connection|
connection.execute('SELECT pg_backend_pid();')
return Grpc::Health::V1::HealthCheckResponse.new(status: :SERVING)
rescue PG::Error, ActiveRecord::ActiveRecordError
return Grpc::Health::V1::HealthCheckResponse.new(status: :NOT_SERVING)
end
end

raise GRPC::BadStatus.new_status_exception(GRPC::Core::StatusCodes::NOT_FOUND, 'Unknown service')
end
end
5 changes: 4 additions & 1 deletion bin/docker-entrypoint
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#!/bin/bash -e

if [ "${1}" == "./bin/rails" ] && [ "${2}" == "server" ]; then
# prepare database
SAGITTARIUS_PREPARE_DATABASE="true"
fi

if [ "${SAGITTARIUS_PREPARE_DATABASE}" == "true" ]; then
bundle exec rake db:prepare
FILTER=01_application_settings bundle exec rake db:seed_fu
fi
Expand Down
14 changes: 9 additions & 5 deletions lib/sagittarius/middleware/grpc/authentication.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ module Sagittarius
module Middleware
module Grpc
class Authentication < Grpc::AllMethodServerInterceptor
def execute(call:, **_)
authorization_token = call.metadata['authorization']
runtime = Runtime.find_by(token: authorization_token)
ANONYMOUS_SERVICES = %w[grpc.health.v1.Health].freeze

raise GRPC::Unauthenticated, 'No valid runtime token provided' if runtime.nil?
def execute(call:, method:, **_)
authorization_token = call.metadata['authorization']
runtime = Runtime.find_by(token: authorization_token) if authorization_token.present?

Code0::ZeroTrack::Context.push(runtime: { id: runtime.id, namespace_id: runtime.namespace&.id })
if runtime.present?
Code0::ZeroTrack::Context.push(runtime: { id: runtime.id, namespace_id: runtime.namespace&.id })
elsif ANONYMOUS_SERVICES.exclude?(method.owner.service_name) || authorization_token.present?
raise GRPC::Unauthenticated, 'No valid runtime token provided' if runtime.nil?
end

yield
end
Expand Down
40 changes: 36 additions & 4 deletions spec/lib/sagittarius/middleware/grpc/authentication_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'rails_helper'
require 'google/protobuf/well_known_types'
require 'grpc/health/v1/health_services_pb'

RSpec.describe Sagittarius::Middleware::Grpc::Authentication do
let(:rpc_class) do
Expand Down Expand Up @@ -45,11 +46,20 @@ def test(_msg, _call)
end.to raise_error(GRPC::Unauthenticated)
end
# rubocop:enable Lint/EmptyBlock

context 'when anonymous service is called' do
let(:service_class) { Grpc::Health::V1::Health::Service }
let(:method) { service_class.new.method(:check) }

it do
expect { |b| interceptor.request_response(request: request, call: call, method: method, &b) }.to yield_control
end
end
end

context 'when invalid authentication is passed' do
let(:metadata) do
{ authorization: 'token' }
{ 'authorization' => 'token' }
end

# rubocop:disable Lint/EmptyBlock -- the block is part of the api and needs to be given
Expand All @@ -59,6 +69,19 @@ def test(_msg, _call)
end.to raise_error(GRPC::Unauthenticated)
end
# rubocop:enable Lint/EmptyBlock

context 'when anonymous service is called' do
let(:service_class) { Grpc::Health::V1::Health::Service }
let(:method) { service_class.new.method(:check) }

# rubocop:disable Lint/EmptyBlock -- the block is part of the api and needs to be given
it do
expect do
interceptor.request_response(request: request, call: call, method: method) {}
end.to raise_error(GRPC::Unauthenticated)
end
# rubocop:enable Lint/EmptyBlock
end
end

context 'when valid authentication is passed' do
Expand All @@ -77,6 +100,15 @@ def test(_msg, _call)
namespace_id: nil })
end
# rubocop:enable Lint/EmptyBlock

context 'when anonymous service is called' do
let(:service_class) { Grpc::Health::V1::Health::Service }
let(:method) { service_class.new.method(:check) }

it do
expect { |b| interceptor.request_response(request: request, call: call, method: method, &b) }.to yield_control
end
end
end
end

Expand All @@ -93,7 +125,7 @@ def test(_msg, _call)

context 'when invalid authentication is passed' do
let(:metadata) do
{ authorization: 'token' }
{ 'authorization' => 'token' }
end

# rubocop:disable Lint/EmptyBlock -- the block is part of the api and needs to be given
Expand Down Expand Up @@ -137,7 +169,7 @@ def test(_msg, _call)

context 'when invalid authentication is passed' do
let(:metadata) do
{ authorization: 'token' }
{ 'authorization' => 'token' }
end

# rubocop:disable Lint/EmptyBlock -- the block is part of the api and needs to be given
Expand Down Expand Up @@ -181,7 +213,7 @@ def test(_msg, _call)

context 'when invalid authentication is passed' do
let(:metadata) do
{ authorization: 'token' }
{ 'authorization' => 'token' }
end

# rubocop:disable Lint/EmptyBlock -- the block is part of the api and needs to be given
Expand Down