logstash-mixin-validator_support 1.0.1-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c5e8b335df368ec737d61dcb43db27b9876979758c615b69ade06865a973e8b8
4
+ data.tar.gz: b8668657d6af8402ed487f959750d03d49156d22f52304b4c463a8a7e0d1214f
5
+ SHA512:
6
+ metadata.gz: 48b38367a6d71c35ad0fa8d65c898e01f13ef54c8e018259c01d7b620b43398d421735b853699b813af40630f60730a1ad34fc83ba1b57ea2d277781e5a2056e
7
+ data.tar.gz: a6953c1504f89a087df7b9ffd890c8dc8db21cca1665eafed30c39d514c763315d77733637d0dc7a0fb710f25aec2c47da929c04e82f844588b6e9ceed8afc6d
@@ -0,0 +1,3 @@
1
+ # v1.0.0
2
+
3
+ - Introduces plugin parameter validation adapters, including initial backport for `:field_reference` validator.
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2020 Elastic N.V. <http://www.elastic.co>
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,63 @@
1
+ # Validator Support Mixin
2
+
3
+ This gem provides back-ports of new validators that have been added to Logstash
4
+ core. By using this support adapter, plugin developers can use newly-introduced
5
+ validators without constraining the versions of Logstash on which their plugin
6
+ can run.
7
+
8
+ When a plugin using this adapter runs on a version of Logstash that does _not_
9
+ provide the named validator, the back-ported validator provided by this adapter
10
+ is used instead.
11
+
12
+ ## Usage
13
+
14
+ 1. Add this gem as a runtime dependency of your plugin. To avoid conflicts with
15
+ other plugins, you should always use the [pessimistic operator][] `~>` to
16
+ match the minimum `1.x` that provides the back-ports you intend to use:
17
+
18
+ ~~~ ruby
19
+ Gem::Specification.new do |s|
20
+ # ...
21
+
22
+ s.add_runtime_dependency 'logstash-mixin-validator_support', '~>1.0'
23
+ end
24
+ ~~~
25
+
26
+ 2. In your plugin code, require this library and extend one or more of the
27
+ provided validators into your plugin. For example, to use the
28
+ `:field_reference` validator introduced in Logstash 7.11:
29
+
30
+ ~~~ ruby
31
+ require 'logstash/plugin_mixins/validator_support/field_reference_validation_adapter'
32
+
33
+ class LogStash::Inputs::Foo < Logstash::Inputs::Base
34
+ extend LogStash::PluginMixins::ValidatorSupport::FieldReferenceValidationAdapter
35
+
36
+ # ...
37
+ end
38
+ ~~~
39
+
40
+ 3. Use the validator as normal when defining config options; your plugin does
41
+ not need to know whether the validator was provided by Logstash core or by
42
+ this gem.
43
+
44
+ ~~~ ruby
45
+ config :target, :validate => :field_reference
46
+ ~~~
47
+
48
+ ## Development
49
+
50
+ This gem:
51
+ - *MUST* remain API-stable at 1.x
52
+ - *MUST NOT* introduce additional runtime dependencies
53
+
54
+ When developing back-ports, sometimes it may not be possible to provide a
55
+ verbatim validation. In these cases, developers should err on the side of the
56
+ back-port accepting input that the core implementation may consider invalid.
57
+
58
+ Each time a new validator is added, the runtime dependency of this library on
59
+ Logstash core should be updated to require a minimium of the OLDEST supported
60
+ release. This allows plugins using this adapter to supply patch-level fixes to
61
+ any supported Logstash version without maintaining multiple branches.
62
+
63
+ [pessimistic operator]: https://thoughtbot.com/blog/rubys-pessimistic-operator
@@ -0,0 +1,100 @@
1
+ # encoding: utf-8
2
+
3
+ require 'logstash/version'
4
+ require 'logstash/namespace'
5
+
6
+ module LogStash
7
+ module PluginMixins
8
+ module ValidatorSupport
9
+
10
+ ##
11
+ # @api internal
12
+ #
13
+ # @param base [#validate_value]
14
+ # @param validator_name [Symbol]
15
+ def self.native?(base, validator_name)
16
+ native_is_valid, native_coerced_or_error = base.validate_value(nil, validator_name)
17
+
18
+ native_is_valid || !native_coerced_or_error.start_with?('Unknown validator')
19
+ end
20
+
21
+ ##
22
+ # A NamedValidationAdapter is a module that can be mixed into a Logstash
23
+ # plugin to ensure the named validator is present and available, whether
24
+ # provided by Logstash core or approximated with the provided backport
25
+ # implementation.
26
+ #
27
+ # @api internal
28
+ #
29
+ class NamedValidationAdapter < Module
30
+ ##
31
+ # Create a new named validation adapter, to approximate the implementation
32
+ # of a named validation that exists in Logstash Core.
33
+ #
34
+ # @api private
35
+ #
36
+ # @param validator_name [Symbol]
37
+ # @yieldparam value [Hash,Array]
38
+ # @yieldreturn [true, Object]: validation success returns true with coerced value (see: ValidationResult#success)
39
+ # @yieldreturn [false, String]: validation failure returns false with error message (see: ValidationResult#failure)
40
+ def initialize(validator_name, &validator_implementation)
41
+ fail(ArgumentError, '`validator_name` must be a Symbol') unless validator_name.kind_of?(Symbol)
42
+ fail(ArgumentError, '`validator_implementation` block required') unless validator_implementation
43
+
44
+ define_singleton_method(:validate, &validator_implementation)
45
+ define_singleton_method(:name) { "#{NamedValidationAdapter}(#{validator_name})" }
46
+
47
+ define_singleton_method(:extended) do |base|
48
+ # Only include the interceptor if support is not natively provided.
49
+ unless ValidatorSupport.native?(base, validator_name)
50
+ interceptor = NamedValidationInterceptor.new(validator_name, self)
51
+ base.extend(interceptor)
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ ##
58
+ # A NamedValidationInterceptor intercepts requests to validate input with the given
59
+ # name and instead substitutes its own implementation. This implementation will
60
+ # override Logstash core functionality.
61
+ #
62
+ # @api private
63
+ #
64
+ class NamedValidationInterceptor < Module
65
+ ##
66
+ # @param validator_name [Symbol]
67
+ # @param validator [#validate]
68
+ def initialize(validator_name, validator)
69
+ fail(ArgumentError, '`validator_name` must be a Symbol') unless validator_name.kind_of?(Symbol)
70
+ fail(ArgumentError, '`validator` must respond to `\#{validate}`') unless validator.respond_to?(:validate)
71
+
72
+ define_method(:validate_value) do |value, required_validator|
73
+ if required_validator != validator_name
74
+ super(value, required_validator)
75
+ else
76
+ value = deep_replace(value)
77
+ value = hash_or_array(value)
78
+
79
+ validator.validate(value)
80
+ end
81
+ end
82
+
83
+ define_singleton_method(:name) { "#{NamedValidationInterceptor}(#{validator_name})" }
84
+ end
85
+ end
86
+
87
+ ##
88
+ # Helper functions for returning success and failure tuples
89
+ module ValidationResult
90
+ def self.success(coerced_value)
91
+ [true, coerced_value]
92
+ end
93
+
94
+ def self.failure(error_message)
95
+ [false, error_message]
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ require 'logstash/plugin_mixins/validator_support'
4
+
5
+ module LogStash
6
+ module PluginMixins
7
+ module ValidatorSupport
8
+ field_name = /[^\[\]]+/ # anything but brackets
9
+ path_fragment = /\[#{field_name}\]/ # bracket-wrapped field name
10
+ field_reference_literal = /#{path_fragment}+/ # one or more path fragments
11
+ embedded_field_reference = /\[#{field_reference_literal}\]/ # bracket-wrapped field reference literal
12
+ composite_field_reference = /#{Regexp.union(path_fragment, embedded_field_reference)}+/
13
+
14
+ # anchored pattern matching either a stand-alone field name, or a composite field reference
15
+ field_reference_pattern = /\A#{Regexp.union(field_name,composite_field_reference)}\z/
16
+
17
+ FieldReferenceValidationAdapter = NamedValidationAdapter.new(:field_reference) do |value|
18
+ break ValidationResult.failure("Expected exactly one field reference, got `#{value.inspect}`") unless value.kind_of?(Array) && value.size <= 1
19
+ break ValidationResult.success(nil) if value.empty? || value.first.nil?
20
+
21
+ candidate = value.first
22
+
23
+ break ValidationResult.failure("Expected a valid field reference, got `#{candidate.inspect}`") unless field_reference_pattern =~ candidate
24
+
25
+ break ValidationResult.success(candidate)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ require 'logstash/plugin_mixins/validator_support/field_reference_validation_adapter'
4
+
5
+ describe LogStash::PluginMixins::ValidatorSupport::FieldReferenceValidationAdapter do
6
+ it 'is an instance of NamedValidationAdapter' do
7
+ expect(described_class).to be_a_kind_of LogStash::PluginMixins::ValidatorSupport::NamedValidationAdapter
8
+ end
9
+
10
+ context '#validate' do
11
+ [
12
+ ['@timestamp'],
13
+ ['[@timestamp]'],
14
+ ['[@metadata][ssl]'],
15
+ ['[link][0]'],
16
+ ['one'],
17
+ ['[fruit][[bananas][oranges]]'],
18
+ [],
19
+ [nil]
20
+ ].each do |candidate|
21
+ context "valid input `#{candidate.inspect}`" do
22
+ it 'correctly reports the value as valid', :aggregate_failures do
23
+ is_valid_result, coerced_or_error = described_class.validate(candidate)
24
+
25
+ expect(is_valid_result).to be true
26
+ expect(coerced_or_error).to eq candidate.first
27
+ end
28
+ end
29
+ end
30
+
31
+ [
32
+ ['link[0]'],
33
+ ['][N\\//\\L][D'],
34
+ ["one","two"],
35
+ {"this" => "that"},
36
+ ['[fruit][bananas[oranges]]'],
37
+ ].each do |candidate|
38
+ let(:candidate) { candidate }
39
+
40
+ context "invalid input `#{candidate.inspect}`" do
41
+ it 'correctly reports the value as invalid', :aggregate_failures do
42
+ is_valid_result, coerced_or_error = described_class.validate(candidate)
43
+
44
+ expect(is_valid_result).to be false
45
+ expect(coerced_or_error).to be_a_kind_of String
46
+ expect(coerced_or_error).to_not include('Unknown validator')
47
+ expect(coerced_or_error).to include('field reference')
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ require "logstash/devutils/rspec/spec_helper"
4
+
5
+ require 'logstash/plugin_mixins/validator_support'
6
+
7
+ require 'securerandom'
8
+
9
+ describe LogStash::PluginMixins::ValidatorSupport::NamedValidationAdapter do
10
+ context 'an adapter re-defining a named validator that exists in Logstash core' do
11
+ let(:adapter) { described_class.new(:string) { |value| [false, 'intentional failure'] } }
12
+ let(:plugin_class) { Class.new(LogStash::Plugin) }
13
+ before(:each) { plugin_class.extend(adapter) }
14
+ context '#validate_value' do
15
+ it 'does not intercept validation' do
16
+ expect(adapter).to_not receive(:validate)
17
+
18
+ result = plugin_class.validate_value("banana", :string)
19
+
20
+ expect(result).to be_a_kind_of(Array)
21
+ expect(result.size).to eq(2)
22
+
23
+ expect(result[0]).to eq true
24
+ expect(result[1]).to eq 'banana'
25
+ end
26
+ end
27
+ end
28
+
29
+ context 'an adapter defining a named validator that does not exist in Logstash core' do
30
+ let(:validator_name) { "some_custom_validator_name_#{SecureRandom.hex(10)}".to_sym }
31
+ let(:adapter) { described_class.new(validator_name) { |value| [false, 'intentional failure'] } }
32
+ let(:plugin_class) { Class.new(LogStash::Plugin) }
33
+ before(:each) { plugin_class.extend(adapter) }
34
+
35
+ context '#validate_value' do
36
+ it 'intercepts validation' do
37
+ expect(plugin_class).to receive(:hash_or_array).and_call_original
38
+ expect(plugin_class).to receive(:deep_replace).and_call_original
39
+
40
+ expect(adapter).to receive(:validate).with(["banana"]).and_call_original
41
+
42
+ result = plugin_class.validate_value("banana", validator_name)
43
+
44
+ expect(result).to be_a_kind_of(Array)
45
+ expect(result.size).to eq(2)
46
+
47
+ expect(result[0]).to eq false
48
+ expect(result[1]).to eq 'intentional failure'
49
+ end
50
+ end
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-mixin-validator_support
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: java
6
+ authors:
7
+ - Elastic
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-12-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '6.8'
19
+ name: logstash-core
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.8'
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.9'
33
+ name: rspec
34
+ prerelease: false
35
+ type: :development
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.9'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ name: logstash-devutils
48
+ prerelease: false
49
+ type: :development
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: This gem is meant to be a dependency of any Logstash plugin that wishes
56
+ to use validators introduced in recent versions of Logstash while maintaining backward-compatibility
57
+ with earlier Logstashes. When used on older Logstash versions, it provides back-ports
58
+ of the new validators.
59
+ email: info@elastic.co
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - CHANGELOG.md
65
+ - LICENSE
66
+ - README.md
67
+ - lib/logstash/plugin_mixins/validator_support.rb
68
+ - lib/logstash/plugin_mixins/validator_support/field_reference_validation_adapter.rb
69
+ - spec/logstash/plugin_mixins/validator_support/field_reference_validation_adapter_spec.rb
70
+ - spec/logstash/plugin_mixins/validator_support_spec.rb
71
+ homepage: https://github.com/logstash-plugins/logstash-mixin-validator_support
72
+ licenses:
73
+ - Apache-2.0
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 2.6.11
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Support for the plugin parameter validations introduced in recent releases
95
+ of Logstash, for plugins wishing to use them on older Logstashes
96
+ test_files:
97
+ - spec/logstash/plugin_mixins/validator_support/field_reference_validation_adapter_spec.rb
98
+ - spec/logstash/plugin_mixins/validator_support_spec.rb