strongmind-platform-sdk 3.32.0 → 3.33.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: 999f26d4cd8d102f6dc1016bff6c6c209852c54e69ab1dc14b4768264f248f5c
4
- data.tar.gz: e276aa457755f6d60729f29bdc7255d79561a8dd4582fad39c57593aaebb13c7
3
+ metadata.gz: 7b23cd42819001403fdf176b48df36e0d0acd9fd65a625e24a65899ba3496715
4
+ data.tar.gz: aa7316e0ef335e0cbc423ae5b9f201b6e076d971373966b60e2db229f9b86fc4
5
5
  SHA512:
6
- metadata.gz: db42e98d0b0769986f4f495a4f08b8f0b37904b90abf2d66e5e4e6d91f80a307048b684f546efa0f83bab209d266b2ed086f244ade5114cd93f36aa44196cbcb
7
- data.tar.gz: 98ce988fa4fd168449b2dce2368fd6f6ef669557bd7df3489fc334e94c70e0874e20ad8267836f08978ff2969ff2ae7e2b19fcbf93d941d67a950809dee89d4a
6
+ metadata.gz: d45af1a0c4478d1310763cf3dd33effe6a96fdc6f76ab1dcbcf15fc710a7ad618d82515ec32d9ed65b4ac520c64d1c6722ba1614c57bf56b77823e003d45641a
7
+ data.tar.gz: 3655fa57a8e56e9e31b8b2aa9c40abca15abe7ed7f35c512a31585992c4cbd985e2aef3884e429c76f6362ca4c83c517389089eb7c86084764abe9f121fe931c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [3.33.0] - 2026-07-28
4
+
5
+ - Add `PlatformSdk::Identity::Zitadel::Client` — Zitadel v2 user API client (`#provision_identity`), mirroring the IS4 client's signature. Preserves the IS4 `Id` as the Zitadel `userId` and treats a `409` as an idempotent replay once the preserved id is confirmed to hold the same username.
6
+ - Add `PlatformSdk::Identity::Zitadel::AuthClient` — fetches and caches machine-user access tokens via `client_credentials`, thread-safe under concurrent callers. `Zitadel::Client` takes any token-provider object responding to `#auth_token` (a seam for wrapping `AuthClient`, e.g. behind `Rails.cache`). `AuthClient` accepts a `scope:` keyword (defaults to the management-API audience) and exposes `#expires_at`.
7
+ - Add `PlatformSdk::Identity::Zitadel::UserPayload.from_is4` — maps the IS4 `WithProfile` payload shape onto Zitadel's `AddHumanUser` request, dropping password/reset-email fields (SIS creations are always shells) and marking email/phone unverified.
8
+ - Redact `client_secret`/bearer-token values from the raised error payload in `ErrorHandleable#raise_error_with_payload`, not just the logged line, since the exception itself is handed to consumer instrumentation.
9
+
3
10
  ## [3.32.0] - 2026-06-10
4
11
 
5
12
  - Add `PlatformSdk::LlmGateway::Client#generate_offline_activity` — posts to `POST /activities/generate` with `learning_component`, `learning_objective`, and `grade_level` and returns the parsed response body.
data/Gemfile.lock CHANGED
@@ -1,10 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- strongmind-platform-sdk (3.32.0)
4
+ strongmind-platform-sdk (3.33.0)
5
5
  asset_sync
6
6
  aws-sdk-cloudwatch
7
7
  aws-sdk-secretsmanager (~> 1.66)
8
+ base64
8
9
  faraday (~> 2.5, >= 2.5.2)
9
10
  faraday-retry
10
11
  fog-aws
@@ -124,7 +125,7 @@ GEM
124
125
  base64 (0.2.0)
125
126
  bigdecimal (3.1.8)
126
127
  builder (3.3.0)
127
- cgi (0.5.1)
128
+ cgi (0.5.2)
128
129
  coderay (1.1.3)
129
130
  concurrent-ruby (1.3.3)
130
131
  connection_pool (2.4.1)
@@ -138,7 +139,7 @@ GEM
138
139
  erubi (1.13.0)
139
140
  ethon (0.16.0)
140
141
  ffi (>= 1.15.0)
141
- excon (1.5.0)
142
+ excon (1.6.0)
142
143
  logger
143
144
  factory_bot (6.4.6)
144
145
  activesupport (>= 5.0.0)
@@ -152,6 +153,7 @@ GEM
152
153
  faraday-retry (2.2.1)
153
154
  faraday (~> 2.0)
154
155
  ffi (1.17.0)
156
+ ffi (1.17.0-arm64-darwin)
155
157
  ffi (1.17.0-x86_64-darwin)
156
158
  ffi (1.17.0-x86_64-linux-gnu)
157
159
  fog-aws (3.33.2)
@@ -172,11 +174,14 @@ GEM
172
174
  nokogiri (>= 1.5.11, < 2.0.0)
173
175
  formatador (1.2.3)
174
176
  reline
175
- globalid (1.3.0)
177
+ globalid (1.4.0)
176
178
  activesupport (>= 6.1)
177
179
  google-protobuf (4.33.6)
178
180
  bigdecimal
179
181
  rake (>= 13)
182
+ google-protobuf (4.33.6-arm64-darwin)
183
+ bigdecimal
184
+ rake (>= 13)
180
185
  google-protobuf (4.33.6-x86_64-darwin)
181
186
  bigdecimal
182
187
  rake (>= 13)
@@ -202,7 +207,7 @@ GEM
202
207
  loofah (2.22.0)
203
208
  crass (~> 1.0.2)
204
209
  nokogiri (>= 1.12.0)
205
- mail (2.9.0)
210
+ mail (2.9.1)
206
211
  logger
207
212
  mini_mime (>= 0.1.1)
208
213
  net-imap
@@ -213,7 +218,7 @@ GEM
213
218
  mime-types (3.7.0)
214
219
  logger
215
220
  mime-types-data (~> 3.2025, >= 3.2025.0507)
216
- mime-types-data (3.2026.0414)
221
+ mime-types-data (3.2026.0701)
217
222
  mini_mime (1.1.5)
218
223
  mini_portile2 (2.8.7)
219
224
  minitest (5.24.1)
@@ -221,7 +226,7 @@ GEM
221
226
  mutex_m (0.2.0)
222
227
  net-http (0.4.1)
223
228
  uri
224
- net-imap (0.6.4.1)
229
+ net-imap (0.6.6)
225
230
  date
226
231
  net-protocol
227
232
  net-pop (0.1.2)
@@ -231,12 +236,14 @@ GEM
231
236
  net-smtp (0.5.1)
232
237
  net-protocol
233
238
  nio4r (2.7.5)
234
- nokogiri (1.16.7)
239
+ nokogiri (1.19.4)
235
240
  mini_portile2 (~> 2.8.2)
236
241
  racc (~> 1.4)
237
- nokogiri (1.16.7-x86_64-darwin)
242
+ nokogiri (1.19.4-arm64-darwin)
243
+ racc (~> 1.4)
244
+ nokogiri (1.19.4-x86_64-darwin)
238
245
  racc (~> 1.4)
239
- nokogiri (1.16.7-x86_64-linux)
246
+ nokogiri (1.19.4-x86_64-linux-gnu)
240
247
  racc (~> 1.4)
241
248
  opentelemetry-api (1.8.0)
242
249
  logger
@@ -363,6 +370,7 @@ GEM
363
370
  redis-client (>= 0.22.2)
364
371
  sqlite3 (1.7.3)
365
372
  mini_portile2 (~> 2.8.0)
373
+ sqlite3 (1.7.3-arm64-darwin)
366
374
  sqlite3 (1.7.3-x86_64-darwin)
367
375
  sqlite3 (1.7.3-x86_64-linux)
368
376
  stringio (3.1.1)
@@ -390,13 +398,14 @@ GEM
390
398
  crack (>= 0.3.2)
391
399
  hashdiff (>= 0.4.0, < 2.0.0)
392
400
  webrick (1.8.1)
393
- websocket-driver (0.8.1)
401
+ websocket-driver (0.8.2)
394
402
  base64
395
403
  websocket-extensions (>= 0.1.0)
396
404
  websocket-extensions (0.1.5)
397
405
  zeitwerk (2.6.17)
398
406
 
399
407
  PLATFORMS
408
+ arm64-darwin
400
409
  ruby
401
410
  x86_64-darwin-21
402
411
  x86_64-linux
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "faraday"
4
+ require "platform_sdk/version"
4
5
 
5
6
  module PlatformSdk
6
7
  module CanvasApiWrapper
@@ -15,7 +16,13 @@ module PlatformSdk
15
16
  def initialize(domain:, token:)
16
17
  @host = "https://#{domain}"
17
18
  @token = token
18
- @connection = Faraday.new(url: host, headers: { 'Authorization' => "Bearer #{token}" })
19
+ @connection = Faraday.new(
20
+ url: host,
21
+ headers: {
22
+ 'Authorization' => "Bearer #{token}",
23
+ 'User-Agent' => "StrongMind-PlatformSDK/#{PlatformSdk::VERSION}"
24
+ }
25
+ )
19
26
  end
20
27
 
21
28
  # @param course_id [Integer]
@@ -4,6 +4,13 @@ module PlatformSdk
4
4
  module Identity
5
5
  # Error handling for Identity SDK
6
6
  module ErrorHandleable
7
+ # The logged payload is the raw request body, which for token endpoints
8
+ # carries client credentials; redact those fields (form-encoded and
9
+ # JSON shapes) so an auth outage can't write secrets to consumer logs.
10
+ SENSITIVE_KEYS = 'client_secret|client_assertion|refresh_token|password'
11
+ FORM_SECRET_PATTERN = /(#{SENSITIVE_KEYS})=[^&]*/i
12
+ JSON_SECRET_PATTERN = /("(?:#{SENSITIVE_KEYS})"\s*:\s*")[^"]*(")/i
13
+
7
14
  def with_rescue
8
15
  yield
9
16
  rescue Faraday::TimeoutError => e
@@ -15,14 +22,62 @@ module PlatformSdk
15
22
  end
16
23
 
17
24
  def raise_error_with_payload(exception_class, error)
18
- json_log = {
19
- exception: exception_class.new.class.name.demodulize,
20
- payload: error.response.dig(:request, :body),
25
+ Rails.logger.info(error_log_payload(exception_class, error).to_json) if defined?(Rails)
26
+ # The exception itself carries error.response on to consumer
27
+ # instrumentation (Sentry, custom error handlers), so the raw
28
+ # request body/headers - which can hold a client_secret or bearer
29
+ # token - must be scrubbed here too, not just in the log line above.
30
+ raise exception_class, scrub_response(error.response)
31
+ end
32
+
33
+ # No ActiveSupport here (String#demodulize): this must work for
34
+ # non-Rails consumers, where the log line is skipped but this hash is
35
+ # still built.
36
+ def error_log_payload(exception_class, error)
37
+ {
38
+ exception: exception_class.name.split('::').last,
39
+ payload: scrub_secrets(error.response.dig(:request, :body)),
21
40
  response_body: error.response[:body],
22
41
  status: error.response[:status]
23
42
  }.compact
24
- Rails.logger.info json_log.to_json if defined?(Rails)
25
- raise exception_class, error.response
43
+ end
44
+
45
+ def scrub_secrets(body)
46
+ return body unless body.is_a?(String)
47
+
48
+ body.gsub(FORM_SECRET_PATTERN) { "#{Regexp.last_match(1)}=[REDACTED]" }
49
+ .gsub(JSON_SECRET_PATTERN, '\1[REDACTED]\2')
50
+ end
51
+
52
+ # Returns a scrubbed copy of the Faraday error response hash; the
53
+ # original (and its nested :request hash) are left untouched. Only
54
+ # [:request][:body] and [:request][:headers] are touched -
55
+ # [:status] and [:body] (the response body) are read elsewhere
56
+ # (e.g. e.response&.dig(:status), e.response&.dig(:body, 'paramName'))
57
+ # and must reach consumers unchanged.
58
+ def scrub_response(response)
59
+ return response unless response.is_a?(Hash)
60
+
61
+ scrubbed = response.dup
62
+ scrubbed[:request] = scrub_request(response[:request]) if response[:request].is_a?(Hash)
63
+ scrubbed
64
+ end
65
+
66
+ def scrub_request(request)
67
+ scrubbed_request = request.dup
68
+ scrubbed_request[:body] = scrub_secrets(request[:body]) if request[:body].is_a?(String)
69
+ scrubbed_request[:headers] = scrub_headers(request[:headers]) if request[:headers].is_a?(Hash)
70
+ scrubbed_request
71
+ end
72
+
73
+ # dup (not a rebuilt Hash) so a Faraday::Utils::Headers keeps its
74
+ # class and case-insensitive lookup on the scrubbed copy.
75
+ def scrub_headers(headers)
76
+ scrubbed = headers.dup
77
+ scrubbed.each_key do |key|
78
+ scrubbed[key] = '[REDACTED]' if key.to_s.casecmp('authorization').zero?
79
+ end
80
+ scrubbed
26
81
  end
27
82
  end
28
83
  end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformSdk
4
+ module Identity
5
+ module Zitadel
6
+ # Fetches machine-user access tokens from Zitadel via client_credentials.
7
+ # Tokens are opaque bearer tokens; expiry tracking uses expires_in.
8
+ class AuthClient
9
+ include ErrorHandleable
10
+
11
+ API_SCOPE = 'openid urn:zitadel:iam:org:project:id:zitadel:aud'
12
+ EXPIRY_SKEW_SECONDS = 60
13
+ OPEN_TIMEOUT_SECONDS = 2
14
+ READ_TIMEOUT_SECONDS = 5
15
+
16
+ attr_reader :conn, :expires_at
17
+
18
+ def initialize(base_url, client_id, client_secret, scope: API_SCOPE)
19
+ @client_id = client_id
20
+ @client_secret = client_secret
21
+ @scope = scope
22
+ @token_lock = Mutex.new
23
+ @conn = build_connection(base_url)
24
+ end
25
+
26
+ # The lock makes concurrent callers (Puma/Sidekiq threads) share one
27
+ # fetch instead of racing: an unguarded reader could also observe
28
+ # @token assigned but @expires_at still nil mid-fetch and crash in
29
+ # expired?. Serializing on the bounded (2s/5s) fetch is acceptable
30
+ # for the shadow path.
31
+ def auth_token
32
+ @token_lock.synchronize do
33
+ fetch_token if expired?
34
+ @token
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def build_connection(base_url)
41
+ Faraday.new(base_url) do |conn|
42
+ conn.request :url_encoded
43
+ conn.response :raise_error
44
+ conn.response :json
45
+ conn.options.open_timeout = OPEN_TIMEOUT_SECONDS
46
+ conn.options.timeout = READ_TIMEOUT_SECONDS
47
+ conn.adapter :net_http
48
+ end
49
+ end
50
+
51
+ def expired?
52
+ @token.nil? || Time.now.utc >= @expires_at
53
+ end
54
+
55
+ # Both fields are read into locals before either ivar is assigned: a
56
+ # malformed 200 (access_token without expires_in) must leave the cache
57
+ # untouched so the next call retries instead of comparing against a
58
+ # nil @expires_at forever.
59
+ def fetch_token
60
+ body = with_rescue { @conn.post('/oauth/v2/token', token_request_params).body }
61
+ token = body.fetch('access_token')
62
+ expires_at = Time.now.utc + body.fetch('expires_in').to_i - EXPIRY_SKEW_SECONDS
63
+ @token = token
64
+ @expires_at = expires_at
65
+ end
66
+
67
+ def token_request_params
68
+ {
69
+ grant_type: 'client_credentials',
70
+ client_id: @client_id,
71
+ client_secret: @client_secret,
72
+ scope: @scope
73
+ }
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformSdk
4
+ module Identity
5
+ module Zitadel
6
+ # Client for the Zitadel v2 user API. Deliberately mirrors the IS4
7
+ # Client's #provision_identity signature so consuming apps can call
8
+ # either interchangeably. Short timeouts, no retry middleware: this is
9
+ # the best-effort shadow path and must never hang a provisioning request.
10
+ #
11
+ # Token acquisition is a seam: the SDK ships Zitadel::AuthClient as the
12
+ # client_credentials implementation, but this class only needs an
13
+ # object responding to #auth_token. Consumers may pass an AuthClient
14
+ # directly, wrap one (e.g. a Rails.cache-backed provider that shares a
15
+ # token across processes), or supply any other object with that
16
+ # interface.
17
+ class Client
18
+ include ErrorHandleable
19
+
20
+ OPEN_TIMEOUT_SECONDS = 2
21
+ READ_TIMEOUT_SECONDS = 5
22
+
23
+ def initialize(base_url, token_provider)
24
+ @auth = token_provider
25
+ @conn = Faraday.new(base_url) do |conn|
26
+ conn.request :authorization, 'Bearer', -> { @auth.auth_token }
27
+ conn.request :json
28
+ conn.response :raise_error
29
+ conn.response :json
30
+ conn.options.open_timeout = OPEN_TIMEOUT_SECONDS
31
+ conn.options.timeout = READ_TIMEOUT_SECONDS
32
+ conn.adapter :net_http
33
+ end
34
+ end
35
+
36
+ def provision_identity(is4_params)
37
+ payload = UserPayload.from_is4(is4_params)
38
+ post_payload('/v2/users/human', payload)
39
+ rescue PlatformSdk::Identity::ClientError => e
40
+ raise unless e.response&.dig(:status) == 409
41
+
42
+ verify_existing!(payload, e)
43
+ end
44
+
45
+ private
46
+
47
+ # A 409 is idempotent-replay success only when the preserved id exists
48
+ # AND still holds this username; a matching id with a different
49
+ # username is a diverged record, not a replay, so the 409 stands.
50
+ def verify_existing!(payload, original_error)
51
+ user = fetch_user(payload[:userId], original_error)
52
+ raise original_error unless user['username'] == payload[:username]
53
+
54
+ { 'userId' => payload[:userId], 'alreadyExisted' => true }
55
+ end
56
+
57
+ # An inconclusive verify re-raises the conflict, not the transient: the
58
+ # 409 is the actionable signal (id or username collision) for the
59
+ # caller's hook. Faraday::Error is the ancestor of the SDK taxonomy
60
+ # (ClientError/ServerError/TimeoutError) AND of the transport failures
61
+ # with_rescue never maps (ConnectionFailed, SSLError, ParsingError), so
62
+ # a connect refusal or open timeout is inconclusive too, not a leak.
63
+ def fetch_user(user_id, original_error)
64
+ get_payload("/v2/users/#{user_id}").fetch('user', {})
65
+ rescue Faraday::Error
66
+ raise original_error
67
+ end
68
+
69
+ def get_payload(path)
70
+ with_rescue do
71
+ @conn.get(path).body
72
+ end
73
+ end
74
+
75
+ def post_payload(path, body)
76
+ with_rescue do
77
+ @conn.post(path) { |req| req.body = body }.body
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformSdk
4
+ module Identity
5
+ module Zitadel
6
+ # Maps the IS4 WithProfile payload shape onto Zitadel v2 AddHumanUser.
7
+ # sendPasswordResetEmail / PasswordResetReturnUrl are IS4-only concepts
8
+ # and are dropped. No password is ever sent: SIS creations are shells.
9
+ # The mixed key casing is faithful to the IS4 payload: PascalCase
10
+ # throughout except phoneNumber (see Services::Identity in Central).
11
+ module UserPayload
12
+ module_function
13
+
14
+ def from_is4(is4_params)
15
+ params = is4_params.transform_keys(&:to_s)
16
+ identity_fields(params)
17
+ .merge(profile: profile_fields(params))
18
+ .merge(optional_fields(params))
19
+ end
20
+
21
+ def identity_fields(params)
22
+ {
23
+ userId: required(params, 'Id'),
24
+ username: required(params, 'Username'),
25
+ email: { email: required(params, 'Email'), isVerified: false }
26
+ }
27
+ end
28
+
29
+ def profile_fields(params)
30
+ username = required(params, 'Username')
31
+ {
32
+ givenName: presence(params['FirstName']) || username,
33
+ familyName: presence(params['LastName']) || username
34
+ }
35
+ end
36
+
37
+ def optional_fields(params)
38
+ fields = {}
39
+ phone = presence(params['phoneNumber'])
40
+ fields[:phone] = { phone:, isVerified: false } if phone
41
+ fields.merge(metadata_fields(params))
42
+ end
43
+
44
+ def metadata_fields(params)
45
+ source_system_id = presence(params['SourceSystemId'])
46
+ return {} unless source_system_id
47
+
48
+ { metadata: [{ key: 'sourceSystemId', value: Base64.strict_encode64(source_system_id) }] }
49
+ end
50
+
51
+ # userId == IS4 Id is the migration's id-preservation invariant; a
52
+ # blank required field must raise here rather than reach Zitadel,
53
+ # which would mint its own id for a null userId.
54
+ def required(params, key)
55
+ presence(params[key]) || raise(ArgumentError, "IS4 payload is missing #{key}")
56
+ end
57
+
58
+ def presence(value)
59
+ stripped = value.to_s.strip
60
+ stripped.empty? ? nil : stripped
61
+ end
62
+ private_class_method :presence, :required, :metadata_fields, :optional_fields,
63
+ :profile_fields, :identity_fields
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,13 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "date"
4
- require "faraday"
5
- require "faraday/net_http"
6
- require "json"
7
- require "jwt"
3
+ require 'base64'
4
+ require 'date'
5
+ require 'faraday'
6
+ require 'faraday/net_http'
7
+ require 'json'
8
+ require 'jwt'
8
9
 
9
- require "platform_sdk/identity/error_handleable"
10
- require "platform_sdk/identity/clients"
10
+ require 'platform_sdk/identity/error_handleable'
11
+ require 'platform_sdk/identity/clients'
12
+ require 'platform_sdk/identity/zitadel/auth_client'
13
+ require 'platform_sdk/identity/zitadel/user_payload'
14
+ require 'platform_sdk/identity/zitadel/client'
11
15
 
12
16
  module PlatformSdk
13
17
  module Identity
@@ -2,8 +2,8 @@
2
2
 
3
3
  module PlatformSdk
4
4
  MAJOR = 3
5
- MINOR = 32
5
+ MINOR = 33
6
6
  PATCH = 0
7
7
 
8
- VERSION = "#{PlatformSdk::MAJOR}.#{PlatformSdk::MINOR}.#{PlatformSdk::PATCH}"
8
+ VERSION = "#{PlatformSdk::MAJOR}.#{PlatformSdk::MINOR}.#{PlatformSdk::PATCH}".freeze
9
9
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strongmind-platform-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.32.0
4
+ version: 3.33.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Platform Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-06-10 00:00:00.000000000 Z
11
+ date: 2026-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base64
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: faraday
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -305,6 +319,9 @@ files:
305
319
  - lib/platform_sdk/identity.rb
306
320
  - lib/platform_sdk/identity/clients.rb
307
321
  - lib/platform_sdk/identity/error_handleable.rb
322
+ - lib/platform_sdk/identity/zitadel/auth_client.rb
323
+ - lib/platform_sdk/identity/zitadel/client.rb
324
+ - lib/platform_sdk/identity/zitadel/user_payload.rb
308
325
  - lib/platform_sdk/jira.rb
309
326
  - lib/platform_sdk/jira/service_management_client.rb
310
327
  - lib/platform_sdk/jobs/send_noun_to_pipeline_job.rb