connectors_service 8.7.0.0.pre.20221117T004928Z → 8.11.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config/connectors.yml +10 -8
- data/lib/app/config.rb +6 -1
- data/lib/app/console_app.rb +1 -1
- data/lib/app/dispatcher.rb +18 -3
- data/lib/connectors/base/connector.rb +39 -22
- data/lib/connectors/crawler/scheduler.rb +36 -0
- data/lib/connectors/example/connector.rb +2 -2
- data/lib/connectors/example/example_advanced_snippet_validator.rb +4 -3
- data/lib/connectors/gitlab/connector.rb +4 -4
- data/lib/connectors/gitlab/gitlab_advanced_snippet_validator.rb +8 -10
- data/lib/{connectors_app/// → connectors/job_trigger_method.rb} +6 -5
- data/lib/connectors/mongodb/connector.rb +66 -56
- data/lib/connectors/mongodb/mongo_advanced_snippet_against_schema_validator.rb +2 -2
- data/lib/connectors/mongodb/mongo_advanced_snippet_schema.rb +3 -2
- data/lib/connectors/mongodb/mongo_advanced_snippet_snake_case_transformer.rb +49 -0
- data/lib/connectors/registry.rb +1 -1
- data/lib/connectors/tolerable_error_helper.rb +5 -1
- data/lib/connectors_utility.rb +6 -3
- data/lib/core/configuration.rb +13 -1
- data/lib/core/connector_job.rb +48 -7
- data/lib/core/connector_settings.rb +52 -20
- data/lib/core/elastic_connector_actions.rb +54 -38
- data/lib/core/filtering/advanced_snippet/advanced_snippet_against_schema_validator.rb +32 -0
- data/lib/core/filtering/advanced_snippet/advanced_snippet_validator.rb +27 -0
- data/lib/core/filtering/filter_validator.rb +103 -0
- data/lib/{connectors/base/advanced_snippet_against_schema_validator.rb → core/filtering/hash_against_schema_validator.rb} +58 -44
- data/lib/core/filtering/post_process_engine.rb +2 -2
- data/lib/core/filtering/processing_stage.rb +20 -0
- data/lib/core/filtering/{simple_rule.rb → simple_rules/simple_rule.rb} +34 -1
- data/lib/core/filtering/simple_rules/simple_rules_parser.rb +44 -0
- data/lib/core/filtering/simple_rules/validation/no_conflicting_policies_rules_validator.rb +47 -0
- data/lib/core/filtering/simple_rules/validation/simple_rules_schema.rb +68 -0
- data/lib/core/filtering/simple_rules/validation/simple_rules_validator.rb +25 -0
- data/lib/core/filtering/simple_rules/validation/single_rule_against_schema_validator.rb +37 -0
- data/lib/core/filtering/transform/filter_transformer.rb +26 -0
- data/lib/core/filtering/transform/filter_transformer_facade.rb +61 -0
- data/lib/core/filtering/transform/transformation_target.rb +10 -0
- data/lib/core/filtering/validation_job_runner.rb +1 -3
- data/lib/core/filtering.rb +5 -3
- data/lib/core/job_cleanup.rb +66 -0
- data/lib/core/jobs/consumer.rb +62 -64
- data/lib/core/jobs/producer.rb +3 -0
- data/lib/core/scheduler.rb +67 -52
- data/lib/core/sync_job_runner.rb +170 -83
- data/lib/core.rb +1 -0
- data/lib/utility/bulk_queue.rb +1 -1
- data/lib/utility/constants.rb +0 -2
- data/lib/utility/error_monitor.rb +26 -5
- data/lib/utility/es_client.rb +4 -0
- data/lib/utility/filtering.rb +4 -0
- metadata +32 -21
- data/lib/connectors/base/advanced_snippet_validator.rb +0 -34
- data/lib/connectors/base/simple_rules_parser.rb +0 -42
- data/lib/connectors/mongodb/mongo_rules_parser.rb +0 -81
@@ -7,83 +7,90 @@
|
|
7
7
|
|
8
8
|
require 'active_support/core_ext/hash'
|
9
9
|
require 'utility/logger'
|
10
|
-
require 'connectors/base/advanced_snippet_validator'
|
11
|
-
require 'core/filtering/validation_status'
|
12
10
|
|
13
|
-
module
|
14
|
-
module
|
15
|
-
class
|
11
|
+
module Core
|
12
|
+
module Filtering
|
13
|
+
class SchemaValidator
|
16
14
|
|
17
15
|
MAX_RECURSION_DEPTH = 50
|
18
|
-
ADVANCED_SNIPPET_ID = 'advanced_snippet'
|
19
16
|
|
20
|
-
def initialize(
|
21
|
-
super(advanced_snippet)
|
17
|
+
def initialize(schema: {}, payload: {}, error_id: '')
|
22
18
|
@schema = schema
|
19
|
+
@payload = payload
|
20
|
+
@error_id = error_id
|
23
21
|
end
|
24
22
|
|
25
|
-
def
|
26
|
-
validation_result = validate_against_schema(@schema, @advanced_snippet)
|
27
|
-
log_validation_result(validation_result)
|
28
|
-
validation_result
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def validate_against_schema(config_schema, advanced_snippet, recursion_depth = 0)
|
23
|
+
def validate_against_schema(schema = @schema, payload = @payload, recursion_depth = 0)
|
34
24
|
# Prevent unintentional/intentional SystemStackErrors/crashes
|
35
25
|
return unexpected_error if exceeded_recursion_depth?(recursion_depth)
|
36
26
|
|
37
|
-
return valid_snippet
|
27
|
+
return valid_snippet unless schema.present?
|
38
28
|
|
39
|
-
schema_fields =
|
40
|
-
snippet_field_names =
|
29
|
+
schema_fields = schema[:fields].is_a?(Hash) ? schema.dig(:fields, :values) : schema[:fields]
|
30
|
+
snippet_field_names = payload&.keys&.map(&:to_s)
|
41
31
|
schema_field_names = schema_fields.map { |field| field[:name] }
|
42
32
|
|
43
33
|
return unexpected_field(schema_field_names, snippet_field_names) if unexpected_field_present?(snippet_field_names, schema_field_names)
|
44
34
|
|
45
|
-
return fields_constraint_violation(
|
35
|
+
return fields_constraint_violation(schema[:fields]) if fields_constraints_violated?(schema[:fields], payload)
|
46
36
|
|
47
37
|
schema_fields.each do |field|
|
48
38
|
name = field[:name]
|
49
39
|
type = field[:type]
|
50
40
|
optional = field[:optional] || false
|
51
41
|
|
52
|
-
snippet_field_value =
|
42
|
+
snippet_field_value = payload.nil? ? nil : payload.with_indifferent_access[name]
|
53
43
|
|
54
44
|
next if optional && (snippet_field_value.nil? || !snippet_field_value.present?)
|
55
45
|
|
56
|
-
return
|
46
|
+
return required_value_missing(name) if is_required_value_missing?(snippet_field_value)
|
57
47
|
|
58
|
-
|
48
|
+
type_error_present, error_message = type_error_present?(name, type, snippet_field_value)
|
49
|
+
|
50
|
+
return wrong_type(error_message) if type_error_present
|
59
51
|
|
60
52
|
if field[:fields].present?
|
61
53
|
validation_result = validate_against_schema(field, snippet_field_value, recursion_depth + 1)
|
62
54
|
|
63
|
-
return validation_result unless validation_result[:
|
55
|
+
return validation_result unless validation_result[:state] == Core::Filtering::ValidationStatus::VALID
|
64
56
|
end
|
65
57
|
end
|
66
58
|
|
67
59
|
valid_snippet
|
68
60
|
end
|
69
61
|
|
70
|
-
def fields_constraints_violated?(
|
71
|
-
return false
|
62
|
+
def fields_constraints_violated?(fields, payload)
|
63
|
+
return false if !fields.present? || !fields.is_a?(Hash)
|
72
64
|
|
73
|
-
constraints =
|
65
|
+
constraints = fields[:constraints]
|
74
66
|
constraints = constraints.is_a?(Array) ? constraints : [constraints]
|
75
67
|
|
76
68
|
constraints.each do |constraint|
|
77
|
-
return true unless constraint.call(
|
69
|
+
return true unless constraint.call(payload)
|
78
70
|
end
|
79
71
|
|
80
72
|
false
|
81
73
|
end
|
82
74
|
|
83
|
-
def type_error_present?(schema_type,
|
84
|
-
|
75
|
+
def type_error_present?(field_name, schema_type, actual_value)
|
76
|
+
if schema_type.is_a?(Proc)
|
77
|
+
result = schema_type.call(actual_value)
|
78
|
+
|
79
|
+
# could already have a custom error message
|
80
|
+
if result.is_a?(Array)
|
81
|
+
is_valid, error_msg = result
|
82
|
+
|
83
|
+
return !is_valid, error_msg
|
84
|
+
end
|
85
|
+
|
86
|
+
# could only return a single boolean
|
87
|
+
return !result, 'Custom type matcher validation failed.'
|
88
|
+
end
|
89
|
+
|
90
|
+
error_msg = "Expected field type '#{schema_type}' for field '#{field_name}', but got value '#{actual_value.inspect}' of type '#{actual_value.class}'."
|
91
|
+
return true, error_msg unless actual_value.is_a?(schema_type)
|
85
92
|
|
86
|
-
|
93
|
+
false
|
87
94
|
end
|
88
95
|
|
89
96
|
def exceeded_recursion_depth?(recursion_depth)
|
@@ -96,12 +103,18 @@ module Connectors
|
|
96
103
|
end
|
97
104
|
|
98
105
|
def unexpected_field_present?(actual_field_names, expected_field_names)
|
106
|
+
return false unless actual_field_names.present?
|
107
|
+
|
99
108
|
difference = actual_field_names - expected_field_names
|
100
109
|
|
101
110
|
# we have field names, which we didn't expect
|
102
111
|
!difference.empty?
|
103
112
|
end
|
104
113
|
|
114
|
+
def is_required_value_missing?(snippet_field_value)
|
115
|
+
!snippet_field_value.present?
|
116
|
+
end
|
117
|
+
|
105
118
|
def valid_snippet
|
106
119
|
{
|
107
120
|
:state => Core::Filtering::ValidationStatus::VALID,
|
@@ -109,37 +122,37 @@ module Connectors
|
|
109
122
|
}
|
110
123
|
end
|
111
124
|
|
112
|
-
def
|
125
|
+
def required_value_missing(field)
|
113
126
|
{
|
114
127
|
:state => Core::Filtering::ValidationStatus::INVALID,
|
115
128
|
:errors => [
|
116
129
|
{
|
117
|
-
:ids => [
|
118
|
-
:messages => ["
|
130
|
+
:ids => [@error_id],
|
131
|
+
:messages => ["Required value missing for field '#{field}'."]
|
119
132
|
}
|
120
133
|
]
|
121
134
|
}
|
122
135
|
end
|
123
136
|
|
124
|
-
def
|
137
|
+
def unexpected_field(expected_fields, actual_fields)
|
125
138
|
{
|
126
139
|
:state => Core::Filtering::ValidationStatus::INVALID,
|
127
140
|
:errors => [
|
128
141
|
{
|
129
|
-
:ids => [
|
130
|
-
:messages => ["
|
142
|
+
:ids => [@error_id],
|
143
|
+
:messages => ["Encountered unexpected fields '#{actual_fields}'. Expected: '#{expected_fields}'."]
|
131
144
|
}
|
132
145
|
]
|
133
146
|
}
|
134
147
|
end
|
135
148
|
|
136
|
-
def
|
149
|
+
def wrong_type(error_message)
|
137
150
|
{
|
138
151
|
:state => Core::Filtering::ValidationStatus::INVALID,
|
139
152
|
:errors => [
|
140
153
|
{
|
141
|
-
:ids => [
|
142
|
-
:messages => [
|
154
|
+
:ids => [@error_id],
|
155
|
+
:messages => [error_message]
|
143
156
|
}
|
144
157
|
]
|
145
158
|
}
|
@@ -150,8 +163,8 @@ module Connectors
|
|
150
163
|
:state => Core::Filtering::ValidationStatus::INVALID,
|
151
164
|
:errors => [
|
152
165
|
{
|
153
|
-
:ids => [
|
154
|
-
:messages => ["A fields constraint was violated for fields: '#{fields[:values].map { |v| v[:name] }}'.
|
166
|
+
:ids => [@error_id],
|
167
|
+
:messages => ["A fields constraint was violated for fields: '#{fields[:values].map { |v| v[:name] }}'."]
|
155
168
|
}
|
156
169
|
]
|
157
170
|
}
|
@@ -162,12 +175,13 @@ module Connectors
|
|
162
175
|
:state => Core::Filtering::ValidationStatus::INVALID,
|
163
176
|
:errors => [
|
164
177
|
{
|
165
|
-
:ids => [
|
178
|
+
:ids => [@error_id],
|
166
179
|
:messages => ['Unexpected error. Check logs for details.']
|
167
180
|
}
|
168
181
|
]
|
169
182
|
}
|
170
183
|
end
|
184
|
+
|
171
185
|
end
|
172
186
|
end
|
173
187
|
end
|
@@ -14,8 +14,8 @@ module Core
|
|
14
14
|
class PostProcessEngine
|
15
15
|
attr_reader :rules
|
16
16
|
|
17
|
-
def initialize(
|
18
|
-
@rules = ordered_rules(
|
17
|
+
def initialize(filtering)
|
18
|
+
@rules = ordered_rules(filtering)
|
19
19
|
end
|
20
20
|
|
21
21
|
def process(document)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#
|
2
|
+
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
3
|
+
# or more contributor license agreements. Licensed under the Elastic License;
|
4
|
+
# you may not use this file except in compliance with the Elastic License.
|
5
|
+
#
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
module Core
|
9
|
+
module Filtering
|
10
|
+
class ProcessingStage
|
11
|
+
PRE = 'pre-processing'
|
12
|
+
POST = 'post-processing'
|
13
|
+
|
14
|
+
ALL = [
|
15
|
+
PRE,
|
16
|
+
POST
|
17
|
+
]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -16,6 +16,11 @@ module Core
|
|
16
16
|
class Policy
|
17
17
|
INCLUDE = 'include'
|
18
18
|
EXCLUDE = 'exclude'
|
19
|
+
|
20
|
+
POLICIES = [
|
21
|
+
INCLUDE,
|
22
|
+
EXCLUDE
|
23
|
+
]
|
19
24
|
end
|
20
25
|
|
21
26
|
class Rule
|
@@ -26,6 +31,16 @@ module Core
|
|
26
31
|
CONTAINS = 'contains'
|
27
32
|
LESS_THAN = '<'
|
28
33
|
GREATER_THAN = '>'
|
34
|
+
|
35
|
+
RULES = [
|
36
|
+
REGEX,
|
37
|
+
EQUALS,
|
38
|
+
STARTS_WITH,
|
39
|
+
ENDS_WITH,
|
40
|
+
CONTAINS,
|
41
|
+
LESS_THAN,
|
42
|
+
GREATER_THAN
|
43
|
+
]
|
29
44
|
end
|
30
45
|
|
31
46
|
attr_reader :policy, :field, :rule, :value, :id
|
@@ -123,6 +138,18 @@ module Core
|
|
123
138
|
@rule_hash
|
124
139
|
end
|
125
140
|
|
141
|
+
def try_coerce_value
|
142
|
+
coerced = to_float(value)
|
143
|
+
begin
|
144
|
+
coerced = to_date(value) if coerced.is_a?(String)
|
145
|
+
rescue ArgumentError
|
146
|
+
coerced = to_bool(value) if coerced.is_a?(String)
|
147
|
+
end
|
148
|
+
coerced
|
149
|
+
rescue StandardError
|
150
|
+
value
|
151
|
+
end
|
152
|
+
|
126
153
|
private
|
127
154
|
|
128
155
|
def to_bool(str)
|
@@ -134,7 +161,13 @@ module Core
|
|
134
161
|
def to_date(str)
|
135
162
|
DateTime.parse(str)
|
136
163
|
rescue ArgumentError
|
137
|
-
Time.at(
|
164
|
+
Time.at(Integer(value)) # try with it as an int string of millis
|
165
|
+
end
|
166
|
+
|
167
|
+
def to_float(value)
|
168
|
+
Float(value)
|
169
|
+
rescue StandardError
|
170
|
+
value
|
138
171
|
end
|
139
172
|
end
|
140
173
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#
|
2
|
+
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
3
|
+
# or more contributor license agreements. Licensed under the Elastic License;
|
4
|
+
# you may not use this file except in compliance with the Elastic License.
|
5
|
+
#
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
9
|
+
require 'active_support/core_ext/object/blank'
|
10
|
+
require 'core/filtering/simple_rules/simple_rule'
|
11
|
+
|
12
|
+
module Core
|
13
|
+
module Filtering
|
14
|
+
module SimpleRules
|
15
|
+
class SimpleRulesParser
|
16
|
+
def initialize(rules)
|
17
|
+
@rules = (rules || []).map(&:with_indifferent_access).filter { |r| r[:id] != 'DEFAULT' }.sort_by { |r| r[:order] }
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse
|
21
|
+
merge_rules(@rules.map do |rule_hash|
|
22
|
+
rule = Core::Filtering::SimpleRule.new(rule_hash)
|
23
|
+
unless rule.is_include? || rule.is_exclude?
|
24
|
+
raise "Unknown policy: #{rule.policy}"
|
25
|
+
end
|
26
|
+
parse_rule(rule)
|
27
|
+
end)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# merge all rules into a filter object or array
|
33
|
+
# in a base case, does no transformations
|
34
|
+
def merge_rules(rules)
|
35
|
+
rules || []
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse_rule(_rule)
|
39
|
+
raise 'Not implemented'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#
|
2
|
+
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
3
|
+
# or more contributor license agreements. Licensed under the Elastic License;
|
4
|
+
# you may not use this file except in compliance with the Elastic License.
|
5
|
+
#
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
require 'core/filtering/simple_rules/validation/simple_rules_validator'
|
9
|
+
require 'core/filtering/validation_status'
|
10
|
+
|
11
|
+
module Core
|
12
|
+
module Filtering
|
13
|
+
module SimpleRules
|
14
|
+
module Validation
|
15
|
+
class NoConflictingPoliciesRulesValidator < Core::Filtering::SimpleRules::Validation::SimpleRulesValidator
|
16
|
+
|
17
|
+
def are_rules_valid
|
18
|
+
rule_field_value_to_policy = {}
|
19
|
+
|
20
|
+
@rules.each do |simple_rule|
|
21
|
+
rule_field_value = simple_rule.slice('rule', 'field', 'value')
|
22
|
+
policy = simple_rule['policy']
|
23
|
+
|
24
|
+
return conflicting_rules(rule_field_value) if rule_field_value_to_policy.key?(rule_field_value)
|
25
|
+
|
26
|
+
rule_field_value_to_policy[rule_field_value] = policy
|
27
|
+
end
|
28
|
+
|
29
|
+
{ :state => Core::Filtering::ValidationStatus::VALID, :errors => [] }
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def conflicting_rules(rule_type_value)
|
35
|
+
{
|
36
|
+
:state => Core::Filtering::ValidationStatus::INVALID,
|
37
|
+
:errors => [
|
38
|
+
:ids => [SIMPLE_RULES_ID],
|
39
|
+
:messages => ["Two simple rules with same rule (#{rule_type_value['rule']}), field (#{rule_type_value['field']}), value (#{rule_type_value['value']}) and conflicting policies detected."]
|
40
|
+
]
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#
|
2
|
+
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
3
|
+
# or more contributor license agreements. Licensed under the Elastic License;
|
4
|
+
# you may not use this file except in compliance with the Elastic License.
|
5
|
+
#
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
require 'core/filtering/simple_rules/simple_rule'
|
9
|
+
|
10
|
+
module Core
|
11
|
+
module Filtering
|
12
|
+
module SimpleRules
|
13
|
+
module Validation
|
14
|
+
DEFAULT_RULE_ID = 'DEFAULT'
|
15
|
+
|
16
|
+
ALLOWED_VALUE_TYPES = ->(rule_value) { rule_value.is_a?(String) || rule_value.is_a?(Integer) || rule_value.is_a?(TrueClass) || rule_value.is_a?(FalseClass) }
|
17
|
+
MATCH_ALL_REGEX_NOT_ALLOWED = ->(simple_rule) { simple_rule['id'] == DEFAULT_RULE_ID || !(simple_rule['rule'] == Core::Filtering::SimpleRule::Rule::REGEX && (simple_rule['value'] == '(.*)' || simple_rule['value'] == '.*')) }
|
18
|
+
|
19
|
+
SINGLE_RULE_SCHEMA = {
|
20
|
+
:fields => {
|
21
|
+
:constraints => [MATCH_ALL_REGEX_NOT_ALLOWED],
|
22
|
+
:values => [
|
23
|
+
{
|
24
|
+
:name => 'id',
|
25
|
+
:type => String,
|
26
|
+
:optional => false
|
27
|
+
},
|
28
|
+
{
|
29
|
+
:name => 'field',
|
30
|
+
:type => String,
|
31
|
+
:optional => false
|
32
|
+
},
|
33
|
+
{
|
34
|
+
:name => 'value',
|
35
|
+
:type => ALLOWED_VALUE_TYPES,
|
36
|
+
:optional => false
|
37
|
+
},
|
38
|
+
{
|
39
|
+
:name => 'policy',
|
40
|
+
:type => ->(policy) { Core::Filtering::SimpleRule::Policy::POLICIES.include?(policy) },
|
41
|
+
:optional => false
|
42
|
+
},
|
43
|
+
{
|
44
|
+
:name => 'rule',
|
45
|
+
:type => ->(rule) { Core::Filtering::SimpleRule::Rule::RULES.include?(rule) },
|
46
|
+
:optional => false
|
47
|
+
},
|
48
|
+
{
|
49
|
+
:name => 'order',
|
50
|
+
:type => ->(order) { order.is_a?(Integer) && order >= 0 },
|
51
|
+
},
|
52
|
+
{
|
53
|
+
:name => 'updated_at',
|
54
|
+
:type => String,
|
55
|
+
:optional => true
|
56
|
+
},
|
57
|
+
{
|
58
|
+
:name => 'created_at',
|
59
|
+
:type => String,
|
60
|
+
:optional => true
|
61
|
+
}
|
62
|
+
]
|
63
|
+
}
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
2
|
+
# or more contributor license agreements. Licensed under the Elastic License;
|
3
|
+
# you may not use this file except in compliance with the Elastic License.
|
4
|
+
#
|
5
|
+
# frozen_string_literal: true
|
6
|
+
|
7
|
+
module Core
|
8
|
+
module Filtering
|
9
|
+
module SimpleRules
|
10
|
+
module Validation
|
11
|
+
SIMPLE_RULES_ID = 'simple_rules'
|
12
|
+
|
13
|
+
class SimpleRulesValidator
|
14
|
+
def initialize(rules)
|
15
|
+
@rules = rules || []
|
16
|
+
end
|
17
|
+
|
18
|
+
def are_rules_valid
|
19
|
+
raise 'Simple rules validation not implemented'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#
|
2
|
+
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
3
|
+
# or more contributor license agreements. Licensed under the Elastic License;
|
4
|
+
# you may not use this file except in compliance with the Elastic License.
|
5
|
+
#
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
require 'core/filtering/simple_rules/validation/simple_rules_validator'
|
9
|
+
require 'core/filtering/hash_against_schema_validator'
|
10
|
+
require 'core/filtering/simple_rules/validation/simple_rules_schema'
|
11
|
+
|
12
|
+
module Core
|
13
|
+
module Filtering
|
14
|
+
module SimpleRules
|
15
|
+
module Validation
|
16
|
+
class SingleRuleAgainstSchemaValidator < Core::Filtering::SimpleRules::Validation::SimpleRulesValidator
|
17
|
+
|
18
|
+
def initialize(rules, schema = Core::Filtering::SimpleRules::Validation::SINGLE_RULE_SCHEMA)
|
19
|
+
super(rules)
|
20
|
+
@schema = schema
|
21
|
+
@schema_validator = SchemaValidator.new(error_id: SIMPLE_RULES_ID)
|
22
|
+
end
|
23
|
+
|
24
|
+
def are_rules_valid
|
25
|
+
@rules.each do |rule|
|
26
|
+
validation_result = @schema_validator.validate_against_schema(@schema, rule)
|
27
|
+
return validation_result unless validation_result[:state] == Core::Filtering::ValidationStatus::VALID
|
28
|
+
end
|
29
|
+
|
30
|
+
{ :state => Core::Filtering::ValidationStatus::VALID, :errors => [] }
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#
|
2
|
+
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
3
|
+
# or more contributor license agreements. Licensed under the Elastic License;
|
4
|
+
# you may not use this file except in compliance with the Elastic License.
|
5
|
+
#
|
6
|
+
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
module Core
|
10
|
+
module Filtering
|
11
|
+
module Transform
|
12
|
+
class FilterTransformer
|
13
|
+
|
14
|
+
def initialize(filter = {}, transformation = (->(_filter) { filter }))
|
15
|
+
@filter = filter
|
16
|
+
@transformation = transformation
|
17
|
+
end
|
18
|
+
|
19
|
+
def transform
|
20
|
+
@transformation.call(@filter)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#
|
2
|
+
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
3
|
+
# or more contributor license agreements. Licensed under the Elastic License;
|
4
|
+
# you may not use this file except in compliance with the Elastic License.
|
5
|
+
#
|
6
|
+
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require 'core/filtering/transform/transformation_target'
|
10
|
+
require 'core/filtering/transform/filter_transformer'
|
11
|
+
|
12
|
+
module Core
|
13
|
+
module Filtering
|
14
|
+
module Transform
|
15
|
+
class FilterTransformerFacade < Core::Filtering::Transform::FilterTransformer
|
16
|
+
|
17
|
+
def initialize(filter = {},
|
18
|
+
filter_transformers = {
|
19
|
+
Core::Filtering::Transform::TransformationTarget::ADVANCED_SNIPPET => [],
|
20
|
+
Core::Filtering::Transform::TransformationTarget::RULES => [],
|
21
|
+
})
|
22
|
+
super(filter)
|
23
|
+
|
24
|
+
rule_transformer_classes = filter_transformers[Core::Filtering::Transform::TransformationTarget::RULES]
|
25
|
+
snippet_transformer_classes = filter_transformers[Core::Filtering::Transform::TransformationTarget::ADVANCED_SNIPPET]
|
26
|
+
|
27
|
+
@rule_transformers = rule_transformer_classes.is_a?(Array) ? rule_transformer_classes : [rule_transformer_classes]
|
28
|
+
@snippet_transformers = snippet_transformer_classes.is_a?(Array) ? snippet_transformer_classes : [snippet_transformer_classes]
|
29
|
+
|
30
|
+
@facade = FilterTransformer.new(filter, execute_rule_and_snippet_transformations)
|
31
|
+
end
|
32
|
+
|
33
|
+
def transform
|
34
|
+
@facade.transform
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def execute_rule_and_snippet_transformations
|
40
|
+
lambda do |filter|
|
41
|
+
rules = filter[:rules]
|
42
|
+
advanced_snippet = filter[:advanced_snippet]
|
43
|
+
|
44
|
+
{
|
45
|
+
:rules => call_transformers(@rule_transformers, rules),
|
46
|
+
:advanced_snippet => call_transformers(@snippet_transformers, advanced_snippet)
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def call_transformers(transformer_classes, payload)
|
52
|
+
transformer_classes.each do |transformer_class|
|
53
|
+
payload = transformer_class.new(payload).transform if transformer_class.present?
|
54
|
+
end
|
55
|
+
|
56
|
+
payload
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -11,8 +11,6 @@ require 'connectors/registry'
|
|
11
11
|
|
12
12
|
module Core
|
13
13
|
module Filtering
|
14
|
-
DEFAULT_DOMAIN = 'DEFAULT'
|
15
|
-
|
16
14
|
class ValidationJobRunner
|
17
15
|
def initialize(connector_settings)
|
18
16
|
@connector_settings = connector_settings
|
@@ -27,7 +25,7 @@ module Core
|
|
27
25
|
validation_result = @connector_class.validate_filtering(@connector_settings.filtering[:draft])
|
28
26
|
|
29
27
|
# currently only used for connectors -> DEFAULT domain can be assumed (will be changed with the integration of crawler)
|
30
|
-
ElasticConnectorActions.update_filtering_validation(@connector_settings.id, { DEFAULT_DOMAIN => validation_result })
|
28
|
+
ElasticConnectorActions.update_filtering_validation(@connector_settings.id, { Core::Filtering::DEFAULT_DOMAIN => validation_result })
|
31
29
|
|
32
30
|
@validation_finished = true
|
33
31
|
rescue StandardError => e
|
data/lib/core/filtering.rb
CHANGED
@@ -8,10 +8,12 @@
|
|
8
8
|
|
9
9
|
require 'core/filtering/post_process_engine'
|
10
10
|
require 'core/filtering/post_process_result'
|
11
|
-
require 'core/filtering/simple_rule'
|
11
|
+
require 'core/filtering/simple_rules/simple_rule'
|
12
12
|
require 'core/filtering/validation_job_runner'
|
13
13
|
require 'core/filtering/validation_status'
|
14
14
|
|
15
|
-
module Core
|
16
|
-
|
15
|
+
module Core
|
16
|
+
module Filtering
|
17
|
+
DEFAULT_DOMAIN = 'DEFAULT'
|
18
|
+
end
|
17
19
|
end
|