mihari 7.1.0 → 7.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6930da0e95068ca8e30d1f226be5692e85375f796b7246cafdd2bec566d00ff7
4
- data.tar.gz: 2bf34b1231bffcd88d402ffda335960ad929b1de91cd51b257c9c24f7b2fc16f
3
+ metadata.gz: 8ea0adf73bba53f264c22f8885d44e24de5657a2a77c2b7ea3533bb5acf6e78b
4
+ data.tar.gz: 77ab077d9322a22b0e399c81c057485aec1c4cdb1a14f15cbd81f1a3650f37a6
5
5
  SHA512:
6
- metadata.gz: fd515cdbde67d10c3fcae14c8e45a7929a34931701be176c9f9a294d3db310f522a3e186aefe548d6f119c5c8552723114da4ee6f790dbbe0391138dca9cc00e
7
- data.tar.gz: 5f4a3e1049ad55af018cf9ed2186dda49bd18517d37bc84cad6e6f60b10589834ac3bd1f09333e7f9773fab43442400c097c1063f1c304d5be5eb8991af7ec77
6
+ metadata.gz: 3b68702c146819189140c0c5626c27f7b53f94021dd21138f0ac2758366486cebb7c450e0168f76cfc3d9940ee86eb2b279eb1725a3922614f51930dcb0e6b71
7
+ data.tar.gz: e30c01360a6d382e73a8e88a40a5cd3f1dba6bac9ebbbe9b87b9b51cff4a6dc59676d19eec4fe757a3a40d78a560886e434802b74fdf125e663b73ae4c7abd8a
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
@@ -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,17 @@ 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.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.class_key} failed - #{result.failure}")
101
+ Success([])
104
102
  end
105
103
 
106
104
  class << self
@@ -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
@@ -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
@@ -30,13 +30,17 @@ module Mihari
30
30
  # @return [Dry::Monads::Result::Success<Object>, Dry::Monads::Result::Failure]
31
31
  #
32
32
  def result(artifacts)
33
- Try[StandardError] do
33
+ result = Try[StandardError] do
34
34
  retry_on_error(
35
35
  times: retry_times,
36
36
  interval: retry_interval,
37
37
  exponential_backoff: retry_exponential_backoff
38
38
  ) { call(artifacts) }
39
39
  end.to_result
40
+
41
+ Mihari.logger.warn("Emitter:#{self.class.class_key} failed - #{result.failure}") if result.failure?
42
+
43
+ result
40
44
  end
41
45
 
42
46
  class << self
@@ -19,17 +19,23 @@ 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
+ Mihari.logger.warn("Enricher:#{self.class.class_key} failed: #{result.failure}") if result.failure?
37
+
38
+ result
33
39
  end
34
40
 
35
41
  class << self
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "7.1.0"
4
+ VERSION = "7.1.1"
5
5
  end