mihari 7.1.0 → 7.1.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.
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