descope 1.0.7 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yaml +51 -12
- data/.github/workflows/publish-gem.yaml +6 -33
- data/.github/workflows/release-please.yaml +36 -0
- data/.gitignore +3 -2
- data/.release-please-manifest.json +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +21 -0
- data/Gemfile +7 -6
- data/Gemfile.lock +33 -32
- data/README.md +11 -0
- data/examples/ruby-on-rails-api/descope/package-lock.json +16 -10
- data/examples/ruby-on-rails-api/descope/yarn.lock +3 -3
- data/lib/descope/mixins/http.rb +2 -2
- data/lib/descope/mixins/initializer.rb +4 -2
- data/lib/descope/version.rb +1 -1
- data/spec/integration/lib.descope/api/v1/auth/enchantedlink_spec.rb +19 -21
- data/spec/integration/lib.descope/api/v1/auth/magiclink_spec.rb +5 -1
- data/spec/integration/lib.descope/api/v1/auth/otp_spec.rb +5 -1
- data/spec/integration/lib.descope/api/v1/auth/session_spec.rb +24 -5
- data/spec/integration/lib.descope/api/v1/auth/totp_spec.rb +5 -1
- data/spec/integration/lib.descope/api/v1/management/access_key_spec.rb +10 -2
- data/spec/integration/lib.descope/api/v1/management/authz_spec.rb +26 -5
- data/spec/integration/lib.descope/api/v1/management/permissions_spec.rb +20 -2
- data/spec/integration/lib.descope/api/v1/management/project_spec.rb +16 -2
- data/spec/integration/lib.descope/api/v1/management/roles_spec.rb +114 -36
- data/spec/integration/lib.descope/api/v1/management/user_spec.rb +20 -3
- data/spec/lib.descope/mixins/http_spec.rb +17 -6
- data/spec/support/utils.rb +15 -0
- metadata +4 -3
|
@@ -3,31 +3,25 @@
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
5
|
def poll_for_session(descope_client, pending_ref)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
while !done && i < max_tries
|
|
6
|
+
@client.logger.info('Waiting for session to be created...')
|
|
7
|
+
|
|
8
|
+
SpecUtils.wait_for_condition(max_wait: 60, interval: 3, description: 'enchanted link session') do
|
|
10
9
|
begin
|
|
11
|
-
i += 1
|
|
12
|
-
@client.logger.info('waiting 4 seconds for session to be created...')
|
|
13
|
-
sleep(4)
|
|
14
|
-
print '.'
|
|
15
10
|
@client.logger.info("Getting session for pending_ref: #{pending_ref}...")
|
|
16
11
|
jwt_response = descope_client.enchanted_link_get_session(pending_ref)
|
|
17
|
-
|
|
12
|
+
|
|
13
|
+
if jwt_response
|
|
14
|
+
@client.logger.info("jwt_response: #{jwt_response}")
|
|
15
|
+
refresh_token = jwt_response[Descope::Mixins::Common::REFRESH_SESSION_TOKEN_NAME]['jwt']
|
|
16
|
+
@client.logger.info("refresh_token: #{refresh_token}")
|
|
17
|
+
return refresh_token
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
false
|
|
18
21
|
rescue Descope::AuthException, Descope::Unauthorized => e
|
|
19
|
-
@client.logger.info("
|
|
20
|
-
|
|
22
|
+
@client.logger.info("Waiting for session, err: #{e}")
|
|
23
|
+
false
|
|
21
24
|
end
|
|
22
|
-
|
|
23
|
-
next unless jwt_response
|
|
24
|
-
|
|
25
|
-
@client.logger.info("jwt_response: #{jwt_response}")
|
|
26
|
-
refresh_token = jwt_response[Descope::Mixins::Common::REFRESH_SESSION_TOKEN_NAME]['jwt']
|
|
27
|
-
|
|
28
|
-
@client.logger.info("refresh_token: #{refresh_token}")
|
|
29
|
-
done = true
|
|
30
|
-
return refresh_token
|
|
31
25
|
end
|
|
32
26
|
end
|
|
33
27
|
|
|
@@ -62,7 +56,11 @@ describe Descope::Api::V1::Auth::EnchantedLink do
|
|
|
62
56
|
all_users['users'].each do |user|
|
|
63
57
|
if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
|
|
64
58
|
@client.logger.info("Deleting ruby spec test user #{user['loginIds'][0]}")
|
|
65
|
-
|
|
59
|
+
begin
|
|
60
|
+
@client.delete_user(user['loginIds'][0])
|
|
61
|
+
rescue Descope::NotFound => e
|
|
62
|
+
@client.logger.info("User already deleted: #{e.message}")
|
|
63
|
+
end
|
|
66
64
|
end
|
|
67
65
|
end
|
|
68
66
|
end
|
|
@@ -13,7 +13,11 @@ describe Descope::Api::V1::Auth::MagicLink do
|
|
|
13
13
|
all_users['users'].each do |user|
|
|
14
14
|
if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
|
|
15
15
|
@client.logger.info("Deleting ruby spec test user #{user['loginIds'][0]}")
|
|
16
|
-
|
|
16
|
+
begin
|
|
17
|
+
@client.delete_user(user['loginIds'][0])
|
|
18
|
+
rescue Descope::NotFound => e
|
|
19
|
+
@client.logger.info("User already deleted: #{e.message}")
|
|
20
|
+
end
|
|
17
21
|
end
|
|
18
22
|
end
|
|
19
23
|
end
|
|
@@ -21,7 +21,11 @@ describe Descope::Api::V1::Auth::OTP do
|
|
|
21
21
|
all_users['users'].each do |user|
|
|
22
22
|
if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
|
|
23
23
|
@client.logger.info("Deleting ruby spec test user #{user['loginIds'][0]}")
|
|
24
|
-
|
|
24
|
+
begin
|
|
25
|
+
@client.delete_user(user['loginIds'][0])
|
|
26
|
+
rescue Descope::NotFound => e
|
|
27
|
+
@client.logger.info("User already deleted: #{e.message}")
|
|
28
|
+
end
|
|
25
29
|
end
|
|
26
30
|
end
|
|
27
31
|
end
|
|
@@ -5,6 +5,20 @@ require 'spec_helper'
|
|
|
5
5
|
describe Descope::Api::V1::Session do
|
|
6
6
|
before(:all) do
|
|
7
7
|
@client = DescopeClient.new(Configuration.config)
|
|
8
|
+
|
|
9
|
+
# Cleanup any existing test users before starting
|
|
10
|
+
@client.logger.info('Cleaning up any existing test users before starting...')
|
|
11
|
+
all_users = @client.search_all_users
|
|
12
|
+
all_users['users'].each do |user|
|
|
13
|
+
if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
|
|
14
|
+
@client.logger.info("Deleting existing ruby spec test user #{user['loginIds'][0]}")
|
|
15
|
+
begin
|
|
16
|
+
@client.delete_user(user['loginIds'][0])
|
|
17
|
+
rescue Descope::NotFound => e
|
|
18
|
+
@client.logger.info("User already deleted: #{e.message}")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
8
22
|
end
|
|
9
23
|
|
|
10
24
|
after(:all) do
|
|
@@ -13,7 +27,11 @@ describe Descope::Api::V1::Session do
|
|
|
13
27
|
all_users['users'].each do |user|
|
|
14
28
|
if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
|
|
15
29
|
@client.logger.info("Deleting ruby spec test user #{user['loginIds'][0]}")
|
|
16
|
-
|
|
30
|
+
begin
|
|
31
|
+
@client.delete_user(user['loginIds'][0])
|
|
32
|
+
rescue Descope::NotFound => e
|
|
33
|
+
@client.logger.info("User already deleted: #{e.message}")
|
|
34
|
+
end
|
|
17
35
|
end
|
|
18
36
|
end
|
|
19
37
|
end
|
|
@@ -21,9 +39,10 @@ describe Descope::Api::V1::Session do
|
|
|
21
39
|
context 'test session methods' do
|
|
22
40
|
it 'should refresh session with refresh token' do
|
|
23
41
|
@password = SpecUtils.generate_password
|
|
24
|
-
|
|
42
|
+
# Add timestamp to ensure unique login_id across multiple test runs
|
|
43
|
+
user = build(:user, login_id: "session_test_#{Time.now.to_i}_#{SecureRandom.hex(4)}")
|
|
25
44
|
|
|
26
|
-
@client.logger.info(
|
|
45
|
+
@client.logger.info("1. Sign up with password for user: #{user[:login_id]}")
|
|
27
46
|
res = @client.password_sign_up(login_id: user[:login_id], password: @password, user:)
|
|
28
47
|
@client.logger.info("sign up with password res: #{res}")
|
|
29
48
|
original_refresh_token = res[REFRESH_SESSION_TOKEN_NAME]['jwt']
|
|
@@ -32,8 +51,8 @@ describe Descope::Api::V1::Session do
|
|
|
32
51
|
login_res = @client.password_sign_in(login_id: user[:login_id], password: @password)
|
|
33
52
|
@client.logger.info("sign_in res: #{login_res}")
|
|
34
53
|
|
|
35
|
-
@client.logger.info('3.
|
|
36
|
-
sleep(
|
|
54
|
+
@client.logger.info('3. Wait briefly to ensure token timestamps differ')
|
|
55
|
+
sleep(2) # Wait 2 seconds to ensure new token will have different 'iat' timestamp
|
|
37
56
|
|
|
38
57
|
@client.logger.info('4. Refresh session')
|
|
39
58
|
refresh_session_res = @client.refresh_session(refresh_token: login_res[REFRESH_SESSION_TOKEN_NAME]['jwt'])
|
|
@@ -14,7 +14,11 @@ describe Descope::Api::V1::Auth::TOTP do
|
|
|
14
14
|
all_users['users'].each do |user|
|
|
15
15
|
if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
|
|
16
16
|
@client.logger.info("Deleting ruby spec test user #{user['loginIds'][0]}")
|
|
17
|
-
|
|
17
|
+
begin
|
|
18
|
+
@client.delete_user(user['loginIds'][0])
|
|
19
|
+
rescue Descope::NotFound => e
|
|
20
|
+
@client.logger.info("User already deleted: #{e.message}")
|
|
21
|
+
end
|
|
18
22
|
end
|
|
19
23
|
end
|
|
20
24
|
end
|
|
@@ -30,8 +30,16 @@ describe Descope::Api::V1::Management::AccessKey do
|
|
|
30
30
|
@tenant_id = @client.create_tenant(name: 'some-new-tenant')['id']
|
|
31
31
|
@client.logger.info('creating access key')
|
|
32
32
|
@access_key = @client.create_access_key(name: @key_name, key_tenants: [{ tenant_id: @tenant_id }])
|
|
33
|
-
@client.logger.info("waiting for access key #{@access_key['key']['id']} to be active
|
|
34
|
-
|
|
33
|
+
@client.logger.info("waiting for access key #{@access_key['key']['id']} to be active")
|
|
34
|
+
SpecUtils.wait_for_condition(max_wait: 65, interval: 3, description: 'access key to be active') do
|
|
35
|
+
begin
|
|
36
|
+
key = @client.load_access_key(@access_key['key']['id'])
|
|
37
|
+
key['key']['status'] == 'active'
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
@client.logger.info("Waiting for key activation: #{e.message}")
|
|
40
|
+
false
|
|
41
|
+
end
|
|
42
|
+
end
|
|
35
43
|
end
|
|
36
44
|
|
|
37
45
|
it 'should create the access key and load it' do
|
|
@@ -12,7 +12,12 @@ describe Descope::Api::V1::Management::Authz do
|
|
|
12
12
|
|
|
13
13
|
context 'authz ops' do
|
|
14
14
|
before(:all) do
|
|
15
|
-
|
|
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
|
|
16
21
|
end
|
|
17
22
|
|
|
18
23
|
it 'should create a new schema' do
|
|
@@ -160,13 +165,17 @@ describe Descope::Api::V1::Management::Authz do
|
|
|
160
165
|
end
|
|
161
166
|
|
|
162
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
|
+
|
|
163
172
|
@client.authz_create_relations(
|
|
164
173
|
[
|
|
165
174
|
{
|
|
166
|
-
"resource":
|
|
175
|
+
"resource": unique_resource,
|
|
167
176
|
"relationDefinition": 'owner',
|
|
168
177
|
"namespace": 'note',
|
|
169
|
-
"target":
|
|
178
|
+
"target": unique_user
|
|
170
179
|
}
|
|
171
180
|
]
|
|
172
181
|
)
|
|
@@ -176,14 +185,26 @@ describe Descope::Api::V1::Management::Authz do
|
|
|
176
185
|
relations = @client.authz_has_relations?(
|
|
177
186
|
[
|
|
178
187
|
{
|
|
179
|
-
"resource":
|
|
188
|
+
"resource": unique_resource,
|
|
180
189
|
"relationDefinition": 'viewer',
|
|
181
190
|
"namespace": 'note',
|
|
182
|
-
"target":
|
|
191
|
+
"target": unique_user
|
|
183
192
|
}
|
|
184
193
|
]
|
|
185
194
|
)
|
|
186
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
|
+
)
|
|
187
208
|
end
|
|
188
209
|
end
|
|
189
210
|
end
|
|
@@ -7,16 +7,34 @@ describe Descope::Api::V1::Management::Permission do
|
|
|
7
7
|
raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
|
|
8
8
|
|
|
9
9
|
@client = DescopeClient.new(Configuration.config)
|
|
10
|
+
@test_description = "#{SpecUtils.build_prefix} Ruby SDK"
|
|
11
|
+
|
|
12
|
+
# Cleanup any leftover permissions from previous failed runs
|
|
10
13
|
@client.load_all_permissions['permissions'].each do |perm|
|
|
11
|
-
if perm['description'] ==
|
|
14
|
+
if perm['description'] == @test_description
|
|
12
15
|
puts "Deleting permission: #{perm['name']}"
|
|
13
16
|
@client.delete_permission(perm['name'])
|
|
14
17
|
end
|
|
15
18
|
end
|
|
16
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
|
|
17
35
|
|
|
18
36
|
it 'should create update and delete a permission' do
|
|
19
|
-
@client.create_permission(name: 'test_permission', description:
|
|
37
|
+
@client.create_permission(name: 'test_permission', description: @test_description)
|
|
20
38
|
all_permissions = @client.load_all_permissions['permissions']
|
|
21
39
|
expect(all_permissions.any? { |perm| perm['name'] == 'test_permission' }).to eq(true)
|
|
22
40
|
@client.update_permission(name: 'test_permission', new_name: 'test_permission_2')
|
|
@@ -8,15 +8,29 @@ describe Descope::Api::V1::Management::Project do
|
|
|
8
8
|
|
|
9
9
|
@client = DescopeClient.new(Configuration.config)
|
|
10
10
|
@export_output = @client.export_project
|
|
11
|
+
@original_project_name = nil
|
|
11
12
|
end
|
|
12
13
|
|
|
13
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
|
+
|
|
14
25
|
after(:all) do
|
|
15
|
-
|
|
26
|
+
# Restore the original project name
|
|
27
|
+
@client.rename_project(@original_project_name) if @original_project_name
|
|
16
28
|
end
|
|
17
29
|
|
|
18
30
|
it 'should rename a project' do
|
|
19
|
-
|
|
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)
|
|
20
34
|
end
|
|
21
35
|
|
|
22
36
|
it 'should export a project' do
|
|
@@ -7,74 +7,144 @@ describe Descope::Api::V1::Management::Role do
|
|
|
7
7
|
raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
|
|
8
8
|
|
|
9
9
|
@client = DescopeClient.new(Configuration.config)
|
|
10
|
-
@
|
|
11
|
-
@client.logger.info(
|
|
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...')
|
|
12
25
|
@client.load_all_permissions['permissions'].each do |perm|
|
|
13
|
-
if perm['description']
|
|
26
|
+
if perm['description'] == @description
|
|
14
27
|
@client.logger.info("Deleting permission: #{perm['name']}")
|
|
15
28
|
@client.delete_permission(perm['name'])
|
|
16
29
|
end
|
|
17
30
|
end
|
|
18
31
|
|
|
19
|
-
@client.logger.info('Deleting all roles for
|
|
32
|
+
@client.logger.info('Deleting all roles for this test run...')
|
|
20
33
|
@client.load_all_roles['roles'].each do |role|
|
|
21
|
-
|
|
22
|
-
if role['description'] == 'Ruby SDK'
|
|
34
|
+
if role['description'] == @description
|
|
23
35
|
@client.logger.info("Deleting role: #{role['name']}")
|
|
24
36
|
@client.delete_role(name: role['name'], tenant_id: role['tenantId'])
|
|
25
37
|
end
|
|
26
38
|
end
|
|
27
39
|
|
|
28
|
-
@client.logger.info('Deleting all tenants for
|
|
29
|
-
@client.search_all_tenants(names: [
|
|
40
|
+
@client.logger.info('Deleting all tenants for this test run...')
|
|
41
|
+
@client.search_all_tenants(names: [@tenant_name])['tenants'].each do |tenant|
|
|
30
42
|
@client.logger.info("Deleting tenant: #{tenant['name']}")
|
|
31
43
|
@client.delete_tenant(tenant['id'])
|
|
32
44
|
end
|
|
33
45
|
@client.logger.info('Cleanup completed. Starting tests...')
|
|
34
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
|
|
35
92
|
|
|
36
93
|
it 'should create update and delete a role' do
|
|
37
94
|
@client.logger.info('Testing role creation, update, deletion and search...')
|
|
38
95
|
|
|
39
96
|
# Create permissions
|
|
40
97
|
@client.logger.info('creating viewer permission for role')
|
|
41
|
-
@client.create_permission(name:
|
|
98
|
+
@client.create_permission(name: @permission_viewer, description: @description)
|
|
42
99
|
|
|
43
100
|
@client.logger.info('creating editor permission for role')
|
|
44
|
-
@client.create_permission(name:
|
|
101
|
+
@client.create_permission(name: @permission_editor, description: @description)
|
|
45
102
|
|
|
46
103
|
@client.logger.info('creating admin permission for role')
|
|
47
|
-
@client.create_permission(name:
|
|
104
|
+
@client.create_permission(name: @permission_admin, description: @description)
|
|
48
105
|
|
|
49
106
|
# Create tenants
|
|
50
|
-
@client.logger.info(
|
|
51
|
-
tenant_id = @client.create_tenant(name:
|
|
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
|
|
52
122
|
|
|
53
123
|
# Create roles
|
|
54
|
-
@client.logger.info(
|
|
55
|
-
@client.create_role(name:
|
|
56
|
-
@client.logger.info(
|
|
57
|
-
@client.create_role(name:
|
|
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:)
|
|
58
128
|
|
|
59
129
|
# check all roles matching the correct permission
|
|
60
130
|
@client.logger.info('check all roles matching the correct permission (load roles)')
|
|
61
131
|
roles = @client.load_all_roles['roles']
|
|
62
132
|
roles.each do |role|
|
|
63
|
-
expect(role['permissionNames']).to include(
|
|
64
|
-
expect(role['permissionNames']).to include(
|
|
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
|
|
65
135
|
end
|
|
66
136
|
|
|
67
137
|
@client.logger.info('updating role')
|
|
68
138
|
@client.update_role(
|
|
69
|
-
name:
|
|
70
|
-
new_name:
|
|
71
|
-
description:
|
|
72
|
-
permission_names: [
|
|
139
|
+
name: @role_viewer,
|
|
140
|
+
new_name: @role_editor,
|
|
141
|
+
description: @description,
|
|
142
|
+
permission_names: [@permission_editor]
|
|
73
143
|
)
|
|
74
144
|
|
|
75
145
|
@client.logger.info('searching for roles by role names...')
|
|
76
|
-
all_roles = @client.search_roles(role_names:
|
|
77
|
-
expected_roles =
|
|
146
|
+
all_roles = @client.search_roles(role_names: [@role_admin, @role_editor])['roles']
|
|
147
|
+
expected_roles = [@role_editor, @role_admin]
|
|
78
148
|
role_count = 0
|
|
79
149
|
expected_roles.each do |expected_role|
|
|
80
150
|
expect(all_roles.map { |role| role['name'] }).to include(expected_role)
|
|
@@ -83,8 +153,8 @@ describe Descope::Api::V1::Management::Role do
|
|
|
83
153
|
expect(role_count).to eq(2)
|
|
84
154
|
|
|
85
155
|
@client.logger.info('searching for roles with role name like...')
|
|
86
|
-
all_roles = @client.search_roles(role_name_like:
|
|
87
|
-
expected_roles =
|
|
156
|
+
all_roles = @client.search_roles(role_name_like: "#{@test_prefix}Ruby-SDK-test")['roles']
|
|
157
|
+
expected_roles = [@role_editor, @role_admin]
|
|
88
158
|
role_count = 0
|
|
89
159
|
expected_roles.each do |expected_role|
|
|
90
160
|
expect(all_roles.map { |role| role['name'] }).to include(expected_role)
|
|
@@ -94,25 +164,33 @@ describe Descope::Api::V1::Management::Role do
|
|
|
94
164
|
expect(role_count).to eq(2)
|
|
95
165
|
|
|
96
166
|
@client.logger.info('searching for roles with permission names...')
|
|
97
|
-
all_roles = @client.search_roles(permission_names:
|
|
98
|
-
expect(all_roles.map { |role| role['name'] }).to include(
|
|
167
|
+
all_roles = @client.search_roles(permission_names: [@permission_admin])['roles']
|
|
168
|
+
expect(all_roles.map { |role| role['name'] }).to include(@role_admin)
|
|
99
169
|
|
|
100
170
|
@client.logger.info('searching for roles with tenant ids...')
|
|
101
|
-
all_roles = @client.search_roles(role_name_like:
|
|
102
|
-
expect(all_roles.map { |role| role['name'] }).to include(
|
|
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)
|
|
103
173
|
|
|
104
174
|
@client.logger.info('deleting permission')
|
|
105
175
|
|
|
106
|
-
@client.delete_permission(
|
|
107
|
-
@client.delete_permission(
|
|
176
|
+
@client.delete_permission(@permission_editor)
|
|
177
|
+
@client.delete_permission(@permission_admin)
|
|
108
178
|
|
|
109
179
|
@client.logger.info('deleting editor role')
|
|
110
|
-
@client.delete_role(name:
|
|
180
|
+
@client.delete_role(name: @role_editor)
|
|
111
181
|
|
|
112
182
|
@client.logger.info('deleting admin role')
|
|
113
|
-
|
|
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
|
|
114
188
|
|
|
115
189
|
@client.logger.info('deleting tenant')
|
|
116
|
-
|
|
190
|
+
begin
|
|
191
|
+
@client.delete_tenant(tenant_id)
|
|
192
|
+
rescue Descope::NotFound => e
|
|
193
|
+
@client.logger.info("Tenant already deleted: #{e.message}")
|
|
194
|
+
end
|
|
117
195
|
end
|
|
118
196
|
end
|
|
@@ -102,7 +102,17 @@ describe Descope::Api::V1::Management::User do
|
|
|
102
102
|
created_user = @client.create_user(**user)['user']
|
|
103
103
|
loaded_user = @client.load_user(created_user['loginIds'][0])['user']
|
|
104
104
|
expect(loaded_user['loginIds']).to eq(created_user['loginIds'])
|
|
105
|
-
|
|
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
|
|
106
116
|
|
|
107
117
|
@client.delete_user(created_user['loginIds'][0])
|
|
108
118
|
begin
|
|
@@ -115,8 +125,10 @@ describe Descope::Api::V1::Management::User do
|
|
|
115
125
|
it 'should search all users' do
|
|
116
126
|
users = FactoryBot.build_list(:user, 5)
|
|
117
127
|
@client.create_batch_users(users)
|
|
128
|
+
# Wait for batch creation to propagate
|
|
129
|
+
sleep 1.0
|
|
118
130
|
all_users = @client.search_all_users
|
|
119
|
-
sdk_users = all_users['users'].select { |user| user['middleName']
|
|
131
|
+
sdk_users = all_users['users'].select { |user| user['middleName']&.include?('Ruby-SDK-User') }
|
|
120
132
|
expect(sdk_users.length).to be >= 5
|
|
121
133
|
end
|
|
122
134
|
|
|
@@ -128,7 +140,12 @@ describe Descope::Api::V1::Management::User do
|
|
|
128
140
|
all_roles['roles'].each do |role|
|
|
129
141
|
@client.delete_role(name: role['name']) if role['name'] == role_name
|
|
130
142
|
end
|
|
131
|
-
|
|
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
|
|
132
149
|
|
|
133
150
|
user_args = build(:user)
|
|
134
151
|
test_user = @client.create_test_user(**user_args)['user']
|
|
@@ -94,6 +94,17 @@ describe Descope::Mixins::HTTP do
|
|
|
94
94
|
expect(result['cookies']['DSR']).to eq('refresh_jwt_token')
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
+
it 'parses cookies from Set-Cookie headers with symbol key (real RestClient behavior)' do
|
|
98
|
+
# RestClient returns headers with symbol keys like :set_cookie, not string keys
|
|
99
|
+
mock_headers = { set_cookie: set_cookie_headers }
|
|
100
|
+
|
|
101
|
+
result = @instance.safe_parse_json(mock_body, cookies: {}, headers: mock_headers)
|
|
102
|
+
|
|
103
|
+
expect(result['cookies']).to_not be_nil
|
|
104
|
+
expect(result['cookies']['DS']).to eq('session_jwt_token')
|
|
105
|
+
expect(result['cookies']['DSR']).to eq('refresh_jwt_token')
|
|
106
|
+
end
|
|
107
|
+
|
|
97
108
|
it 'parses cookies from Set-Cookie header when headers is a string' do
|
|
98
109
|
mock_headers = { 'Set-Cookie' => set_cookie_headers.first }
|
|
99
110
|
|
|
@@ -120,7 +131,7 @@ describe Descope::Mixins::HTTP do
|
|
|
120
131
|
"DS=#{jwt_session}; Path=/; Domain=custom.example.com; HttpOnly; Secure; SameSite=None",
|
|
121
132
|
"DSR=#{jwt_refresh}; Path=/; Domain=custom.example.com; HttpOnly; Secure; SameSite=None; Max-Age=2592000"
|
|
122
133
|
]
|
|
123
|
-
mock_headers = {
|
|
134
|
+
mock_headers = { set_cookie: complex_headers }
|
|
124
135
|
|
|
125
136
|
result = @instance.safe_parse_json(mock_body, cookies: {}, headers: mock_headers)
|
|
126
137
|
|
|
@@ -134,7 +145,7 @@ describe Descope::Mixins::HTTP do
|
|
|
134
145
|
'CLOUDFLARE_SESSION=cf_token; Path=/; Domain=.example.com; HttpOnly',
|
|
135
146
|
'DSR=refresh_token; Path=/; Domain=dev.example.com; HttpOnly'
|
|
136
147
|
]
|
|
137
|
-
mock_headers = {
|
|
148
|
+
mock_headers = { set_cookie: mixed_headers }
|
|
138
149
|
|
|
139
150
|
result = @instance.safe_parse_json(mock_body, cookies: {}, headers: mock_headers)
|
|
140
151
|
|
|
@@ -175,7 +186,7 @@ describe Descope::Mixins::HTTP do
|
|
|
175
186
|
'DS=; Path=/; Domain=example.com', # Empty value
|
|
176
187
|
'=value_without_name; Path=/', # No name
|
|
177
188
|
]
|
|
178
|
-
mock_headers = {
|
|
189
|
+
mock_headers = { set_cookie: malformed_headers }
|
|
179
190
|
|
|
180
191
|
result = @instance.safe_parse_json(mock_body, cookies: {}, headers: mock_headers)
|
|
181
192
|
|
|
@@ -186,7 +197,7 @@ describe Descope::Mixins::HTTP do
|
|
|
186
197
|
it 'prefers RestClient cookies over Set-Cookie headers when both available' do
|
|
187
198
|
mock_cookies = { 'DS' => 'restclient_token' }
|
|
188
199
|
set_cookie_headers = ['DS=header_token; Path=/; Domain=example.com']
|
|
189
|
-
mock_headers = {
|
|
200
|
+
mock_headers = { set_cookie: set_cookie_headers }
|
|
190
201
|
|
|
191
202
|
result = @instance.safe_parse_json(mock_body, cookies: mock_cookies, headers: mock_headers)
|
|
192
203
|
|
|
@@ -204,7 +215,7 @@ describe Descope::Mixins::HTTP do
|
|
|
204
215
|
allow(mock_response).to receive(:body).and_return('{"success": true}')
|
|
205
216
|
allow(mock_response).to receive(:cookies).and_return({})
|
|
206
217
|
allow(mock_response).to receive(:headers).and_return({
|
|
207
|
-
|
|
218
|
+
set_cookie: ['DS=test_token; Domain=custom.example.com']
|
|
208
219
|
})
|
|
209
220
|
|
|
210
221
|
allow(@instance).to receive(:call).and_return(mock_response)
|
|
@@ -215,4 +226,4 @@ describe Descope::Mixins::HTTP do
|
|
|
215
226
|
expect(result['cookies']['DS']).to eq('test_token')
|
|
216
227
|
end
|
|
217
228
|
end
|
|
218
|
-
end
|
|
229
|
+
end
|