From 44de8233caa12649e1680f0738a49811dfe94d74 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jelizaveta=20Leme=C5=A1eva?=
 <jelizaveta.lemeseva@vinted.com>
Date: Wed, 22 Jun 2022 14:25:13 +0200
Subject: [PATCH 1/5] Add gRPC credentials to cofiguration

---
 lib/temporal/configuration.rb   | 8 +++++---
 lib/temporal/connection.rb      | 3 ++-
 lib/temporal/connection/grpc.rb | 7 ++++---
 3 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/lib/temporal/configuration.rb b/lib/temporal/configuration.rb
index 8d36615c..d2edaead 100644
--- a/lib/temporal/configuration.rb
+++ b/lib/temporal/configuration.rb
@@ -7,12 +7,12 @@
 
 module Temporal
   class Configuration
-    Connection = Struct.new(:type, :host, :port, keyword_init: true)
+    Connection = Struct.new(:type, :host, :port, :credentials, keyword_init: true)
     Execution = Struct.new(:namespace, :task_queue, :timeouts, :headers, keyword_init: true)
 
     attr_reader :timeouts, :error_handlers
     attr_writer :converter
-    attr_accessor :connection_type, :host, :port, :logger, :metrics_adapter, :namespace, :task_queue, :headers
+    attr_accessor :connection_type, :host, :port, :credentials, :logger, :metrics_adapter, :namespace, :task_queue, :headers
 
     # See https://docs.temporal.io/blog/activity-timeouts/ for general docs.
     # We want an infinite execution timeout for cron schedules and other perpetual workflows.
@@ -53,6 +53,7 @@ def initialize
       @headers = DEFAULT_HEADERS
       @converter = DEFAULT_CONVERTER
       @error_handlers = []
+      @credentials = :this_channel_is_insecure
     end
 
     def on_error(&block)
@@ -79,7 +80,8 @@ def for_connection
       Connection.new(
         type: connection_type,
         host: host,
-        port: port
+        port: port,
+        credentials: credentials
       ).freeze
     end
 
diff --git a/lib/temporal/connection.rb b/lib/temporal/connection.rb
index b499ca73..791534bf 100644
--- a/lib/temporal/connection.rb
+++ b/lib/temporal/connection.rb
@@ -10,12 +10,13 @@ def self.generate(configuration)
       connection_class = CLIENT_TYPES_MAP[configuration.type]
       host = configuration.host
       port = configuration.port
+      credentials = configuration.credentials
 
       hostname = `hostname`
       thread_id = Thread.current.object_id
       identity = "#{thread_id}@#{hostname}"
 
-      connection_class.new(host, port, identity)
+      connection_class.new(host, port, identity, credentials)
     end
   end
 end
diff --git a/lib/temporal/connection/grpc.rb b/lib/temporal/connection/grpc.rb
index dd306b97..9b0d9699 100644
--- a/lib/temporal/connection/grpc.rb
+++ b/lib/temporal/connection/grpc.rb
@@ -31,9 +31,10 @@ class GRPC
         max_page_size: 100
       }.freeze
 
-      def initialize(host, port, identity, options = {})
+      def initialize(host, port, identity, credentials, options = {})
         @url = "#{host}:#{port}"
         @identity = identity
+        @credentials = credentials
         @poll = true
         @poll_mutex = Mutex.new
         @poll_request = nil
@@ -536,12 +537,12 @@ def cancel_polling_request
 
       private
 
-      attr_reader :url, :identity, :options, :poll_mutex, :poll_request
+      attr_reader :url, :identity, :credentials, :options, :poll_mutex, :poll_request
 
       def client
         @client ||= Temporal::Api::WorkflowService::V1::WorkflowService::Stub.new(
           url,
-          :this_channel_is_insecure,
+          credentials,
           timeout: 60
         )
       end

From e8213e68f4ea51b9ad373625096fd59530235c47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jelizaveta=20Leme=C5=A1eva?=
 <jelizaveta.lemeseva@vinted.com>
Date: Wed, 22 Jun 2022 14:25:39 +0200
Subject: [PATCH 2/5] Add tests

---
 spec/unit/lib/temporal/connection_spec.rb | 58 +++++++++++++++++++++++
 spec/unit/lib/temporal/grpc_spec.rb       |  2 +-
 2 files changed, 59 insertions(+), 1 deletion(-)
 create mode 100644 spec/unit/lib/temporal/connection_spec.rb

diff --git a/spec/unit/lib/temporal/connection_spec.rb b/spec/unit/lib/temporal/connection_spec.rb
new file mode 100644
index 00000000..dff88b0a
--- /dev/null
+++ b/spec/unit/lib/temporal/connection_spec.rb
@@ -0,0 +1,58 @@
+describe Temporal::Connection do
+  subject { described_class.generate(config.for_connection) }
+
+  let(:connection_type) { :grpc }
+  let(:credentials) { nil }
+  let(:config) do
+    config = Temporal::Configuration.new
+    config.connection_type = connection_type
+    config.credentials = credentials if credentials
+    config
+  end
+
+  context 'insecure' do
+    let(:credentials) { :this_channel_is_insecure }
+
+    it 'generates a grpc connection' do
+      expect(subject).to be_kind_of(Temporal::Connection::GRPC)
+      expect(subject.send(:identity)).not_to be_nil
+      expect(subject.send(:credentials)).to eq(:this_channel_is_insecure)
+    end
+  end
+
+  context 'ssl' do
+    let(:credentials) { GRPC::Core::ChannelCredentials.new }
+
+    it 'generates a grpc connection' do
+      expect(subject).to be_kind_of(Temporal::Connection::GRPC)
+      expect(subject.send(:identity)).not_to be_nil
+      expect(subject.send(:credentials)).to be_kind_of(GRPC::Core::ChannelCredentials)
+    end
+  end
+
+  context 'oauth2' do
+    let(:credentials) { GRPC::Core::CallCredentials.new(proc { { authorization: 'token' } }) }
+
+    it 'generates a grpc connection' do
+      expect(subject).to be_kind_of(Temporal::Connection::GRPC)
+      expect(subject.send(:identity)).not_to be_nil
+      expect(subject.send(:credentials)).to be_kind_of(GRPC::Core::CallCredentials)
+    end
+  end
+
+  context 'ssl + oauth2' do
+    let(:credentials) do
+      GRPC::Core::ChannelCredentials.new.compose(
+        GRPC::Core::CallCredentials.new(
+          proc { { authorization: 'token' } }
+        )
+      )
+    end
+
+    it 'generates a grpc connection' do
+      expect(subject).to be_kind_of(Temporal::Connection::GRPC)
+      expect(subject.send(:identity)).not_to be_nil
+      expect(subject.send(:credentials)).to be_kind_of(GRPC::Core::ChannelCredentials)
+    end
+  end
+end
diff --git a/spec/unit/lib/temporal/grpc_spec.rb b/spec/unit/lib/temporal/grpc_spec.rb
index d828d537..ef617341 100644
--- a/spec/unit/lib/temporal/grpc_spec.rb
+++ b/spec/unit/lib/temporal/grpc_spec.rb
@@ -10,7 +10,7 @@
   let(:run_id) { SecureRandom.uuid }
   let(:now) { Time.now}
 
-  subject { Temporal::Connection::GRPC.new(nil, nil, identity) }
+  subject { Temporal::Connection::GRPC.new(nil, nil, identity, :this_channel_is_insecure) }
 
   class TestDeserializer
     extend Temporal::Concerns::Payloads

From 879490f2d7713173fc855f12719114ac81d3681b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jelizaveta=20Leme=C5=A1eva?=
 <jelizaveta.lemeseva@vinted.com>
Date: Wed, 22 Jun 2022 14:27:34 +0200
Subject: [PATCH 3/5] Update README.md

---
 README.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/README.md b/README.md
index 838fda7a..11a2c8ba 100644
--- a/README.md
+++ b/README.md
@@ -59,6 +59,7 @@ Temporal.configure do |config|
   config.port = 7233
   config.namespace = 'ruby-samples'
   config.task_queue = 'hello-world'
+  config.credentials = :this_channel_is_insecure
 end
 
 begin
@@ -114,6 +115,57 @@ curl -O https://raw.githubusercontent.com/temporalio/docker-compose/main/docker-
 docker-compose up
 ```
 
+## Using Credentials
+
+### SSL
+
+In many production deployments you will end up connecting to your Temporal Services via SSL. In this
+case you must read the public cert of the CA that issued your Temporal server's SSL cert and create
+an instance of [gRPC Channel Credentials](https://grpc.io/docs/guides/auth/#with-server-authentication-ssltls-1).
+
+Configure your Temporal connection:
+
+```ruby
+Temporal.configure do |config|
+    config.host = 'localhost'
+    config.port = 7233
+    config.namespace = 'ruby-samples'
+    config.task_queue = 'hello-world'
+    config.credentials = GRPC::Core::ChannelCredentials.new(root_cert, client_key, client_chain)
+end
+```
+
+### OAuth2 Token
+
+Use gRPC Call Credentials to add OAuth2 token to gRPC calls:
+
+```ruby
+Temporal.configure do |config|
+    config.host = 'localhost'
+    config.port = 7233
+    config.namespace = 'ruby-samples'
+    config.task_queue = 'hello-world'
+    config.credentials = GRPC::Core::CallCredentials.new(updater_proc)
+end
+```
+`updater_proc` should be a method that returns `proc`. See an example of `updater_proc` in [googleauth](https://www.rubydoc.info/gems/googleauth/0.1.0/Signet/OAuth2/Client) library.
+
+### Combining Credentials
+
+To configure both SSL and OAuth2 token cedentials use `compose` method:
+
+```ruby
+Temporal.configure do |config|
+    config.host = 'localhost'
+    config.port = 7233
+    config.namespace = 'ruby-samples'
+    config.task_queue = 'hello-world'
+    config.credentials = GRPC::Core::ChannelCredentials.new(root_cert, client_key, client_chain).compose(
+        GRPC::Core::CallCredentials.new(token.updater_proc)
+    )
+end
+```
+
 ## Workflows
 
 A workflow is defined using pure Ruby code, however it should contain only a high-level

From 088e09b58c10e4819c3c8c7270acb39ae2454a26 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jelizaveta=20Leme=C5=A1eva?=
 <jelizaveta.lemeseva@vinted.com>
Date: Wed, 22 Jun 2022 14:52:21 +0200
Subject: [PATCH 4/5] Use default DYNAMIC_CONFIG_FILE_PATH env var for
 temporalio/auto-setup container in CI

---
 .circleci/config.yml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index b23efce7..ed0d5eb0 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -29,7 +29,6 @@ jobs:
           - POSTGRES_USER=postgres
           - POSTGRES_PWD=temporal
           - POSTGRES_SEEDS=postgres
-          - DYNAMIC_CONFIG_FILE_PATH=config/dynamicconfig/development.yaml
 
     environment:
       - TEMPORAL_HOST=temporal

From 04d0f6f3e242f3dca36ca4b0a2c048922b032107 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jelizaveta=20Leme=C5=A1eva?=
 <jelizaveta.lemeseva@vinted.com>
Date: Thu, 23 Jun 2022 10:13:51 +0200
Subject: [PATCH 5/5] Update README.md

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 11a2c8ba..7f5ff27d 100644
--- a/README.md
+++ b/README.md
@@ -120,7 +120,7 @@ docker-compose up
 ### SSL
 
 In many production deployments you will end up connecting to your Temporal Services via SSL. In this
-case you must read the public cert of the CA that issued your Temporal server's SSL cert and create
+case you must read the public certificate of the CA that issued your Temporal server's SSL certificate and create
 an instance of [gRPC Channel Credentials](https://grpc.io/docs/guides/auth/#with-server-authentication-ssltls-1).
 
 Configure your Temporal connection: