descope 1.0.6 → 1.1.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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +51 -12
  3. data/.github/workflows/publish-gem.yaml +6 -26
  4. data/.github/workflows/release-please.yaml +36 -0
  5. data/.gitignore +5 -2
  6. data/.release-please-manifest.json +1 -1
  7. data/.ruby-version +1 -1
  8. data/CHANGELOG.md +21 -0
  9. data/Gemfile +8 -7
  10. data/Gemfile.lock +70 -56
  11. data/README.md +170 -51
  12. data/examples/ruby-on-rails-api/descope/Gemfile +8 -8
  13. data/examples/ruby-on-rails-api/descope/Gemfile.lock +1 -1
  14. data/examples/ruby-on-rails-api/descope/package-lock.json +203 -141
  15. data/examples/ruby-on-rails-api/descope/package.json +1 -1
  16. data/examples/ruby-on-rails-api/descope/yarn.lock +185 -87
  17. data/lib/descope/api/v1/auth/enchantedlink.rb +3 -1
  18. data/lib/descope/api/v1/auth/magiclink.rb +3 -1
  19. data/lib/descope/api/v1/auth/otp.rb +3 -1
  20. data/lib/descope/api/v1/auth/password.rb +6 -2
  21. data/lib/descope/api/v1/auth/totp.rb +3 -1
  22. data/lib/descope/api/v1/auth.rb +47 -12
  23. data/lib/descope/api/v1/management/common.rb +20 -5
  24. data/lib/descope/api/v1/management/sso_application.rb +236 -0
  25. data/lib/descope/api/v1/management/sso_settings.rb +2 -24
  26. data/lib/descope/api/v1/management/user.rb +151 -13
  27. data/lib/descope/api/v1/management.rb +2 -0
  28. data/lib/descope/api/v1/session.rb +37 -4
  29. data/lib/descope/mixins/common.rb +1 -0
  30. data/lib/descope/mixins/http.rb +60 -9
  31. data/lib/descope/mixins/initializer.rb +5 -2
  32. data/lib/descope/mixins/logging.rb +12 -4
  33. data/lib/descope/version.rb +1 -1
  34. data/spec/descope/api/v1/auth_spec.rb +29 -0
  35. data/spec/descope/api/v1/auth_token_extraction_spec.rb +126 -0
  36. data/spec/descope/api/v1/session_refresh_spec.rb +98 -0
  37. data/spec/factories/user.rb +1 -1
  38. data/spec/integration/lib.descope/api/v1/auth/enchantedlink_spec.rb +20 -22
  39. data/spec/integration/lib.descope/api/v1/auth/magiclink_spec.rb +6 -2
  40. data/spec/integration/lib.descope/api/v1/auth/otp_spec.rb +6 -2
  41. data/spec/integration/lib.descope/api/v1/auth/session_spec.rb +68 -0
  42. data/spec/integration/lib.descope/api/v1/auth/totp_spec.rb +6 -2
  43. data/spec/integration/lib.descope/api/v1/management/access_key_spec.rb +12 -1
  44. data/spec/integration/lib.descope/api/v1/management/audit_spec.rb +5 -3
  45. data/spec/integration/lib.descope/api/v1/management/authz_spec.rb +28 -5
  46. data/spec/integration/lib.descope/api/v1/management/flow_spec.rb +3 -1
  47. data/spec/integration/lib.descope/api/v1/management/permissions_spec.rb +22 -2
  48. data/spec/integration/lib.descope/api/v1/management/project_spec.rb +18 -2
  49. data/spec/integration/lib.descope/api/v1/management/roles_spec.rb +116 -36
  50. data/spec/integration/lib.descope/api/v1/management/user_spec.rb +74 -8
  51. data/spec/lib.descope/api/v1/auth/enchantedlink_spec.rb +11 -2
  52. data/spec/lib.descope/api/v1/auth/password_spec.rb +10 -1
  53. data/spec/lib.descope/api/v1/auth_spec.rb +167 -5
  54. data/spec/lib.descope/api/v1/cookie_domain_fix_integration_spec.rb +245 -0
  55. data/spec/lib.descope/api/v1/management/sso_application_spec.rb +217 -0
  56. data/spec/lib.descope/api/v1/management/sso_settings_spec.rb +2 -2
  57. data/spec/lib.descope/api/v1/management/user_spec.rb +134 -46
  58. data/spec/lib.descope/api/v1/session_spec.rb +119 -6
  59. data/spec/lib.descope/mixins/http_spec.rb +229 -0
  60. data/spec/support/client_config.rb +0 -1
  61. data/spec/support/utils.rb +21 -0
  62. metadata +14 -8
@@ -4,6 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Audit do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
8
10
  @client.logger.info('Deleting all tenants for Ruby SDK...')
9
11
  @client.search_all_tenants(names: ['Ruby-SDK-test'])['tenants'].each do |tenant|
@@ -16,7 +18,7 @@ describe Descope::Api::V1::Management::Audit do
16
18
  after(:all) do
17
19
  all_users = @client.search_all_users
18
20
  all_users['users'].each do |user|
19
- if user['middleName'] == 'Ruby SDK User'
21
+ if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
20
22
  puts "Deleting ruby spec test user #{user['loginIds'][0]}"
21
23
  @client.delete_user(user['loginIds'][0])
22
24
  end
@@ -39,14 +41,14 @@ describe Descope::Api::V1::Management::Audit do
39
41
  created_user = @client.create_user(**user)['user']
40
42
 
41
43
  expect do
42
- res = @client.audit_create_event(
44
+ @client.audit_create_event(
45
+ user_id: created_user['loginId'],
43
46
  action: 'pencil.created',
44
47
  type: 'info',
45
48
  tenant_id:,
46
49
  actor_id: created_user['loginIds'][0],
47
50
  data: { 'key' => 'value' }
48
51
  )
49
- expect(res).to eq({})
50
52
  end.not_to raise_error
51
53
  end
52
54
  end
@@ -4,13 +4,20 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Authz do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
8
10
  puts 'authz schema delete'
9
11
  end
10
12
 
11
13
  context 'authz ops' do
12
14
  before(:all) do
13
- @client.authz_delete_schema
15
+ # Instead of deleting the entire schema, we'll work with it
16
+ # This allows parallel test execution
17
+ # Only delete schema if we're running in isolation
18
+ if ENV['AUTHZ_FULL_TEST'] == 'true'
19
+ @client.authz_delete_schema
20
+ end
14
21
  end
15
22
 
16
23
  it 'should create a new schema' do
@@ -158,13 +165,17 @@ describe Descope::Api::V1::Management::Authz do
158
165
  end
159
166
 
160
167
  it 'should create a relation between a resource and user' do
168
+ # Use unique resource name to avoid conflicts between parallel tests
169
+ unique_resource = "#{SpecUtils.build_prefix}some-doc"
170
+ unique_user = "#{SpecUtils.build_prefix}user1"
171
+
161
172
  @client.authz_create_relations(
162
173
  [
163
174
  {
164
- "resource": 'some-doc',
175
+ "resource": unique_resource,
165
176
  "relationDefinition": 'owner',
166
177
  "namespace": 'note',
167
- "target": 'user1'
178
+ "target": unique_user
168
179
  }
169
180
  ]
170
181
  )
@@ -174,14 +185,26 @@ describe Descope::Api::V1::Management::Authz do
174
185
  relations = @client.authz_has_relations?(
175
186
  [
176
187
  {
177
- "resource": 'some-doc',
188
+ "resource": unique_resource,
178
189
  "relationDefinition": 'viewer',
179
190
  "namespace": 'note',
180
- "target": 'user1'
191
+ "target": unique_user
181
192
  }
182
193
  ]
183
194
  )
184
195
  expect(relations['relationQueries'][0]['hasRelation']).to be_truthy
196
+
197
+ # Clean up the test relations
198
+ @client.authz_delete_relations(
199
+ [
200
+ {
201
+ "resource": unique_resource,
202
+ "relationDefinition": 'owner',
203
+ "namespace": 'note',
204
+ "target": unique_user
205
+ }
206
+ ]
207
+ )
185
208
  end
186
209
  end
187
210
  end
@@ -4,6 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Flow do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
8
10
  end
9
11
 
@@ -38,7 +40,7 @@ describe Descope::Api::V1::Management::Flow do
38
40
  it 'should import the current project theme' do
39
41
  export_theme = @client.export_theme
40
42
  export_theme_current_version = export_theme['theme']['version']
41
- imported_theme = @client.import_theme(export_theme)
43
+ imported_theme = @client.import_theme(export_theme['theme'])
42
44
  expect(imported_theme['theme']['version']).to be(export_theme_current_version + 1)
43
45
  end
44
46
  end
@@ -4,17 +4,37 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Permission do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
10
+ @test_description = "#{SpecUtils.build_prefix} Ruby SDK"
11
+
12
+ # Cleanup any leftover permissions from previous failed runs
8
13
  @client.load_all_permissions['permissions'].each do |perm|
9
- if perm['description'] == 'Ruby SDK'
14
+ if perm['description'] == @test_description
10
15
  puts "Deleting permission: #{perm['name']}"
11
16
  @client.delete_permission(perm['name'])
12
17
  end
13
18
  end
14
19
  end
20
+
21
+ after(:all) do
22
+ # Safety cleanup to ensure no test permissions are left behind
23
+ @client.logger.info('Cleaning up test permissions...')
24
+ begin
25
+ @client.load_all_permissions['permissions'].each do |perm|
26
+ if perm['description'] == @test_description
27
+ @client.logger.info("Deleting leftover permission: #{perm['name']}")
28
+ @client.delete_permission(perm['name'])
29
+ end
30
+ end
31
+ rescue StandardError => e
32
+ @client.logger.info("Error during permission cleanup: #{e.message}")
33
+ end
34
+ end
15
35
 
16
36
  it 'should create update and delete a permission' do
17
- @client.create_permission(name: 'test_permission', description: 'Ruby SDK')
37
+ @client.create_permission(name: 'test_permission', description: @test_description)
18
38
  all_permissions = @client.load_all_permissions['permissions']
19
39
  expect(all_permissions.any? { |perm| perm['name'] == 'test_permission' }).to eq(true)
20
40
  @client.update_permission(name: 'test_permission', new_name: 'test_permission_2')
@@ -4,17 +4,33 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Project do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
8
10
  @export_output = @client.export_project
11
+ @original_project_name = nil
9
12
  end
10
13
 
11
14
  context 'Test project methods' do
15
+ before(:all) do
16
+ # Get the current project name before we modify it
17
+ # Store it so we can restore it later
18
+ begin
19
+ @original_project_name = @client.export_project['project']['name']
20
+ rescue StandardError
21
+ @original_project_name = 'Ruby-SDK-Prod'
22
+ end
23
+ end
24
+
12
25
  after(:all) do
13
- @client.rename_project('Ruby-SDK-Prod')
26
+ # Restore the original project name
27
+ @client.rename_project(@original_project_name) if @original_project_name
14
28
  end
15
29
 
16
30
  it 'should rename a project' do
17
- @client.rename_project('TEST-Ruby-SDK-Prod')
31
+ # Use a unique name based on build prefix to avoid conflicts
32
+ unique_name = "#{SpecUtils.build_prefix}TEST-Ruby-SDK-Prod"
33
+ @client.rename_project(unique_name)
18
34
  end
19
35
 
20
36
  it 'should export a project' do
@@ -4,75 +4,147 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Role do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
8
- @client.logger.info('Staring cleanup before tests...')
9
- @client.logger.info('Deleting all permissions for Ruby SDK...')
10
+ @test_prefix = SpecUtils.build_prefix
11
+ @client.logger.info("Starting cleanup before tests with prefix: #{@test_prefix}...")
12
+
13
+ # Define resource names with unique prefix for parallel execution
14
+ @permission_viewer = "#{@test_prefix}viewer"
15
+ @permission_editor = "#{@test_prefix}editor"
16
+ @permission_admin = "#{@test_prefix}admin"
17
+ @role_viewer = "#{@test_prefix}Ruby-SDK-test-viewer"
18
+ @role_editor = "#{@test_prefix}Ruby-SDK-test-editor"
19
+ @role_admin = "#{@test_prefix}Ruby-SDK-test-admin"
20
+ @tenant_name = "#{@test_prefix}Ruby-SDK-test"
21
+ @description = "#{@test_prefix}Ruby SDK"
22
+
23
+ # Cleanup any leftover resources from previous failed runs
24
+ @client.logger.info('Deleting all permissions for this test run...')
10
25
  @client.load_all_permissions['permissions'].each do |perm|
11
- if perm['description'] =~ /Ruby SDK/
26
+ if perm['description'] == @description
12
27
  @client.logger.info("Deleting permission: #{perm['name']}")
13
28
  @client.delete_permission(perm['name'])
14
29
  end
15
30
  end
16
31
 
17
- @client.logger.info('Deleting all roles for Ruby SDK...')
32
+ @client.logger.info('Deleting all roles for this test run...')
18
33
  @client.load_all_roles['roles'].each do |role|
19
- puts "got role: #{role}"
20
- if role['description'] == 'Ruby SDK'
34
+ if role['description'] == @description
21
35
  @client.logger.info("Deleting role: #{role['name']}")
22
36
  @client.delete_role(name: role['name'], tenant_id: role['tenantId'])
23
37
  end
24
38
  end
25
39
 
26
- @client.logger.info('Deleting all tenants for Ruby SDK...')
27
- @client.search_all_tenants(names: ['Ruby-SDK-test'])['tenants'].each do |tenant|
40
+ @client.logger.info('Deleting all tenants for this test run...')
41
+ @client.search_all_tenants(names: [@tenant_name])['tenants'].each do |tenant|
28
42
  @client.logger.info("Deleting tenant: #{tenant['name']}")
29
43
  @client.delete_tenant(tenant['id'])
30
44
  end
31
45
  @client.logger.info('Cleanup completed. Starting tests...')
32
46
  end
47
+
48
+ after(:all) do
49
+ # Cleanup after tests to ensure no resources are left behind
50
+ @client.logger.info('Cleaning up test resources...')
51
+
52
+ begin
53
+ @client.delete_permission(@permission_viewer) if defined?(@permission_viewer)
54
+ rescue StandardError => e
55
+ @client.logger.info("Permission #{@permission_viewer} already deleted or doesn't exist: #{e.message}")
56
+ end
57
+
58
+ begin
59
+ @client.delete_permission(@permission_editor) if defined?(@permission_editor)
60
+ rescue StandardError => e
61
+ @client.logger.info("Permission #{@permission_editor} already deleted or doesn't exist: #{e.message}")
62
+ end
63
+
64
+ begin
65
+ @client.delete_permission(@permission_admin) if defined?(@permission_admin)
66
+ rescue StandardError => e
67
+ @client.logger.info("Permission #{@permission_admin} already deleted or doesn't exist: #{e.message}")
68
+ end
69
+
70
+ # Delete any roles with our test description
71
+ begin
72
+ @client.load_all_roles['roles'].each do |role|
73
+ if role['description'] == @description
74
+ @client.delete_role(name: role['name'], tenant_id: role['tenantId'])
75
+ end
76
+ end
77
+ rescue StandardError => e
78
+ @client.logger.info("Error cleaning up roles: #{e.message}")
79
+ end
80
+
81
+ # Delete tenant
82
+ begin
83
+ @client.search_all_tenants(names: [@tenant_name])['tenants'].each do |tenant|
84
+ @client.delete_tenant(tenant['id'])
85
+ end
86
+ rescue StandardError => e
87
+ @client.logger.info("Error cleaning up tenant: #{e.message}")
88
+ end
89
+
90
+ @client.logger.info('Cleanup completed.')
91
+ end
33
92
 
34
93
  it 'should create update and delete a role' do
35
94
  @client.logger.info('Testing role creation, update, deletion and search...')
36
95
 
37
96
  # Create permissions
38
97
  @client.logger.info('creating viewer permission for role')
39
- @client.create_permission(name: 'viewer', description: 'Viewer Permission Ruby SDK')
98
+ @client.create_permission(name: @permission_viewer, description: @description)
40
99
 
41
100
  @client.logger.info('creating editor permission for role')
42
- @client.create_permission(name: 'editor', description: 'Editor Permission Ruby SDK')
101
+ @client.create_permission(name: @permission_editor, description: @description)
43
102
 
44
103
  @client.logger.info('creating admin permission for role')
45
- @client.create_permission(name: 'admin', description: 'Admin Permission Ruby SDK')
104
+ @client.create_permission(name: @permission_admin, description: @description)
46
105
 
47
106
  # Create tenants
48
- @client.logger.info('creating Ruby-SDK-test tenant')
49
- tenant_id = @client.create_tenant(name: 'Ruby-SDK-test')['id']
107
+ @client.logger.info("creating #{@tenant_name} tenant")
108
+ tenant_id = @client.create_tenant(name: @tenant_name)['id']
109
+ @client.logger.info("Created tenant with id: #{tenant_id}")
110
+
111
+ # Wait for tenant to be available (polling, up to 5 seconds)
112
+ timeout = 5.0
113
+ interval = 0.1
114
+ waited = 0.0
115
+ loop do
116
+ tenants = @client.search_all_tenants(names: [@tenant_name])['tenants']
117
+ break if tenants.any? { |t| t['id'] == tenant_id }
118
+ raise "Tenant #{@tenant_name} not available after #{timeout} seconds" if waited >= timeout
119
+ sleep(interval)
120
+ waited += interval
121
+ end
50
122
 
51
123
  # Create roles
52
- @client.logger.info('creating Ruby-SDK-test role')
53
- @client.create_role(name: 'Ruby-SDK-test-viewer', description: 'Ruby SDK', permission_names: ['viewer'])
54
- @client.logger.info('creating Ruby-SDK-test-admin role')
55
- @client.create_role(name: 'Ruby-SDK-test-admin', description: 'Ruby SDK', permission_names: ['admin'], tenant_id:)
124
+ @client.logger.info("creating #{@role_viewer} role")
125
+ @client.create_role(name: @role_viewer, description: @description, permission_names: [@permission_viewer])
126
+ @client.logger.info("creating #{@role_admin} role")
127
+ @client.create_role(name: @role_admin, description: @description, permission_names: [@permission_admin], tenant_id:)
56
128
 
57
129
  # check all roles matching the correct permission
58
130
  @client.logger.info('check all roles matching the correct permission (load roles)')
59
131
  roles = @client.load_all_roles['roles']
60
132
  roles.each do |role|
61
- expect(role['permissionNames']).to include('viewer') if role['name'] == 'Ruby-SDK-test-viewer'
62
- expect(role['permissionNames']).to include('admin') if role['name'] == 'Ruby-SDK-test-admin'
133
+ expect(role['permissionNames']).to include(@permission_viewer) if role['name'] == @role_viewer
134
+ expect(role['permissionNames']).to include(@permission_admin) if role['name'] == @role_admin
63
135
  end
64
136
 
65
137
  @client.logger.info('updating role')
66
138
  @client.update_role(
67
- name: 'Ruby-SDK-test-viewer',
68
- new_name: 'Ruby-SDK-test-editor',
69
- description: 'Ruby SDK',
70
- permission_names: ['editor']
139
+ name: @role_viewer,
140
+ new_name: @role_editor,
141
+ description: @description,
142
+ permission_names: [@permission_editor]
71
143
  )
72
144
 
73
145
  @client.logger.info('searching for roles by role names...')
74
- all_roles = @client.search_roles(role_names: %w[Ruby-SDK-test-admin Ruby-SDK-test-editor])['roles']
75
- expected_roles = %w[Ruby-SDK-test-editor Ruby-SDK-test-admin]
146
+ all_roles = @client.search_roles(role_names: [@role_admin, @role_editor])['roles']
147
+ expected_roles = [@role_editor, @role_admin]
76
148
  role_count = 0
77
149
  expected_roles.each do |expected_role|
78
150
  expect(all_roles.map { |role| role['name'] }).to include(expected_role)
@@ -81,8 +153,8 @@ describe Descope::Api::V1::Management::Role do
81
153
  expect(role_count).to eq(2)
82
154
 
83
155
  @client.logger.info('searching for roles with role name like...')
84
- all_roles = @client.search_roles(role_name_like: 'Ruby-SDK-test')['roles']
85
- expected_roles = %w[Ruby-SDK-test-editor Ruby-SDK-test-admin]
156
+ all_roles = @client.search_roles(role_name_like: "#{@test_prefix}Ruby-SDK-test")['roles']
157
+ expected_roles = [@role_editor, @role_admin]
86
158
  role_count = 0
87
159
  expected_roles.each do |expected_role|
88
160
  expect(all_roles.map { |role| role['name'] }).to include(expected_role)
@@ -92,25 +164,33 @@ describe Descope::Api::V1::Management::Role do
92
164
  expect(role_count).to eq(2)
93
165
 
94
166
  @client.logger.info('searching for roles with permission names...')
95
- all_roles = @client.search_roles(permission_names: %w[admin])['roles']
96
- expect(all_roles.map { |role| role['name'] }).to include('Ruby-SDK-test-admin')
167
+ all_roles = @client.search_roles(permission_names: [@permission_admin])['roles']
168
+ expect(all_roles.map { |role| role['name'] }).to include(@role_admin)
97
169
 
98
170
  @client.logger.info('searching for roles with tenant ids...')
99
- all_roles = @client.search_roles(role_name_like: 'Ruby-SDK-test', tenant_ids: [tenant_id])['roles']
100
- expect(all_roles.map { |role| role['name'] }).to include('Ruby-SDK-test-admin')
171
+ all_roles = @client.search_roles(role_name_like: "#{@test_prefix}Ruby-SDK-test", tenant_ids: [tenant_id])['roles']
172
+ expect(all_roles.map { |role| role['name'] }).to include(@role_admin)
101
173
 
102
174
  @client.logger.info('deleting permission')
103
175
 
104
- @client.delete_permission('editor')
105
- @client.delete_permission('admin')
176
+ @client.delete_permission(@permission_editor)
177
+ @client.delete_permission(@permission_admin)
106
178
 
107
179
  @client.logger.info('deleting editor role')
108
- @client.delete_role(name: 'Ruby-SDK-test-editor')
180
+ @client.delete_role(name: @role_editor)
109
181
 
110
182
  @client.logger.info('deleting admin role')
111
- @client.delete_role(name: 'Ruby-SDK-test-admin', tenant_id:)
183
+ begin
184
+ @client.delete_role(name: @role_admin, tenant_id:)
185
+ rescue Descope::Unauthorized, Descope::NotFound => e
186
+ @client.logger.info("Admin role already deleted or tenant invalid: #{e.message}")
187
+ end
112
188
 
113
189
  @client.logger.info('deleting tenant')
114
- @client.delete_tenant(tenant_id)
190
+ begin
191
+ @client.delete_tenant(tenant_id)
192
+ rescue Descope::NotFound => e
193
+ @client.logger.info("Tenant already deleted: #{e.message}")
194
+ end
115
195
  end
116
196
  end
@@ -4,17 +4,21 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::User do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
9
+ @client = DescopeClient.new(Configuration.config)
10
+
7
11
  @password = SpecUtils.generate_password
8
12
  @new_password = SpecUtils.generate_password
9
13
  @user = build(:user)
10
- @client = DescopeClient.new(Configuration.config)
14
+
11
15
  include Descope::Mixins::Common::DeliveryMethod
12
16
  end
13
17
 
14
18
  after(:all) do
15
19
  all_users = @client.search_all_users
16
20
  all_users['users'].each do |user|
17
- if user['middleName'] == 'Ruby SDK User'
21
+ if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
18
22
  puts "Deleting ruby spec test user #{user['loginIds'][0]}"
19
23
  @client.delete_user(user['loginIds'][0])
20
24
  end
@@ -58,12 +62,57 @@ describe Descope::Api::V1::Management::User do
58
62
  expect(updated_user['first_name']).to eq(created_user[updated_first_name])
59
63
  end
60
64
 
65
+ it 'should patch a user' do
66
+ user = build(:user)
67
+ role_name = 'some-new-role'
68
+
69
+ # ensure no roles exist with that name
70
+ all_roles = @client.load_all_roles
71
+ all_roles['roles'].each do |role|
72
+ @client.delete_role(name: role['name']) if role['name'] == role_name
73
+ end
74
+
75
+ @client.create_role(name: role_name)
76
+ @client.create_user(**user)['user']
77
+ updated_first_name = 'new name'
78
+ updated_given_name = 'new given name'
79
+ update_phone_number = "+1#{Faker::Number.number(digits: 10)}"
80
+ updated_role_names = [role_name]
81
+ updated_middle_name = 'new middle name'
82
+ updated_user = @client.patch_user(
83
+ **user,
84
+ name: updated_first_name,
85
+ given_name: updated_given_name,
86
+ phone: update_phone_number,
87
+ role_names: updated_role_names,
88
+ middle_name: updated_middle_name
89
+ )['user']
90
+
91
+ puts "updated_user #{updated_user}"
92
+
93
+ expect(updated_user['name']).to eq(updated_first_name)
94
+ expect(updated_user['givenName']).to eq(updated_given_name)
95
+ expect(updated_user['phone']).to eq(update_phone_number)
96
+ expect(updated_user['roleNames']).to eq(updated_role_names)
97
+ expect(updated_user['middleName']).to eq(updated_middle_name)
98
+ end
99
+
61
100
  it 'should delete a user' do
62
101
  user = build(:user)
63
102
  created_user = @client.create_user(**user)['user']
64
103
  loaded_user = @client.load_user(created_user['loginIds'][0])['user']
65
104
  expect(loaded_user['loginIds']).to eq(created_user['loginIds'])
66
- sleep 10
105
+
106
+ # Wait for user to be fully propagated before deletion
107
+ SpecUtils.wait_for_condition(max_wait: 15, interval: 2, description: 'user to be ready for deletion') do
108
+ begin
109
+ @client.load_user(created_user['loginIds'][0])
110
+ true
111
+ rescue StandardError => e
112
+ @client.logger.info("Waiting for user propagation: #{e.message}")
113
+ false
114
+ end
115
+ end
67
116
 
68
117
  @client.delete_user(created_user['loginIds'][0])
69
118
  begin
@@ -76,19 +125,36 @@ describe Descope::Api::V1::Management::User do
76
125
  it 'should search all users' do
77
126
  users = FactoryBot.build_list(:user, 5)
78
127
  @client.create_batch_users(users)
128
+ # Wait for batch creation to propagate
129
+ sleep 1.0
79
130
  all_users = @client.search_all_users
80
- sdk_users = all_users['users'].select { |user| user['middleName'] == 'Ruby SDK User' }
131
+ sdk_users = all_users['users'].select { |user| user['middleName']&.include?('Ruby-SDK-User') }
81
132
  expect(sdk_users.length).to be >= 5
82
133
  end
83
134
 
84
135
  it 'should create a test user' do
85
136
  @client.delete_all_test_users
86
- sleep 5
137
+ # ensure no roles exist with that name
138
+ role_name = 'some-new-role'
139
+ all_roles = @client.load_all_roles
140
+ all_roles['roles'].each do |role|
141
+ @client.delete_role(name: role['name']) if role['name'] == role_name
142
+ end
143
+
144
+ # Wait for role deletion to propagate
145
+ SpecUtils.wait_for_condition(max_wait: 10, interval: 1, description: 'role deletion to propagate') do
146
+ all_roles = @client.load_all_roles
147
+ all_roles['roles'].none? { |role| role['name'] == role_name }
148
+ end
149
+
87
150
  user_args = build(:user)
88
151
  test_user = @client.create_test_user(**user_args)['user']
89
- test_users = @client.search_all_users(test_users_only: true)['users']
152
+ @client.create_role(name: role_name)
153
+ @client.user_add_roles(login_id: test_user['loginIds'][0], role_names: [role_name])
154
+ test_users = @client.search_all_test_users(role_names: [role_name])['users']
90
155
  expect(test_users.length).to be >= 1
91
156
  expect(test_users[0]['loginIds'][0]).to eq(test_user['loginIds'][0])
157
+ expect(test_users[0]['roleNames']).to eq([role_name])
92
158
  end
93
159
 
94
160
  it 'should update user status' do
@@ -191,8 +257,8 @@ describe Descope::Api::V1::Management::User do
191
257
  new_password = SpecUtils.generate_password
192
258
  @client.set_password(login_id: user['loginIds'][0], password: new_password)
193
259
  @client.password_sign_in(login_id: user['loginIds'][0], password:)
194
- rescue Descope::ServerError => e
195
- expect(e.message).to match(/"errorCode":"E062909"/)
260
+ rescue Descope::Unauthorized => e
261
+ expect(e.message).to match(/"Invalid signin credentials"/)
196
262
  end
197
263
  end
198
264
 
@@ -51,7 +51,7 @@ describe Descope::Api::V1::EnchantedLink do
51
51
 
52
52
  it 'is expected to validate refresh token and not raise an error with refresh token and valid login options' do
53
53
  expect do
54
- @instance.send(:validate_refresh_token_provided, { mfa: true, stepup: true }, 'some-token')
54
+ @instance.send(:validate_refresh_token_provided, { mfa: true, stepup: true }, 'some-token')
55
55
  end.not_to raise_error
56
56
  end
57
57
 
@@ -148,7 +148,16 @@ describe Descope::Api::V1::EnchantedLink do
148
148
  end
149
149
 
150
150
  it 'is expected to get session by pending ref with enchanted link' do
151
- jwt_response = { 'fake': 'response' }
151
+ jwt_response = {
152
+ 'sessionJwt' => 'fake_session_jwt',
153
+ 'refreshJwt' => 'fake_refresh_jwt',
154
+ 'cookies' => {
155
+ 'refresh_token' => 'fake_refresh_cookie'
156
+ }
157
+ }
158
+ allow(@instance).to receive(:post).with(
159
+ GET_SESSION_ENCHANTEDLINK_AUTH_PATH, { pendingRef: 'pendingRef' }
160
+ ).and_return(jwt_response)
152
161
  allow(@instance).to receive(:generate_jwt_response).and_return(jwt_response)
153
162
 
154
163
  expect do
@@ -43,9 +43,18 @@ describe Descope::Api::V1::Password do
43
43
  end
44
44
 
45
45
  it 'is expected to sign in with password' do
46
+ response_body = {
47
+ 'sessionJwt' => 'fake_session_jwt',
48
+ 'refreshJwt' => 'fake_refresh_jwt',
49
+ 'cookies' => {
50
+ 'refresh_token' => 'fake_refresh_cookie'
51
+ }
52
+ }
53
+
46
54
  expect(@instance).to receive(:post).with(
47
55
  SIGN_IN_PASSWORD_PATH, { loginId: 'test', password: 's3cr3t', ssoAppId: nil }
48
- )
56
+ ).and_return(response_body)
57
+
49
58
  # stub the jwt_get_unverified_header method to return the kid of the public key created above
50
59
  allow(@instance).to receive(:generate_jwt_response).and_return({})
51
60
  expect { @instance.password_sign_in(login_id: 'test', password: 's3cr3t') }.not_to raise_error