workos 5.11.0 → 5.12.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.yml +0 -2
- data/.rubocop.yml +5 -6
- data/.rubocop_todo.yml +94 -0
- data/.ruby-version +1 -1
- data/Gemfile.lock +20 -15
- data/lib/workos/cache.rb +94 -0
- data/lib/workos/organization.rb +11 -1
- data/lib/workos/organizations.rb +5 -2
- data/lib/workos/session.rb +3 -3
- data/lib/workos/version.rb +1 -1
- data/lib/workos.rb +1 -0
- data/spec/lib/workos/cache_spec.rb +94 -0
- data/spec/lib/workos/organizations_spec.rb +15 -0
- data/spec/lib/workos/session_spec.rb +46 -0
- data/spec/support/fixtures/vcr_cassettes/organization/update_with_stripe_customer_id.yml +78 -0
- data/workos.gemspec +2 -2
- metadata +14 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6852c01440a63d103cd39a4c0aee2eeb5d1215d79a3e8eb2a3053b5aa3f3376e
|
4
|
+
data.tar.gz: 71c5c53d1f8fc5219903cfcfc23cbeb657da1db2c64980fa9d8914bd6ae92b1d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb001da89bc0cf2866dcfd4d4c5207ddc7c960538ab413c45fcd5d5f80e4c97e205cc0e3fb51bdaaf8af984e9e30ad5c317c30e453c8e6579c1914350dfe3f2c
|
7
|
+
data.tar.gz: 5fe92a1ad40c3bced46b0597430b02ea36b20c82f109614df332695aa7d9f613a025e0f30d3afcaab978c5b3de6882a3a67886e55343de513fb508950664a5d3
|
data/.github/workflows/ci.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
Enabled: false
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
4
3
|
Layout/DotPosition:
|
5
4
|
EnforcedStyle: trailing
|
6
5
|
Layout/EmptyLineAfterMagicComment:
|
@@ -8,11 +7,11 @@ Layout/EmptyLineAfterMagicComment:
|
|
8
7
|
Layout/EmptyLines:
|
9
8
|
Enabled: false
|
10
9
|
Layout/LineLength:
|
11
|
-
|
10
|
+
AllowedPatterns:
|
12
11
|
- 'VCR\.use_cassette'
|
13
12
|
- '(\A|\s)/.*?/'
|
14
13
|
Metrics/BlockLength:
|
15
|
-
|
14
|
+
AllowedMethods: ['describe', 'context', 'before', 'it']
|
16
15
|
Metrics/MethodLength:
|
17
16
|
Max: 30
|
18
17
|
Metrics/ModuleLength:
|
@@ -28,4 +27,4 @@ Style/TrailingCommaInArguments:
|
|
28
27
|
Style/TrailingCommaInHashLiteral:
|
29
28
|
EnforcedStyleForMultiline: 'consistent_comma'
|
30
29
|
AllCops:
|
31
|
-
TargetRubyVersion:
|
30
|
+
TargetRubyVersion: 3.1
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2025-01-22 21:38:20 UTC using RuboCop version 1.71.0.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 1
|
10
|
+
# This cop supports safe autocorrection (--autocorrect).
|
11
|
+
# Configuration parameters: EnforcedStyleAlignWith.
|
12
|
+
# SupportedStylesAlignWith: either, start_of_block, start_of_line
|
13
|
+
Layout/BlockAlignment:
|
14
|
+
Exclude:
|
15
|
+
- 'spec/lib/workos/session_spec.rb'
|
16
|
+
|
17
|
+
# Offense count: 2
|
18
|
+
# This cop supports safe autocorrection (--autocorrect).
|
19
|
+
Layout/EmptyLinesAroundMethodBody:
|
20
|
+
Exclude:
|
21
|
+
- 'lib/workos/mfa.rb'
|
22
|
+
- 'lib/workos/user_management.rb'
|
23
|
+
|
24
|
+
# Offense count: 1
|
25
|
+
# This cop supports safe autocorrection (--autocorrect).
|
26
|
+
Layout/SpaceAroundMethodCallOperator:
|
27
|
+
Exclude:
|
28
|
+
- 'spec/lib/workos/directory_sync_spec.rb'
|
29
|
+
|
30
|
+
# Offense count: 1
|
31
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
32
|
+
Lint/DuplicateRequire:
|
33
|
+
Exclude:
|
34
|
+
- 'lib/workos/session.rb'
|
35
|
+
|
36
|
+
# Offense count: 3
|
37
|
+
# Configuration parameters: AllowedParentClasses.
|
38
|
+
Lint/MissingSuper:
|
39
|
+
Exclude:
|
40
|
+
- 'lib/workos/directory_group.rb'
|
41
|
+
- 'lib/workos/directory_user.rb'
|
42
|
+
- 'lib/workos/errors.rb'
|
43
|
+
|
44
|
+
# Offense count: 5
|
45
|
+
# Configuration parameters: CountComments, CountAsOne.
|
46
|
+
Metrics/ClassLength:
|
47
|
+
Max: 624
|
48
|
+
|
49
|
+
# Offense count: 8
|
50
|
+
# This cop supports safe autocorrection (--autocorrect).
|
51
|
+
# Configuration parameters: EnforcedStyle.
|
52
|
+
# SupportedStyles: separated, grouped
|
53
|
+
Style/AccessorGrouping:
|
54
|
+
Exclude:
|
55
|
+
- 'lib/workos/errors.rb'
|
56
|
+
|
57
|
+
# Offense count: 34
|
58
|
+
# This cop supports safe autocorrection (--autocorrect).
|
59
|
+
# Configuration parameters: EnforcedStyle.
|
60
|
+
# SupportedStyles: braces, no_braces
|
61
|
+
Style/HashAsLastArrayItem:
|
62
|
+
Exclude:
|
63
|
+
- 'spec/lib/workos/directory_sync_spec.rb'
|
64
|
+
- 'spec/lib/workos/event_spec.rb'
|
65
|
+
- 'spec/lib/workos/organizations_spec.rb'
|
66
|
+
- 'spec/lib/workos/sso_spec.rb'
|
67
|
+
- 'spec/lib/workos/user_management_spec.rb'
|
68
|
+
|
69
|
+
# Offense count: 2
|
70
|
+
# This cop supports safe autocorrection (--autocorrect).
|
71
|
+
Style/KeywordParametersOrder:
|
72
|
+
Exclude:
|
73
|
+
- 'lib/workos/organizations.rb'
|
74
|
+
|
75
|
+
# Offense count: 3
|
76
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
77
|
+
# Configuration parameters: SafeForConstants.
|
78
|
+
Style/RedundantFetchBlock:
|
79
|
+
Exclude:
|
80
|
+
- 'spec/lib/workos/cache_spec.rb'
|
81
|
+
|
82
|
+
# Offense count: 1
|
83
|
+
# This cop supports safe autocorrection (--autocorrect).
|
84
|
+
# Configuration parameters: AllowMultipleReturnValues.
|
85
|
+
Style/RedundantReturn:
|
86
|
+
Exclude:
|
87
|
+
- 'lib/workos/directory_user.rb'
|
88
|
+
|
89
|
+
# Offense count: 2
|
90
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
91
|
+
Style/SlicingWithRange:
|
92
|
+
Exclude:
|
93
|
+
- 'lib/workos/deprecated_hash_wrapper.rb'
|
94
|
+
- 'lib/workos/session.rb'
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.1.4
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
workos (5.
|
4
|
+
workos (5.12.0)
|
5
5
|
encryptor (~> 3.0)
|
6
6
|
jwt (~> 2.8)
|
7
7
|
|
@@ -19,16 +19,18 @@ GEM
|
|
19
19
|
diff-lcs (1.5.1)
|
20
20
|
encryptor (3.0.0)
|
21
21
|
hashdiff (1.1.0)
|
22
|
+
json (2.9.1)
|
22
23
|
jwt (2.10.1)
|
23
24
|
base64
|
24
|
-
|
25
|
-
|
25
|
+
language_server-protocol (3.17.0.3)
|
26
|
+
parallel (1.26.3)
|
27
|
+
parser (3.3.7.0)
|
26
28
|
ast (~> 2.4.1)
|
27
29
|
racc
|
28
30
|
public_suffix (5.0.4)
|
29
|
-
racc (1.
|
31
|
+
racc (1.8.1)
|
30
32
|
rainbow (3.1.1)
|
31
|
-
regexp_parser (2.
|
33
|
+
regexp_parser (2.10.0)
|
32
34
|
rexml (3.2.6)
|
33
35
|
rspec (3.9.0)
|
34
36
|
rspec-core (~> 3.9.0)
|
@@ -43,19 +45,22 @@ GEM
|
|
43
45
|
diff-lcs (>= 1.2.0, < 2.0)
|
44
46
|
rspec-support (~> 3.9.0)
|
45
47
|
rspec-support (3.9.4)
|
46
|
-
rubocop (
|
48
|
+
rubocop (1.71.0)
|
49
|
+
json (~> 2.3)
|
50
|
+
language_server-protocol (>= 3.17.0)
|
47
51
|
parallel (~> 1.10)
|
48
|
-
parser (>=
|
52
|
+
parser (>= 3.3.0.2)
|
49
53
|
rainbow (>= 2.2.2, < 4.0)
|
50
|
-
regexp_parser (>=
|
51
|
-
|
52
|
-
rubocop-ast (>= 0.6.0)
|
54
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
55
|
+
rubocop-ast (>= 1.36.2, < 2.0)
|
53
56
|
ruby-progressbar (~> 1.7)
|
54
|
-
unicode-display_width (>=
|
55
|
-
rubocop-ast (1.
|
56
|
-
parser (>= 3.3.0
|
57
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
58
|
+
rubocop-ast (1.37.0)
|
59
|
+
parser (>= 3.3.1.0)
|
57
60
|
ruby-progressbar (1.13.0)
|
58
|
-
unicode-display_width (1.
|
61
|
+
unicode-display_width (3.1.4)
|
62
|
+
unicode-emoji (~> 4.0, >= 4.0.4)
|
63
|
+
unicode-emoji (4.0.4)
|
59
64
|
vcr (5.0.0)
|
60
65
|
webmock (3.23.0)
|
61
66
|
addressable (>= 2.8.0)
|
@@ -68,7 +73,7 @@ PLATFORMS
|
|
68
73
|
DEPENDENCIES
|
69
74
|
bundler (>= 2.0.1)
|
70
75
|
rspec (~> 3.9.0)
|
71
|
-
rubocop (~>
|
76
|
+
rubocop (~> 1.71)
|
72
77
|
vcr (~> 5.0.0)
|
73
78
|
webmock
|
74
79
|
workos!
|
data/lib/workos/cache.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WorkOS
|
4
|
+
# The Cache module provides a simple in-memory cache for storing values
|
5
|
+
# This module is not meant to be instantiated in a user space, and is used internally by the SDK
|
6
|
+
module Cache
|
7
|
+
# The Entry class represents a cache entry with a value and an expiration time
|
8
|
+
class Entry
|
9
|
+
attr_reader :value, :expires_at
|
10
|
+
|
11
|
+
# Initializes a new cache entry
|
12
|
+
# @param value [Object] The value to store in the cache
|
13
|
+
# @param expires_in_seconds [Integer, nil] The expiration time for the value in seconds, or nil for no expiration
|
14
|
+
def initialize(value, expires_in_seconds)
|
15
|
+
@value = value
|
16
|
+
@expires_at = expires_in_seconds ? Time.now + expires_in_seconds : nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# Checks if the entry has expired
|
20
|
+
# @return [Boolean] True if the entry has expired, false otherwise
|
21
|
+
def expired?
|
22
|
+
return false if expires_at.nil?
|
23
|
+
|
24
|
+
Time.now > @expires_at
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
# Fetches a value from the cache, or calls the block to fetch the value if it is not present
|
30
|
+
# @param key [String] The key to fetch the value for
|
31
|
+
# @param expires_in [Integer] The expiration time for the value in seconds
|
32
|
+
# @param force [Boolean] If true, the value will be fetched from the block even if it is present in the cache
|
33
|
+
# @param block [Proc] The block to call to fetch the value if it is not present in the cache
|
34
|
+
# @return [Object] The value fetched from the cache or the block
|
35
|
+
def fetch(key, expires_in: nil, force: false, &block)
|
36
|
+
entry = store[key]
|
37
|
+
|
38
|
+
if force || entry.nil? || entry.expired?
|
39
|
+
value = block.call
|
40
|
+
store[key] = Entry.new(value, expires_in)
|
41
|
+
return value
|
42
|
+
end
|
43
|
+
|
44
|
+
entry.value
|
45
|
+
end
|
46
|
+
|
47
|
+
# Reads a value from the cache
|
48
|
+
# @param key [String] The key to read the value for
|
49
|
+
# @return [Object] The value read from the cache, or nil if the value is not present or has expired
|
50
|
+
def read(key)
|
51
|
+
entry = store[key]
|
52
|
+
return nil if entry.nil? || entry.expired?
|
53
|
+
|
54
|
+
entry.value
|
55
|
+
end
|
56
|
+
|
57
|
+
# Writes a value to the cache
|
58
|
+
# @param key [String] The key to write the value for
|
59
|
+
# @param value [Object] The value to write to the cache
|
60
|
+
# @param expires_in [Integer] The expiration time for the value in seconds
|
61
|
+
# @return [Object] The value written to the cache
|
62
|
+
def write(key, value, expires_in: nil)
|
63
|
+
store[key] = Entry.new(value, expires_in)
|
64
|
+
value
|
65
|
+
end
|
66
|
+
|
67
|
+
# Deletes a value from the cache
|
68
|
+
# @param key [String] The key to delete the value for
|
69
|
+
def delete(key)
|
70
|
+
store.delete(key)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Clears all values from the cache
|
74
|
+
def clear
|
75
|
+
store.clear
|
76
|
+
end
|
77
|
+
|
78
|
+
# Checks if a value exists in the cache
|
79
|
+
# @param key [String] The key to check for
|
80
|
+
# @return [Boolean] True if the value exists and has not expired, false otherwise
|
81
|
+
def exist?(key)
|
82
|
+
entry = store[key]
|
83
|
+
!(entry.nil? || entry.expired?)
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# The in-memory store for the cache
|
89
|
+
def store
|
90
|
+
@store ||= {}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/workos/organization.rb
CHANGED
@@ -7,7 +7,15 @@ module WorkOS
|
|
7
7
|
class Organization
|
8
8
|
include HashProvider
|
9
9
|
|
10
|
-
attr_accessor
|
10
|
+
attr_accessor(
|
11
|
+
:id,
|
12
|
+
:domains,
|
13
|
+
:stripe_customer_id,
|
14
|
+
:name,
|
15
|
+
:allow_profiles_outside_organization,
|
16
|
+
:created_at,
|
17
|
+
:updated_at,
|
18
|
+
)
|
11
19
|
|
12
20
|
def initialize(json)
|
13
21
|
hash = JSON.parse(json, symbolize_names: true)
|
@@ -16,6 +24,7 @@ module WorkOS
|
|
16
24
|
@name = hash[:name]
|
17
25
|
@allow_profiles_outside_organization = hash[:allow_profiles_outside_organization]
|
18
26
|
@domains = hash[:domains]
|
27
|
+
@stripe_customer_id = hash[:stripe_customer_id]
|
19
28
|
@created_at = hash[:created_at]
|
20
29
|
@updated_at = hash[:updated_at]
|
21
30
|
end
|
@@ -26,6 +35,7 @@ module WorkOS
|
|
26
35
|
name: name,
|
27
36
|
allow_profiles_outside_organization: allow_profiles_outside_organization,
|
28
37
|
domains: domains,
|
38
|
+
stripe_customer_id: stripe_customer_id,
|
29
39
|
created_at: created_at,
|
30
40
|
updated_at: updated_at,
|
31
41
|
}
|
data/lib/workos/organizations.rb
CHANGED
@@ -71,7 +71,7 @@ module WorkOS
|
|
71
71
|
|
72
72
|
# Create an organization
|
73
73
|
#
|
74
|
-
# @param [Array<Hash>] domain_data List of domain hashes describing an
|
74
|
+
# @param [Array<Hash>] domain_data List of domain hashes describing an organization domain.
|
75
75
|
# @option domain_data [String] domain The domain that belongs to the organization.
|
76
76
|
# @option domain_data [String] state The state of the domain. "verified" or "pending"
|
77
77
|
# @param [String] name A unique, descriptive name for the organization
|
@@ -118,9 +118,10 @@ module WorkOS
|
|
118
118
|
# Update an organization
|
119
119
|
#
|
120
120
|
# @param [String] organization Organization unique identifier
|
121
|
-
# @param [Array<Hash>] domain_data List of domain hashes describing an
|
121
|
+
# @param [Array<Hash>] domain_data List of domain hashes describing an organization domain.
|
122
122
|
# @option domain_data [String] domain The domain that belongs to the organization.
|
123
123
|
# @option domain_data [String] state The state of the domain. "verified" or "pending"
|
124
|
+
# @param [String] stripe_customer_id The Stripe customer ID associated with this organization.
|
124
125
|
# @param [String] name A unique, descriptive name for the organization
|
125
126
|
# @param [Boolean, nil] allow_profiles_outside_organization Whether Connections
|
126
127
|
# within the Organization allow profiles that are outside of the Organization's configured User Email Domains.
|
@@ -129,6 +130,7 @@ module WorkOS
|
|
129
130
|
# Deprecated: Use domain_data instead.
|
130
131
|
def update_organization(
|
131
132
|
organization:,
|
133
|
+
stripe_customer_id: nil,
|
132
134
|
domain_data: nil,
|
133
135
|
domains: nil,
|
134
136
|
name: nil,
|
@@ -136,6 +138,7 @@ module WorkOS
|
|
136
138
|
)
|
137
139
|
body = { name: name }
|
138
140
|
body[:domain_data] = domain_data if domain_data
|
141
|
+
body[:stripe_customer_id] = stripe_customer_id if stripe_customer_id
|
139
142
|
|
140
143
|
if domains
|
141
144
|
warn_deprecation '`domains` is deprecated. Use `domain_data` instead.'
|
data/lib/workos/session.rb
CHANGED
@@ -11,7 +11,6 @@ require 'uri'
|
|
11
11
|
module WorkOS
|
12
12
|
# The Session class provides helper methods for working with WorkOS sessions
|
13
13
|
# This class is not meant to be instantiated in a user space, and is instantiated internally but exposed.
|
14
|
-
# rubocop:disable Metrics/ClassLength
|
15
14
|
class Session
|
16
15
|
attr_accessor :jwks, :jwks_algorithms, :user_management, :cookie_password, :session_data, :client_id
|
17
16
|
|
@@ -23,7 +22,9 @@ module WorkOS
|
|
23
22
|
@session_data = session_data
|
24
23
|
@client_id = client_id
|
25
24
|
|
26
|
-
@jwks =
|
25
|
+
@jwks = Cache.fetch("jwks_#{client_id}", expires_in: 5 * 60) do
|
26
|
+
create_remote_jwk_set(URI(@user_management.get_jwks_url(client_id)))
|
27
|
+
end
|
27
28
|
@jwks_algorithms = @jwks.map { |key| key[:alg] }.compact.uniq
|
28
29
|
end
|
29
30
|
|
@@ -178,5 +179,4 @@ module WorkOS
|
|
178
179
|
end
|
179
180
|
# rubocop:enable Naming/PredicateName
|
180
181
|
end
|
181
|
-
# rubocop:enable Metrics/ClassLength
|
182
182
|
end
|
data/lib/workos/version.rb
CHANGED
data/lib/workos.rb
CHANGED
@@ -45,6 +45,7 @@ module WorkOS
|
|
45
45
|
autoload :AuthenticationFactorAndChallenge, 'workos/authentication_factor_and_challenge'
|
46
46
|
autoload :AuthenticationResponse, 'workos/authentication_response'
|
47
47
|
autoload :AuditLogs, 'workos/audit_logs'
|
48
|
+
autoload :Cache, 'workos/cache'
|
48
49
|
autoload :Challenge, 'workos/challenge'
|
49
50
|
autoload :Client, 'workos/client'
|
50
51
|
autoload :Connection, 'workos/connection'
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe WorkOS::Cache do
|
4
|
+
before { described_class.clear }
|
5
|
+
|
6
|
+
describe '.write and .read' do
|
7
|
+
it 'stores and retrieves data' do
|
8
|
+
described_class.write('key', 'value')
|
9
|
+
expect(described_class.read('key')).to eq('value')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'returns nil if key does not exist' do
|
13
|
+
expect(described_class.read('missing')).to be_nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.fetch' do
|
18
|
+
it 'returns cached value when present and not expired' do
|
19
|
+
described_class.write('key', 'value')
|
20
|
+
fetch_value = described_class.fetch('key') { 'new_value' }
|
21
|
+
expect(fetch_value).to eq('value')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'executes block and caches value when not present' do
|
25
|
+
fetch_value = described_class.fetch('key') { 'new_value' }
|
26
|
+
expect(fetch_value).to eq('new_value')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'executes block and caches value when force is true' do
|
30
|
+
described_class.write('key', 'value')
|
31
|
+
fetch_value = described_class.fetch('key', force: true) { 'new_value' }
|
32
|
+
expect(fetch_value).to eq('new_value')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'expiration' do
|
37
|
+
it 'expires values after specified time' do
|
38
|
+
described_class.write('key', 'value', expires_in: 0.1)
|
39
|
+
expect(described_class.read('key')).to eq('value')
|
40
|
+
sleep 0.2
|
41
|
+
expect(described_class.read('key')).to be_nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'executes block and caches new value when expired' do
|
45
|
+
described_class.write('key', 'old_value', expires_in: 0.1)
|
46
|
+
sleep 0.2
|
47
|
+
fetch_value = described_class.fetch('key') { 'new_value' }
|
48
|
+
expect(fetch_value).to eq('new_value')
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'does not expire values when expires_in is nil' do
|
52
|
+
described_class.write('key', 'value', expires_in: nil)
|
53
|
+
sleep 0.2
|
54
|
+
expect(described_class.read('key')).to eq('value')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '.exist?' do
|
59
|
+
it 'returns true if key exists' do
|
60
|
+
described_class.write('key', 'value')
|
61
|
+
expect(described_class.exist?('key')).to be true
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns false if expired' do
|
65
|
+
described_class.write('key', 'value', expires_in: 0.1)
|
66
|
+
sleep 0.2
|
67
|
+
expect(described_class.exist?('key')).to be false
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'returns false if key does not exist' do
|
71
|
+
expect(described_class.exist?('missing')).to be false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '.delete' do
|
76
|
+
it 'deletes key' do
|
77
|
+
described_class.write('key', 'value')
|
78
|
+
described_class.delete('key')
|
79
|
+
expect(described_class.read('key')).to be_nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '.clear' do
|
84
|
+
it 'removes all keys from the cache' do
|
85
|
+
described_class.write('key1', 'value1')
|
86
|
+
described_class.write('key2', 'value2')
|
87
|
+
|
88
|
+
described_class.clear
|
89
|
+
|
90
|
+
expect(described_class.read('key1')).to be_nil
|
91
|
+
expect(described_class.read('key2')).to be_nil
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -295,6 +295,21 @@ describe WorkOS::Organizations do
|
|
295
295
|
end
|
296
296
|
end
|
297
297
|
end
|
298
|
+
context 'with a stripe_customer_id' do
|
299
|
+
it 'updates the organization' do
|
300
|
+
VCR.use_cassette 'organization/update_with_stripe_customer_id' do
|
301
|
+
organization = described_class.update_organization(
|
302
|
+
organization: 'org_01JJ5H14CAA2SQ5G9HNN6TBZ05',
|
303
|
+
name: 'Test Organization',
|
304
|
+
stripe_customer_id: 'cus_123',
|
305
|
+
)
|
306
|
+
|
307
|
+
expect(organization.id).to eq('org_01JJ5H14CAA2SQ5G9HNN6TBZ05')
|
308
|
+
expect(organization.name).to eq('Test Organization')
|
309
|
+
expect(organization.stripe_customer_id).to eq('cus_123')
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
298
313
|
end
|
299
314
|
|
300
315
|
describe '.delete_organization' do
|
@@ -19,6 +19,52 @@ describe WorkOS::Session do
|
|
19
19
|
allow(user_management).to receive(:get_jwks_url).with(client_id).and_return(jwks_url)
|
20
20
|
end
|
21
21
|
|
22
|
+
describe 'JWKS caching' do
|
23
|
+
before do
|
24
|
+
WorkOS::Cache.clear
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'caches and returns JWKS' do
|
28
|
+
expect(Net::HTTP).to receive(:get).once
|
29
|
+
session1 = WorkOS::Session.new(
|
30
|
+
user_management: user_management,
|
31
|
+
client_id: client_id,
|
32
|
+
session_data: session_data,
|
33
|
+
cookie_password: cookie_password,
|
34
|
+
)
|
35
|
+
|
36
|
+
session2 = WorkOS::Session.new(
|
37
|
+
user_management: user_management,
|
38
|
+
client_id: client_id,
|
39
|
+
session_data: session_data,
|
40
|
+
cookie_password: cookie_password,
|
41
|
+
)
|
42
|
+
|
43
|
+
expect(session1.jwks.map(&:export)).to eq(session2.jwks.map(&:export))
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'fetches JWKS from remote when cache is expired' do
|
47
|
+
expect(Net::HTTP).to receive(:get).twice
|
48
|
+
session1 = WorkOS::Session.new(
|
49
|
+
user_management: user_management,
|
50
|
+
client_id: client_id,
|
51
|
+
session_data: session_data,
|
52
|
+
cookie_password: cookie_password,
|
53
|
+
)
|
54
|
+
|
55
|
+
allow(Time).to receive(:now).and_return(Time.now + 301)
|
56
|
+
|
57
|
+
session2 = WorkOS::Session.new(
|
58
|
+
user_management: user_management,
|
59
|
+
client_id: client_id,
|
60
|
+
session_data: session_data,
|
61
|
+
cookie_password: cookie_password,
|
62
|
+
)
|
63
|
+
|
64
|
+
expect(session1.jwks.map(&:export)).to eq(session2.jwks.map(&:export))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
22
68
|
it 'raises an error if cookie_password is nil or empty' do
|
23
69
|
expect do
|
24
70
|
WorkOS::Session.new(
|
@@ -0,0 +1,78 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: put
|
5
|
+
uri: https://api.workos.com/organizations/org_01JJ5H14CAA2SQ5G9HNN6TBZ05
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"name":"Test Organization","stripe_customer_id":"cus_123"}'
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
+
Accept:
|
15
|
+
- "*/*"
|
16
|
+
User-Agent:
|
17
|
+
- WorkOS; ruby/3.1.4; arm64-darwin24; v5.11.1
|
18
|
+
Authorization:
|
19
|
+
- Bearer <API_KEY>
|
20
|
+
response:
|
21
|
+
status:
|
22
|
+
code: 200
|
23
|
+
message: OK
|
24
|
+
headers:
|
25
|
+
Date:
|
26
|
+
- Wed, 22 Jan 2025 16:50:26 GMT
|
27
|
+
Content-Type:
|
28
|
+
- application/json; charset=utf-8
|
29
|
+
Transfer-Encoding:
|
30
|
+
- chunked
|
31
|
+
Connection:
|
32
|
+
- keep-alive
|
33
|
+
Cf-Ray:
|
34
|
+
- 90610b03f84db9f1-SEA
|
35
|
+
Cf-Cache-Status:
|
36
|
+
- DYNAMIC
|
37
|
+
Etag:
|
38
|
+
- W/"1cc-uqKwJf4L85rLspCK9lJ1ceRlbSA"
|
39
|
+
Strict-Transport-Security:
|
40
|
+
- max-age=15552000; includeSubDomains
|
41
|
+
Vary:
|
42
|
+
- Origin, Accept-Encoding
|
43
|
+
Access-Control-Allow-Credentials:
|
44
|
+
- 'true'
|
45
|
+
Content-Security-Policy:
|
46
|
+
- 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self''
|
47
|
+
https: data:;frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src
|
48
|
+
''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests'
|
49
|
+
Expect-Ct:
|
50
|
+
- max-age=0
|
51
|
+
Referrer-Policy:
|
52
|
+
- no-referrer
|
53
|
+
X-Content-Type-Options:
|
54
|
+
- nosniff
|
55
|
+
X-Dns-Prefetch-Control:
|
56
|
+
- 'off'
|
57
|
+
X-Download-Options:
|
58
|
+
- noopen
|
59
|
+
X-Frame-Options:
|
60
|
+
- SAMEORIGIN
|
61
|
+
X-Permitted-Cross-Domain-Policies:
|
62
|
+
- none
|
63
|
+
X-Request-Id:
|
64
|
+
- 7b62039f-40f4-4c2c-9ef9-7b1f63615481
|
65
|
+
X-Xss-Protection:
|
66
|
+
- '0'
|
67
|
+
Set-Cookie:
|
68
|
+
- _cfuvid=TPT.bwe9giSuDXv9bDFC8leHolKCFKy2kdsa0G89jGI-1737564626875-0.0.1.1-604800000;
|
69
|
+
path=/; domain=.workos.com; HttpOnly; Secure; SameSite=None
|
70
|
+
Server:
|
71
|
+
- cloudflare
|
72
|
+
body:
|
73
|
+
encoding: ASCII-8BIT
|
74
|
+
string: '{"object":"organization","id":"org_01JJ5H14CAA2SQ5G9HNN6TBZ05","name":"Test
|
75
|
+
Organization","allow_profiles_outside_organization":false,"created_at":"2025-01-21T22:51:46.441Z","updated_at":"2025-01-22T16:50:26.789Z","domains":[{"verification_strategy":"manual","state":"verified","object":"organization_domain","id":"org_domain_01JJ5H14CKRGAE9HVA1Y9YABSX","organization_id":"org_01JJ5H14CAA2SQ5G9HNN6TBZ05","domain":"example.me"}],"stripe_customer_id":"cus_123"}'
|
76
|
+
http_version:
|
77
|
+
recorded_at: Wed, 22 Jan 2025 16:50:26 GMT
|
78
|
+
recorded_with: VCR 5.0.0
|
data/workos.gemspec
CHANGED
@@ -26,9 +26,9 @@ Gem::Specification.new do |spec|
|
|
26
26
|
|
27
27
|
spec.add_development_dependency 'bundler', '>= 2.0.1'
|
28
28
|
spec.add_development_dependency 'rspec', '~> 3.9.0'
|
29
|
-
spec.add_development_dependency 'rubocop', '~>
|
29
|
+
spec.add_development_dependency 'rubocop', '~> 1.71'
|
30
30
|
spec.add_development_dependency 'vcr', '~> 5.0.0'
|
31
31
|
spec.add_development_dependency 'webmock'
|
32
32
|
|
33
|
-
spec.required_ruby_version = '>=
|
33
|
+
spec.required_ruby_version = '>= 3.1'
|
34
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: workos
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- WorkOS
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-01-
|
11
|
+
date: 2025-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: encryptor
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '1.71'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '1.71'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: vcr
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,6 +123,7 @@ files:
|
|
123
123
|
- ".gitignore"
|
124
124
|
- ".rspec"
|
125
125
|
- ".rubocop.yml"
|
126
|
+
- ".rubocop_todo.yml"
|
126
127
|
- ".ruby-version"
|
127
128
|
- Gemfile
|
128
129
|
- Gemfile.lock
|
@@ -136,6 +137,7 @@ files:
|
|
136
137
|
- lib/workos/audit_logs.rb
|
137
138
|
- lib/workos/authentication_factor_and_challenge.rb
|
138
139
|
- lib/workos/authentication_response.rb
|
140
|
+
- lib/workos/cache.rb
|
139
141
|
- lib/workos/challenge.rb
|
140
142
|
- lib/workos/client.rb
|
141
143
|
- lib/workos/configuration.rb
|
@@ -184,6 +186,7 @@ files:
|
|
184
186
|
- lib/workos/webhooks.rb
|
185
187
|
- lib/workos/widgets.rb
|
186
188
|
- spec/lib/workos/audit_logs_spec.rb
|
189
|
+
- spec/lib/workos/cache_spec.rb
|
187
190
|
- spec/lib/workos/client.rb
|
188
191
|
- spec/lib/workos/configuration_spec.rb
|
189
192
|
- spec/lib/workos/directory_sync_spec.rb
|
@@ -270,6 +273,7 @@ files:
|
|
270
273
|
- spec/support/fixtures/vcr_cassettes/organization/list.yml
|
271
274
|
- spec/support/fixtures/vcr_cassettes/organization/list_organization_roles.yml
|
272
275
|
- spec/support/fixtures/vcr_cassettes/organization/update.yml
|
276
|
+
- spec/support/fixtures/vcr_cassettes/organization/update_with_stripe_customer_id.yml
|
273
277
|
- spec/support/fixtures/vcr_cassettes/organization/update_without_name.yml
|
274
278
|
- spec/support/fixtures/vcr_cassettes/passwordless/create_session.yml
|
275
279
|
- spec/support/fixtures/vcr_cassettes/passwordless/create_session_invalid.yml
|
@@ -382,7 +386,7 @@ licenses:
|
|
382
386
|
- MIT
|
383
387
|
metadata:
|
384
388
|
documentation_uri: https://docs.workos.com/sdk/ruby
|
385
|
-
post_install_message:
|
389
|
+
post_install_message:
|
386
390
|
rdoc_options: []
|
387
391
|
require_paths:
|
388
392
|
- lib
|
@@ -390,7 +394,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
390
394
|
requirements:
|
391
395
|
- - ">="
|
392
396
|
- !ruby/object:Gem::Version
|
393
|
-
version: '
|
397
|
+
version: '3.1'
|
394
398
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
395
399
|
requirements:
|
396
400
|
- - ">="
|
@@ -398,11 +402,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
398
402
|
version: '0'
|
399
403
|
requirements: []
|
400
404
|
rubygems_version: 3.4.19
|
401
|
-
signing_key:
|
405
|
+
signing_key:
|
402
406
|
specification_version: 4
|
403
407
|
summary: API client for WorkOS
|
404
408
|
test_files:
|
405
409
|
- spec/lib/workos/audit_logs_spec.rb
|
410
|
+
- spec/lib/workos/cache_spec.rb
|
406
411
|
- spec/lib/workos/client.rb
|
407
412
|
- spec/lib/workos/configuration_spec.rb
|
408
413
|
- spec/lib/workos/directory_sync_spec.rb
|
@@ -489,6 +494,7 @@ test_files:
|
|
489
494
|
- spec/support/fixtures/vcr_cassettes/organization/list.yml
|
490
495
|
- spec/support/fixtures/vcr_cassettes/organization/list_organization_roles.yml
|
491
496
|
- spec/support/fixtures/vcr_cassettes/organization/update.yml
|
497
|
+
- spec/support/fixtures/vcr_cassettes/organization/update_with_stripe_customer_id.yml
|
492
498
|
- spec/support/fixtures/vcr_cassettes/organization/update_without_name.yml
|
493
499
|
- spec/support/fixtures/vcr_cassettes/passwordless/create_session.yml
|
494
500
|
- spec/support/fixtures/vcr_cassettes/passwordless/create_session_invalid.yml
|