mihari 5.4.1 → 5.4.2
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/frontend/package-lock.json +145 -146
- data/frontend/package.json +8 -8
- data/frontend/src/swagger.yaml +306 -272
- data/lib/mihari/cli/alert.rb +11 -0
- data/lib/mihari/cli/main.rb +6 -1
- data/lib/mihari/commands/alert.rb +42 -0
- data/lib/mihari/commands/rule.rb +2 -2
- data/lib/mihari/commands/search.rb +20 -59
- data/lib/mihari/config.rb +1 -1
- data/lib/mihari/emitters/base.rb +1 -1
- data/lib/mihari/emitters/database.rb +2 -2
- data/lib/mihari/errors.rb +23 -2
- data/lib/mihari/http.rb +7 -1
- data/lib/mihari/schemas/alert.rb +14 -0
- data/lib/mihari/services/alert_proxy.rb +106 -0
- data/lib/mihari/services/alert_runner.rb +22 -0
- data/lib/mihari/services/{rule.rb → rule_proxy.rb} +10 -6
- data/lib/mihari/services/rule_runner.rb +49 -0
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/endpoints/alerts.rb +22 -0
- data/lib/mihari/web/endpoints/rules.rb +8 -8
- data/lib/mihari/web/public/assets/{index-61dc587c.js → index-4d7eda9f.js} +1 -1
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +29 -27
- data/lib/mihari.rb +6 -1
- data/mihari.gemspec +2 -3
- metadata +14 -23
- data/Steepfile +0 -31
data/lib/mihari/cli/main.rb
CHANGED
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
require "thor"
|
|
4
4
|
|
|
5
5
|
# Commands
|
|
6
|
+
require "mihari/commands/alert"
|
|
7
|
+
require "mihari/commands/database"
|
|
6
8
|
require "mihari/commands/search"
|
|
7
9
|
require "mihari/commands/version"
|
|
8
10
|
require "mihari/commands/web"
|
|
9
|
-
require "mihari/commands/database"
|
|
10
11
|
|
|
11
12
|
# CLIs
|
|
12
13
|
require "mihari/cli/base"
|
|
13
14
|
|
|
15
|
+
require "mihari/cli/alert"
|
|
14
16
|
require "mihari/cli/database"
|
|
15
17
|
require "mihari/cli/rule"
|
|
16
18
|
|
|
@@ -26,6 +28,9 @@ module Mihari
|
|
|
26
28
|
|
|
27
29
|
desc "rule", "Sub commands for rule"
|
|
28
30
|
subcommand "rule", Rule
|
|
31
|
+
|
|
32
|
+
desc "alert", "Sub commands for alert"
|
|
33
|
+
subcommand "alert", Alert
|
|
29
34
|
end
|
|
30
35
|
end
|
|
31
36
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mihari
|
|
4
|
+
module Commands
|
|
5
|
+
module Alert
|
|
6
|
+
class << self
|
|
7
|
+
def included(thor)
|
|
8
|
+
thor.class_eval do
|
|
9
|
+
desc "add [PATH]", "Add an alert"
|
|
10
|
+
#
|
|
11
|
+
# @param [String] path
|
|
12
|
+
#
|
|
13
|
+
def add(path)
|
|
14
|
+
Mihari::Database.with_db_connection do
|
|
15
|
+
proxy = Mihari::Services::AlertProxy.from_path(path)
|
|
16
|
+
proxy.validate!
|
|
17
|
+
|
|
18
|
+
runner = Mihari::Services::AlertRunner.new(proxy)
|
|
19
|
+
|
|
20
|
+
begin
|
|
21
|
+
alert = runner.run
|
|
22
|
+
rescue ActiveRecord::RecordNotFound => e
|
|
23
|
+
# if there is a ActiveRecord::RecordNotFound, output that error without the stack trace
|
|
24
|
+
Mihari.logger.error e.to_s
|
|
25
|
+
return
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if alert.nil?
|
|
29
|
+
Mihari.logger.info "There is no new artifact found"
|
|
30
|
+
return
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
data = Mihari::Entities::Alert.represent(alert)
|
|
34
|
+
puts JSON.pretty_generate(data.as_json)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/mihari/commands/rule.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Mihari
|
|
|
15
15
|
# @param [String] path
|
|
16
16
|
#
|
|
17
17
|
def validate(path)
|
|
18
|
-
rule = Services::
|
|
18
|
+
rule = Services::RuleProxy.from_path_or_id(path)
|
|
19
19
|
|
|
20
20
|
begin
|
|
21
21
|
rule.validate!
|
|
@@ -47,7 +47,7 @@ module Mihari
|
|
|
47
47
|
# @return [Mihari::Services::Rule]
|
|
48
48
|
#
|
|
49
49
|
def rule_template
|
|
50
|
-
Services::
|
|
50
|
+
Services::RuleProxy.from_path File.expand_path("../templates/rule.yml.erb", __dir__)
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
#
|
|
@@ -4,60 +4,6 @@ module Mihari
|
|
|
4
4
|
module Commands
|
|
5
5
|
module Search
|
|
6
6
|
class << self
|
|
7
|
-
class RuleWrapper
|
|
8
|
-
include Mixins::ErrorNotification
|
|
9
|
-
|
|
10
|
-
# @return [Nihari::Structs::Rule]
|
|
11
|
-
attr_reader :rule
|
|
12
|
-
|
|
13
|
-
# @return [Boolean]
|
|
14
|
-
attr_reader :force_overwrite
|
|
15
|
-
|
|
16
|
-
def initialize(rule, force_overwrite:)
|
|
17
|
-
@rule = rule
|
|
18
|
-
@force_overwrite = force_overwrite
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def force_overwrite?
|
|
22
|
-
force_overwrite
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
#
|
|
26
|
-
# @return [Boolean]
|
|
27
|
-
#
|
|
28
|
-
def diff?
|
|
29
|
-
model = Mihari::Rule.find(rule.id)
|
|
30
|
-
model.data != rule.data.deep_stringify_keys
|
|
31
|
-
rescue ActiveRecord::RecordNotFound
|
|
32
|
-
false
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def update_or_create
|
|
36
|
-
rule.to_model.save
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def run
|
|
40
|
-
begin
|
|
41
|
-
analyzer = rule.to_analyzer
|
|
42
|
-
rescue ConfigurationError => e
|
|
43
|
-
# if there is a configuration error, output that error without the stack trace
|
|
44
|
-
Mihari.logger.error e.to_s
|
|
45
|
-
return
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
with_error_notification do
|
|
49
|
-
alert = analyzer.run
|
|
50
|
-
if alert.nil?
|
|
51
|
-
Mihari.logger.info "There is no new artifact found"
|
|
52
|
-
return
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
data = Mihari::Entities::Alert.represent(alert)
|
|
56
|
-
puts JSON.pretty_generate(data.as_json)
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
7
|
def included(thor)
|
|
62
8
|
thor.class_eval do
|
|
63
9
|
desc "search [PATH]", "Search by a rule"
|
|
@@ -69,7 +15,7 @@ module Mihari
|
|
|
69
15
|
#
|
|
70
16
|
def search(path_or_id)
|
|
71
17
|
Mihari::Database.with_db_connection do
|
|
72
|
-
rule = Services::
|
|
18
|
+
rule = Services::RuleProxy.from_path_or_id path_or_id
|
|
73
19
|
|
|
74
20
|
begin
|
|
75
21
|
rule.validate!
|
|
@@ -78,15 +24,30 @@ module Mihari
|
|
|
78
24
|
end
|
|
79
25
|
|
|
80
26
|
force_overwrite = options["force_overwrite"] || false
|
|
81
|
-
|
|
27
|
+
runner = Services::RuleRunner.new(rule, force_overwrite: force_overwrite)
|
|
82
28
|
|
|
83
|
-
if
|
|
29
|
+
if runner.diff? && !force_overwrite
|
|
84
30
|
message = "There is diff in the rule (#{rule.id}). Are you sure you want to overwrite the rule? (y/n)"
|
|
85
31
|
return unless yes?(message)
|
|
86
32
|
end
|
|
87
33
|
|
|
88
|
-
|
|
89
|
-
|
|
34
|
+
runner.update_or_create
|
|
35
|
+
|
|
36
|
+
begin
|
|
37
|
+
alert = runner.run
|
|
38
|
+
rescue ConfigurationError => e
|
|
39
|
+
# if there is a configuration error, output that error without the stack trace
|
|
40
|
+
Mihari.logger.error e.to_s
|
|
41
|
+
return
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
if alert.nil?
|
|
45
|
+
Mihari.logger.info "There is no new artifact found"
|
|
46
|
+
return
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
data = Mihari::Entities::Alert.represent(alert)
|
|
50
|
+
puts JSON.pretty_generate(data.as_json)
|
|
90
51
|
end
|
|
91
52
|
end
|
|
92
53
|
end
|
data/lib/mihari/config.rb
CHANGED
|
@@ -146,7 +146,7 @@ module Mihari
|
|
|
146
146
|
@retry_times = ENV.fetch("RETRY_TIMES", 3).to_i
|
|
147
147
|
@retry_interval = ENV.fetch("RETRY_INTERVAL", 5).to_i
|
|
148
148
|
|
|
149
|
-
@pagination_limit = ENV.fetch("PAGINATION_LIMIT",
|
|
149
|
+
@pagination_limit = ENV.fetch("PAGINATION_LIMIT", 100).to_i
|
|
150
150
|
end
|
|
151
151
|
end
|
|
152
152
|
end
|
data/lib/mihari/emitters/base.rb
CHANGED
|
@@ -10,10 +10,10 @@ module Mihari
|
|
|
10
10
|
#
|
|
11
11
|
# Create an alert
|
|
12
12
|
#
|
|
13
|
-
# @return [Mihari::Alert]
|
|
13
|
+
# @return [Mihari::Alert, nil]
|
|
14
14
|
#
|
|
15
15
|
def emit
|
|
16
|
-
return if artifacts.empty?
|
|
16
|
+
return nil if artifacts.empty?
|
|
17
17
|
|
|
18
18
|
tags = rule.tags.filter_map { |name| Tag.find_or_create_by(name: name) }.uniq
|
|
19
19
|
taggings = tags.map { |tag| Tagging.new(tag_id: tag.id) }
|
data/lib/mihari/errors.rb
CHANGED
|
@@ -15,17 +15,38 @@ module Mihari
|
|
|
15
15
|
|
|
16
16
|
class RuleValidationError < Error; end
|
|
17
17
|
|
|
18
|
+
class AlertValidationError < Error; end
|
|
19
|
+
|
|
18
20
|
class YAMLSyntaxError < Error; end
|
|
19
21
|
|
|
20
22
|
class ConfigurationError < Error; end
|
|
21
23
|
|
|
24
|
+
# errors for HTTP interactions
|
|
22
25
|
class HTTPError < Error; end
|
|
23
26
|
|
|
24
|
-
class StatusCodeError < HTTPError; end
|
|
25
|
-
|
|
26
27
|
class NetworkError < HTTPError; end
|
|
27
28
|
|
|
28
29
|
class TimeoutError < HTTPError; end
|
|
29
30
|
|
|
30
31
|
class SSLError < HTTPError; end
|
|
32
|
+
|
|
33
|
+
class StatusCodeError < HTTPError
|
|
34
|
+
# @return [Integer]
|
|
35
|
+
attr_reader :status_code
|
|
36
|
+
|
|
37
|
+
# @return [String, nil]
|
|
38
|
+
attr_reader :body
|
|
39
|
+
|
|
40
|
+
#
|
|
41
|
+
# @param [String] msg
|
|
42
|
+
# @param [Integer] status_code
|
|
43
|
+
# @param [String, nil] body
|
|
44
|
+
#
|
|
45
|
+
def initialize(msg, status_code, body)
|
|
46
|
+
super(msg)
|
|
47
|
+
|
|
48
|
+
@status_code = status_code
|
|
49
|
+
@body = body
|
|
50
|
+
end
|
|
51
|
+
end
|
|
31
52
|
end
|
data/lib/mihari/http.rb
CHANGED
|
@@ -94,7 +94,13 @@ module Mihari
|
|
|
94
94
|
Net::HTTP.start(url.host, url.port, https_options) do |http|
|
|
95
95
|
res = http.request(req)
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
unless res.is_a?(Net::HTTPSuccess)
|
|
98
|
+
raise StatusCodeError.new(
|
|
99
|
+
"Unsuccessful response code returned: #{res.code}",
|
|
100
|
+
res.code.to_i,
|
|
101
|
+
res.body
|
|
102
|
+
)
|
|
103
|
+
end
|
|
98
104
|
|
|
99
105
|
res
|
|
100
106
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mihari
|
|
4
|
+
module Schemas
|
|
5
|
+
Alert = Dry::Schema.Params do
|
|
6
|
+
required(:rule_id).value(:string)
|
|
7
|
+
required(:artifacts).value(array[:string])
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class AlertContract < Dry::Validation::Contract
|
|
11
|
+
params(Alert)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mihari
|
|
4
|
+
module Services
|
|
5
|
+
class AlertProxy
|
|
6
|
+
# @return [Hash]
|
|
7
|
+
attr_reader :data
|
|
8
|
+
|
|
9
|
+
# @return [Array, nil]
|
|
10
|
+
attr_reader :errors
|
|
11
|
+
|
|
12
|
+
#
|
|
13
|
+
# Initialize
|
|
14
|
+
#
|
|
15
|
+
# @param [Hash] data
|
|
16
|
+
#
|
|
17
|
+
def initialize(data)
|
|
18
|
+
@data = data.deep_symbolize_keys
|
|
19
|
+
|
|
20
|
+
@errors = nil
|
|
21
|
+
|
|
22
|
+
validate
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# @return [Boolean]
|
|
27
|
+
#
|
|
28
|
+
def errors?
|
|
29
|
+
return false if @errors.nil?
|
|
30
|
+
|
|
31
|
+
!@errors.empty?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def validate
|
|
35
|
+
contract = Schemas::AlertContract.new
|
|
36
|
+
result = contract.call(data)
|
|
37
|
+
|
|
38
|
+
@data = result.to_h
|
|
39
|
+
@errors = result.errors
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def validate!
|
|
43
|
+
return unless errors?
|
|
44
|
+
|
|
45
|
+
Mihari.logger.error "Failed to parse the input as an alert:"
|
|
46
|
+
Mihari.logger.error JSON.pretty_generate(errors.to_h)
|
|
47
|
+
|
|
48
|
+
raise AlertValidationError, errors
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def [](key)
|
|
52
|
+
data key.to_sym
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
#
|
|
56
|
+
# @return [String]
|
|
57
|
+
#
|
|
58
|
+
def rule_id
|
|
59
|
+
@rule_id ||= data[:rule_id]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
#
|
|
63
|
+
# @return [Array<Mihari::Artifact>]
|
|
64
|
+
#
|
|
65
|
+
def artifacts
|
|
66
|
+
@artifacts ||= data[:artifacts].map do |data|
|
|
67
|
+
artifact = Artifact.new(data: data)
|
|
68
|
+
artifact.rule_id = rule_id
|
|
69
|
+
artifact
|
|
70
|
+
end.uniq(&:data).select(&:valid?)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
#
|
|
74
|
+
# @return [Mihari::Services::RuleProxy]
|
|
75
|
+
#
|
|
76
|
+
def rule
|
|
77
|
+
@rule ||= Services::RuleProxy.from_model(Mihari::Rule.find(rule_id))
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class << self
|
|
81
|
+
#
|
|
82
|
+
# Load rule from YAML string
|
|
83
|
+
#
|
|
84
|
+
# @param [String] yaml
|
|
85
|
+
#
|
|
86
|
+
# @return [Mihari::Services::Alert]
|
|
87
|
+
#
|
|
88
|
+
def from_yaml(yaml)
|
|
89
|
+
Services::AlertProxy.new YAML.safe_load(yaml, permitted_classes: [Date, Symbol])
|
|
90
|
+
rescue Psych::SyntaxError => e
|
|
91
|
+
raise YAMLSyntaxError, e.message
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @param [String] path
|
|
95
|
+
#
|
|
96
|
+
# @return [Mihari::Services::Alert, nil]
|
|
97
|
+
#
|
|
98
|
+
def from_path(path)
|
|
99
|
+
return nil unless Pathname(path).exist?
|
|
100
|
+
|
|
101
|
+
from_yaml File.read(path)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mihari
|
|
4
|
+
module Services
|
|
5
|
+
class AlertRunner
|
|
6
|
+
# @return [Mihari::Services::AlertProxy]
|
|
7
|
+
attr_reader :alert
|
|
8
|
+
|
|
9
|
+
def initialize(alert)
|
|
10
|
+
@alert = alert
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
#
|
|
14
|
+
# @return [Mihari::Alert]
|
|
15
|
+
#
|
|
16
|
+
def run
|
|
17
|
+
emitter = Mihari::Emitters::Database.new(artifacts: alert.artifacts, rule: alert.rule)
|
|
18
|
+
emitter.emit
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -9,7 +9,11 @@ require "yaml"
|
|
|
9
9
|
|
|
10
10
|
module Mihari
|
|
11
11
|
module Services
|
|
12
|
-
|
|
12
|
+
#
|
|
13
|
+
# proxy (or converter) class for rule
|
|
14
|
+
# proxying rule schema data into analyzer & model
|
|
15
|
+
#
|
|
16
|
+
class RuleProxy
|
|
13
17
|
include Mixins::FalsePositive
|
|
14
18
|
|
|
15
19
|
# @return [Hash]
|
|
@@ -141,7 +145,7 @@ module Mihari
|
|
|
141
145
|
#
|
|
142
146
|
# @return [Mihari::Rule]
|
|
143
147
|
#
|
|
144
|
-
def
|
|
148
|
+
def model
|
|
145
149
|
rule = Mihari::Rule.find(id)
|
|
146
150
|
|
|
147
151
|
rule.title = title
|
|
@@ -161,7 +165,7 @@ module Mihari
|
|
|
161
165
|
#
|
|
162
166
|
# @return [Mihari::Analyzers::Rule]
|
|
163
167
|
#
|
|
164
|
-
def
|
|
168
|
+
def analyzer
|
|
165
169
|
Mihari::Analyzers::Rule.new self
|
|
166
170
|
end
|
|
167
171
|
|
|
@@ -174,7 +178,7 @@ module Mihari
|
|
|
174
178
|
# @return [Mihari::Services::Rule]
|
|
175
179
|
#
|
|
176
180
|
def from_yaml(yaml)
|
|
177
|
-
Services::
|
|
181
|
+
Services::RuleProxy.new YAML.safe_load(ERB.new(yaml).result, permitted_classes: [Date, Symbol])
|
|
178
182
|
rescue Psych::SyntaxError => e
|
|
179
183
|
raise YAMLSyntaxError, e.message
|
|
180
184
|
end
|
|
@@ -185,7 +189,7 @@ module Mihari
|
|
|
185
189
|
# @return [Mihari::Services::Rule]
|
|
186
190
|
#
|
|
187
191
|
def from_model(model)
|
|
188
|
-
Services::
|
|
192
|
+
Services::RuleProxy.new model.data
|
|
189
193
|
end
|
|
190
194
|
|
|
191
195
|
#
|
|
@@ -211,7 +215,7 @@ module Mihari
|
|
|
211
215
|
def from_id(id)
|
|
212
216
|
return nil unless Mihari::Rule.exists?(id)
|
|
213
217
|
|
|
214
|
-
Services::
|
|
218
|
+
Services::RuleProxy.from_model Mihari::Rule.find(id)
|
|
215
219
|
end
|
|
216
220
|
|
|
217
221
|
#
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mihari
|
|
4
|
+
module Services
|
|
5
|
+
class RuleRunner
|
|
6
|
+
include Mixins::ErrorNotification
|
|
7
|
+
|
|
8
|
+
# @return [Mihari::Services::RuleProxy]
|
|
9
|
+
attr_reader :rule
|
|
10
|
+
|
|
11
|
+
# @return [Boolean]
|
|
12
|
+
attr_reader :force_overwrite
|
|
13
|
+
|
|
14
|
+
def initialize(rule, force_overwrite:)
|
|
15
|
+
@rule = rule
|
|
16
|
+
@force_overwrite = force_overwrite
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def force_overwrite?
|
|
20
|
+
force_overwrite
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
#
|
|
24
|
+
# @return [Boolean]
|
|
25
|
+
#
|
|
26
|
+
def diff?
|
|
27
|
+
model = Mihari::Rule.find(rule.id)
|
|
28
|
+
model.data != rule.data.deep_stringify_keys
|
|
29
|
+
rescue ActiveRecord::RecordNotFound
|
|
30
|
+
false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def update_or_create
|
|
34
|
+
rule.model.save
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
# @return [Mihari::Alert, nil]
|
|
39
|
+
#
|
|
40
|
+
def run
|
|
41
|
+
analyzer = rule.analyzer
|
|
42
|
+
|
|
43
|
+
with_error_notification do
|
|
44
|
+
analyzer.run
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/mihari/version.rb
CHANGED
|
@@ -67,6 +67,28 @@ module Mihari
|
|
|
67
67
|
status 204
|
|
68
68
|
present({ message: "" }, with: Entities::Message)
|
|
69
69
|
end
|
|
70
|
+
|
|
71
|
+
desc "Create an alert", {
|
|
72
|
+
success: Entities::Alert,
|
|
73
|
+
summary: "Create an alert"
|
|
74
|
+
}
|
|
75
|
+
params do
|
|
76
|
+
requires :ruleId, type: String, documentation: { param_type: "body" }
|
|
77
|
+
requires :artifacts, type: Array, documentation: { type: String, is_array: true, param_type: "body" }
|
|
78
|
+
end
|
|
79
|
+
post "/" do
|
|
80
|
+
proxy = Services::AlertProxy.new(params.to_snake_keys)
|
|
81
|
+
runner = Services::AlertRunner.new(proxy)
|
|
82
|
+
|
|
83
|
+
begin
|
|
84
|
+
alert = runner.run
|
|
85
|
+
rescue ActiveRecord::RecordNotFound
|
|
86
|
+
error!({ message: "Rule:#{params["ruleId"]} is not found" }, 404)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
status 201
|
|
90
|
+
present alert, with: Entities::Alert
|
|
91
|
+
end
|
|
70
92
|
end
|
|
71
93
|
end
|
|
72
94
|
end
|
|
@@ -83,12 +83,12 @@ module Mihari
|
|
|
83
83
|
id = params["id"].to_s
|
|
84
84
|
|
|
85
85
|
begin
|
|
86
|
-
rule = Mihari::Services::
|
|
86
|
+
rule = Mihari::Services::RuleProxy.from_model(Mihari::Rule.find(id))
|
|
87
87
|
rescue ActiveRecord::RecordNotFound
|
|
88
88
|
error!({ message: "ID:#{id} is not found" }, 404)
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
-
analyzer = rule.
|
|
91
|
+
analyzer = rule.analyzer
|
|
92
92
|
analyzer.run
|
|
93
93
|
|
|
94
94
|
status 201
|
|
@@ -106,7 +106,7 @@ module Mihari
|
|
|
106
106
|
yaml = params[:yaml]
|
|
107
107
|
|
|
108
108
|
begin
|
|
109
|
-
rule = Services::
|
|
109
|
+
rule = Services::RuleProxy.from_yaml(yaml)
|
|
110
110
|
rescue YAMLSyntaxError => e
|
|
111
111
|
error!({ message: e.message }, 400)
|
|
112
112
|
end
|
|
@@ -129,13 +129,13 @@ module Mihari
|
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
begin
|
|
132
|
-
rule.
|
|
132
|
+
rule.model.save
|
|
133
133
|
rescue ActiveRecord::RecordNotUnique
|
|
134
134
|
error!({ message: "ID:#{rule.id} is already registered" }, 400)
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
status 201
|
|
138
|
-
present rule.
|
|
138
|
+
present rule.model, with: Entities::Rule
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
desc "Update a rule", {
|
|
@@ -157,7 +157,7 @@ module Mihari
|
|
|
157
157
|
end
|
|
158
158
|
|
|
159
159
|
begin
|
|
160
|
-
rule = Services::
|
|
160
|
+
rule = Services::RuleProxy.from_yaml(yaml)
|
|
161
161
|
rescue YAMLSyntaxError => e
|
|
162
162
|
error!({ message: e.message }, 400)
|
|
163
163
|
end
|
|
@@ -172,13 +172,13 @@ module Mihari
|
|
|
172
172
|
end
|
|
173
173
|
|
|
174
174
|
begin
|
|
175
|
-
rule.
|
|
175
|
+
rule.model.save
|
|
176
176
|
rescue ActiveRecord::RecordNotUnique
|
|
177
177
|
error!({ message: "ID:#{id} is already registered" }, 400)
|
|
178
178
|
end
|
|
179
179
|
|
|
180
180
|
status 201
|
|
181
|
-
present rule.
|
|
181
|
+
present rule.model, with: Entities::Rule
|
|
182
182
|
end
|
|
183
183
|
|
|
184
184
|
desc "Delete a rule", {
|