logstash-mixin-validator_support 1.0.1-java

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.
@@ -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