workos 2.5.1 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +13 -11
  3. data/lib/workos/audit_log_export.rb +55 -0
  4. data/lib/workos/audit_logs.rb +107 -0
  5. data/lib/workos/client.rb +2 -0
  6. data/lib/workos/errors.rb +15 -1
  7. data/lib/workos/organizations.rb +4 -1
  8. data/lib/workos/types/audit_log_export_struct.rb +17 -0
  9. data/lib/workos/types/intent_enum.rb +1 -0
  10. data/lib/workos/types.rb +1 -0
  11. data/lib/workos/version.rb +1 -1
  12. data/lib/workos/webhooks.rb +49 -2
  13. data/lib/workos.rb +2 -0
  14. data/sorbet/rbi/sorbet-typed/lib/rainbow/all/rainbow.rbi +5 -5
  15. data/spec/lib/workos/audit_logs_spec.rb +149 -0
  16. data/spec/lib/workos/organizations_spec.rb +73 -9
  17. data/spec/lib/workos/portal_spec.rb +15 -0
  18. data/spec/lib/workos/webhooks_spec.rb +130 -84
  19. data/spec/support/fixtures/vcr_cassettes/audit_logs/create_event.yml +59 -0
  20. data/spec/support/fixtures/vcr_cassettes/audit_logs/create_event_custom_idempotency_key.yml +60 -0
  21. data/spec/support/fixtures/vcr_cassettes/audit_logs/create_event_invalid.yml +59 -0
  22. data/spec/support/fixtures/vcr_cassettes/audit_logs/create_export.yml +76 -0
  23. data/spec/support/fixtures/vcr_cassettes/audit_logs/create_export_with_filters.yml +78 -0
  24. data/spec/support/fixtures/vcr_cassettes/audit_logs/get_export.yml +73 -0
  25. data/spec/support/fixtures/vcr_cassettes/organization/create_with_duplicate_idempotency_key_and_different_payload.yml +155 -0
  26. data/spec/support/fixtures/vcr_cassettes/organization/create_with_duplicate_idempotency_key_and_payload.yml +154 -0
  27. data/spec/support/fixtures/vcr_cassettes/organization/create_with_idempotency_key.yml +79 -0
  28. data/spec/support/fixtures/vcr_cassettes/portal/generate_link_audit_logs.yml +72 -0
  29. data/spec/support/webhook_payload.txt +1 -1
  30. metadata +28 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: efe8fb9e00262c08d11cebcc39e65ad5728771bb1f132ea88302c78205134a3b
4
- data.tar.gz: 1532164858cc02a9e46d9cb8ac0c10b0e5401812da204840cd3760342462bfb7
3
+ metadata.gz: f9c1d1a239604c91126acc4b7c4482abaf306abf129eb9c4260cd2af6eb832a8
4
+ data.tar.gz: e614d8659cac83f4f1d4aca7ac930b6f1a89aa14f09bb4905b44797b77ee41cc
5
5
  SHA512:
6
- metadata.gz: bd4c7ada118af7b5ee60d28db25844264bda9a8249b0b3d0a33c11696c77f57d020cfe6e7410d4661bb7c3832e0ec83af2acc0468b4dc4b21e633a5af12bec16
7
- data.tar.gz: 8ecebf2811768a093ae87518124b4e1ff8bb3caefbc3ed1ff36ea0a81243030968bf204d535c63422e43718d811f13c682ad058c33e132977b283509457e30f3
6
+ metadata.gz: c7ac7ebb757400aa6f4195776662347cc0763aab1170d5a3678fa96324d6fcd5f59a80e75cd3df2082d710beff957f97cb0de6c287a9ea1ebf7631dcdf41ad3c
7
+ data.tar.gz: c655246d047fd79f7ab963b44ab5ab37912c5b8e4a7663cb9597c505cdc99903c308dd74fa024968d45dd4aff624e8b379be3a162b5c7082d9aa99fbc0749ee6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- workos (2.5.1)
4
+ workos (2.7.0)
5
5
  sorbet-runtime (~> 0.5)
6
6
 
7
7
  GEM
@@ -58,17 +58,19 @@ GEM
58
58
  simplecov_json_formatter (~> 0.1)
59
59
  simplecov-html (0.12.3)
60
60
  simplecov_json_formatter (0.1.2)
61
- sorbet (0.5.6388)
62
- sorbet-static (= 0.5.6388)
61
+ sorbet (0.5.10346)
62
+ sorbet-static (= 0.5.10346)
63
63
  sorbet-runtime (0.5.10323)
64
- sorbet-static (0.5.6388-universal-darwin-14)
65
- sorbet-static (0.5.6388-universal-darwin-15)
66
- sorbet-static (0.5.6388-universal-darwin-16)
67
- sorbet-static (0.5.6388-universal-darwin-17)
68
- sorbet-static (0.5.6388-universal-darwin-18)
69
- sorbet-static (0.5.6388-universal-darwin-19)
70
- sorbet-static (0.5.6388-universal-darwin-20)
71
- sorbet-static (0.5.6388-x86_64-linux)
64
+ sorbet-static (0.5.10346-universal-darwin-14)
65
+ sorbet-static (0.5.10346-universal-darwin-15)
66
+ sorbet-static (0.5.10346-universal-darwin-16)
67
+ sorbet-static (0.5.10346-universal-darwin-17)
68
+ sorbet-static (0.5.10346-universal-darwin-18)
69
+ sorbet-static (0.5.10346-universal-darwin-19)
70
+ sorbet-static (0.5.10346-universal-darwin-20)
71
+ sorbet-static (0.5.10346-universal-darwin-21)
72
+ sorbet-static (0.5.10346-universal-darwin-22)
73
+ sorbet-static (0.5.10346-x86_64-linux)
72
74
  unicode-display_width (1.7.0)
73
75
  vcr (5.0.0)
74
76
  webmock (3.12.2)
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module WorkOS
5
+ # The AuditLogExport class represents the WorkOS entity created when exporting Audit Log Events.
6
+ class AuditLogExport
7
+ include HashProvider
8
+ extend T::Sig
9
+
10
+ attr_accessor :object, :id, :state, :url, :created_at, :updated_at
11
+
12
+ sig { params(json: String).void }
13
+ def initialize(json)
14
+ raw = parse_json(json)
15
+
16
+ @object = T.let(raw.object, String)
17
+ @id = T.let(raw.id, String)
18
+ @state = T.let(raw.state, String)
19
+ @url = raw.url
20
+ @created_at = T.let(raw.created_at, String)
21
+ @updated_at = T.let(raw.updated_at, String)
22
+ end
23
+
24
+ def to_json(*)
25
+ {
26
+ object: object,
27
+ id: id,
28
+ state: state,
29
+ url: url,
30
+ created_at: created_at,
31
+ updated_at: updated_at,
32
+ }
33
+ end
34
+
35
+ private
36
+
37
+ sig do
38
+ params(
39
+ json_string: String,
40
+ ).returns(WorkOS::Types::AuditLogExportStruct)
41
+ end
42
+ def parse_json(json_string)
43
+ hash = JSON.parse(json_string, symbolize_names: true)
44
+
45
+ WorkOS::Types::AuditLogExportStruct.new(
46
+ object: hash[:object],
47
+ id: hash[:id],
48
+ state: hash[:state],
49
+ url: hash[:url],
50
+ created_at: hash[:created_at],
51
+ updated_at: hash[:updated_at],
52
+ )
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ require 'net/http'
5
+ require 'uri'
6
+
7
+ module WorkOS
8
+ # The Audit Logs module provides convenience methods for working with the
9
+ # WorkOS Audit Logs platform. You'll need a valid API key.
10
+ module AuditLogs
11
+ class << self
12
+ extend T::Sig
13
+ include Client
14
+
15
+ # Create an Audit Log Event.
16
+ #
17
+ # @param [String] organization An Organization ID
18
+ # @param [Hash] event An Audit Log Event
19
+ # @param [String] idempotency_key An idempotency key
20
+ #
21
+ # @return [nil]
22
+ sig do
23
+ params(
24
+ organization: String,
25
+ event: Hash,
26
+ idempotency_key: T.nilable(String),
27
+ ).void
28
+ end
29
+ def create_event(organization:, event:, idempotency_key: nil)
30
+ request = post_request(
31
+ path: '/audit_logs/events',
32
+ auth: true,
33
+ idempotency_key: idempotency_key,
34
+ body: {
35
+ organization_id: organization,
36
+ event: event,
37
+ },
38
+ )
39
+
40
+ execute_request(request: request)
41
+ end
42
+
43
+ # Create an Export of Audit Log Events.
44
+ #
45
+ # @param [String] organization An Organization ID
46
+ # @param [String] range_start ISO-8601 datetime
47
+ # @param [String] range_end ISO-8601 datetime
48
+ # @param [Array<String>] actions A list of actions to filter by
49
+ # @param [Array<String>] actors A list of actor names to filter by
50
+ # @param [Array<String>] targets A list of target types to filter by
51
+ #
52
+ # @return [WorkOS::AuditLogExport]
53
+ sig do
54
+ params(
55
+ organization: String,
56
+ range_start: String,
57
+ range_end: String,
58
+ actions: T.nilable(T::Array[String]),
59
+ actors: T.nilable(T::Array[String]),
60
+ targets: T.nilable(T::Array[String]),
61
+ ).returns(WorkOS::AuditLogExport)
62
+ end
63
+ def create_export(organization:, range_start:, range_end:, actions: nil, actors: nil, targets: nil)
64
+ body = {
65
+ organization_id: organization,
66
+ range_start: range_start,
67
+ range_end: range_end,
68
+ }
69
+
70
+ body['actions'] = actions unless actions.nil?
71
+ body['actors'] = actors unless actors.nil?
72
+ body['targets'] = targets unless targets.nil?
73
+
74
+ request = post_request(
75
+ path: '/audit_logs/exports',
76
+ auth: true,
77
+ body: body,
78
+ )
79
+
80
+ response = execute_request(request: request)
81
+
82
+ WorkOS::AuditLogExport.new(response.body)
83
+ end
84
+
85
+ # Retrieves an Export of Audit Log Events
86
+ #
87
+ # @param [String] id An Audit Log Export ID
88
+ #
89
+ # @return [WorkOS::AuditLogExport]
90
+ sig do
91
+ params(
92
+ id: String,
93
+ ).returns(WorkOS::AuditLogExport)
94
+ end
95
+ def get_export(id:)
96
+ request = get_request(
97
+ auth: true,
98
+ path: "/audit_logs/exports/#{id}",
99
+ )
100
+
101
+ response = execute_request(request: request)
102
+
103
+ WorkOS::AuditLogExport.new(response.body)
104
+ end
105
+ end
106
+ end
107
+ end
data/lib/workos/client.rb CHANGED
@@ -138,6 +138,8 @@ module WorkOS
138
138
  message: json['message'],
139
139
  http_status: http_status,
140
140
  request_id: response['x-request-id'],
141
+ code: json['code'],
142
+ errors: json['errors'],
141
143
  )
142
144
  when 401
143
145
  raise AuthenticationError.new(
data/lib/workos/errors.rb CHANGED
@@ -9,7 +9,10 @@ module WorkOS
9
9
 
10
10
  attr_reader :http_status
11
11
  attr_reader :request_id
12
+ attr_reader :code
13
+ attr_reader :errors
12
14
 
15
+ # rubocop:disable Metrics/ParameterLists
13
16
  sig do
14
17
  params(
15
18
  message: T.nilable(String),
@@ -18,16 +21,27 @@ module WorkOS
18
21
  http_status: T.nilable(Integer),
19
22
  request_id: T.nilable(String),
20
23
  code: T.nilable(String),
24
+ errors: T.nilable(T::Array[T::Hash[T.untyped, T.untyped]]),
21
25
  ).void
22
26
  end
23
- def initialize(message: nil, error: nil, error_description: nil, http_status: nil, request_id: nil, code: nil)
27
+ def initialize(
28
+ message: nil,
29
+ error: nil,
30
+ error_description: nil,
31
+ http_status: nil,
32
+ request_id: nil,
33
+ code: nil,
34
+ errors: nil
35
+ )
24
36
  @message = message
25
37
  @error = error
26
38
  @error_description = error_description
27
39
  @http_status = http_status
28
40
  @request_id = request_id
29
41
  @code = code
42
+ @errors = errors
30
43
  end
44
+ # rubocop:enable Metrics/ParameterLists
31
45
 
32
46
  sig { returns(String) }
33
47
  def to_s
@@ -82,14 +82,16 @@ module WorkOS
82
82
  # @param [String] name A unique, descriptive name for the organization
83
83
  # @param [Boolean, nil] allow_profiles_outside_organization Whether Connections
84
84
  # within the Organization allow profiles that are outside of the Organization's configured User Email Domains.
85
+ # @param [String] idempotency_key An idempotency key
85
86
  sig do
86
87
  params(
87
88
  domains: T::Array[String],
88
89
  name: String,
89
90
  allow_profiles_outside_organization: T.nilable(T::Boolean),
91
+ idempotency_key: T.nilable(String),
90
92
  ).returns(WorkOS::Organization)
91
93
  end
92
- def create_organization(domains:, name:, allow_profiles_outside_organization: nil)
94
+ def create_organization(domains:, name:, allow_profiles_outside_organization: nil, idempotency_key: nil)
93
95
  request = post_request(
94
96
  auth: true,
95
97
  body: {
@@ -98,6 +100,7 @@ module WorkOS
98
100
  allow_profiles_outside_organization: allow_profiles_outside_organization,
99
101
  },
100
102
  path: '/organizations',
103
+ idempotency_key: idempotency_key,
101
104
  )
102
105
 
103
106
  response = execute_request(request: request)
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module WorkOS
5
+ module Types
6
+ # This AuditLogExportStruct acts as a typed interface
7
+ # for the AuditLogExport class
8
+ class AuditLogExportStruct < T::Struct
9
+ const :object, String
10
+ const :id, String
11
+ const :state, String
12
+ const :url, T.nilable(String)
13
+ const :created_at, String
14
+ const :updated_at, String
15
+ end
16
+ end
17
+ end
@@ -9,6 +9,7 @@ module WorkOS
9
9
  enums do
10
10
  SSO = new('sso')
11
11
  DSYNC = new('dsync')
12
+ AUDIT_LOGS = new('audit_logs')
12
13
  end
13
14
  end
14
15
  end
data/lib/workos/types.rb CHANGED
@@ -5,6 +5,7 @@ module WorkOS
5
5
  # WorkOS believes strongly in typed languages,
6
6
  # so we're using Sorbet throughout this Ruby gem.
7
7
  module Types
8
+ require_relative 'types/audit_log_export_struct'
8
9
  require_relative 'types/connection_struct'
9
10
  require_relative 'types/directory_struct'
10
11
  require_relative 'types/directory_group_struct'
@@ -2,5 +2,5 @@
2
2
  # typed: strong
3
3
 
4
4
  module WorkOS
5
- VERSION = '2.5.1'
5
+ VERSION = '2.7.0'
6
6
  end
@@ -55,8 +55,25 @@ module WorkOS
55
55
  WorkOS::Webhook.new(payload)
56
56
  end
57
57
 
58
- private
59
-
58
+ # Verifies WorkOS-Signature header from request
59
+ # rubocop:disable Layout/LineLength
60
+ #
61
+ # @param [String] payload The payload from the webhook sent by WorkOS. This is the RAW_POST_DATA of the request.
62
+ # @param [String] sig_header The signature from the webhook sent by WorkOS.
63
+ # @param [String] secret The webhook secret from the WorkOS dashboard.
64
+ # @param [Integer] tolerance The time tolerance in seconds for the webhook.
65
+ #
66
+ # @example
67
+ # WorkOS::Webhooks.verify_header(
68
+ # payload: "{"id": "wh_123","data":{"id":"directory_user_01FAEAJCR3ZBZ30D8BD1924TVG","state":"active","emails":[{"type":"work","value":"blair@foo-corp.com","primary":true}],"idp_id":"00u1e8mutl6wlH3lL4x7","object":"directory_user","username":"blair@foo-corp.com","last_name":"Lunchford","first_name":"Blair","directory_id":"directory_01F9M7F68PZP8QXP8G7X5QRHS7","raw_attributes":{"name":{"givenName":"Blair","familyName":"Lunchford","middleName":"Elizabeth","honorificPrefix":"Ms."},"title":"Developer Success Engineer","active":true,"emails":[{"type":"work","value":"blair@foo-corp.com","primary":true}],"groups":[],"locale":"en-US","schemas":["urn:ietf:params:scim:schemas:core:2.0:User","urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],"userName":"blair@foo-corp.com","addresses":[{"region":"CA","primary":true,"locality":"San Francisco","postalCode":"94016"}],"externalId":"00u1e8mutl6wlH3lL4x7","displayName":"Blair Lunchford","urn:ietf:params:scim:schemas:extension:enterprise:2.0:User":{"manager":{"value":"2","displayName":"Kate Chapman"},"division":"Engineering","department":"Customer Success"}}},"event":"dsync.user.created"}",
69
+ # sig_header: 't=1626125972272, v1=80f7ab7efadc306eb5797c588cee9410da9be4416782b497bf1e1bf4175fb928',
70
+ # secret: 'LJlTiC19GmCKWs8AE0IaOQcos',
71
+ # )
72
+ #
73
+ # => true
74
+ #
75
+ # @return Boolean
76
+ # rubocop:enable Layout/LineLength
60
77
  sig do
61
78
  params(
62
79
  payload: String,
@@ -105,6 +122,18 @@ module WorkOS
105
122
  end
106
123
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
107
124
 
125
+ # Extracts timestamp and signature hash from WorkOS-Signature header
126
+ #
127
+ # @param [String] sig_header The signature from the webhook sent by WorkOS.
128
+ #
129
+ # @example
130
+ # WorkOS::Webhooks.get_timestamp_and_signature_hash(
131
+ # sig_header: 't=1626125972272, v1=80f7ab7efadc306eb5797c588cee9410da9be4416782b497bf1e1bf4175fb928',
132
+ # )
133
+ #
134
+ # => ['1626125972272', '80f7ab7efadc306eb5797c588cee9410da9be4416782b497bf1e1bf4175fb928']
135
+ #
136
+ # @return Array
108
137
  sig do
109
138
  params(
110
139
  sig_header: String,
@@ -127,6 +156,24 @@ module WorkOS
127
156
  [timestamp, signature_hash]
128
157
  end
129
158
 
159
+ # Computes expected signature
160
+ # rubocop:disable Layout/LineLength
161
+ #
162
+ # @param [String] timestamp The timestamp from the webhook signature.
163
+ # @param [String] payload The payload from the webhook sent by WorkOS. This is the RAW_POST_DATA of the request.
164
+ # @param [String] secret The webhook secret from the WorkOS dashboard.
165
+ #
166
+ # @example
167
+ # WorkOS::Webhooks.compute_signature(
168
+ # timestamp: '1626125972272',
169
+ # payload: "{"id": "wh_123","data":{"id":"directory_user_01FAEAJCR3ZBZ30D8BD1924TVG","state":"active","emails":[{"type":"work","value":"blair@foo-corp.com","primary":true}],"idp_id":"00u1e8mutl6wlH3lL4x7","object":"directory_user","username":"blair@foo-corp.com","last_name":"Lunchford","first_name":"Blair","directory_id":"directory_01F9M7F68PZP8QXP8G7X5QRHS7","raw_attributes":{"name":{"givenName":"Blair","familyName":"Lunchford","middleName":"Elizabeth","honorificPrefix":"Ms."},"title":"Developer Success Engineer","active":true,"emails":[{"type":"work","value":"blair@foo-corp.com","primary":true}],"groups":[],"locale":"en-US","schemas":["urn:ietf:params:scim:schemas:core:2.0:User","urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],"userName":"blair@foo-corp.com","addresses":[{"region":"CA","primary":true,"locality":"San Francisco","postalCode":"94016"}],"externalId":"00u1e8mutl6wlH3lL4x7","displayName":"Blair Lunchford","urn:ietf:params:scim:schemas:extension:enterprise:2.0:User":{"manager":{"value":"2","displayName":"Kate Chapman"},"division":"Engineering","department":"Customer Success"}}},"event":"dsync.user.created"}",
170
+ # secret: 'LJlTiC19GmCKWs8AE0IaOQcos',
171
+ # )
172
+ #
173
+ # => '80f7ab7efadc306eb5797c588cee9410da9be4416782b497bf1e1bf4175fb928'
174
+ #
175
+ # @return String
176
+ # rubocop:enable Layout/LineLength
130
177
  sig do
131
178
  params(
132
179
  timestamp: String,
data/lib/workos.rb CHANGED
@@ -39,6 +39,8 @@ module WorkOS
39
39
  autoload :Types, 'workos/types'
40
40
  autoload :Client, 'workos/client'
41
41
  autoload :Configuration, 'workos/configuration'
42
+ autoload :AuditLogExport, 'workos/audit_log_export'
43
+ autoload :AuditLogs, 'workos/audit_logs'
42
44
  autoload :AuditTrail, 'workos/audit_trail'
43
45
  autoload :Connection, 'workos/connection'
44
46
  autoload :DirectorySync, 'workos/directory_sync'
@@ -30,7 +30,7 @@ module Rainbow
30
30
  sig { returns(Integer) }
31
31
  attr_reader :num
32
32
 
33
- sig { params(ground: Symbol, num: Integer).returns(Indexed) }
33
+ sig { params(ground: Symbol, num: Integer).void }
34
34
  def initialize(ground, num); end
35
35
 
36
36
  sig { returns(T::Array[Integer]) }
@@ -46,7 +46,7 @@ module Rainbow
46
46
  sig { returns(String) }
47
47
  def self.valid_names; end
48
48
 
49
- sig { params(ground: Symbol, name: Symbol).returns(Named) }
49
+ sig { params(ground: Symbol, name: Symbol).void }
50
50
  def initialize(ground, name); end
51
51
  end
52
52
 
@@ -57,7 +57,7 @@ module Rainbow
57
57
  sig { params(value: Numeric).returns(Integer) }
58
58
  def to_ansi_domain(value); end
59
59
 
60
- sig { params(ground: Symbol, values: Integer).returns(RGB) }
60
+ sig { params(ground: Symbol, values: Integer).void }
61
61
  def initialize(ground, *values); end
62
62
 
63
63
  sig { returns(T::Array[Integer]) }
@@ -73,7 +73,7 @@ module Rainbow
73
73
  sig { returns(String) }
74
74
  def self.valid_names; end
75
75
 
76
- sig { params(ground: Symbol, name: Symbol).returns(X11Named) }
76
+ sig { params(ground: Symbol, name: Symbol).void }
77
77
  def initialize(ground, name); end
78
78
  end
79
79
  end
@@ -260,7 +260,7 @@ module Rainbow
260
260
  sig { returns(T::Boolean) }
261
261
  attr_accessor :enabled
262
262
 
263
- sig { params(enabled: T::Boolean).returns(Wrapper) }
263
+ sig { params(enabled: T::Boolean).void }
264
264
  def initialize(enabled = true); end
265
265
 
266
266
  sig { params(string: String).returns(T.any(Rainbow::Presenter, Rainbow::NullPresenter)) }
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ describe WorkOS::AuditLogs do
5
+ it_behaves_like 'client'
6
+
7
+ before do
8
+ WorkOS.configure do |config|
9
+ config.key = 'example_api_key'
10
+ end
11
+ end
12
+
13
+ describe '.create_event' do
14
+ context 'with valid event payload' do
15
+ let(:valid_event) do
16
+ {
17
+ action: 'user.signed_in',
18
+ occurred_at: '2022-08-22T15:04:19.704Z',
19
+ actor: {
20
+ id: 'user_123',
21
+ type: 'user',
22
+ name: 'User',
23
+ metadata: {
24
+ foo: 'bar',
25
+ },
26
+ },
27
+ targets: [{
28
+ id: 'team_123',
29
+ type: 'team',
30
+ name: 'Team',
31
+ metadata: {
32
+ foo: 'bar',
33
+ },
34
+ }],
35
+ context: {
36
+ location: '1.1.1.1',
37
+ user_agent: 'Mozilla',
38
+ },
39
+ }
40
+ end
41
+
42
+ context 'with idempotency key' do
43
+ it 'creates an event' do
44
+ VCR.use_cassette 'audit_logs/create_event_custom_idempotency_key', match_requests_on: %i[path body] do
45
+ response = described_class.create_event(
46
+ organization: 'org_123',
47
+ event: valid_event,
48
+ idempotency_key: 'idempotency_key',
49
+ )
50
+
51
+ expect(response).to eq T::Private::Types::Void::VOID
52
+ end
53
+ end
54
+ end
55
+
56
+ context 'without idempotency key' do
57
+ it 'creates an event' do
58
+ VCR.use_cassette 'audit_logs/create_event', match_requests_on: %i[path body] do
59
+ response = described_class.create_event(
60
+ organization: 'org_123',
61
+ event: valid_event,
62
+ )
63
+
64
+ expect(response).to eq T::Private::Types::Void::VOID
65
+ end
66
+ end
67
+ end
68
+
69
+ context 'with invalid event' do
70
+ it 'returns error' do
71
+ VCR.use_cassette 'audit_logs/create_event_invalid', match_requests_on: %i[path body] do
72
+ described_class.create_event(
73
+ organization: 'org_123',
74
+ event: valid_event,
75
+ )
76
+ rescue WorkOS::InvalidRequestError => e
77
+ expect(
78
+ e.message,
79
+ ).to eq 'Status 400, Invalid Audit Log event - request ID: 1cf9b8e7-5910-4a6d-a333-46bcf841422e'
80
+ expect(e.code).to eq 'invalid_audit_log'
81
+ expect(e.errors.count).to eq 1
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ describe '.create_export' do
89
+ context 'without filters applied' do
90
+ it 'creates an event' do
91
+ VCR.use_cassette 'audit_logs/create_export', match_requests_on: %i[path body] do
92
+ audit_log_export = described_class.create_export(
93
+ organization: 'org_123',
94
+ range_start: '2022-06-22T15:04:19.704Z',
95
+ range_end: '2022-08-22T15:04:19.704Z',
96
+ )
97
+
98
+ expect(audit_log_export).to have_attributes(
99
+ object: 'audit_log_export',
100
+ id: 'audit_log_export_123',
101
+ state: 'pending',
102
+ url: nil,
103
+ created_at: '2022-08-22T15:04:19.704Z',
104
+ updated_at: '2022-08-22T15:04:19.704Z',
105
+ )
106
+ end
107
+ end
108
+ end
109
+
110
+ context 'with filters applied' do
111
+ it 'creates an export' do
112
+ VCR.use_cassette 'audit_logs/create_export_with_filters', match_requests_on: %i[path body] do
113
+ audit_log_export = described_class.create_export(
114
+ organization: 'org_123',
115
+ range_start: '2022-06-22T15:04:19.704Z',
116
+ range_end: '2022-08-22T15:04:19.704Z',
117
+ actions: ['user.signed_in'],
118
+ actors: ['Jon Smith'],
119
+ targets: %w[user team],
120
+ )
121
+
122
+ expect(audit_log_export.object).to eq 'audit_log_export'
123
+ expect(audit_log_export.id).to eq 'audit_log_export_123'
124
+ expect(audit_log_export.state).to eq 'pending'
125
+ expect(audit_log_export.url).to eq nil
126
+ expect(audit_log_export.created_at).to eq '2022-08-22T15:04:19.704Z'
127
+ expect(audit_log_export.updated_at).to eq '2022-08-22T15:04:19.704Z'
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ describe '.get_export' do
134
+ it 'returns an export' do
135
+ VCR.use_cassette 'audit_logs/get_export', match_requests_on: %i[path] do
136
+ audit_log_export = described_class.get_export(
137
+ id: 'audit_log_export_123',
138
+ )
139
+
140
+ expect(audit_log_export.object).to eq 'audit_log_export'
141
+ expect(audit_log_export.id).to eq 'audit_log_export_123'
142
+ expect(audit_log_export.state).to eq 'ready'
143
+ expect(audit_log_export.url).to eq 'https://audit-logs.com/download.csv'
144
+ expect(audit_log_export.created_at).to eq '2022-08-22T15:04:19.704Z'
145
+ expect(audit_log_export.updated_at).to eq '2022-08-22T15:04:19.704Z'
146
+ end
147
+ end
148
+ end
149
+ end