mihari 7.1.0 → 7.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/README.md +2 -1
  4. data/Rakefile +39 -1
  5. data/lib/mihari/actor.rb +5 -5
  6. data/lib/mihari/analyzers/base.rb +18 -11
  7. data/lib/mihari/analyzers/passivetotal.rb +1 -1
  8. data/lib/mihari/analyzers/securitytrails.rb +1 -1
  9. data/lib/mihari/analyzers/virustotal.rb +1 -1
  10. data/lib/mihari/analyzers/virustotal_intelligence.rb +2 -2
  11. data/lib/mihari/cli/application.rb +16 -4
  12. data/lib/mihari/commands/alert.rb +5 -5
  13. data/lib/mihari/commands/artifact.rb +5 -5
  14. data/lib/mihari/commands/rule.rb +6 -6
  15. data/lib/mihari/commands/search.rb +1 -1
  16. data/lib/mihari/commands/tag.rb +3 -3
  17. data/lib/mihari/concerns/retriable.rb +1 -1
  18. data/lib/mihari/constants.rb +1 -1
  19. data/lib/mihari/database.rb +1 -1
  20. data/lib/mihari/emitters/base.rb +15 -1
  21. data/lib/mihari/emitters/database.rb +4 -0
  22. data/lib/mihari/emitters/misp.rb +7 -0
  23. data/lib/mihari/emitters/slack.rb +7 -0
  24. data/lib/mihari/emitters/the_hive.rb +7 -0
  25. data/lib/mihari/emitters/webhook.rb +7 -0
  26. data/lib/mihari/enrichers/base.rb +9 -1
  27. data/lib/mihari/enrichers/google_public_dns.rb +1 -1
  28. data/lib/mihari/rule.rb +2 -14
  29. data/lib/mihari/schemas/analyzer.rb +19 -19
  30. data/lib/mihari/schemas/emitter.rb +5 -5
  31. data/lib/mihari/schemas/enricher.rb +4 -4
  32. data/lib/mihari/structs/config.rb +1 -1
  33. data/lib/mihari/version.rb +1 -1
  34. data/lib/mihari/web/public/assets/{index-U5u7qHZZ.js → index-Guw2aMpk.js} +53 -53
  35. data/lib/mihari/web/public/index.html +1 -1
  36. data/lib/mihari/web/public/redoc-static.html +28 -28
  37. data/lib/mihari.rb +14 -3
  38. data/mihari.gemspec +4 -4
  39. data/mkdocs.yml +1 -1
  40. metadata +57 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6930da0e95068ca8e30d1f226be5692e85375f796b7246cafdd2bec566d00ff7
4
- data.tar.gz: 2bf34b1231bffcd88d402ffda335960ad929b1de91cd51b257c9c24f7b2fc16f
3
+ metadata.gz: 52d1c8320fdb5233c9738f3b4599868260fef892599cdfb42da6c3af17583b75
4
+ data.tar.gz: 625cd92558eff5a4d5613e588cc5ee85b9b714a9af211788da1a294d8d54ac45
5
5
  SHA512:
6
- metadata.gz: fd515cdbde67d10c3fcae14c8e45a7929a34931701be176c9f9a294d3db310f522a3e186aefe548d6f119c5c8552723114da4ee6f790dbbe0391138dca9cc00e
7
- data.tar.gz: 5f4a3e1049ad55af018cf9ed2186dda49bd18517d37bc84cad6e6f60b10589834ac3bd1f09333e7f9773fab43442400c097c1063f1c304d5be5eb8991af7ec77
6
+ metadata.gz: 96811d3ebfffcb27a7577b814be280916dd46bd3477233374ffafd2bf784d9e5133f89b1d7650c722c25e2f678f82380f5ced2eff8f9b7e1f3c96583f54a1114
7
+ data.tar.gz: 5c13581e670c7aff158e93335fe9c626294cad622f153e61a338f31bb5a1e459302f34a3a9ddf18e0bb322e1359c43a6b782387cdc800f9b047c04e5521f4c70
data/.rubocop.yml CHANGED
@@ -17,6 +17,8 @@ RSpec/MultipleMemoizedHelpers:
17
17
  Max: 10
18
18
  RSpec/ExampleLength:
19
19
  Max: 20
20
+ RSpec/FilePath:
21
+ SpecSuffixOnly: true
20
22
  require:
21
23
  - rubocop-factory_bot
22
24
  - rubocop-rake
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # mihari
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/mihari.svg)](https://badge.fury.io/rb/mihari)
4
- [![Ruby CI](https://github.com/ninoseki/mihari/actions/workflows/test.yml/badge.svg)](https://github.com/ninoseki/mihari/actions/workflows/test.yml)
4
+ [![Ruby CI](https://github.com/ninoseki/mihari/actions/workflows/ruby.yml/badge.svg)](https://github.com/ninoseki/mihari/actions/workflows/ruby.yml)
5
+ [![Node.js CI](https://github.com/ninoseki/mihari/actions/workflows/node.yml/badge.svg)](https://github.com/ninoseki/mihari/actions/workflows/node.yml)
5
6
  [![Coverage Status](https://coveralls.io/repos/github/ninoseki/mihari/badge.svg?branch=master)](https://coveralls.io/github/ninoseki/mihari?branch=master)
6
7
  [![CodeFactor](https://www.codefactor.io/repository/github/ninoseki/mihari/badge)](https://www.codefactor.io/repository/github/ninoseki/mihari)
7
8
 
data/Rakefile CHANGED
@@ -7,11 +7,49 @@ RSpec::Core::RakeTask.new(:spec)
7
7
 
8
8
  task default: :spec
9
9
 
10
- desc "run rackup (via rerun)"
10
+ desc "Run rackup (with rerun)"
11
11
  task :rackup do
12
12
  sh "rerun --pattern '{Gemfile.lock,lib/**/*.rb,lib/*.rb}' -- rackup config.ru"
13
13
  end
14
14
 
15
+ def recursive_delete(hash, to_remove)
16
+ hash.delete(to_remove)
17
+ hash.each_value do |value|
18
+ recursive_delete(value, to_remove) if value.is_a? Hash
19
+ end
20
+ end
21
+
22
+ def build_swagger_doc(path)
23
+ require_relative "lib/mihari"
24
+ require_relative "lib/mihari/web/application"
25
+
26
+ require "rack/test"
27
+
28
+ app = Mihari::Web::App.new
29
+ session = Rack::Test::Session.new(app)
30
+
31
+ res = session.request("/api/swagger_doc")
32
+
33
+ json = JSON.parse(res.body.to_s)
34
+ # remove host because it can be varied
35
+ keys_to_remove = %w[host]
36
+ keys_to_remove.each do |key|
37
+ recursive_delete json, key
38
+ end
39
+
40
+ f = File.open(path, "w")
41
+ f.write json.to_yaml
42
+ f.close
43
+ end
44
+
45
+ namespace :build do
46
+ desc "Build Swagger doc"
47
+ task :swagger, [:path] do |_t, args|
48
+ args.with_defaults(path: "./frontend/swagger.yaml")
49
+ build_swagger_doc args.path
50
+ end
51
+ end
52
+
15
53
  def ci?
16
54
  ENV.fetch("CI", false)
17
55
  end
data/lib/mihari/actor.rb CHANGED
@@ -55,7 +55,7 @@ module Mihari
55
55
 
56
56
  joined = self.class.configuration_keys.join(", ")
57
57
  be = (self.class.configuration_keys.length > 1) ? "are" : "is"
58
- message = "#{self.class.class_key} is not configured correctly. #{joined} #{be} missing."
58
+ message = "#{self.class.key} is not configured correctly. #{joined} #{be} missing."
59
59
  raise ConfigurationError, message
60
60
  end
61
61
 
@@ -75,22 +75,22 @@ module Mihari
75
75
  #
76
76
  # @return [String]
77
77
  #
78
- def class_key
78
+ def key
79
79
  to_s.split("::").last.downcase
80
80
  end
81
81
 
82
82
  #
83
83
  # @return [Array<String>, nil]
84
84
  #
85
- def class_key_aliases
85
+ def key_aliases
86
86
  nil
87
87
  end
88
88
 
89
89
  #
90
90
  # @return [Array<String>]
91
91
  #
92
- def class_keys
93
- ([class_key] + [class_key_aliases]).flatten.compact.map(&:downcase)
92
+ def keys
93
+ ([key] + [key_aliases]).flatten.compact.map(&:downcase)
94
94
  end
95
95
  end
96
96
  end
@@ -65,7 +65,7 @@ module Mihari
65
65
  # It is set automatically in #initialize
66
66
  artifact = artifact.is_a?(Models::Artifact) ? artifact : Models::Artifact.new(data: artifact)
67
67
 
68
- artifact.source = self.class.class_key
68
+ artifact.source = self.class.key
69
69
  artifact.query = query
70
70
 
71
71
  artifact
@@ -80,7 +80,7 @@ module Mihari
80
80
  end
81
81
 
82
82
  def result(...)
83
- res = Try[StandardError] do
83
+ result = Try[StandardError] do
84
84
  retry_on_error(
85
85
  times: retry_times,
86
86
  interval: retry_interval,
@@ -88,19 +88,26 @@ module Mihari
88
88
  ) do
89
89
  call(...)
90
90
  end
91
- end
92
-
93
- return res.recover { [] } if ignore_error?
91
+ end.to_result
94
92
 
95
- result = res.to_result
96
93
  return result if result.success?
97
94
 
98
95
  # Wrap failure with AnalyzerError to explicitly name a failed analyzer
99
- Failure AnalyzerError.new(
100
- result.failure.message,
101
- self.class.class_key,
102
- cause: result.failure
103
- )
96
+ error = AnalyzerError.new(result.failure.message, self.class.key, cause: result.failure)
97
+ return Failure(error) unless ignore_error?
98
+
99
+ # Return Success if ignore_error? is true with logging
100
+ Mihari.logger.warn("Analyzer:#{self.class.key} with #{truncated_query} failed - #{result.failure}")
101
+ Success([])
102
+ end
103
+
104
+ #
105
+ # Truncate query for logging
106
+ #
107
+ # @return [String]
108
+ #
109
+ def truncated_query
110
+ query.truncate(32)
104
111
  end
105
112
 
106
113
  class << self
@@ -57,7 +57,7 @@ module Mihari
57
57
  #
58
58
  # @return [Array<String>, nil]
59
59
  #
60
- def class_key_aliases
60
+ def key_aliases
61
61
  ["pt"]
62
62
  end
63
63
  end
@@ -51,7 +51,7 @@ module Mihari
51
51
  #
52
52
  # @return [Array<String>, nil]
53
53
  #
54
- def class_key_aliases
54
+ def key_aliases
55
55
  ["st"]
56
56
  end
57
57
  end
@@ -46,7 +46,7 @@ module Mihari
46
46
  #
47
47
  # @return [Array<String>, nil]
48
48
  #
49
- def class_key_aliases
49
+ def key_aliases
50
50
  ["vt"]
51
51
  end
52
52
  end
@@ -34,14 +34,14 @@ module Mihari
34
34
  #
35
35
  # @return [String]
36
36
  #
37
- def class_key
37
+ def key
38
38
  "virustotal_intelligence"
39
39
  end
40
40
 
41
41
  #
42
42
  # @return [Array<String>, nil]
43
43
  #
44
- def class_key_aliases
44
+ def key_aliases
45
45
  ["vt_intel"]
46
46
  end
47
47
  end
@@ -38,6 +38,21 @@ module Mihari
38
38
  include Concerns::ErrorUnwrappable
39
39
 
40
40
  no_commands do
41
+ #
42
+ # @param [StandardError] error
43
+ #
44
+ # @return [String, Hash, nil]
45
+ #
46
+ def error_to_detail(error)
47
+ # Dirty hack to show the DB error message
48
+ # (NOTE: #safe_execute block suppress #with_db_connection's error message)
49
+ if error.is_a?(ActiveRecord::StatementInvalid)
50
+ return "DB migration is not yet complete. Please run 'mihari db migrate'."
51
+ end
52
+
53
+ error.respond_to?(:detail) ? error.detail : nil
54
+ end
55
+
41
56
  def safe_execute
42
57
  yield
43
58
  rescue StandardError => e
@@ -48,10 +63,7 @@ module Mihari
48
63
  # Raise error if debug is set as true
49
64
  raise error if options["debug"]
50
65
 
51
- data = Entities::ErrorMessage.represent(
52
- message: error.message,
53
- detail: error.respond_to?(:detail) ? error.detail : nil
54
- )
66
+ data = Entities::ErrorMessage.represent(message: error.message, detail: error_to_detail(error))
55
67
  warn JSON.pretty_generate(data.as_json)
56
68
 
57
69
  Sentry.capture_exception(error) if Sentry.initialized? && !error.is_a?(ValidationError)
@@ -26,7 +26,7 @@ module Mihari
26
26
  end
27
27
  end
28
28
 
29
- desc "create [PATH]", "Create an alert"
29
+ desc "create PATH", "Create an alert"
30
30
  around :with_db_connection
31
31
  #
32
32
  # @param [String] path
@@ -46,7 +46,7 @@ module Mihari
46
46
  puts JSON.pretty_generate(data.as_json)
47
47
  end
48
48
 
49
- desc "list [QUERY]", "List/search alerts"
49
+ desc "list QUERY", "List/search alerts"
50
50
  around :with_db_connection
51
51
  method_option :page, type: :numeric, default: 1
52
52
  method_option :limit, type: :numeric, default: 10
@@ -67,7 +67,7 @@ module Mihari
67
67
  desc "list-transform QUERY", "List/search alerts with transformation"
68
68
  around :with_db_connection
69
69
  method_option :template, type: :string, required: true, aliases: "-t",
70
- description: "Jbuilder template itself or a path to a template file"
70
+ desc: "Jbuilder template stringor a path to a template"
71
71
  method_option :page, type: :numeric, default: 1
72
72
  method_option :limit, type: :numeric, default: 10
73
73
  #
@@ -86,7 +86,7 @@ module Mihari
86
86
  )
87
87
  end
88
88
 
89
- desc "get [ID]", "Get an alert"
89
+ desc "get ID", "Get an alert"
90
90
  around :with_db_connection
91
91
  #
92
92
  # @param [Integer] id
@@ -97,7 +97,7 @@ module Mihari
97
97
  puts JSON.pretty_generate(data.as_json)
98
98
  end
99
99
 
100
- desc "delete [ID]", "Delete an alert"
100
+ desc "delete ID", "Delete an alert"
101
101
  around :with_db_connection
102
102
  #
103
103
  # @param [Integer] id
@@ -25,7 +25,7 @@ module Mihari
25
25
  end
26
26
  end
27
27
 
28
- desc "list [QUERY]", "List/search artifacts"
28
+ desc "list QUERY", "List/search artifacts"
29
29
  around :with_db_connection
30
30
  method_option :page, type: :numeric, default: 1
31
31
  method_option :limit, type: :numeric, default: 10
@@ -46,7 +46,7 @@ module Mihari
46
46
  desc "list-transform QUERY", "List/search artifacts with transformation"
47
47
  around :with_db_connection
48
48
  method_option :template, type: :string, required: true, aliases: "-t",
49
- description: "Jbuilder template itself or a path to a template file"
49
+ desc: "Jbuilder template stringor a path to a template"
50
50
  method_option :page, type: :numeric, default: 1
51
51
  method_option :limit, type: :numeric, default: 10
52
52
  #
@@ -65,7 +65,7 @@ module Mihari
65
65
  )
66
66
  end
67
67
 
68
- desc "get [ID]", "Get an artifact"
68
+ desc "get ID", "Get an artifact"
69
69
  around :with_db_connection
70
70
  #
71
71
  # @param [Integer] id
@@ -76,7 +76,7 @@ module Mihari
76
76
  puts JSON.pretty_generate(data.as_json)
77
77
  end
78
78
 
79
- desc "enrich [ID]", "Enrich an artifact"
79
+ desc "enrich ID", "Enrich an artifact"
80
80
  around :with_db_connection
81
81
  #
82
82
  # @param [Integer] id
@@ -85,7 +85,7 @@ module Mihari
85
85
  Services::ArtifactEnricher.result(id).value!
86
86
  end
87
87
 
88
- desc "delete [ID]", "Delete an artifact"
88
+ desc "delete ID", "Delete an artifact"
89
89
  around :with_db_connection
90
90
  #
91
91
  # @param [Integer] id
@@ -26,7 +26,7 @@ module Mihari
26
26
  end
27
27
  end
28
28
 
29
- desc "validate [PATH]", "Validate a rule file"
29
+ desc "validate PATH", "Validate a rule"
30
30
  #
31
31
  # Validate format of a rule
32
32
  #
@@ -37,7 +37,7 @@ module Mihari
37
37
  puts rule.data.to_yaml
38
38
  end
39
39
 
40
- desc "init [PATH]", "Initialize a new rule file"
40
+ desc "init PATH", "Initialize a new rule"
41
41
  #
42
42
  # Initialize a new rule file
43
43
  #
@@ -50,7 +50,7 @@ module Mihari
50
50
  Services::RuleInitializer.call(path)
51
51
  end
52
52
 
53
- desc "list [QUERY]", "List/search rules"
53
+ desc "list QUERY", "List/search rules"
54
54
  around :with_db_connection
55
55
  method_option :page, type: :numeric, default: 1
56
56
  method_option :limit, type: :numeric, default: 10
@@ -71,7 +71,7 @@ module Mihari
71
71
  desc "list-transform QUERY", "List/search rules with transformation"
72
72
  around :with_db_connection
73
73
  method_option :template, type: :string, required: true, aliases: "-t",
74
- description: "Jbuilder template itself or a path to a template file"
74
+ desc: "Jbuilder template stringor a path to a template"
75
75
  method_option :page, type: :numeric, default: 1
76
76
  method_option :limit, type: :numeric, default: 10
77
77
  #
@@ -90,7 +90,7 @@ module Mihari
90
90
  )
91
91
  end
92
92
 
93
- desc "get [ID]", "Get a rule"
93
+ desc "get ID", "Get a rule"
94
94
  around :with_db_connection
95
95
  def get(id)
96
96
  value = Services::RuleGetter.result(id).value!
@@ -98,7 +98,7 @@ module Mihari
98
98
  puts JSON.pretty_generate(data.as_json)
99
99
  end
100
100
 
101
- desc "delete [ID]", "Delete a rule"
101
+ desc "delete ID", "Delete a rule"
102
102
  around :with_db_connection
103
103
  #
104
104
  # @param [String] id
@@ -11,7 +11,7 @@ module Mihari
11
11
  thor.class_eval do
12
12
  include Concerns::DatabaseConnectable
13
13
 
14
- desc "search [PATH_OR_ID]", "Search by a rule"
14
+ desc "search PATH_OR_ID", "Search by a rule"
15
15
  around :with_db_connection
16
16
  method_option :force_overwrite, type: :boolean, default: false, aliases: "-f",
17
17
  desc: "Force overwriting a rule"
@@ -25,7 +25,7 @@ module Mihari
25
25
  end
26
26
  end
27
27
 
28
- desc "list", "List/search tags"
28
+ desc "list QUERY", "List/search tags"
29
29
  around :with_db_connection
30
30
  method_option :page, type: :numeric, default: 1
31
31
  method_option :limit, type: :numeric, default: 10
@@ -46,7 +46,7 @@ module Mihari
46
46
  desc "list-transform QUERY", "List/search tags with transformation"
47
47
  around :with_db_connection
48
48
  method_option :template, type: :string, required: true, aliases: "-t",
49
- description: "Jbuilder template itself or a path to a template file"
49
+ desc: "Jbuilder template stringor a path to a template"
50
50
  method_option :page, type: :numeric, default: 1
51
51
  method_option :limit, type: :numeric, default: 10
52
52
  #
@@ -65,7 +65,7 @@ module Mihari
65
65
  )
66
66
  end
67
67
 
68
- desc "delete [ID]", "Delete a tag"
68
+ desc "delete ID", "Delete a tag"
69
69
  around :with_db_connection
70
70
  #
71
71
  # @param [Integer] id
@@ -21,7 +21,7 @@ module Mihari
21
21
 
22
22
  case error
23
23
  when StatusError
24
- error.status_code != 404
24
+ ![401, 404].include?(error.status_code)
25
25
  else
26
26
  false
27
27
  end
@@ -5,7 +5,7 @@ module Mihari
5
5
  DEFAULT_DATA_TYPES = Types::DataTypes.values.freeze
6
6
 
7
7
  # @return [Array<Hash>]
8
- DEFAULT_EMITTERS = Emitters::Database.class_keys.map { |name| { emitter: name.downcase } }.freeze
8
+ DEFAULT_EMITTERS = Emitters::Database.keys.map { |name| { emitter: name.downcase } }.freeze
9
9
 
10
10
  # @return [Array<Hash>]
11
11
  DEFAULT_ENRICHERS = Mihari.enricher_to_class.keys.map { |name| { enricher: name.downcase } }.freeze
@@ -156,7 +156,7 @@ module Mihari
156
156
  Mihari::Database.connect unless connected?
157
157
  yield
158
158
  rescue ActiveRecord::StatementInvalid
159
- Mihari.logger.error("The DB migration is not yet complete. Please run 'mihari db migrate'.")
159
+ Mihari.logger.error("DB migration is not yet complete. Please run 'mihari db migrate'.")
160
160
  ensure
161
161
  Mihari::Database.close
162
162
  end
@@ -19,6 +19,14 @@ module Mihari
19
19
  @rule = rule
20
20
  end
21
21
 
22
+ # A target to emit the data
23
+ #
24
+ # @return [String]
25
+ #
26
+ def target
27
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
28
+ end
29
+
22
30
  #
23
31
  # @param [Array<Mihari::Models::Artifact>] artifacts
24
32
  #
@@ -30,13 +38,19 @@ module Mihari
30
38
  # @return [Dry::Monads::Result::Success<Object>, Dry::Monads::Result::Failure]
31
39
  #
32
40
  def result(artifacts)
33
- Try[StandardError] do
41
+ result = Try[StandardError] do
34
42
  retry_on_error(
35
43
  times: retry_times,
36
44
  interval: retry_interval,
37
45
  exponential_backoff: retry_exponential_backoff
38
46
  ) { call(artifacts) }
39
47
  end.to_result
48
+
49
+ if result.failure?
50
+ Mihari.logger.warn("Emitter:#{self.class.key} for #{target.truncate(32)} failed - #{result.failure}")
51
+ end
52
+
53
+ result
40
54
  end
41
55
 
42
56
  class << self
@@ -21,6 +21,10 @@ module Mihari
21
21
  alert
22
22
  end
23
23
 
24
+ def target
25
+ Mihari.config.database_url.host || Mihari.config.database_url.to_s
26
+ end
27
+
24
28
  class << self
25
29
  def configuration_keys
26
30
  %w[database_url]
@@ -56,6 +56,13 @@ module Mihari
56
56
  })
57
57
  end
58
58
 
59
+ #
60
+ # @return [String]
61
+ #
62
+ def target
63
+ URI(url).host || "N/A"
64
+ end
65
+
59
66
  class << self
60
67
  def configuration_keys
61
68
  %w[misp_url misp_api_key]
@@ -165,6 +165,13 @@ module Mihari
165
165
  webhook_url?
166
166
  end
167
167
 
168
+ #
169
+ # @return [String]
170
+ #
171
+ def target
172
+ channel
173
+ end
174
+
168
175
  #
169
176
  # @return [::Slack::Notifier]
170
177
  #
@@ -33,6 +33,13 @@ module Mihari
33
33
  api_key? && url?
34
34
  end
35
35
 
36
+ #
37
+ # @return [String]
38
+ #
39
+ def target
40
+ URI(url).host || "N/A"
41
+ end
42
+
36
43
  #
37
44
  # Create a Hive alert
38
45
  #
@@ -55,6 +55,13 @@ module Mihari
55
55
  %w[http https].include? url.scheme.downcase
56
56
  end
57
57
 
58
+ #
59
+ # @return [String]
60
+ #
61
+ def target
62
+ URI(url).host || "N/A"
63
+ end
64
+
58
65
  #
59
66
  # @param [Array<Mihari::Models::Artifact>] artifacts
60
67
  #
@@ -19,17 +19,25 @@ module Mihari
19
19
  raise NotImplementedError, "You must implement #{self.class}##{__method__}"
20
20
  end
21
21
 
22
+ #
23
+ # @param [Mihari::Models::Artifact] value
22
24
  #
23
25
  # @return [Dry::Monads::Result::Success<Object>, Dry::Monads::Result::Failure]
24
26
  #
25
27
  def result(value)
26
- Try[StandardError] do
28
+ result = Try[StandardError] do
27
29
  retry_on_error(
28
30
  times: retry_times,
29
31
  interval: retry_interval,
30
32
  exponential_backoff: retry_exponential_backoff
31
33
  ) { call value }
32
34
  end.to_result
35
+
36
+ if result.failure?
37
+ Mihari.logger.warn("Enricher:#{self.class.key} for #{value.truncate(32)} failed: #{result.failure}")
38
+ end
39
+
40
+ result
33
41
  end
34
42
 
35
43
  class << self
@@ -21,7 +21,7 @@ module Mihari
21
21
  #
22
22
  # @return [String]
23
23
  #
24
- def class_key
24
+ def key
25
25
  "google_public_dns"
26
26
  end
27
27
  end
data/lib/mihari/rule.rb CHANGED
@@ -188,20 +188,8 @@ module Mihari
188
188
  def bulk_emit
189
189
  return [] if enriched_artifacts.empty?
190
190
 
191
- # NOTE: separate parallel execution and logging
192
- # because the logger does not work along with Parallel
193
- results = Parallel.map(emitters) { |emitter| emitter.result enriched_artifacts }
194
- results.zip(emitters).map do |result_and_emitter|
195
- result, emitter = result_and_emitter
196
-
197
- case result
198
- when Success
199
- Mihari.logger.info "Emission by #{emitter.class} succeed"
200
- else
201
- Mihari.logger.info "Emission by #{emitter.class} failed: #{result.failure}"
202
- end
203
-
204
- result.value_or nil
191
+ Parallel.map(emitters) do |emitter|
192
+ emitter.result(enriched_artifacts).value_or nil
205
193
  end.compact
206
194
  end
207
195