strongdm 15.41.0 → 15.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b1e9f52173a0bece622752999286e3fbefef573f7c9a8cee68fc6687e73414d
4
- data.tar.gz: 6cc7b1cc2900a86d9ecb939b67dff13189ced426becb976e110070d3b16efb9f
3
+ metadata.gz: 07b05d002ea762434e9a42b6da278425d8bb2adf661df165169151ead7aedbda
4
+ data.tar.gz: fff4b6adece624583f2ccc960359612db92edde0a6af9ada9468013740cc5f16
5
5
  SHA512:
6
- metadata.gz: 49280bb2ba6cb9925a9a8a6456cb05d3fcfd9fb26992e04490c82ea19f31ac0e158a5aa6883bc96a6a7be6a3d117dc0f34a5dc02bb7bf73ab9b9b5d21c803aa8
7
- data.tar.gz: 868450c0b94a863c315ee0a881c1d3d0627e2284eb3c28cc3682ee62f0c0566ce4a93afa0ba7f3cc5889a40281f0d1f2220f9d7652048b060e060e34c00b9146
6
+ metadata.gz: 63a76d68d110c41c6c7838a4927186c8606a0c61c4eacfa2d47a729e4e0754561331e70d80a5e1f2916caae212619296c42bf38a15f0c07bc8d641d122fbebb4
7
+ data.tar.gz: 22e7bb7ce4c40f7935ef05feb46d1dbc2e41a9d2ccb2fa6526743dec30e55c5fe6819f9502e4c0d790b88478162ba10588372fde8691d6f2183db6ed60eb49f0
data/.git/ORIG_HEAD CHANGED
@@ -1 +1 @@
1
- b20e3c16d138fc17c80e82311c7613a915bc3569
1
+ b23f0912dbe900e5bd24222f9971c7820ddf128d
data/.git/index CHANGED
Binary file
data/.git/logs/HEAD CHANGED
@@ -1,3 +1,3 @@
1
- 0000000000000000000000000000000000000000 b20e3c16d138fc17c80e82311c7613a915bc3569 root <root@e35d0cf551cb.(none)> 1765963630 +0000 clone: from github.com:strongdm/strongdm-sdk-ruby.git
2
- b20e3c16d138fc17c80e82311c7613a915bc3569 b20e3c16d138fc17c80e82311c7613a915bc3569 root <root@e35d0cf551cb.(none)> 1765963630 +0000 checkout: moving from master to master
3
- b20e3c16d138fc17c80e82311c7613a915bc3569 b23f0912dbe900e5bd24222f9971c7820ddf128d root <root@e35d0cf551cb.(none)> 1765963630 +0000 merge origin/development: Fast-forward
1
+ 0000000000000000000000000000000000000000 b23f0912dbe900e5bd24222f9971c7820ddf128d root <root@cbe5b8a77e04.(none)> 1766504191 +0000 clone: from github.com:strongdm/strongdm-sdk-ruby.git
2
+ b23f0912dbe900e5bd24222f9971c7820ddf128d b23f0912dbe900e5bd24222f9971c7820ddf128d root <root@cbe5b8a77e04.(none)> 1766504191 +0000 checkout: moving from master to master
3
+ b23f0912dbe900e5bd24222f9971c7820ddf128d 1170439941e521c29339b4d2314cae0e1526759e root <root@cbe5b8a77e04.(none)> 1766504191 +0000 merge origin/development: Fast-forward
@@ -1,2 +1,2 @@
1
- 0000000000000000000000000000000000000000 b20e3c16d138fc17c80e82311c7613a915bc3569 root <root@e35d0cf551cb.(none)> 1765963630 +0000 clone: from github.com:strongdm/strongdm-sdk-ruby.git
2
- b20e3c16d138fc17c80e82311c7613a915bc3569 b23f0912dbe900e5bd24222f9971c7820ddf128d root <root@e35d0cf551cb.(none)> 1765963630 +0000 merge origin/development: Fast-forward
1
+ 0000000000000000000000000000000000000000 b23f0912dbe900e5bd24222f9971c7820ddf128d root <root@cbe5b8a77e04.(none)> 1766504191 +0000 clone: from github.com:strongdm/strongdm-sdk-ruby.git
2
+ b23f0912dbe900e5bd24222f9971c7820ddf128d 1170439941e521c29339b4d2314cae0e1526759e root <root@cbe5b8a77e04.(none)> 1766504191 +0000 merge origin/development: Fast-forward
@@ -1 +1 @@
1
- 0000000000000000000000000000000000000000 b20e3c16d138fc17c80e82311c7613a915bc3569 root <root@e35d0cf551cb.(none)> 1765963630 +0000 clone: from github.com:strongdm/strongdm-sdk-ruby.git
1
+ 0000000000000000000000000000000000000000 b23f0912dbe900e5bd24222f9971c7820ddf128d root <root@cbe5b8a77e04.(none)> 1766504191 +0000 clone: from github.com:strongdm/strongdm-sdk-ruby.git
data/.git/packed-refs CHANGED
@@ -1,6 +1,6 @@
1
1
  # pack-refs with: peeled fully-peeled sorted
2
- b23f0912dbe900e5bd24222f9971c7820ddf128d refs/remotes/origin/development
3
- b20e3c16d138fc17c80e82311c7613a915bc3569 refs/remotes/origin/master
2
+ 1170439941e521c29339b4d2314cae0e1526759e refs/remotes/origin/development
3
+ b23f0912dbe900e5bd24222f9971c7820ddf128d refs/remotes/origin/master
4
4
  2e4fe8087177ddea9b3991ca499f758384839c89 refs/tags/untagged-84fd83a4484c785cce63
5
5
  04f604866214fab4d5663b5171a3e596331577bd refs/tags/v0.9.4
6
6
  6f9a7b75b345c65fb554884907b7060680c807b7 refs/tags/v0.9.5
@@ -128,6 +128,7 @@ e2a4215bd3bbfb822423e11e81b9ad47bef03840 refs/tags/v15.36.0
128
128
  740f705c286a25c2abae5a44b52fe330cc4e3e71 refs/tags/v15.39.0
129
129
  cf3b15b82cb0c4229609c07c870c6cb4fd38ef75 refs/tags/v15.4.0
130
130
  b20e3c16d138fc17c80e82311c7613a915bc3569 refs/tags/v15.40.0
131
+ b23f0912dbe900e5bd24222f9971c7820ddf128d refs/tags/v15.41.0
131
132
  0be2c5e7f7a90c49077548cb3a9bce234219b9f0 refs/tags/v15.5.0
132
133
  4b9cd43c5dda3f369b82b6a56132a5470ff9ff53 refs/tags/v15.6.0
133
134
  6e8e9210b26f02ebe925b8e81909ba42985cfde7 refs/tags/v15.7.0
@@ -1 +1 @@
1
- b23f0912dbe900e5bd24222f9971c7820ddf128d
1
+ 1170439941e521c29339b4d2314cae0e1526759e
data/lib/constants.rb CHANGED
@@ -333,6 +333,7 @@ module SDM
333
333
  RESOURCE_LOCKED = "user locked a resource"
334
334
  RESOURCE_UNLOCKED = "user unlocked a resource"
335
335
  RESOURCE_FORCE_UNLOCKED = "admin force-unlocked a resource"
336
+ RESOURCE_LOCK_REJECTED = "user lock rejected for a resource"
336
337
  CONCURRENT_AUTHENTICATION_REVOKED_PER_ORG_SETTING = "concurrent authentications revoked per organization settings"
337
338
  PEERING_GROUP_TOGGLED = "peering group toggled"
338
339
  PEERING_GROUP_CREATED = "peering group created"
@@ -0,0 +1,200 @@
1
+ # Copyright 2020 StrongDM Inc
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+
16
+ # @internal Code generated by protogen. DO NOT EDIT.
17
+
18
+ require "openssl"
19
+ require_relative "./grpc/plumbing"
20
+
21
+ module SDM
22
+ # MethodInterceptor provides a generic hook system for modifying
23
+ # requests and responses before/after gRPC calls
24
+ class MethodInterceptor
25
+ def initialize(client)
26
+ @client = client
27
+ @before_hooks = {}
28
+ @after_hooks = {}
29
+ end
30
+
31
+ # Register a hook to run before a method call
32
+ # method_name: "ServiceName.MethodName" (e.g., "ManagedSecrets.Create")
33
+ # block: receives (service_instance, request) and should return modified request
34
+ def before(method_name, &block)
35
+ @before_hooks[method_name] = block
36
+ end
37
+
38
+ # Register a hook to run after a method call
39
+ # method_name: "ServiceName.MethodName"
40
+ # block: receives (service_instance, request, response) and should return modified response
41
+ def after(method_name, &block)
42
+ @after_hooks[method_name] = block
43
+ end
44
+
45
+ # Execute before hooks for a method
46
+ def execute_before(method_name, service_instance, request)
47
+ hook = @before_hooks[method_name]
48
+ return request unless hook
49
+ hook.call(service_instance, request)
50
+ end
51
+
52
+ # Execute after hooks for a method
53
+ def execute_after(method_name, service_instance, request, response)
54
+ hook = @after_hooks[method_name]
55
+ return response unless hook
56
+ hook.call(service_instance, request, response)
57
+ end
58
+ end
59
+
60
+ # SecretEncryptionInterceptor implements encryption for managed secrets
61
+ class SecretEncryptionInterceptor
62
+ def initialize(client)
63
+ @client = client
64
+ @public_key_cache = {}
65
+ @private_key = nil
66
+ end
67
+
68
+ # Lazy-load private key for retrievals
69
+ def private_key
70
+ @private_key ||= OpenSSL::PKey::RSA.new(4096)
71
+ end
72
+
73
+ # Cache a secret engine's public key
74
+ def cache_public_key(engine_id, public_key_pem)
75
+ return if public_key_pem.nil? || public_key_pem.empty?
76
+ @public_key_cache[engine_id] = OpenSSL::PKey::RSA.new(public_key_pem)
77
+ end
78
+
79
+ # Get cached public key
80
+ def get_public_key(engine_id)
81
+ @public_key_cache[engine_id]
82
+ end
83
+
84
+ # Encrypt data using RSA-OAEP with SHA256
85
+ def encrypt(public_key, plaintext)
86
+ return plaintext if plaintext.nil? || plaintext.empty?
87
+ public_key.encrypt(plaintext, rsa_padding_mode: "oaep", rsa_oaep_md: "sha256", rsa_mgf1_md: "sha256")
88
+ end
89
+
90
+ # Decrypt data using RSA-OAEP with SHA256
91
+ def decrypt(ciphertext)
92
+ return ciphertext if ciphertext.nil? || ciphertext.empty?
93
+ private_key.decrypt(ciphertext, rsa_padding_mode: "oaep", rsa_oaep_md: "sha256", rsa_mgf1_md: "sha256")
94
+ end
95
+
96
+ # Export public key in PEM format
97
+ def export_public_key
98
+ private_key.public_key.to_pem
99
+ end
100
+
101
+ # Setup hooks on the interceptor
102
+ def setup(interceptor)
103
+ setup_managed_secrets_hooks(interceptor)
104
+ setup_secret_engines_hooks(interceptor)
105
+ end
106
+
107
+ private
108
+
109
+ def setup_managed_secrets_hooks(interceptor)
110
+ # Hook for ManagedSecrets.Create - encrypt before sending
111
+ interceptor.before("ManagedSecrets.Create") do |service, req|
112
+ secret = req.managed_secret
113
+ if secret && !secret.value.nil? && !secret.value.empty? && !secret.secret_engine_id.nil?
114
+ # Try to get public key from cache or fetch it
115
+ pub_key = get_public_key(secret.secret_engine_id)
116
+ if pub_key.nil?
117
+ begin
118
+ @client.secret_engines.get(secret.secret_engine_id)
119
+ pub_key = get_public_key(secret.secret_engine_id)
120
+ rescue
121
+ # If fetch fails, let server handle it
122
+ end
123
+ end
124
+
125
+ # Encrypt if we have the key
126
+ if pub_key
127
+ secret.value = encrypt(pub_key, secret.value)
128
+ end
129
+ end
130
+ req
131
+ end
132
+
133
+ # Hook for ManagedSecrets.Update - encrypt before sending
134
+ interceptor.before("ManagedSecrets.Update") do |service, req|
135
+ secret = req.managed_secret
136
+ if secret && !secret.value.nil? && !secret.value.empty? && !secret.secret_engine_id.nil?
137
+ pub_key = get_public_key(secret.secret_engine_id)
138
+ if pub_key.nil?
139
+ begin
140
+ @client.secret_engines.get(secret.secret_engine_id)
141
+ pub_key = get_public_key(secret.secret_engine_id)
142
+ rescue
143
+ # If fetch fails, let server handle it
144
+ end
145
+ end
146
+
147
+ if pub_key
148
+ secret.value = encrypt(pub_key, secret.value)
149
+ end
150
+ end
151
+ req
152
+ end
153
+
154
+ # Hook for ManagedSecrets.Retrieve - add public key and decrypt response
155
+ interceptor.before("ManagedSecrets.Retrieve") do |service, req|
156
+ if req.public_key.nil? || req.public_key.empty?
157
+ req.public_key = export_public_key
158
+ end
159
+ req
160
+ end
161
+
162
+ interceptor.after("ManagedSecrets.Retrieve") do |service, req, resp|
163
+ # Only decrypt if we provided the public key
164
+ if req.public_key == export_public_key
165
+ secret = resp.managed_secret
166
+ if secret && !secret.value.nil? && !secret.value.empty?
167
+ secret.value = decrypt(secret.value)
168
+ end
169
+ end
170
+ resp
171
+ end
172
+ end
173
+
174
+ def setup_secret_engines_hooks(interceptor)
175
+ # Hook for SecretEngines.Get - cache public key after response
176
+ interceptor.after("SecretEngines.Get") do |service, req, resp|
177
+ engine = Plumbing::convert_secret_engine_to_porcelain(resp.secret_engine)
178
+ if engine && !engine.id.nil? && !engine.public_key.nil?
179
+ cache_public_key(engine.id, engine.public_key)
180
+ end
181
+ resp
182
+ end
183
+ end
184
+ end
185
+
186
+ # EnumeratorInterceptor provides utilities for wrapping enumerators with hooks
187
+ module EnumeratorInterceptor
188
+ # Wraps an enumerator to cache secret engine public keys
189
+ def self.wrap_secret_engine_list(enumerator, encryption_interceptor)
190
+ Enumerator.new do |yielder|
191
+ enumerator.each do |engine|
192
+ if engine && !engine.id.nil? && !engine.public_key.nil?
193
+ encryption_interceptor.cache_public_key(engine.id, engine.public_key)
194
+ end
195
+ yielder << engine
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
data/lib/strongdm.rb CHANGED
@@ -16,6 +16,7 @@
16
16
  # @internal Code generated by protogen. DO NOT EDIT.
17
17
 
18
18
  require_relative "./svc"
19
+ require_relative "./interceptors"
19
20
  require "base64"
20
21
  require "grpc"
21
22
  require "openssl"
@@ -30,7 +31,7 @@ module SDM #:nodoc:
30
31
  DEFAULT_RETRY_FACTOR = 1.6
31
32
  DEFAULT_RETRY_JITTER = 0.2
32
33
  API_VERSION = "2025-04-14"
33
- USER_AGENT = "strongdm-sdk-ruby/15.41.0"
34
+ USER_AGENT = "strongdm-sdk-ruby/15.43.0"
34
35
  private_constant :DEFAULT_BASE_RETRY_DELAY, :DEFAULT_MAX_RETRY_DELAY, :DEFAULT_RETRY_FACTOR, :DEFAULT_RETRY_JITTER, :API_VERSION, :USER_AGENT
35
36
 
36
37
  # Creates a new strongDM API client.
@@ -47,6 +48,10 @@ module SDM #:nodoc:
47
48
  @page_limit = page_limit
48
49
  @retry_rate_limit_errors = retry_rate_limit_errors
49
50
  @snapshot_time = nil
51
+ # Initialize method interceptor for request/response hooks
52
+ @interceptor = MethodInterceptor.new(self)
53
+ @encryption_interceptor = SecretEncryptionInterceptor.new(self)
54
+ @encryption_interceptor.setup(@interceptor)
50
55
  begin
51
56
  if insecure
52
57
  @channel = GRPC::Core::Channel.new(host, {}, :this_channel_is_insecure)
@@ -234,6 +239,8 @@ module SDM #:nodoc:
234
239
  attr_reader :api_access_key
235
240
  # Optional timestamp at which to provide historical data
236
241
  attr_reader :snapshot_time
242
+ # Method interceptor for request/response hooks (read-only).
243
+ attr_reader :interceptor
237
244
  # AccessRequests are requests for access to a resource that may match a Workflow.
238
245
  #
239
246
  # See {AccessRequests}.