Class: Mihari::Rule
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
#normalize_falsepositive, #valid_falsepositive?
Methods inherited from Service
call, #result, result
Constructor Details
#initialize(**data) ⇒ Rule
21
22
23
24
25
26
27
28
29
|
# File 'lib/mihari/rule.rb', line 21
def initialize(**data)
super()
@data = data.deep_symbolize_keys
@errors = nil
@base_time = Time.now.utc
validate!
end
|
Instance Attribute Details
#base_time ⇒ Time
14
15
16
|
# File 'lib/mihari/rule.rb', line 14
def base_time
@base_time
end
|
#data ⇒ Hash
8
9
10
|
# File 'lib/mihari/rule.rb', line 8
def data
@data
end
|
#errors ⇒ Array?
11
12
13
|
# File 'lib/mihari/rule.rb', line 11
def errors
@errors
end
|
Class Method Details
270
271
272
|
# File 'lib/mihari/rule.rb', line 270
def from_model(model)
new(**model.data)
end
|
Load rule from YAML string
260
261
262
263
|
# File 'lib/mihari/rule.rb', line 260
def from_yaml(yaml)
data = YAML.safe_load(ERB.new(yaml).result, permitted_classes: [Date, Symbol])
new(**data)
end
|
Instance Method Details
#[](key) ⇒ Object
40
41
42
|
# File 'lib/mihari/rule.rb', line 40
def [](key)
data key.to_sym
end
|
#artifact_ttl ⇒ Integer?
126
127
128
|
# File 'lib/mihari/rule.rb', line 126
def artifact_ttl
data[:artifact_ttl]
end
|
Returns a list of artifacts matched with queries/analyzers (with the rule ID)
135
136
137
138
139
140
141
142
143
|
# File 'lib/mihari/rule.rb', line 135
def artifacts
analyzer_results.flat_map do |result|
artifacts = result.value!
artifacts.map do |artifact|
artifact.rule_id = id
artifact
end
end
end
|
188
189
190
191
192
193
194
|
# File 'lib/mihari/rule.rb', line 188
def bulk_emit
return [] if enriched_artifacts.empty?
Parallel.map(emitters) do |emitter|
emitter.result(enriched_artifacts).value_or nil
end.compact
end
|
Set artifacts & run emitters in parallel
201
202
203
204
205
206
207
208
209
|
# File 'lib/mihari/rule.rb', line 201
def call
analyzers
emitters
alert_or_something = bulk_emit
alert_or_something.find { |res| res.is_a?(Mihari::Models::Alert) }
end
|
#created_on ⇒ Date?
89
90
91
|
# File 'lib/mihari/rule.rb', line 89
def created_on
data[:created_on]
end
|
#data_types ⇒ Array<String>
82
83
84
|
# File 'lib/mihari/rule.rb', line 82
def data_types
data[:data_types]
end
|
#description ⇒ String
61
62
63
|
# File 'lib/mihari/rule.rb', line 61
def description
data[:description]
end
|
#diff? ⇒ Boolean
234
235
236
237
238
239
|
# File 'lib/mihari/rule.rb', line 234
def diff?
model = Mihari::Models::Rule.find(id)
model.data != diff_comparable_data
rescue ActiveRecord::RecordNotFound
false
end
|
176
177
178
179
180
181
|
# File 'lib/mihari/rule.rb', line 176
def enriched_artifacts
@enriched_artifacts ||= Parallel.map(unique_artifacts) do |artifact|
enrichers.each { |enricher| artifact.enrich_by_enricher enricher }
artifact
end
end
|
#errors? ⇒ Boolean
34
35
36
37
38
|
# File 'lib/mihari/rule.rb', line 34
def errors?
return false if @errors.nil?
!@errors.empty?
end
|
#exists? ⇒ Boolean
244
245
246
|
# File 'lib/mihari/rule.rb', line 244
def exists?
Mihari::Models::Rule.exists? id
end
|
#falsepositives ⇒ Array<String, RegExp>
119
120
121
|
# File 'lib/mihari/rule.rb', line 119
def falsepositives
@falsepositives ||= data[:falsepositives].map { |fp| normalize_falsepositive fp }
end
|
#id ⇒ String
47
48
49
|
# File 'lib/mihari/rule.rb', line 47
def id
data[:id]
end
|
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
# File 'lib/mihari/rule.rb', line 214
def model
Mihari::Models::Rule.find(id).tap do |rule|
rule.title = title
rule.description = description
rule.data = data
rule.taggings = taggings
end
rescue ActiveRecord::RecordNotFound
Mihari::Models::Rule.new(
id: id,
title: title,
description: description,
data: data,
taggings: taggings
)
end
|
Normalize artifacts
-
Reject invalid artifacts (for just in case)
-
Select artifacts with allowed data types
-
Reject artifacts with false positive values
-
Set rule ID
154
155
156
157
158
|
# File 'lib/mihari/rule.rb', line 154
def normalized_artifacts
valid_artifacts = artifacts.uniq(&:data).select(&:valid?)
date_type_allowed_artifacts = valid_artifacts.select { |artifact| data_types.include? artifact.data_type }
date_type_allowed_artifacts.reject { |artifact| falsepositive? artifact.data }
end
|
#queries ⇒ Array<Hash>
75
76
77
|
# File 'lib/mihari/rule.rb', line 75
def queries
data[:queries]
end
|
112
113
114
|
# File 'lib/mihari/rule.rb', line 112
def taggings
tags.map { |tag| Models::Tagging.find_or_create_by(tag_id: tag.id, rule_id: id) }
end
|
103
104
105
106
107
|
# File 'lib/mihari/rule.rb', line 103
def tags
data[:tags].uniq.filter_map do |name|
Models::Tag.find_or_create_by(name: name)
end
end
|
#title ⇒ String
54
55
56
|
# File 'lib/mihari/rule.rb', line 54
def title
data[:title]
end
|
Uniquify artifacts (assure rule level uniqueness)
165
166
167
168
169
|
# File 'lib/mihari/rule.rb', line 165
def unique_artifacts
normalized_artifacts.select do |artifact|
artifact.unique?(base_time: base_time, artifact_ttl: artifact_ttl)
end
end
|
#update_or_create ⇒ Object
248
249
250
|
# File 'lib/mihari/rule.rb', line 248
def update_or_create
model.save
end
|
#updated_on ⇒ Date?
96
97
98
|
# File 'lib/mihari/rule.rb', line 96
def updated_on
data[:updated_on]
end
|
#yaml ⇒ String
68
69
70
|
# File 'lib/mihari/rule.rb', line 68
def yaml
data.deep_stringify_keys.to_yaml
end
|