workos 5.31.1 → 6.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/lint-pr-title.yml +20 -0
- data/.github/workflows/release-please.yml +25 -0
- data/.github/workflows/release.yml +4 -40
- data/.release-please-manifest.json +3 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +4 -4
- data/lib/workos/authentication_response.rb +11 -7
- data/lib/workos/encryptors/aes_gcm.rb +49 -0
- data/lib/workos/encryptors.rb +9 -0
- data/lib/workos/refresh_authentication_response.rb +11 -7
- data/lib/workos/session.rb +29 -32
- data/lib/workos/user_management.rb +14 -1
- data/lib/workos/version.rb +1 -1
- data/lib/workos.rb +1 -0
- data/release-please-config.json +12 -0
- data/spec/lib/workos/encryptors/aes_gcm_spec.rb +41 -0
- data/spec/lib/workos/session_spec.rb +88 -1
- data/spec/lib/workos/user_management_spec.rb +65 -0
- data/workos.gemspec +1 -1
- metadata +13 -5
- data/.github/workflows/version-bump.yml +0 -80
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c2b3e2f56e5f5ffc2d59d27eb6613c018b24ec57ff270ed9e95730a46aafdc6
|
|
4
|
+
data.tar.gz: 6e001f5af6046daf9b640f570cd7318767fc106e90cdf3c9e7f8a3b0c11d1b3b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aa0bdfff2eb4de65c9bd5679be9f44b36df9eafd5eb8d3826f490d435825f61f3df32768e77b8954df538a3e3af2963aaba3fe23c89148b7f7619d83ea349c46
|
|
7
|
+
data.tar.gz: 6ae668143797a324cea0db2d9d779fe803c13f9defc62d707bb7b4419ba931a71d12ff5dd4bdc17da5c6c284623b1484a111817a1294e1f02f0e1e741dd15781
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Lint PR Title
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request_target:
|
|
5
|
+
types:
|
|
6
|
+
- opened
|
|
7
|
+
- edited
|
|
8
|
+
- synchronize
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
pull-requests: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
main:
|
|
15
|
+
name: Validate PR title
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: amannn/action-semantic-pull-request@v6
|
|
19
|
+
env:
|
|
20
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Release Please
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
pull-requests: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
release-please:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Generate token
|
|
17
|
+
id: generate-token
|
|
18
|
+
uses: actions/create-github-app-token@v2
|
|
19
|
+
with:
|
|
20
|
+
app-id: ${{ vars.SDK_BOT_APP_ID }}
|
|
21
|
+
private-key: ${{ secrets.SDK_BOT_PRIVATE_KEY }}
|
|
22
|
+
|
|
23
|
+
- uses: googleapis/release-please-action@v4
|
|
24
|
+
with:
|
|
25
|
+
token: ${{ steps.generate-token.outputs.token }}
|
|
@@ -1,53 +1,16 @@
|
|
|
1
1
|
name: Release
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
|
|
5
|
-
types: [
|
|
6
|
-
branches: [main]
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
7
6
|
|
|
8
7
|
defaults:
|
|
9
8
|
run:
|
|
10
9
|
shell: bash
|
|
11
10
|
|
|
12
11
|
jobs:
|
|
13
|
-
create-release:
|
|
14
|
-
name: Create GitHub Release
|
|
15
|
-
if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'version-bump')
|
|
16
|
-
runs-on: ubuntu-latest
|
|
17
|
-
permissions:
|
|
18
|
-
contents: write
|
|
19
|
-
outputs:
|
|
20
|
-
version: ${{ steps.get-version.outputs.version }}
|
|
21
|
-
steps:
|
|
22
|
-
- name: Generate token
|
|
23
|
-
id: generate-token
|
|
24
|
-
uses: actions/create-github-app-token@v2
|
|
25
|
-
with:
|
|
26
|
-
app-id: ${{ vars.SDK_BOT_APP_ID }}
|
|
27
|
-
private-key: ${{ secrets.SDK_BOT_PRIVATE_KEY }}
|
|
28
|
-
|
|
29
|
-
- name: Checkout
|
|
30
|
-
uses: actions/checkout@v6
|
|
31
|
-
with:
|
|
32
|
-
token: ${{ steps.generate-token.outputs.token }}
|
|
33
|
-
|
|
34
|
-
- name: Get version from version.rb
|
|
35
|
-
id: get-version
|
|
36
|
-
run: |
|
|
37
|
-
VERSION=$(grep "VERSION = " lib/workos/version.rb | sed "s/.*VERSION = '\(.*\)'/\1/")
|
|
38
|
-
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
39
|
-
|
|
40
|
-
- name: Create Release
|
|
41
|
-
uses: softprops/action-gh-release@v2
|
|
42
|
-
with:
|
|
43
|
-
tag_name: v${{ steps.get-version.outputs.version }}
|
|
44
|
-
name: v${{ steps.get-version.outputs.version }}
|
|
45
|
-
generate_release_notes: true
|
|
46
|
-
token: ${{ steps.generate-token.outputs.token }}
|
|
47
|
-
|
|
48
12
|
publish:
|
|
49
13
|
name: Publish to RubyGems
|
|
50
|
-
needs: create-release
|
|
51
14
|
runs-on: ubuntu-latest
|
|
52
15
|
permissions:
|
|
53
16
|
id-token: write
|
|
@@ -72,5 +35,6 @@ jobs:
|
|
|
72
35
|
|
|
73
36
|
- name: Publish to RubyGems
|
|
74
37
|
run: |
|
|
38
|
+
VERSION="${GITHUB_REF_NAME#v}"
|
|
75
39
|
bundle exec rake build
|
|
76
|
-
gem push pkg/workos-${
|
|
40
|
+
gem push pkg/workos-${VERSION}.gem --host https://rubygems.org
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [6.1.0](https://github.com/workos/workos-ruby/compare/workos-v6.0.0...workos/v6.1.0) (2026-02-10)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add support for totp_secret ([#300](https://github.com/workos/workos-ruby/issues/300)) ([c0a26bf](https://github.com/workos/workos-ruby/commit/c0a26bf745fb49ebaac7c5241e99d51188b886bb))
|
|
9
|
+
* Include Feature Flags decoded from the JWT in the payload of a Session ([#386](https://github.com/workos/workos-ruby/issues/386)) ([31a0e79](https://github.com/workos/workos-ruby/commit/31a0e7901247652182dcaad95e131357b93d0d71))
|
|
10
|
+
* **workos-ruby:** Add `connection` to `authorization_url` ([#78](https://github.com/workos/workos-ruby/issues/78)) ([c3a0e8e](https://github.com/workos/workos-ruby/commit/c3a0e8e4031a3ee888d925c11f1fd2fb152f0a16))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* add `invitation_token` parameter to authentication methods ([#438](https://github.com/workos/workos-ruby/issues/438)) ([d24e3dc](https://github.com/workos/workos-ruby/commit/d24e3dc2995de26970415e4570a7ed810d432715))
|
data/Gemfile.lock
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
workos (
|
|
4
|
+
workos (6.1.0)
|
|
5
5
|
encryptor (~> 3.0)
|
|
6
|
-
jwt (~>
|
|
6
|
+
jwt (~> 3.1)
|
|
7
7
|
|
|
8
8
|
GEM
|
|
9
9
|
remote: https://rubygems.org/
|
|
@@ -11,7 +11,7 @@ GEM
|
|
|
11
11
|
addressable (2.8.6)
|
|
12
12
|
public_suffix (>= 2.0.2, < 6.0)
|
|
13
13
|
ast (2.4.2)
|
|
14
|
-
base64 (0.
|
|
14
|
+
base64 (0.3.0)
|
|
15
15
|
bigdecimal (3.1.7)
|
|
16
16
|
crack (1.0.0)
|
|
17
17
|
bigdecimal
|
|
@@ -20,7 +20,7 @@ GEM
|
|
|
20
20
|
encryptor (3.0.0)
|
|
21
21
|
hashdiff (1.1.0)
|
|
22
22
|
json (2.9.1)
|
|
23
|
-
jwt (
|
|
23
|
+
jwt (3.1.2)
|
|
24
24
|
base64
|
|
25
25
|
language_server-protocol (3.17.0.3)
|
|
26
26
|
parallel (1.26.3)
|
|
@@ -31,13 +31,17 @@ module WorkOS
|
|
|
31
31
|
@oauth_tokens = json[:oauth_tokens] ? WorkOS::OAuthTokens.new(json[:oauth_tokens].to_json) : nil
|
|
32
32
|
@sealed_session =
|
|
33
33
|
if session && session[:seal_session]
|
|
34
|
-
WorkOS::Session.seal_data(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
WorkOS::Session.seal_data(
|
|
35
|
+
{
|
|
36
|
+
access_token: access_token,
|
|
37
|
+
refresh_token: refresh_token,
|
|
38
|
+
user: user.to_json,
|
|
39
|
+
organization_id: organization_id,
|
|
40
|
+
impersonator: impersonator.to_json,
|
|
41
|
+
},
|
|
42
|
+
session[:cookie_password],
|
|
43
|
+
encryptor: session[:encryptor],
|
|
44
|
+
)
|
|
41
45
|
end
|
|
42
46
|
end
|
|
43
47
|
# rubocop:enable Metrics/AbcSize
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'encryptor'
|
|
4
|
+
require 'securerandom'
|
|
5
|
+
require 'json'
|
|
6
|
+
require 'base64'
|
|
7
|
+
|
|
8
|
+
module WorkOS
|
|
9
|
+
module Encryptors
|
|
10
|
+
# Default encryptor using AES-256-GCM.
|
|
11
|
+
# Implements the encryptor interface: #seal(data, key) and #unseal(sealed_data, key)
|
|
12
|
+
class AesGcm
|
|
13
|
+
# Encrypts and seals data using AES-256-GCM
|
|
14
|
+
# @param data [Hash] The data to seal
|
|
15
|
+
# @param key [String] The encryption key
|
|
16
|
+
# @return [String] Base64-encoded sealed data
|
|
17
|
+
def seal(data, key)
|
|
18
|
+
iv = SecureRandom.random_bytes(12)
|
|
19
|
+
|
|
20
|
+
encrypted_data = Encryptor.encrypt(
|
|
21
|
+
value: JSON.generate(data),
|
|
22
|
+
key: key,
|
|
23
|
+
iv: iv,
|
|
24
|
+
algorithm: 'aes-256-gcm',
|
|
25
|
+
)
|
|
26
|
+
Base64.encode64(iv + encrypted_data)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Decrypts and unseals data using AES-256-GCM
|
|
30
|
+
# @param sealed_data [String] The sealed data to unseal
|
|
31
|
+
# @param key [String] The decryption key
|
|
32
|
+
# @return [Hash] The unsealed data with symbolized keys
|
|
33
|
+
def unseal(sealed_data, key)
|
|
34
|
+
decoded_data = Base64.decode64(sealed_data)
|
|
35
|
+
iv = decoded_data[0..11]
|
|
36
|
+
encrypted_data = decoded_data[12..]
|
|
37
|
+
|
|
38
|
+
decrypted_data = Encryptor.decrypt(
|
|
39
|
+
value: encrypted_data,
|
|
40
|
+
key: key,
|
|
41
|
+
iv: iv,
|
|
42
|
+
algorithm: 'aes-256-gcm',
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
JSON.parse(decrypted_data, symbolize_names: true)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WorkOS
|
|
4
|
+
# Encryptors module provides pluggable encryption implementations for session data.
|
|
5
|
+
# The default encryptor is AesGcm, which uses AES-256-GCM encryption.
|
|
6
|
+
module Encryptors
|
|
7
|
+
autoload :AesGcm, 'workos/encryptors/aes_gcm'
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -22,13 +22,17 @@ module WorkOS
|
|
|
22
22
|
end
|
|
23
23
|
@sealed_session =
|
|
24
24
|
if session && session[:seal_session]
|
|
25
|
-
WorkOS::Session.seal_data(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
WorkOS::Session.seal_data(
|
|
26
|
+
{
|
|
27
|
+
access_token: access_token,
|
|
28
|
+
refresh_token: refresh_token,
|
|
29
|
+
user: user.to_json,
|
|
30
|
+
organization_id: organization_id,
|
|
31
|
+
impersonator: impersonator.to_json,
|
|
32
|
+
},
|
|
33
|
+
session[:cookie_password],
|
|
34
|
+
encryptor: session[:encryptor],
|
|
35
|
+
)
|
|
32
36
|
end
|
|
33
37
|
end
|
|
34
38
|
# rubocop:enable Metrics/AbcSize
|
data/lib/workos/session.rb
CHANGED
|
@@ -12,11 +12,14 @@ 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
14
|
class Session
|
|
15
|
-
attr_accessor :jwks, :jwks_algorithms, :user_management, :cookie_password, :session_data, :client_id
|
|
15
|
+
attr_accessor :jwks, :jwks_algorithms, :user_management, :cookie_password, :session_data, :client_id, :encryptor
|
|
16
16
|
|
|
17
|
-
def initialize(user_management:, client_id:, session_data:, cookie_password:)
|
|
17
|
+
def initialize(user_management:, client_id:, session_data:, cookie_password:, encryptor: nil)
|
|
18
18
|
raise ArgumentError, 'cookiePassword is required' if cookie_password.nil? || cookie_password.empty?
|
|
19
19
|
|
|
20
|
+
@encryptor = encryptor || WorkOS::Encryptors::AesGcm.new
|
|
21
|
+
validate_encryptor!(@encryptor)
|
|
22
|
+
|
|
20
23
|
@user_management = user_management
|
|
21
24
|
@cookie_password = cookie_password
|
|
22
25
|
@session_data = session_data
|
|
@@ -30,13 +33,14 @@ module WorkOS
|
|
|
30
33
|
|
|
31
34
|
# Authenticates the user based on the session data
|
|
32
35
|
# @param include_expired [Boolean] If true, returns decoded token data even when expired (default: false)
|
|
36
|
+
# @param block [Proc] Optional block to call to extract additional claims from the decoded JWT
|
|
33
37
|
# @return [Hash] A hash containing the authentication response and a reason if the authentication failed
|
|
34
38
|
# rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
|
|
35
|
-
def authenticate(include_expired: false)
|
|
39
|
+
def authenticate(include_expired: false, &claim_extractor)
|
|
36
40
|
return { authenticated: false, reason: 'NO_SESSION_COOKIE_PROVIDED' } if @session_data.nil?
|
|
37
41
|
|
|
38
42
|
begin
|
|
39
|
-
session = Session.unseal_data(@session_data, @cookie_password)
|
|
43
|
+
session = Session.unseal_data(@session_data, @cookie_password, encryptor: @encryptor)
|
|
40
44
|
rescue StandardError
|
|
41
45
|
return { authenticated: false, reason: 'INVALID_SESSION_COOKIE' }
|
|
42
46
|
end
|
|
@@ -59,7 +63,7 @@ module WorkOS
|
|
|
59
63
|
return { authenticated: false, reason: 'INVALID_JWT' } if expired && !include_expired
|
|
60
64
|
|
|
61
65
|
# Return full data for valid tokens or when include_expired is true
|
|
62
|
-
{
|
|
66
|
+
result = {
|
|
63
67
|
authenticated: !expired,
|
|
64
68
|
session_id: decoded['sid'],
|
|
65
69
|
organization_id: decoded['org_id'],
|
|
@@ -72,6 +76,8 @@ module WorkOS
|
|
|
72
76
|
impersonator: session[:impersonator],
|
|
73
77
|
reason: expired ? 'INVALID_JWT' : nil,
|
|
74
78
|
}
|
|
79
|
+
result.merge!(claim_extractor.call(decoded)) if block_given?
|
|
80
|
+
result
|
|
75
81
|
rescue JWT::DecodeError
|
|
76
82
|
{ authenticated: false, reason: 'INVALID_JWT' }
|
|
77
83
|
rescue StandardError => e
|
|
@@ -89,7 +95,7 @@ module WorkOS
|
|
|
89
95
|
cookie_password = options.nil? || options[:cookie_password].nil? ? @cookie_password : options[:cookie_password]
|
|
90
96
|
|
|
91
97
|
begin
|
|
92
|
-
session = Session.unseal_data(@session_data, cookie_password)
|
|
98
|
+
session = Session.unseal_data(@session_data, cookie_password, encryptor: @encryptor)
|
|
93
99
|
rescue StandardError
|
|
94
100
|
return { authenticated: false, reason: 'INVALID_SESSION_COOKIE' }
|
|
95
101
|
end
|
|
@@ -101,7 +107,7 @@ module WorkOS
|
|
|
101
107
|
client_id: @client_id,
|
|
102
108
|
refresh_token: session[:refresh_token],
|
|
103
109
|
organization_id: options.nil? || options[:organization_id].nil? ? nil : options[:organization_id],
|
|
104
|
-
session: { seal_session: true, cookie_password: cookie_password },
|
|
110
|
+
session: { seal_session: true, cookie_password: cookie_password, encryptor: @encryptor },
|
|
105
111
|
)
|
|
106
112
|
|
|
107
113
|
@session_data = auth_response.sealed_session
|
|
@@ -134,43 +140,34 @@ module WorkOS
|
|
|
134
140
|
@user_management.get_logout_url(session_id: auth_response[:session_id], return_to: return_to)
|
|
135
141
|
end
|
|
136
142
|
|
|
137
|
-
# Encrypts and seals data using AES-256-GCM
|
|
143
|
+
# Encrypts and seals data using the provided encryptor (defaults to AES-256-GCM)
|
|
138
144
|
# @param data [Hash] The data to seal
|
|
139
145
|
# @param key [String] The key to use for encryption
|
|
146
|
+
# @param encryptor [Object] Optional encryptor that responds to #seal(data, key)
|
|
140
147
|
# @return [String] The sealed data
|
|
141
|
-
def self.seal_data(data, key)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
encrypted_data = Encryptor.encrypt(
|
|
145
|
-
value: JSON.generate(data),
|
|
146
|
-
key: key,
|
|
147
|
-
iv: iv,
|
|
148
|
-
algorithm: 'aes-256-gcm',
|
|
149
|
-
)
|
|
150
|
-
Base64.encode64(iv + encrypted_data) # Combine IV with encrypted data and encode as base64
|
|
148
|
+
def self.seal_data(data, key, encryptor: nil)
|
|
149
|
+
enc = encryptor || WorkOS::Encryptors::AesGcm.new
|
|
150
|
+
enc.seal(data, key)
|
|
151
151
|
end
|
|
152
152
|
|
|
153
|
-
# Decrypts and unseals data using AES-256-GCM
|
|
153
|
+
# Decrypts and unseals data using the provided encryptor (defaults to AES-256-GCM)
|
|
154
154
|
# @param sealed_data [String] The sealed data to unseal
|
|
155
155
|
# @param key [String] The key to use for decryption
|
|
156
|
+
# @param encryptor [Object] Optional encryptor that responds to #unseal(sealed_data, key)
|
|
156
157
|
# @return [Hash] The unsealed data
|
|
157
|
-
def self.unseal_data(sealed_data, key)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
encrypted_data = decoded_data[12..-1] # Extract the encrypted data
|
|
161
|
-
|
|
162
|
-
decrypted_data = Encryptor.decrypt(
|
|
163
|
-
value: encrypted_data,
|
|
164
|
-
key: key,
|
|
165
|
-
iv: iv,
|
|
166
|
-
algorithm: 'aes-256-gcm',
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
JSON.parse(decrypted_data, symbolize_names: true) # Parse the decrypted JSON string back to original data
|
|
158
|
+
def self.unseal_data(sealed_data, key, encryptor: nil)
|
|
159
|
+
enc = encryptor || WorkOS::Encryptors::AesGcm.new
|
|
160
|
+
enc.unseal(sealed_data, key)
|
|
170
161
|
end
|
|
171
162
|
|
|
172
163
|
private
|
|
173
164
|
|
|
165
|
+
def validate_encryptor!(enc)
|
|
166
|
+
return if enc.respond_to?(:seal) && enc.respond_to?(:unseal)
|
|
167
|
+
|
|
168
|
+
raise ArgumentError, 'encryptor must respond to #seal(data, key) and #unseal(sealed_data, key)'
|
|
169
|
+
end
|
|
170
|
+
|
|
174
171
|
# Creates a JWKS set from a remote JWKS URL
|
|
175
172
|
# @param uri [URI] The URI of the JWKS
|
|
176
173
|
# @return [JWT::JWK::Set] The JWKS set
|
|
@@ -42,14 +42,16 @@ module WorkOS
|
|
|
42
42
|
# @param [String] client_id The WorkOS client ID for the environment
|
|
43
43
|
# @param [String] session_data The sealed session data
|
|
44
44
|
# @param [String] cookie_password The password used to seal the session
|
|
45
|
+
# @param [Object] encryptor Optional custom encryptor that responds to #seal and #unseal
|
|
45
46
|
#
|
|
46
47
|
# @return WorkOS::Session
|
|
47
|
-
def load_sealed_session(client_id:, session_data:, cookie_password:)
|
|
48
|
+
def load_sealed_session(client_id:, session_data:, cookie_password:, encryptor: nil)
|
|
48
49
|
WorkOS::Session.new(
|
|
49
50
|
user_management: self,
|
|
50
51
|
client_id: client_id,
|
|
51
52
|
session_data: session_data,
|
|
52
53
|
cookie_password: cookie_password,
|
|
54
|
+
encryptor: encryptor,
|
|
53
55
|
)
|
|
54
56
|
end
|
|
55
57
|
|
|
@@ -296,16 +298,19 @@ module WorkOS
|
|
|
296
298
|
# @param [String] client_id The WorkOS client ID for the environment
|
|
297
299
|
# @param [String] ip_address The IP address of the request from the user who is attempting to authenticate.
|
|
298
300
|
# @param [String] user_agent The user agent of the request from the user who is attempting to authenticate.
|
|
301
|
+
# @param [String] invitation_token The token of an Invitation, if required.
|
|
299
302
|
# @param [Hash] session An optional hash that determines whether the session should be sealed and
|
|
300
303
|
# the optional cookie password.
|
|
301
304
|
#
|
|
302
305
|
# @return WorkOS::AuthenticationResponse
|
|
306
|
+
# rubocop:disable Metrics/ParameterLists
|
|
303
307
|
def authenticate_with_password(
|
|
304
308
|
email:,
|
|
305
309
|
password:,
|
|
306
310
|
client_id:,
|
|
307
311
|
ip_address: nil,
|
|
308
312
|
user_agent: nil,
|
|
313
|
+
invitation_token: nil,
|
|
309
314
|
session: nil
|
|
310
315
|
)
|
|
311
316
|
validate_session(session)
|
|
@@ -320,6 +325,7 @@ module WorkOS
|
|
|
320
325
|
password: password,
|
|
321
326
|
ip_address: ip_address,
|
|
322
327
|
user_agent: user_agent,
|
|
328
|
+
invitation_token: invitation_token,
|
|
323
329
|
grant_type: 'password',
|
|
324
330
|
},
|
|
325
331
|
),
|
|
@@ -327,6 +333,7 @@ module WorkOS
|
|
|
327
333
|
|
|
328
334
|
WorkOS::AuthenticationResponse.new(response.body, session)
|
|
329
335
|
end
|
|
336
|
+
# rubocop:enable Metrics/ParameterLists
|
|
330
337
|
|
|
331
338
|
# Authenticate a user using OAuth or an organization's SSO connection.
|
|
332
339
|
#
|
|
@@ -335,6 +342,7 @@ module WorkOS
|
|
|
335
342
|
# @param [String] client_id The WorkOS client ID for the environment
|
|
336
343
|
# @param [String] ip_address The IP address of the request from the user who is attempting to authenticate.
|
|
337
344
|
# @param [String] user_agent The user agent of the request from the user who is attempting to authenticate.
|
|
345
|
+
# @param [String] invitation_token The token of an Invitation, if required.
|
|
338
346
|
# @param [Hash] session An optional hash that determines whether the session should be sealed and
|
|
339
347
|
# the optional cookie password.
|
|
340
348
|
#
|
|
@@ -344,6 +352,7 @@ module WorkOS
|
|
|
344
352
|
client_id:,
|
|
345
353
|
ip_address: nil,
|
|
346
354
|
user_agent: nil,
|
|
355
|
+
invitation_token: nil,
|
|
347
356
|
session: nil
|
|
348
357
|
)
|
|
349
358
|
validate_session(session)
|
|
@@ -357,6 +366,7 @@ module WorkOS
|
|
|
357
366
|
client_secret: WorkOS.config.key!,
|
|
358
367
|
ip_address: ip_address,
|
|
359
368
|
user_agent: user_agent,
|
|
369
|
+
invitation_token: invitation_token,
|
|
360
370
|
grant_type: 'authorization_code',
|
|
361
371
|
},
|
|
362
372
|
),
|
|
@@ -413,6 +423,7 @@ module WorkOS
|
|
|
413
423
|
# @param [String] link_authorization_code Used to link an OAuth profile to an existing user,
|
|
414
424
|
# after having completed a Magic Code challenge.
|
|
415
425
|
# @param [String] user_agent The user agent of the request from the user who is attempting to authenticate.
|
|
426
|
+
# @param [String] invitation_token The token of an Invitation, if required.
|
|
416
427
|
# @param [Hash] session An optional hash that determines whether the session should be sealed and
|
|
417
428
|
# the optional cookie password.
|
|
418
429
|
#
|
|
@@ -425,6 +436,7 @@ module WorkOS
|
|
|
425
436
|
ip_address: nil,
|
|
426
437
|
user_agent: nil,
|
|
427
438
|
link_authorization_code: nil,
|
|
439
|
+
invitation_token: nil,
|
|
428
440
|
session: nil
|
|
429
441
|
)
|
|
430
442
|
validate_session(session)
|
|
@@ -441,6 +453,7 @@ module WorkOS
|
|
|
441
453
|
user_agent: user_agent,
|
|
442
454
|
grant_type: 'urn:workos:oauth:grant-type:magic-auth:code',
|
|
443
455
|
link_authorization_code: link_authorization_code,
|
|
456
|
+
invitation_token: invitation_token,
|
|
444
457
|
},
|
|
445
458
|
),
|
|
446
459
|
)
|
data/lib/workos/version.rb
CHANGED
data/lib/workos.rb
CHANGED
|
@@ -56,6 +56,7 @@ module WorkOS
|
|
|
56
56
|
autoload :DirectorySync, 'workos/directory_sync'
|
|
57
57
|
autoload :DirectoryUser, 'workos/directory_user'
|
|
58
58
|
autoload :EmailVerification, 'workos/email_verification'
|
|
59
|
+
autoload :Encryptors, 'workos/encryptors'
|
|
59
60
|
autoload :Event, 'workos/event'
|
|
60
61
|
autoload :Events, 'workos/events'
|
|
61
62
|
autoload :Factor, 'workos/factor'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
|
|
3
|
+
"packages": {
|
|
4
|
+
".": {
|
|
5
|
+
"release-type": "ruby",
|
|
6
|
+
"package-name": "workos",
|
|
7
|
+
"version-file": "lib/workos/version.rb",
|
|
8
|
+
"changelog-path": "CHANGELOG.md",
|
|
9
|
+
"include-component-in-tag": false
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe WorkOS::Encryptors::AesGcm do
|
|
4
|
+
subject(:encryptor) { described_class.new }
|
|
5
|
+
|
|
6
|
+
let(:key) { 'a' * 32 }
|
|
7
|
+
let(:data) { { access_token: 'tok_123', user: { id: 'user_01' } } }
|
|
8
|
+
|
|
9
|
+
describe '#seal' do
|
|
10
|
+
it 'returns a base64-encoded string' do
|
|
11
|
+
sealed = encryptor.seal(data, key)
|
|
12
|
+
expect(sealed).to be_a(String)
|
|
13
|
+
expect { Base64.decode64(sealed) }.not_to raise_error
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'produces different output each time (random IV)' do
|
|
17
|
+
sealed1 = encryptor.seal(data, key)
|
|
18
|
+
sealed2 = encryptor.seal(data, key)
|
|
19
|
+
expect(sealed1).not_to eq(sealed2)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#unseal' do
|
|
24
|
+
it 'round-trips data correctly' do
|
|
25
|
+
sealed = encryptor.seal(data, key)
|
|
26
|
+
unsealed = encryptor.unseal(sealed, key)
|
|
27
|
+
expect(unsealed).to eq(data)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'returns hash with symbolized keys' do
|
|
31
|
+
sealed = encryptor.seal({ 'string_key' => 'value' }, key)
|
|
32
|
+
unsealed = encryptor.unseal(sealed, key)
|
|
33
|
+
expect(unsealed.keys.first).to be_a(Symbol)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'raises error with wrong key' do
|
|
37
|
+
sealed = encryptor.seal(data, key)
|
|
38
|
+
expect { encryptor.unseal(sealed, 'b' * 32) }.to raise_error(OpenSSL::Cipher::CipherError)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -5,8 +5,8 @@ describe WorkOS::Session do
|
|
|
5
5
|
let(:cookie_password) { 'test_very_long_cookie_password__' }
|
|
6
6
|
let(:session_data) { 'test_session_data' }
|
|
7
7
|
let(:jwks_url) { 'https://api.workos.com/sso/jwks/client_123' }
|
|
8
|
-
let(:jwks_hash) { '{"keys":[{"alg":"RS256","kty":"RSA","use":"sig","n":"test_n","e":"AQAB","kid":"sso_oidc_key_pair_123","x5c":["test"],"x5t#S256":"test"}]}' } # rubocop:disable all
|
|
9
8
|
let(:jwk) { JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), { kid: 'sso_oidc_key_pair_123', use: 'sig', alg: 'RS256' }) }
|
|
9
|
+
let(:jwks_hash) { { keys: [jwk.export] }.to_json }
|
|
10
10
|
|
|
11
11
|
before do
|
|
12
12
|
allow(Net::HTTP).to receive(:get).and_return(jwks_hash)
|
|
@@ -222,6 +222,29 @@ describe WorkOS::Session do
|
|
|
222
222
|
})
|
|
223
223
|
end
|
|
224
224
|
|
|
225
|
+
it 'merges custom claims from claim_extractor block' do
|
|
226
|
+
custom_payload = payload.merge(custom_claim: 'custom_value', another_claim: 123)
|
|
227
|
+
custom_access_token = JWT.encode(custom_payload, jwk.signing_key, jwk[:alg], { kid: jwk[:kid] })
|
|
228
|
+
custom_session_data = WorkOS::Session.seal_data({
|
|
229
|
+
access_token: custom_access_token,
|
|
230
|
+
user: 'user',
|
|
231
|
+
impersonator: 'impersonator',
|
|
232
|
+
}, cookie_password,)
|
|
233
|
+
session = WorkOS::Session.new(
|
|
234
|
+
user_management: user_management,
|
|
235
|
+
client_id: client_id,
|
|
236
|
+
session_data: custom_session_data,
|
|
237
|
+
cookie_password: cookie_password,
|
|
238
|
+
)
|
|
239
|
+
allow_any_instance_of(JWT::Decode).to receive(:verify_signature).and_return(true)
|
|
240
|
+
result = session.authenticate do |jwt|
|
|
241
|
+
{ my_custom_claim: jwt['custom_claim'], my_other_claim: jwt['another_claim'] }
|
|
242
|
+
end
|
|
243
|
+
expect(result[:authenticated]).to be true
|
|
244
|
+
expect(result[:my_custom_claim]).to eq('custom_value')
|
|
245
|
+
expect(result[:my_other_claim]).to eq(123)
|
|
246
|
+
end
|
|
247
|
+
|
|
225
248
|
describe 'with entitlements' do
|
|
226
249
|
let(:payload) do
|
|
227
250
|
{
|
|
@@ -385,4 +408,68 @@ describe WorkOS::Session do
|
|
|
385
408
|
end
|
|
386
409
|
end
|
|
387
410
|
end
|
|
411
|
+
|
|
412
|
+
describe 'custom encryptor' do
|
|
413
|
+
let(:user_management) { instance_double('UserManagement') }
|
|
414
|
+
let(:custom_encryptor) do
|
|
415
|
+
Class.new do
|
|
416
|
+
def seal(data, _key)
|
|
417
|
+
"CUSTOM:#{JSON.generate(data)}"
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def unseal(sealed_data, _key)
|
|
421
|
+
json = sealed_data.sub('CUSTOM:', '')
|
|
422
|
+
JSON.parse(json, symbolize_names: true)
|
|
423
|
+
end
|
|
424
|
+
end.new
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
before do
|
|
428
|
+
allow(user_management).to receive(:get_jwks_url).with(client_id).and_return(jwks_url)
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
it 'uses custom encryptor for seal_data' do
|
|
432
|
+
sealed = WorkOS::Session.seal_data({ foo: 'bar' }, 'key', encryptor: custom_encryptor)
|
|
433
|
+
expect(sealed).to start_with('CUSTOM:')
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
it 'uses custom encryptor for unseal_data' do
|
|
437
|
+
sealed = 'CUSTOM:{"foo":"bar"}'
|
|
438
|
+
unsealed = WorkOS::Session.unseal_data(sealed, 'key', encryptor: custom_encryptor)
|
|
439
|
+
expect(unsealed).to eq({ foo: 'bar' })
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
it 'accepts custom encryptor in initialize' do
|
|
443
|
+
session = WorkOS::Session.new(
|
|
444
|
+
user_management: user_management,
|
|
445
|
+
client_id: client_id,
|
|
446
|
+
session_data: session_data,
|
|
447
|
+
cookie_password: cookie_password,
|
|
448
|
+
encryptor: custom_encryptor,
|
|
449
|
+
)
|
|
450
|
+
expect(session.encryptor).to eq(custom_encryptor)
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
it 'defaults to AesGcm encryptor when none provided' do
|
|
454
|
+
session = WorkOS::Session.new(
|
|
455
|
+
user_management: user_management,
|
|
456
|
+
client_id: client_id,
|
|
457
|
+
session_data: session_data,
|
|
458
|
+
cookie_password: cookie_password,
|
|
459
|
+
)
|
|
460
|
+
expect(session.encryptor).to be_a(WorkOS::Encryptors::AesGcm)
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
it 'raises ArgumentError for invalid encryptor' do
|
|
464
|
+
expect do
|
|
465
|
+
WorkOS::Session.new(
|
|
466
|
+
user_management: user_management,
|
|
467
|
+
client_id: client_id,
|
|
468
|
+
session_data: session_data,
|
|
469
|
+
cookie_password: cookie_password,
|
|
470
|
+
encryptor: Object.new,
|
|
471
|
+
)
|
|
472
|
+
end.to raise_error(ArgumentError, /must respond to/)
|
|
473
|
+
end
|
|
474
|
+
end
|
|
388
475
|
end
|
|
@@ -588,6 +588,28 @@ describe WorkOS::UserManagement do
|
|
|
588
588
|
end
|
|
589
589
|
end
|
|
590
590
|
end
|
|
591
|
+
|
|
592
|
+
context 'with an invitation_token' do
|
|
593
|
+
it 'includes invitation_token in the request body' do
|
|
594
|
+
expect(described_class).to receive(:post_request) do |options|
|
|
595
|
+
body = options[:body]
|
|
596
|
+
expect(body[:invitation_token]).to eq('invitation_token_123')
|
|
597
|
+
|
|
598
|
+
double('request')
|
|
599
|
+
end.and_return(double('request'))
|
|
600
|
+
|
|
601
|
+
expect(described_class).to receive(:execute_request).and_return(
|
|
602
|
+
double('response', body: '{"user": {"id": "user_123"}, "access_token": "token", "refresh_token": "refresh"}'),
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
described_class.authenticate_with_password(
|
|
606
|
+
email: 'test@workos.app',
|
|
607
|
+
password: 'password123',
|
|
608
|
+
client_id: 'client_123',
|
|
609
|
+
invitation_token: 'invitation_token_123',
|
|
610
|
+
)
|
|
611
|
+
end
|
|
612
|
+
end
|
|
591
613
|
end
|
|
592
614
|
|
|
593
615
|
describe '.authenticate_with_code' do
|
|
@@ -671,6 +693,27 @@ describe WorkOS::UserManagement do
|
|
|
671
693
|
end
|
|
672
694
|
end
|
|
673
695
|
end
|
|
696
|
+
|
|
697
|
+
context 'with an invitation_token' do
|
|
698
|
+
it 'includes invitation_token in the request body' do
|
|
699
|
+
expect(described_class).to receive(:post_request) do |options|
|
|
700
|
+
body = options[:body]
|
|
701
|
+
expect(body[:invitation_token]).to eq('invitation_token_123')
|
|
702
|
+
|
|
703
|
+
double('request')
|
|
704
|
+
end.and_return(double('request'))
|
|
705
|
+
|
|
706
|
+
expect(described_class).to receive(:execute_request).and_return(
|
|
707
|
+
double('response', body: '{"user": {"id": "user_123"}, "access_token": "token", "refresh_token": "refresh"}'),
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
described_class.authenticate_with_code(
|
|
711
|
+
code: '01H93ZZHA0JBHFJH9RR11S83YN',
|
|
712
|
+
client_id: 'client_123',
|
|
713
|
+
invitation_token: 'invitation_token_123',
|
|
714
|
+
)
|
|
715
|
+
end
|
|
716
|
+
end
|
|
674
717
|
end
|
|
675
718
|
|
|
676
719
|
describe '.authenticate_with_refresh_token' do
|
|
@@ -735,6 +778,28 @@ describe WorkOS::UserManagement do
|
|
|
735
778
|
end
|
|
736
779
|
end
|
|
737
780
|
end
|
|
781
|
+
|
|
782
|
+
context 'with an invitation_token' do
|
|
783
|
+
it 'includes invitation_token in the request body' do
|
|
784
|
+
expect(described_class).to receive(:post_request) do |options|
|
|
785
|
+
body = options[:body]
|
|
786
|
+
expect(body[:invitation_token]).to eq('invitation_token_123')
|
|
787
|
+
|
|
788
|
+
double('request')
|
|
789
|
+
end.and_return(double('request'))
|
|
790
|
+
|
|
791
|
+
expect(described_class).to receive(:execute_request).and_return(
|
|
792
|
+
double('response', body: '{"user": {"id": "user_123"}, "access_token": "token", "refresh_token": "refresh"}'),
|
|
793
|
+
)
|
|
794
|
+
|
|
795
|
+
described_class.authenticate_with_magic_auth(
|
|
796
|
+
code: '452079',
|
|
797
|
+
client_id: 'client_123',
|
|
798
|
+
email: 'test@workos.com',
|
|
799
|
+
invitation_token: 'invitation_token_123',
|
|
800
|
+
)
|
|
801
|
+
end
|
|
802
|
+
end
|
|
738
803
|
end
|
|
739
804
|
|
|
740
805
|
describe '.authenticate_with_organization_selection' do
|
data/workos.gemspec
CHANGED
|
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
|
|
|
22
22
|
spec.require_paths = ['lib']
|
|
23
23
|
|
|
24
24
|
spec.add_dependency 'encryptor', '~> 3.0'
|
|
25
|
-
spec.add_dependency 'jwt', '~>
|
|
25
|
+
spec.add_dependency 'jwt', '~> 3.1'
|
|
26
26
|
|
|
27
27
|
spec.add_development_dependency 'bundler', '>= 2.0.1'
|
|
28
28
|
spec.add_development_dependency 'rake'
|
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:
|
|
4
|
+
version: 6.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- WorkOS
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: encryptor
|
|
@@ -30,14 +30,14 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '3.1'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '3.1'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: bundler
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -133,13 +133,16 @@ files:
|
|
|
133
133
|
- ".github/pull_request_template.md"
|
|
134
134
|
- ".github/renovate.json"
|
|
135
135
|
- ".github/workflows/ci.yml"
|
|
136
|
+
- ".github/workflows/lint-pr-title.yml"
|
|
137
|
+
- ".github/workflows/release-please.yml"
|
|
136
138
|
- ".github/workflows/release.yml"
|
|
137
|
-
- ".github/workflows/version-bump.yml"
|
|
138
139
|
- ".gitignore"
|
|
140
|
+
- ".release-please-manifest.json"
|
|
139
141
|
- ".rspec"
|
|
140
142
|
- ".rubocop.yml"
|
|
141
143
|
- ".rubocop_todo.yml"
|
|
142
144
|
- ".ruby-version"
|
|
145
|
+
- CHANGELOG.md
|
|
143
146
|
- Gemfile
|
|
144
147
|
- Gemfile.lock
|
|
145
148
|
- LICENSE
|
|
@@ -166,6 +169,8 @@ files:
|
|
|
166
169
|
- lib/workos/directory_sync.rb
|
|
167
170
|
- lib/workos/directory_user.rb
|
|
168
171
|
- lib/workos/email_verification.rb
|
|
172
|
+
- lib/workos/encryptors.rb
|
|
173
|
+
- lib/workos/encryptors/aes_gcm.rb
|
|
169
174
|
- lib/workos/errors.rb
|
|
170
175
|
- lib/workos/event.rb
|
|
171
176
|
- lib/workos/events.rb
|
|
@@ -205,12 +210,14 @@ files:
|
|
|
205
210
|
- lib/workos/webhook.rb
|
|
206
211
|
- lib/workos/webhooks.rb
|
|
207
212
|
- lib/workos/widgets.rb
|
|
213
|
+
- release-please-config.json
|
|
208
214
|
- spec/lib/workos/audit_logs_spec.rb
|
|
209
215
|
- spec/lib/workos/cache_spec.rb
|
|
210
216
|
- spec/lib/workos/client.rb
|
|
211
217
|
- spec/lib/workos/configuration_spec.rb
|
|
212
218
|
- spec/lib/workos/directory_sync_spec.rb
|
|
213
219
|
- spec/lib/workos/directory_user_spec.rb
|
|
220
|
+
- spec/lib/workos/encryptors/aes_gcm_spec.rb
|
|
214
221
|
- spec/lib/workos/event_spec.rb
|
|
215
222
|
- spec/lib/workos/mfa_spec.rb
|
|
216
223
|
- spec/lib/workos/organizations_spec.rb
|
|
@@ -451,6 +458,7 @@ test_files:
|
|
|
451
458
|
- spec/lib/workos/configuration_spec.rb
|
|
452
459
|
- spec/lib/workos/directory_sync_spec.rb
|
|
453
460
|
- spec/lib/workos/directory_user_spec.rb
|
|
461
|
+
- spec/lib/workos/encryptors/aes_gcm_spec.rb
|
|
454
462
|
- spec/lib/workos/event_spec.rb
|
|
455
463
|
- spec/lib/workos/mfa_spec.rb
|
|
456
464
|
- spec/lib/workos/organizations_spec.rb
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
name: Version Bump
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_dispatch:
|
|
5
|
-
inputs:
|
|
6
|
-
bump_type:
|
|
7
|
-
description: "Version bump type"
|
|
8
|
-
required: true
|
|
9
|
-
type: choice
|
|
10
|
-
options:
|
|
11
|
-
- patch
|
|
12
|
-
- minor
|
|
13
|
-
- major
|
|
14
|
-
|
|
15
|
-
jobs:
|
|
16
|
-
bump-version:
|
|
17
|
-
runs-on: ubuntu-latest
|
|
18
|
-
permissions:
|
|
19
|
-
contents: write
|
|
20
|
-
pull-requests: write
|
|
21
|
-
steps:
|
|
22
|
-
- name: Generate token
|
|
23
|
-
id: generate-token
|
|
24
|
-
uses: actions/create-github-app-token@v2
|
|
25
|
-
with:
|
|
26
|
-
app-id: ${{ vars.SDK_BOT_APP_ID }}
|
|
27
|
-
private-key: ${{ secrets.SDK_BOT_PRIVATE_KEY }}
|
|
28
|
-
|
|
29
|
-
- name: Checkout
|
|
30
|
-
uses: actions/checkout@v6
|
|
31
|
-
with:
|
|
32
|
-
token: ${{ steps.generate-token.outputs.token }}
|
|
33
|
-
|
|
34
|
-
- name: Configure Git
|
|
35
|
-
run: |
|
|
36
|
-
git config user.name "workos-bot[bot]"
|
|
37
|
-
git config user.email "workos-bot[bot]@users.noreply.github.com"
|
|
38
|
-
|
|
39
|
-
- name: Read current version
|
|
40
|
-
id: current-version
|
|
41
|
-
run: |
|
|
42
|
-
CURRENT_VERSION=$(grep "VERSION = " lib/workos/version.rb | sed "s/.*VERSION = '\(.*\)'/\1/")
|
|
43
|
-
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
|
44
|
-
|
|
45
|
-
- name: Bump version
|
|
46
|
-
id: bump-version
|
|
47
|
-
run: |
|
|
48
|
-
CURRENT_VERSION="${{ steps.current-version.outputs.version }}"
|
|
49
|
-
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
|
|
50
|
-
|
|
51
|
-
case "${{ github.event.inputs.bump_type }}" in
|
|
52
|
-
major)
|
|
53
|
-
NEW_VERSION="$((MAJOR + 1)).0.0"
|
|
54
|
-
;;
|
|
55
|
-
minor)
|
|
56
|
-
NEW_VERSION="$MAJOR.$((MINOR + 1)).0"
|
|
57
|
-
;;
|
|
58
|
-
patch)
|
|
59
|
-
NEW_VERSION="$MAJOR.$MINOR.$((PATCH + 1))"
|
|
60
|
-
;;
|
|
61
|
-
esac
|
|
62
|
-
|
|
63
|
-
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
|
64
|
-
|
|
65
|
-
- name: Update version in version.rb
|
|
66
|
-
run: |
|
|
67
|
-
sed -i "s/VERSION = '.*'/VERSION = '${{ steps.bump-version.outputs.new_version }}'/" lib/workos/version.rb
|
|
68
|
-
|
|
69
|
-
- name: Create Pull Request
|
|
70
|
-
uses: peter-evans/create-pull-request@v7
|
|
71
|
-
with:
|
|
72
|
-
token: ${{ steps.generate-token.outputs.token }}
|
|
73
|
-
commit-message: "v${{ steps.bump-version.outputs.new_version }}"
|
|
74
|
-
title: "v${{ steps.bump-version.outputs.new_version }}"
|
|
75
|
-
body: |
|
|
76
|
-
Bumps version from ${{ steps.current-version.outputs.version }} to ${{ steps.bump-version.outputs.new_version }}.
|
|
77
|
-
|
|
78
|
-
This PR was automatically created by the version-bump workflow.
|
|
79
|
-
branch: version-bump-${{ steps.bump-version.outputs.new_version }}
|
|
80
|
-
labels: version-bump
|