smplkit 3.0.95 → 3.0.97
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/lib/smplkit/account/client.rb +128 -0
- data/lib/smplkit/account/models.rb +71 -0
- data/lib/smplkit/api_support.rb +91 -0
- data/lib/smplkit/audit/buffer.rb +3 -1
- data/lib/smplkit/audit/categories.rb +21 -10
- data/lib/smplkit/audit/client.rb +18 -9
- data/lib/smplkit/audit/event_types.rb +26 -10
- data/lib/smplkit/audit/events.rb +93 -17
- data/lib/smplkit/{management/audit.rb → audit/forwarders.rb} +93 -85
- data/lib/smplkit/audit/models.rb +86 -32
- data/lib/smplkit/audit/resource_types.rb +21 -9
- data/lib/smplkit/buffers.rb +250 -0
- data/lib/smplkit/client.rb +161 -70
- data/lib/smplkit/config/client.rb +874 -186
- data/lib/smplkit/config/helpers.rb +44 -6
- data/lib/smplkit/config/models.rb +114 -7
- data/lib/smplkit/config_resolution.rb +17 -9
- data/lib/smplkit/errors.rb +14 -3
- data/lib/smplkit/flags/client.rb +602 -116
- data/lib/smplkit/flags/models.rb +110 -8
- data/lib/smplkit/flags/types.rb +8 -9
- data/lib/smplkit/jobs/client.rb +306 -0
- data/lib/smplkit/jobs/models.rb +47 -18
- data/lib/smplkit/logging/client.rb +755 -191
- data/lib/smplkit/logging/helpers.rb +5 -1
- data/lib/smplkit/logging/levels.rb +3 -1
- data/lib/smplkit/logging/models.rb +163 -6
- data/lib/smplkit/logging/normalize.rb +3 -1
- data/lib/smplkit/logging/resolution.rb +4 -4
- data/lib/smplkit/logging/sources.rb +1 -1
- data/lib/smplkit/platform/client.rb +597 -0
- data/lib/smplkit/platform/models.rb +282 -0
- data/lib/smplkit/{management → platform}/types.rb +21 -4
- data/lib/smplkit/transport.rb +103 -0
- data/lib/smplkit/ws.rb +1 -1
- data/lib/smplkit.rb +18 -6
- metadata +11 -7
- data/lib/smplkit/management/buffer.rb +0 -198
- data/lib/smplkit/management/client.rb +0 -1074
- data/lib/smplkit/management/jobs.rb +0 -226
- data/lib/smplkit/management/models.rb +0 -178
|
@@ -1,44 +1,42 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# SIEM forwarder CRUD for the Smpl Audit client.
|
|
4
|
+
#
|
|
5
|
+
# Forwarders are part of the single unified audit surface — there is no
|
|
6
|
+
# runtime/management split for audit (see +Smplkit::Audit::AuditClient+). This
|
|
7
|
+
# file holds the forwarder CRUD sub-client that the unified +AuditClient+
|
|
8
|
+
# exposes as +.forwarders+:
|
|
9
|
+
#
|
|
10
|
+
# * +ForwardersClient+ — +forwarders.new/get/list/save/delete+
|
|
11
|
+
#
|
|
12
|
+
# The forwarder model classes (+Forwarder+, +ForwarderEnvironment+, …) live in
|
|
13
|
+
# +lib/smplkit/audit/models.rb+.
|
|
3
14
|
module Smplkit
|
|
4
|
-
module
|
|
5
|
-
#
|
|
15
|
+
module Audit
|
|
16
|
+
# Surface for +client.audit.forwarders.*+ — manage the customer's
|
|
17
|
+
# configured SIEM forwarders.
|
|
6
18
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
attr_reader :forwarders
|
|
13
|
-
|
|
14
|
-
def initialize(api_client)
|
|
15
|
-
@forwarders = ForwardersNamespace.new(
|
|
16
|
-
SmplkitGeneratedClient::Audit::ForwardersApi.new(api_client)
|
|
17
|
-
)
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# +mgmt.audit.forwarders.*+ — manage the customer's configured SIEM
|
|
22
|
-
# forwarders.
|
|
23
|
-
#
|
|
24
|
-
# The active-record entry point is {#new_forwarder}: instantiate a
|
|
25
|
-
# draft, mutate fields, then call {Smplkit::Audit::Forwarder#save}.
|
|
26
|
-
# The namespace exposes {#list}, {#get}, and {#delete} directly; the
|
|
27
|
-
# +_create_forwarder+ / +_update_forwarder+ helpers are private and
|
|
28
|
-
# invoked by {Smplkit::Audit::Forwarder#save}.
|
|
29
|
-
class ForwardersNamespace
|
|
19
|
+
# The active-record entry point is {#new}: instantiate a draft, mutate
|
|
20
|
+
# fields, then call {Smplkit::Audit::Forwarder#save}. The client exposes
|
|
21
|
+
# {#list}, {#get}, and {#delete} directly; the +_create_forwarder+ /
|
|
22
|
+
# +_update_forwarder+ helpers are invoked by {Smplkit::Audit::Forwarder#save}.
|
|
23
|
+
class ForwardersClient
|
|
30
24
|
def initialize(api)
|
|
31
25
|
@api = api
|
|
32
26
|
end
|
|
33
27
|
|
|
34
|
-
# Construct an unsaved {Smplkit::Audit::Forwarder} bound to this
|
|
35
|
-
#
|
|
28
|
+
# Construct an unsaved {Smplkit::Audit::Forwarder} bound to this client.
|
|
29
|
+
# Call +#save+ on the returned instance to persist.
|
|
36
30
|
#
|
|
37
|
-
# @param
|
|
31
|
+
# @param id [String] Caller-supplied unique identifier (the forwarder's
|
|
32
|
+
# key). Unique within the account; immutable. The audit service returns
|
|
33
|
+
# 409 if another live forwarder already uses this id.
|
|
34
|
+
# @param name [String] Display name. Defaults to +id+ when not supplied.
|
|
38
35
|
# @param forwarder_type [String] One of {Smplkit::Audit::ForwarderType::VALUES}.
|
|
39
36
|
# @param configuration [Smplkit::Audit::HttpConfiguration] Destination
|
|
40
|
-
# request configuration.
|
|
41
|
-
#
|
|
37
|
+
# request configuration. Header values often carry credentials and are
|
|
38
|
+
# returned in plaintext on reads, so a get-mutate-put round-trip
|
|
39
|
+
# preserves them without re-entering secrets.
|
|
42
40
|
# @param environments [Hash{String => Smplkit::Audit::ForwarderEnvironment, Hash}, nil]
|
|
43
41
|
# Per-environment overrides keyed by environment key (e.g.
|
|
44
42
|
# +"production"+). A forwarder delivers in an environment only when that
|
|
@@ -56,11 +54,9 @@ module Smplkit
|
|
|
56
54
|
# @param filter [Hash, nil] Optional JSON Logic filter; events that don't
|
|
57
55
|
# match are recorded as +filtered_out+ deliveries.
|
|
58
56
|
# @param transform [Object, nil] Optional template applied to each event
|
|
59
|
-
# before delivery.
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
# +TransformType::JSONATA+, +transform+ must be a +String+ (the JSONata
|
|
63
|
-
# expression).
|
|
57
|
+
# before delivery. Must be paired with a non-nil +transform_type+; when
|
|
58
|
+
# +transform_type+ is +TransformType::JSONATA+, +transform+ must be a
|
|
59
|
+
# +String+ (the JSONata expression).
|
|
64
60
|
# @param transform_type [String, nil] Engine that evaluates +transform+ —
|
|
65
61
|
# one of {Smplkit::Audit::TransformType::VALUES}. Must be paired with a
|
|
66
62
|
# non-nil +transform+.
|
|
@@ -68,12 +64,12 @@ module Smplkit
|
|
|
68
64
|
# nil or both set, or when +transform_type+ is +JSONATA+ and +transform+
|
|
69
65
|
# is not a +String+.
|
|
70
66
|
# @return [Smplkit::Audit::Forwarder]
|
|
71
|
-
def
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
67
|
+
def new(id, forwarder_type:, configuration:, name: nil,
|
|
68
|
+
environments: nil, description: nil,
|
|
69
|
+
forward_smplkit_events: false,
|
|
70
|
+
filter: nil, transform: nil, transform_type: nil)
|
|
71
|
+
Forwarder.send(:validate_transform_pair!, transform, transform_type)
|
|
72
|
+
Forwarder.new(
|
|
77
73
|
self,
|
|
78
74
|
id: id,
|
|
79
75
|
name: name || id,
|
|
@@ -90,42 +86,50 @@ module Smplkit
|
|
|
90
86
|
|
|
91
87
|
# List forwarders for the authenticated account.
|
|
92
88
|
#
|
|
93
|
-
# Offset paginated
|
|
94
|
-
#
|
|
95
|
-
# populate +total+ and +total_pages+ in the returned +pagination+
|
|
96
|
-
# block (costs an extra COUNT query server-side).
|
|
89
|
+
# Offset paginated: pass +page_number+ (1-based) and +page_size+
|
|
90
|
+
# (default 1000, max 1000).
|
|
97
91
|
#
|
|
98
|
-
# @
|
|
92
|
+
# @param forwarder_type [String, nil] Restrict the listing to forwarders of
|
|
93
|
+
# this {Smplkit::Audit::ForwarderType}. Omit to list every type.
|
|
94
|
+
# @param page_number [Integer, nil] 1-based page index. Omit for the first
|
|
95
|
+
# page.
|
|
96
|
+
# @param page_size [Integer, nil] Maximum number of forwarders to return in
|
|
97
|
+
# this page (default 1000, max 1000).
|
|
98
|
+
# @param meta_total [Boolean, nil] When +true+, populate +total+ and
|
|
99
|
+
# +total_pages+ in the returned page's +pagination+ block (costs an extra
|
|
100
|
+
# count server-side). Omit to skip it.
|
|
101
|
+
# @return [ForwarderListPage] A page of the matching forwarders.
|
|
99
102
|
def list(forwarder_type: nil, page_number: nil, page_size: nil, meta_total: nil)
|
|
100
103
|
opts = {}
|
|
101
|
-
opts[:filter_forwarder_type] =
|
|
104
|
+
opts[:filter_forwarder_type] = ForwarderType.coerce(forwarder_type) if forwarder_type
|
|
102
105
|
opts[:page_number] = page_number if page_number
|
|
103
106
|
opts[:page_size] = page_size if page_size
|
|
104
107
|
opts[:meta_total] = meta_total unless meta_total.nil?
|
|
105
108
|
|
|
106
|
-
resp =
|
|
107
|
-
forwarders = (resp.data || []).map
|
|
108
|
-
|
|
109
|
-
end
|
|
110
|
-
ForwarderListPage.new(forwarders, Smplkit::Audit.extract_pagination(resp.meta))
|
|
109
|
+
resp = Audit.call_api { @api.list_forwarders(opts) }
|
|
110
|
+
forwarders = (resp.data || []).map { |r| Forwarder.from_resource(r, client: self) }
|
|
111
|
+
ForwarderListPage.new(forwarders, Audit.extract_pagination(resp.meta))
|
|
111
112
|
end
|
|
112
113
|
|
|
113
|
-
# Fetch a single forwarder by id. The returned instance is bound to
|
|
114
|
-
#
|
|
114
|
+
# Fetch a single forwarder by id. The returned instance is bound to this
|
|
115
|
+
# client, so +forwarder.save+ and +forwarder.delete+ work. Header values
|
|
116
|
+
# come back in plaintext, so mutating the returned forwarder and calling
|
|
117
|
+
# +save+ preserves them without re-entering secrets.
|
|
115
118
|
#
|
|
116
|
-
# @param forwarder_id [String]
|
|
117
|
-
# @return [Smplkit::Audit::Forwarder]
|
|
119
|
+
# @param forwarder_id [String] The forwarder's id (key).
|
|
120
|
+
# @return [Smplkit::Audit::Forwarder] The matching forwarder, bound to this client.
|
|
121
|
+
# @raise [Smplkit::NotFoundError] If no live forwarder with that id exists.
|
|
118
122
|
def get(forwarder_id)
|
|
119
|
-
resp =
|
|
120
|
-
|
|
123
|
+
resp = Audit.call_api { @api.get_forwarder(forwarder_id) }
|
|
124
|
+
Forwarder.from_resource(resp.data, client: self)
|
|
121
125
|
end
|
|
122
126
|
|
|
123
|
-
#
|
|
127
|
+
# Delete a forwarder.
|
|
124
128
|
#
|
|
125
129
|
# @param forwarder_id [String]
|
|
126
130
|
# @return [nil]
|
|
127
131
|
def delete(forwarder_id)
|
|
128
|
-
|
|
132
|
+
Audit.call_api { @api.delete_forwarder(forwarder_id) }
|
|
129
133
|
nil
|
|
130
134
|
end
|
|
131
135
|
|
|
@@ -136,22 +140,21 @@ module Smplkit
|
|
|
136
140
|
raise ArgumentError, "Forwarder.id is required on create (caller-supplied key)"
|
|
137
141
|
end
|
|
138
142
|
|
|
139
|
-
resp =
|
|
140
|
-
|
|
143
|
+
resp = Audit.call_api { @api.create_forwarder(build_create_body(forwarder)) }
|
|
144
|
+
Forwarder.from_resource(resp.data, client: self)
|
|
141
145
|
end
|
|
142
146
|
|
|
143
|
-
# @api private — Full-replace PUT for an existing forwarder. Called
|
|
144
|
-
#
|
|
147
|
+
# @api private — Full-replace PUT for an existing forwarder. Called by
|
|
148
|
+
# {Smplkit::Audit::Forwarder#save} on instances with +created_at+.
|
|
145
149
|
#
|
|
146
|
-
# Header values
|
|
147
|
-
#
|
|
148
|
-
#
|
|
149
|
-
# round-trip them.
|
|
150
|
+
# Header values come back in plaintext on the GET path, so a fetched
|
|
151
|
+
# forwarder round-trips through this full-replace PUT with its header
|
|
152
|
+
# values intact — no need to re-enter secrets.
|
|
150
153
|
def _update_forwarder(forwarder)
|
|
151
154
|
raise ArgumentError, "cannot update a Forwarder with no id" if forwarder.id.nil?
|
|
152
155
|
|
|
153
|
-
resp =
|
|
154
|
-
|
|
156
|
+
resp = Audit.call_api { @api.update_forwarder(forwarder.id, build_body(forwarder)) }
|
|
157
|
+
Forwarder.from_resource(resp.data, client: self)
|
|
155
158
|
end
|
|
156
159
|
|
|
157
160
|
private
|
|
@@ -160,16 +163,15 @@ module Smplkit
|
|
|
160
163
|
#
|
|
161
164
|
# Accepts either {Smplkit::Audit::ForwarderEnvironment} values or plain
|
|
162
165
|
# hashes (+{ enabled: true, configuration: HttpConfiguration.new(...) }+)
|
|
163
|
-
# so callers can use the lightweight hash form without importing the
|
|
164
|
-
# model.
|
|
166
|
+
# so callers can use the lightweight hash form without importing the model.
|
|
165
167
|
def normalize_environments(environments)
|
|
166
168
|
return {} if environments.nil? || environments.empty?
|
|
167
169
|
|
|
168
170
|
environments.each_with_object({}) do |(env_key, value), out|
|
|
169
|
-
out[env_key.to_s] = if value.is_a?(
|
|
171
|
+
out[env_key.to_s] = if value.is_a?(ForwarderEnvironment)
|
|
170
172
|
value
|
|
171
173
|
else
|
|
172
|
-
|
|
174
|
+
ForwarderEnvironment.new(
|
|
173
175
|
enabled: value[:enabled] || value["enabled"] || false,
|
|
174
176
|
configuration: value[:configuration] || value["configuration"]
|
|
175
177
|
)
|
|
@@ -186,31 +188,31 @@ module Smplkit
|
|
|
186
188
|
(environments || {}).each_with_object({}) do |(env_key, env), out|
|
|
187
189
|
out[env_key.to_s] = SmplkitGeneratedClient::Audit::ForwarderEnvironment.new(
|
|
188
190
|
enabled: env.enabled,
|
|
189
|
-
configuration: env.configuration.nil? ? nil :
|
|
191
|
+
configuration: env.configuration.nil? ? nil : HttpConfiguration.to_wire(env.configuration)
|
|
190
192
|
)
|
|
191
193
|
end
|
|
192
194
|
end
|
|
193
195
|
|
|
194
196
|
def build_attrs(forwarder)
|
|
195
|
-
# The base
|
|
196
|
-
#
|
|
197
|
+
# The base +enabled+ is server-pinned false; we don't send it.
|
|
198
|
+
# Enablement travels entirely through +environments+.
|
|
197
199
|
SmplkitGeneratedClient::Audit::Forwarder.new(
|
|
198
200
|
name: forwarder.name,
|
|
199
201
|
description: forwarder.description,
|
|
200
|
-
forwarder_type:
|
|
202
|
+
forwarder_type: ForwarderType.coerce(forwarder.forwarder_type),
|
|
201
203
|
forward_smplkit_events: forwarder.forward_smplkit_events,
|
|
202
204
|
environments: environments_to_wire(forwarder.environments),
|
|
203
205
|
filter: forwarder.filter,
|
|
204
|
-
transform_type:
|
|
206
|
+
transform_type: TransformType.coerce(forwarder.transform_type),
|
|
205
207
|
transform: forwarder.transform,
|
|
206
|
-
configuration:
|
|
208
|
+
configuration: HttpConfiguration.to_wire(forwarder.configuration)
|
|
207
209
|
)
|
|
208
210
|
end
|
|
209
211
|
|
|
210
212
|
def build_create_body(forwarder)
|
|
211
|
-
# Create uses the distinct ForwarderCreateRequest envelope; the
|
|
212
|
-
#
|
|
213
|
-
#
|
|
213
|
+
# Create uses the distinct ForwarderCreateRequest envelope; the audit
|
|
214
|
+
# service requires data.id (the customer-supplied key) on create and
|
|
215
|
+
# 409s on conflict.
|
|
214
216
|
resource = SmplkitGeneratedClient::Audit::ForwarderCreateResource.new(
|
|
215
217
|
id: forwarder.id.to_s,
|
|
216
218
|
type: "forwarder",
|
|
@@ -230,13 +232,19 @@ module Smplkit
|
|
|
230
232
|
end
|
|
231
233
|
end
|
|
232
234
|
|
|
233
|
-
# A single page returned from {
|
|
235
|
+
# A single page returned from {ForwardersClient#list}.
|
|
234
236
|
#
|
|
235
237
|
# @!attribute [rw] forwarders
|
|
236
238
|
# @return [Array<Smplkit::Audit::Forwarder>] Forwarders in this page.
|
|
237
239
|
# @!attribute [rw] pagination
|
|
238
240
|
# @return [Hash] +meta.pagination+ block (+:page+, +:size+, and — only when
|
|
239
241
|
# the caller passed +meta_total: true+ — +:total+ / +:total_pages+).
|
|
240
|
-
ForwarderListPage = Struct.new(:forwarders, :pagination)
|
|
242
|
+
ForwarderListPage = Struct.new(:forwarders, :pagination) do
|
|
243
|
+
include Enumerable
|
|
244
|
+
|
|
245
|
+
def each(&) = forwarders.each(&)
|
|
246
|
+
def length = forwarders.length
|
|
247
|
+
alias_method :size, :length
|
|
248
|
+
end
|
|
241
249
|
end
|
|
242
250
|
end
|
data/lib/smplkit/audit/models.rb
CHANGED
|
@@ -8,6 +8,8 @@ module Smplkit
|
|
|
8
8
|
# failures route through {Smplkit::Errors.raise_for_status}, which
|
|
9
9
|
# emits +PaymentRequiredError+ / +NotFoundError+ / +ConflictError+
|
|
10
10
|
# / +ValidationError+ / +Error+ depending on the JSON:API body.
|
|
11
|
+
#
|
|
12
|
+
# @api private
|
|
11
13
|
def self.call_api
|
|
12
14
|
yield
|
|
13
15
|
rescue SmplkitGeneratedClient::Audit::ApiError => e
|
|
@@ -24,6 +26,8 @@ module Smplkit
|
|
|
24
26
|
# URL. Returns nil for non-string input or when the link carries
|
|
25
27
|
# no cursor parameter; trims trailing query params at the next
|
|
26
28
|
# ampersand so they don't leak into the token.
|
|
29
|
+
#
|
|
30
|
+
# @api private
|
|
27
31
|
def self.next_cursor(link)
|
|
28
32
|
return nil unless link.is_a?(String)
|
|
29
33
|
|
|
@@ -39,6 +43,8 @@ module Smplkit
|
|
|
39
43
|
# Returns a hash with +:page+/+:size+ (and +:total+/+:total_pages+ when
|
|
40
44
|
# the request opted into +meta[total]=true+). Always returns a hash so
|
|
41
45
|
# callers don't have to nil-check before reading individual keys.
|
|
46
|
+
#
|
|
47
|
+
# @api private
|
|
42
48
|
def self.extract_pagination(meta)
|
|
43
49
|
pagination = meta&.pagination
|
|
44
50
|
return {} if pagination.nil?
|
|
@@ -56,14 +62,16 @@ module Smplkit
|
|
|
56
62
|
# The audit read endpoints (events list, the resource_type / event_type /
|
|
57
63
|
# category discovery lists) accept an optional comma-separated
|
|
58
64
|
# +filter[environment]+ of real environment keys and/or the reserved
|
|
59
|
-
# +"smplkit"+ control-plane bucket
|
|
60
|
-
#
|
|
65
|
+
# +"smplkit"+ control-plane bucket. The wrapper takes an array of keys for
|
|
66
|
+
# an ergonomic surface and joins it here.
|
|
61
67
|
#
|
|
62
68
|
# +nil+ or an empty array (or one whose entries are all blank) returns
|
|
63
69
|
# +nil+ so the caller omits the query param entirely and behaves exactly
|
|
64
70
|
# as before — existing callers are byte-for-byte unchanged on the wire.
|
|
65
71
|
# +"smplkit"+ is passed through like any other key; it carries no special
|
|
66
72
|
# handling in the SDK.
|
|
73
|
+
#
|
|
74
|
+
# @api private
|
|
67
75
|
def self.join_environments(environments)
|
|
68
76
|
return nil if environments.nil?
|
|
69
77
|
|
|
@@ -71,12 +79,12 @@ module Smplkit
|
|
|
71
79
|
values.empty? ? nil : values.join(",")
|
|
72
80
|
end
|
|
73
81
|
|
|
74
|
-
# Supported SIEM forwarder destination types
|
|
82
|
+
# Supported SIEM forwarder destination types.
|
|
75
83
|
#
|
|
76
84
|
# Members are declared in alphabetical order. Customers pass these
|
|
77
|
-
# constants — or the equivalent string — to the
|
|
78
|
-
# +forwarders+
|
|
79
|
-
# before round-tripping to the wire.
|
|
85
|
+
# constants — or the equivalent string — to the forwarders surface
|
|
86
|
+
# (+client.audit.forwarders+); the wrapper validates membership via
|
|
87
|
+
# {coerce} before round-tripping to the wire.
|
|
80
88
|
module ForwarderType
|
|
81
89
|
DATADOG = "datadog"
|
|
82
90
|
ELASTIC = "elastic"
|
|
@@ -104,7 +112,7 @@ module Smplkit
|
|
|
104
112
|
end
|
|
105
113
|
end
|
|
106
114
|
|
|
107
|
-
# HTTP verb used by a forwarder's outbound delivery
|
|
115
|
+
# HTTP verb used by a forwarder's outbound delivery.
|
|
108
116
|
#
|
|
109
117
|
# Mirrors the audit spec's +HttpConfigurationMethod+ enum so the
|
|
110
118
|
# +HttpConfiguration#method+ field is constrained to a known value
|
|
@@ -135,11 +143,10 @@ module Smplkit
|
|
|
135
143
|
end
|
|
136
144
|
end
|
|
137
145
|
|
|
138
|
-
# Engine that evaluates a forwarder's +transform+ template
|
|
139
|
-
#
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
# public surface.
|
|
146
|
+
# Engine that evaluates a forwarder's +transform+ template.
|
|
147
|
+
# Only +JSONATA+ is supported today; the enum exists so the field is
|
|
148
|
+
# typed instead of accepting any string, and so additional engines
|
|
149
|
+
# can be added without breaking the public surface.
|
|
143
150
|
module TransformType
|
|
144
151
|
JSONATA = "JSONATA"
|
|
145
152
|
|
|
@@ -161,7 +168,7 @@ module Smplkit
|
|
|
161
168
|
end
|
|
162
169
|
end
|
|
163
170
|
|
|
164
|
-
# A single audit event as returned by the audit service
|
|
171
|
+
# A single audit event as returned by the audit service.
|
|
165
172
|
#
|
|
166
173
|
# @!attribute [rw] id
|
|
167
174
|
# @return [String] Server-assigned UUID for this event.
|
|
@@ -181,6 +188,11 @@ module Smplkit
|
|
|
181
188
|
# @return [String, nil] Customer-supplied free-form actor identifier — +nil+ when not provided.
|
|
182
189
|
# @!attribute [rw] actor_label
|
|
183
190
|
# @return [String, nil] Customer-supplied display label for the actor — typically a name or email.
|
|
191
|
+
# @!attribute [rw] category
|
|
192
|
+
# @return [String, nil] Free-form bucket label for the event — e.g.
|
|
193
|
+
# +"auth"+, +"billing"+, +"config-change"+. Stored exactly as supplied;
|
|
194
|
+
# drives the audit log's category filter and the +categories+ discovery
|
|
195
|
+
# listing ({Smplkit::Audit::AuditClient#categories}). +nil+ when not supplied.
|
|
184
196
|
# @!attribute [rw] data
|
|
185
197
|
# @return [Hash{String => Object}] Free-form per-event payload defined by the customer.
|
|
186
198
|
# @!attribute [rw] idempotency_key
|
|
@@ -196,7 +208,7 @@ module Smplkit
|
|
|
196
208
|
AuditEvent = Struct.new(
|
|
197
209
|
:id, :event_type, :resource_type, :resource_id,
|
|
198
210
|
:occurred_at, :created_at,
|
|
199
|
-
:actor_type, :actor_id, :actor_label,
|
|
211
|
+
:actor_type, :actor_id, :actor_label, :category,
|
|
200
212
|
:data, :idempotency_key, :do_not_forward, :environment,
|
|
201
213
|
keyword_init: true
|
|
202
214
|
) do
|
|
@@ -212,6 +224,7 @@ module Smplkit
|
|
|
212
224
|
actor_type: attrs.actor_type,
|
|
213
225
|
actor_id: attrs.actor_id,
|
|
214
226
|
actor_label: attrs.actor_label,
|
|
227
|
+
category: attrs.category,
|
|
215
228
|
data: Smplkit::Helpers.deep_stringify_keys(attrs.data || {}),
|
|
216
229
|
idempotency_key: attrs.idempotency_key,
|
|
217
230
|
do_not_forward: attrs.do_not_forward || false,
|
|
@@ -223,9 +236,9 @@ module Smplkit
|
|
|
223
236
|
# A distinct +resource_type+ slug seen for the account.
|
|
224
237
|
#
|
|
225
238
|
# The +id+ and +resource_type+ are the same value — JSON:API surfaces
|
|
226
|
-
# the customer-facing key as the resource id
|
|
227
|
-
#
|
|
228
|
-
#
|
|
239
|
+
# the customer-facing key as the resource id. The duplication keeps SDK
|
|
240
|
+
# consumers from having to dig into the id field when filtering UI
|
|
241
|
+
# controls; pick whichever name reads better in context.
|
|
229
242
|
#
|
|
230
243
|
# @!attribute [rw] id
|
|
231
244
|
# @return [String] JSON:API resource id (same as +resource_type+).
|
|
@@ -272,8 +285,8 @@ module Smplkit
|
|
|
272
285
|
#
|
|
273
286
|
# Same shape as {ResourceType}/{EventType} — +id+ and +category+ are the
|
|
274
287
|
# same value (JSON:API surfaces the customer-facing key as the resource
|
|
275
|
-
# id
|
|
276
|
-
#
|
|
288
|
+
# id). +created_at+ is the earliest sighting of this category for the
|
|
289
|
+
# account.
|
|
277
290
|
#
|
|
278
291
|
# @!attribute [rw] id
|
|
279
292
|
# @return [String] JSON:API resource id (same as +category+).
|
|
@@ -297,8 +310,8 @@ module Smplkit
|
|
|
297
310
|
# @!attribute [rw] name
|
|
298
311
|
# @return [String] Header name (e.g. +"Authorization"+, +"DD-API-KEY"+).
|
|
299
312
|
# @!attribute [rw] value
|
|
300
|
-
# @return [String] Header value
|
|
301
|
-
#
|
|
313
|
+
# @return [String] Header value. Returned in plaintext on reads, so a
|
|
314
|
+
# get-mutate-put round-trip preserves it without re-entering secrets.
|
|
302
315
|
HttpHeader = Struct.new(:name, :value, keyword_init: true)
|
|
303
316
|
|
|
304
317
|
# Forwarder destination HTTP request shape.
|
|
@@ -309,8 +322,9 @@ module Smplkit
|
|
|
309
322
|
# @return [String] Destination URL the audit service sends each event to.
|
|
310
323
|
# @!attribute [rw] headers
|
|
311
324
|
# @return [Array<HttpHeader>] Headers attached to every outbound request.
|
|
312
|
-
# Values carry credentials and are
|
|
313
|
-
#
|
|
325
|
+
# Values often carry credentials and are returned in plaintext on
|
|
326
|
+
# reads, so a get-mutate-put round-trip preserves them without
|
|
327
|
+
# re-entering secrets.
|
|
314
328
|
# @!attribute [rw] success_status
|
|
315
329
|
# @return [String] Status the destination must return for delivery to count
|
|
316
330
|
# as success — an exact code (+"200"+, +"204"+) or a class (+"2xx"+, +"4xx"+).
|
|
@@ -401,8 +415,8 @@ module Smplkit
|
|
|
401
415
|
# configuration that fully replaces the forwarder's base
|
|
402
416
|
# {Forwarder#configuration} for this environment. +nil+ (the default)
|
|
403
417
|
# inherits the base configuration. As with the base configuration,
|
|
404
|
-
# header values are plaintext on
|
|
405
|
-
#
|
|
418
|
+
# header values are returned in plaintext on reads, so a get-mutate-put
|
|
419
|
+
# round-trip preserves them without re-entering secrets.
|
|
406
420
|
ForwarderEnvironment = Struct.new(:enabled, :configuration, keyword_init: true) do
|
|
407
421
|
def initialize(enabled: false, configuration: nil)
|
|
408
422
|
super
|
|
@@ -422,12 +436,11 @@ module Smplkit
|
|
|
422
436
|
# A SIEM streaming forwarder configured on the customer's account.
|
|
423
437
|
#
|
|
424
438
|
# Active-record style: instantiate via
|
|
425
|
-
# +
|
|
439
|
+
# +client.audit.forwarders.new(...)+, mutate fields directly,
|
|
426
440
|
# and call {#save} to persist or {#delete} to remove. Header values in
|
|
427
|
-
# +configuration.headers+ are returned
|
|
428
|
-
#
|
|
429
|
-
#
|
|
430
|
-
# them client-side.
|
|
441
|
+
# +configuration.headers+ are returned in plaintext on reads, so fetching
|
|
442
|
+
# a forwarder, mutating it, and calling {#save} preserves its header
|
|
443
|
+
# values without re-entering secrets.
|
|
431
444
|
class Forwarder
|
|
432
445
|
# @return [String, nil] Caller-supplied unique identifier (key) for this
|
|
433
446
|
# forwarder. Unique within an account; immutable for the lifetime of
|
|
@@ -494,7 +507,7 @@ module Smplkit
|
|
|
494
507
|
# @return [String, nil] ISO-8601 timestamp of the most recent mutation.
|
|
495
508
|
attr_accessor :updated_at
|
|
496
509
|
|
|
497
|
-
# @return [String, nil]
|
|
510
|
+
# @return [String, nil] Deletion timestamp; +nil+ for live forwarders.
|
|
498
511
|
attr_accessor :deleted_at
|
|
499
512
|
|
|
500
513
|
# @return [Integer, nil] Monotonic version counter, bumped on every server-side write.
|
|
@@ -548,7 +561,7 @@ module Smplkit
|
|
|
548
561
|
end
|
|
549
562
|
alias save! save
|
|
550
563
|
|
|
551
|
-
#
|
|
564
|
+
# Delete this forwarder on the server.
|
|
552
565
|
#
|
|
553
566
|
# @return [nil]
|
|
554
567
|
def delete
|
|
@@ -558,6 +571,47 @@ module Smplkit
|
|
|
558
571
|
end
|
|
559
572
|
alias delete! delete
|
|
560
573
|
|
|
574
|
+
# Set this forwarder's destination configuration in memory.
|
|
575
|
+
#
|
|
576
|
+
# With +environment+ omitted, replaces the base {#configuration}. With
|
|
577
|
+
# +environment+ given, sets the per-environment override's configuration
|
|
578
|
+
# on {#environments}, creating the override entry if it doesn't exist yet
|
|
579
|
+
# (preserving any already-set +enabled+ on it). Call {#save} to persist.
|
|
580
|
+
def set_configuration(configuration, environment: nil)
|
|
581
|
+
if environment.nil?
|
|
582
|
+
@configuration = configuration
|
|
583
|
+
else
|
|
584
|
+
_environment_override(environment).configuration = configuration
|
|
585
|
+
end
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
# Set this forwarder's enablement in memory.
|
|
589
|
+
#
|
|
590
|
+
# With +environment+ omitted, sets the base {#enabled} (which the server
|
|
591
|
+
# pins false regardless — enablement is per-environment). With
|
|
592
|
+
# +environment+ given, sets the per-environment override's +enabled+ on
|
|
593
|
+
# {#environments}, creating the override entry if it doesn't exist yet
|
|
594
|
+
# (preserving any already-set +configuration+ on it). Call {#save} to
|
|
595
|
+
# persist.
|
|
596
|
+
def set_enabled(enabled, environment: nil)
|
|
597
|
+
if environment.nil?
|
|
598
|
+
@enabled = enabled
|
|
599
|
+
else
|
|
600
|
+
_environment_override(environment).enabled = enabled
|
|
601
|
+
end
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# Return the override for +environment+, creating an empty one if absent.
|
|
605
|
+
#
|
|
606
|
+
# The per-environment mutators reach through here so an existing
|
|
607
|
+
# override's other field is preserved when only one of +enabled+ /
|
|
608
|
+
# +configuration+ is being set.
|
|
609
|
+
#
|
|
610
|
+
# @api private
|
|
611
|
+
def _environment_override(environment)
|
|
612
|
+
@environments[environment] ||= ForwarderEnvironment.new
|
|
613
|
+
end
|
|
614
|
+
|
|
561
615
|
# @api private
|
|
562
616
|
def _apply(other)
|
|
563
617
|
@id = other.id
|
|
@@ -5,20 +5,32 @@ module Smplkit
|
|
|
5
5
|
# +client.audit.resource_types.list+ — distinct +resource_type+ slugs
|
|
6
6
|
# seen for the account.
|
|
7
7
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# account has accumulated. Sorted alphabetically; offset pagination
|
|
11
|
-
# (+page_number+ / +page_size+) per ADR-014.
|
|
8
|
+
# Response time is independent of how many years of events the account has
|
|
9
|
+
# accumulated. Sorted alphabetically; offset paginated.
|
|
12
10
|
class ResourceTypes
|
|
13
11
|
def initialize(api)
|
|
14
12
|
@api = api
|
|
15
13
|
end
|
|
16
14
|
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# the
|
|
20
|
-
#
|
|
21
|
-
# the
|
|
15
|
+
# List the distinct +resource_type+ slugs seen in the account.
|
|
16
|
+
#
|
|
17
|
+
# +environments+ scopes the listing to a set of environments: pass an
|
|
18
|
+
# array of environment keys and/or the reserved +"smplkit"+ control-plane
|
|
19
|
+
# bucket; the values are comma-joined into +filter[environment]+. Omitting
|
|
20
|
+
# it (or passing an empty array) leaves the filter off entirely.
|
|
21
|
+
#
|
|
22
|
+
# @param page_number [Integer, nil] 1-based page index. Omit for the first
|
|
23
|
+
# page.
|
|
24
|
+
# @param page_size [Integer, nil] Maximum number of slugs to return in this
|
|
25
|
+
# page.
|
|
26
|
+
# @param meta_total [Boolean, nil] When +true+, populate +total+ and
|
|
27
|
+
# +total_pages+ in the returned page's +pagination+ block (costs an extra
|
|
28
|
+
# count server-side). Omit to skip it.
|
|
29
|
+
# @param environments [Array<String>, nil] Environment keys and/or the
|
|
30
|
+
# reserved +"smplkit"+ control-plane bucket to scope the listing to. Omit
|
|
31
|
+
# to leave the filter off entirely.
|
|
32
|
+
# @return [Smplkit::Audit::ResourceTypeListPage] A page of the matching
|
|
33
|
+
# resource-type slugs.
|
|
22
34
|
def list(page_number: nil, page_size: nil, meta_total: nil, environments: nil)
|
|
23
35
|
opts = {}
|
|
24
36
|
opts[:page_number] = page_number if page_number
|