From 402ccfc67fe5be8c9337ef25197feb712adc3de4 Mon Sep 17 00:00:00 2001 From: Tristan Starck Date: Fri, 4 Mar 2022 11:32:01 -0800 Subject: [PATCH 1/7] Add substring targeting --- CHANGELOG.md | 4 ++ Gemfile.lock | 10 ++--- README.md | 8 ++++ lib/process_settings/target.rb | 6 +++ lib/process_settings/version.rb | 2 +- spec/lib/process_settings/target_spec.rb | 48 ++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd71d14..71e3b43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.20.0] - 2022-03-04 +### Added +- Added substring matching for targeting. See [README.md](README.md#Matching-Values) for usage examples. + ## [0.19.0] - 2021-07-09 ### Fixed - Fixed a bug where accessing a setting that is a `Hash` defined across multiple file entries diff --git a/Gemfile.lock b/Gemfile.lock index 517af42..92b5582 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - process_settings (0.19.0) + process_settings (0.20.0.pre.1) activesupport (>= 4.2, < 7) json listen (~> 3.0) @@ -26,11 +26,11 @@ GEM concurrent-ruby (1.1.7) diff-lcs (1.3) docile (1.4.0) - ffi (1.15.3) + ffi (1.15.5) i18n (1.8.5) concurrent-ruby (~> 1.0) - json (2.1.0) - listen (3.5.1) + json (2.6.1) + listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) method_source (0.9.0) @@ -45,7 +45,7 @@ GEM psych (3.3.2) rainbow (3.0.0) rake (12.3.3) - rb-fsevent (0.11.0) + rb-fsevent (0.11.1) rb-inotify (0.10.1) ffi (~> 1.0) rspec (3.8.0) diff --git a/README.md b/README.md index 843c6fd..0b607d0 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,14 @@ target: ``` This will be applied in any process that has (`service_name == "frontend"` OR `service_name == "auth"`) AND `datacenter == "AWS-US-EAST-1"`. +### Matching Values +By adding a backslash `/` at the front and end of a value, context values will be applied if the string between the backslashes is a substring of the value. +``` +target: + service_name: /frontend/ +``` +This will be applied in any process that has `service_name =~ "frontend"`. As an example this will match `"frontend-1"` + ### Precedence The settings YAML files are always combined in alphabetical order by file path. Later settings take precedence over the earlier ones. diff --git a/lib/process_settings/target.rb b/lib/process_settings/target.rb index 3ea46ab..63e2814 100644 --- a/lib/process_settings/target.rb +++ b/lib/process_settings/target.rb @@ -90,6 +90,12 @@ def target_key_matches?(target_value, context_hash) end when true, false target_value + when String + if target_value =~ /\/.+\// # Any string that starts and ends with backslashes. + context_hash.match?(target_value[1..-2]) + else + target_value == context_hash + end else target_value == context_hash end diff --git a/lib/process_settings/version.rb b/lib/process_settings/version.rb index 1aed95d..4314e89 100644 --- a/lib/process_settings/version.rb +++ b/lib/process_settings/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ProcessSettings - VERSION = '0.19.0' + VERSION = '0.20.0.pre.1' end diff --git a/spec/lib/process_settings/target_spec.rb b/spec/lib/process_settings/target_spec.rb index 31e27b7..c830270 100644 --- a/spec/lib/process_settings/target_spec.rb +++ b/spec/lib/process_settings/target_spec.rb @@ -134,6 +134,54 @@ expect(process_target.target_key_matches?(context_hash)).to be_truthy expect(process_target.target_key_matches?({})).to be_falsey end + + context "for substring matching" do + it "should match on values when using backslash delimiters in target hash" do + context_hash = { + 'service' => 'telecom-1', + 'region' => 'east', + 'cdr' => { 'caller' => '+18056807000' } + } + target_hash = { + 'service' => '/telecom/' + } + process_target = described_class.new(target_hash) + expect(process_target.target_key_matches?(context_hash)).to be_truthy + expect(process_target.target_key_matches?({})).to be_falsey + expect(process_target.target_key_matches?({ 'service' => 'tele' })).to be_falsey + end + + it "should not match if no characters are between the backslash delimiters" do + context_hash = { + 'service' => 'telecom', + 'region' => 'east', + 'cdr' => { 'caller' => '+18056807000' } + } + target_hash = { + 'service' => '//' + } + process_target = described_class.new(target_hash) + expect(process_target.target_key_matches?(context_hash)).to be_falsey + expect(process_target.target_key_matches?({})).to be_falsey + expect(process_target.target_key_matches?({ 'service' => '' })).to be_falsey + expect(process_target.target_key_matches?({ 'service' => '//' })).to be_truthy + end + + it "should not match if only one backslash delimiter is provdied" do + context_hash = { + 'service' => 'telecom', + 'region' => 'east', + 'cdr' => { 'caller' => '+18056807000' } + } + target_hash = { + 'service' => '/telecom' + } + process_target = described_class.new(target_hash) + expect(process_target.target_key_matches?(context_hash)).to be_falsey + expect(process_target.target_key_matches?({})).to be_falsey + expect(process_target.target_key_matches?({ 'service' => '/telecom' })).to be_truthy + end + end end describe "#with_static_context" do From 3af2fba277946f03429f47594ad8a5225464fb3b Mon Sep 17 00:00:00 2001 From: Tristan Starck Date: Fri, 4 Mar 2022 15:48:27 -0800 Subject: [PATCH 2/7] fix pattern matching to not match on internal embedded slashes --- README.md | 4 +- lib/process_settings/target.rb | 4 +- spec/lib/process_settings/target_spec.rb | 131 ++++++++++++++++------- 3 files changed, 97 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 0b607d0..0688094 100644 --- a/README.md +++ b/README.md @@ -165,12 +165,12 @@ target: This will be applied in any process that has (`service_name == "frontend"` OR `service_name == "auth"`) AND `datacenter == "AWS-US-EAST-1"`. ### Matching Values -By adding a backslash `/` at the front and end of a value, context values will be applied if the string between the backslashes is a substring of the value. +By adding a slash `/` at the front and end of a value, context values will be applied if the string between the slashes is a substring of the value. ``` target: service_name: /frontend/ ``` -This will be applied in any process that has `service_name =~ "frontend"`. As an example this will match `"frontend-1"` +This will be applied in any process that has `service_name =~ /frontend/`. As an example this will match `"frontend-1"` ### Precedence The settings YAML files are always combined in alphabetical order by file path. Later settings take precedence over the earlier ones. diff --git a/lib/process_settings/target.rb b/lib/process_settings/target.rb index 63e2814..a3f067e 100644 --- a/lib/process_settings/target.rb +++ b/lib/process_settings/target.rb @@ -91,8 +91,8 @@ def target_key_matches?(target_value, context_hash) when true, false target_value when String - if target_value =~ /\/.+\// # Any string that starts and ends with backslashes. - context_hash.match?(target_value[1..-2]) + if (pattern = target_value[/\A \/ (.+) \/ \z/x, 1]) # Any string that starts and ends with slashes. + context_hash.match?(pattern) else target_value == context_hash end diff --git a/spec/lib/process_settings/target_spec.rb b/spec/lib/process_settings/target_spec.rb index c830270..2437aa5 100644 --- a/spec/lib/process_settings/target_spec.rb +++ b/spec/lib/process_settings/target_spec.rb @@ -135,51 +135,106 @@ expect(process_target.target_key_matches?({})).to be_falsey end - context "for substring matching" do - it "should match on values when using backslash delimiters in target hash" do - context_hash = { - 'service' => 'telecom-1', + describe "for substring matching" do + subject { process_target.target_key_matches?(context_hash) } + let(:process_target) { described_class.new(target_hash) } + let(:context_hash) do + { + 'service' => service, 'region' => 'east', 'cdr' => { 'caller' => '+18056807000' } } - target_hash = { - 'service' => '/telecom/' - } - process_target = described_class.new(target_hash) - expect(process_target.target_key_matches?(context_hash)).to be_truthy - expect(process_target.target_key_matches?({})).to be_falsey - expect(process_target.target_key_matches?({ 'service' => 'tele' })).to be_falsey end - it "should not match if no characters are between the backslash delimiters" do - context_hash = { - 'service' => 'telecom', - 'region' => 'east', - 'cdr' => { 'caller' => '+18056807000' } - } - target_hash = { - 'service' => '//' - } - process_target = described_class.new(target_hash) - expect(process_target.target_key_matches?(context_hash)).to be_falsey - expect(process_target.target_key_matches?({})).to be_falsey - expect(process_target.target_key_matches?({ 'service' => '' })).to be_falsey - expect(process_target.target_key_matches?({ 'service' => '//' })).to be_truthy + context "with target value that has a slash at the start and end" do + let(:target_hash) { { 'service' => '/telecom/' } } + + context "when context hash value matches" do + let(:service) { 'telecom-1' } + + it { is_expected.to be_truthy } + end + + context "with an empty context hash" do + let(:context_hash) { {} } + it { is_expected.to be_falsey } + end + + context "with a non-matching context value" do + let(:service) { 'tele' } + it { is_expected.to be_falsey } + end end - it "should not match if only one backslash delimiter is provdied" do - context_hash = { - 'service' => 'telecom', - 'region' => 'east', - 'cdr' => { 'caller' => '+18056807000' } - } - target_hash = { - 'service' => '/telecom' - } - process_target = described_class.new(target_hash) - expect(process_target.target_key_matches?(context_hash)).to be_falsey - expect(process_target.target_key_matches?({})).to be_falsey - expect(process_target.target_key_matches?({ 'service' => '/telecom' })).to be_truthy + context "when target value only has a leading slash" do + let(:target_hash) { { 'service' => '/telecom' } } + + context "when context hash value has the string but not the slash" do + let(:service) { 'telecom' } + + it { is_expected.to be_falsey } + end + + context "when context hash value exactly matches target value" do + let(:service) { '/telecom' } + it { is_expected.to be_truthy } + end + end + + context "when target value only has a trailing slash" do + let(:target_hash) { { 'service' => 'telecom/' } } + + context "when context hash value has the string but not the slash" do + let(:service) { 'telecom' } + + it { is_expected.to be_falsey } + end + + context "when context hash value exactly matches target value" do + let(:service) { 'telecom/' } + it { is_expected.to be_truthy } + end + end + + context "when target value has embedded slashes (not at the front or back)" do + let(:target_hash) { { 'service' => 'tmp/dir/log' } } + + context "when context hash value is the target value except the first and last character" do + let(:service) { 'mp/dir/lo' } + it { is_expected.to be_falsey } + end + + context "when context hash value exactly matches target value" do + let(:service) { 'tmp/dir/log' } + it { is_expected.to be_truthy } + end + end + + context "when target value is valid and also has embedded slashes" do + let(:target_hash) { { 'service' => '/tmp/dir/log/'} } + + context "when context hash value matches the target" do + let(:service) { 'tmp/dir/log/service-log.txt' } + it { is_expected.to be_truthy } + end + + context "when context hash only has whats between the embedded slashes" do + let(:service) { 'dir' } + it { is_expected.to be_falsey } + end + end + + context "when target value is two slashes and nothing else" do + let(:target_hash) { { 'service' => '//' } } + context "when context hash value exactly matches" do + let(:service) {'//' } + it { is_expected.to be_truthy } + end + + context "when context hash value is empty" do + let(:service) {'' } + it { is_expected.to be_falsey } + end end end end From 7a82f9b4046d9a53b9a850a30b304ed3291de6b4 Mon Sep 17 00:00:00 2001 From: Tristan Starck Date: Mon, 7 Mar 2022 10:50:55 -0800 Subject: [PATCH 3/7] use regex matching example in readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0688094..2f67171 100644 --- a/README.md +++ b/README.md @@ -165,12 +165,12 @@ target: This will be applied in any process that has (`service_name == "frontend"` OR `service_name == "auth"`) AND `datacenter == "AWS-US-EAST-1"`. ### Matching Values -By adding a slash `/` at the front and end of a value, context values will be applied if the string between the slashes is a substring of the value. +To provide a regular expression for matching, surround it with a leading and trailing slash `/`. For example: ``` target: - service_name: /frontend/ + service_name: /frontend-\d/ ``` -This will be applied in any process that has `service_name =~ /frontend/`. As an example this will match `"frontend-1"` +This will be applied in any process that has `service_name` that has `frontend-` followed with a number. As an example this will match `"frontend-1"` ### Precedence The settings YAML files are always combined in alphabetical order by file path. Later settings take precedence over the earlier ones. From c2e5de20970435ffe3ac81416505ef8c7f855ff7 Mon Sep 17 00:00:00 2001 From: Tristan Starck Date: Mon, 7 Mar 2022 16:07:52 -0800 Subject: [PATCH 4/7] swap wording to regex instead of substring --- CHANGELOG.md | 2 +- README.md | 4 ++-- spec/lib/process_settings/target_spec.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71e3b43..4e178fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0 ## [0.20.0] - 2022-03-04 ### Added -- Added substring matching for targeting. See [README.md](README.md#Matching-Values) for usage examples. +- Added regular expressions capabilities to targeting. See [README.md](README.md#Regexp-Targeting) for usage examples. ## [0.19.0] - 2021-07-09 ### Fixed diff --git a/README.md b/README.md index 2f67171..888f55c 100644 --- a/README.md +++ b/README.md @@ -164,8 +164,8 @@ target: ``` This will be applied in any process that has (`service_name == "frontend"` OR `service_name == "auth"`) AND `datacenter == "AWS-US-EAST-1"`. -### Matching Values -To provide a regular expression for matching, surround it with a leading and trailing slash `/`. For example: +### Regexp Targeting +To provide a regular expression for targeting, surround it with a leading and trailing slash `/`. For example: ``` target: service_name: /frontend-\d/ diff --git a/spec/lib/process_settings/target_spec.rb b/spec/lib/process_settings/target_spec.rb index 2437aa5..82080b4 100644 --- a/spec/lib/process_settings/target_spec.rb +++ b/spec/lib/process_settings/target_spec.rb @@ -135,7 +135,7 @@ expect(process_target.target_key_matches?({})).to be_falsey end - describe "for substring matching" do + describe "for regex matching" do subject { process_target.target_key_matches?(context_hash) } let(:process_target) { described_class.new(target_hash) } let(:context_hash) do From 8730e8ed21b9448718967b52683240daa1b0b58b Mon Sep 17 00:00:00 2001 From: Tristan Starck Date: Fri, 25 Mar 2022 11:21:05 -0700 Subject: [PATCH 5/7] utilize ruby yaml parser's regex keyword --- CHANGELOG.md | 2 +- README.md | 4 +- lib/process_settings/target.rb | 8 +-- spec/bin/combine_process_settings_spec.rb | 5 ++ .../combined_process_settings-20.yml | 47 ++++++++++++++++ .../production/settings/regex_target.yml | 5 ++ spec/lib/process_settings/target_spec.rb | 56 +++---------------- .../targeted_settings_spec.rb | 15 +++++ 8 files changed, 84 insertions(+), 58 deletions(-) create mode 100644 spec/fixtures/production/combined_process_settings-20.yml create mode 100644 spec/fixtures/production/settings/regex_target.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e178fe..adb8a6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.20.0] - 2022-03-04 +## [0.20.0] - Unreleased ### Added - Added regular expressions capabilities to targeting. See [README.md](README.md#Regexp-Targeting) for usage examples. diff --git a/README.md b/README.md index 888f55c..fb154cb 100644 --- a/README.md +++ b/README.md @@ -165,10 +165,10 @@ target: This will be applied in any process that has (`service_name == "frontend"` OR `service_name == "auth"`) AND `datacenter == "AWS-US-EAST-1"`. ### Regexp Targeting -To provide a regular expression for targeting, surround it with a leading and trailing slash `/`. For example: +To provide a regular expression for targeting, use the ruby regex keyword `!ruby/regexp` followed by your regular expression. For example: ``` target: - service_name: /frontend-\d/ + service_name: !ruby/regexp /frontend-\d/ ``` This will be applied in any process that has `service_name` that has `frontend-` followed with a number. As an example this will match `"frontend-1"` diff --git a/lib/process_settings/target.rb b/lib/process_settings/target.rb index a3f067e..257dcd7 100644 --- a/lib/process_settings/target.rb +++ b/lib/process_settings/target.rb @@ -90,12 +90,8 @@ def target_key_matches?(target_value, context_hash) end when true, false target_value - when String - if (pattern = target_value[/\A \/ (.+) \/ \z/x, 1]) # Any string that starts and ends with slashes. - context_hash.match?(pattern) - else - target_value == context_hash - end + when Regexp + context_hash.match?(target_value) else target_value == context_hash end diff --git a/spec/bin/combine_process_settings_spec.rb b/spec/bin/combine_process_settings_spec.rb index 091e17f..ae1d113 100644 --- a/spec/bin/combine_process_settings_spec.rb +++ b/spec/bin/combine_process_settings_spec.rb @@ -32,6 +32,11 @@ max_recording_seconds: 600 answer_odds: 100 status_change_min_days: + - filename: regex_target.yml + target: + service: !ruby/regexp /frontend/ + settings: + test_setting: 100 - filename: stop_incoming_requests.yml target: region: east diff --git a/spec/fixtures/production/combined_process_settings-20.yml b/spec/fixtures/production/combined_process_settings-20.yml new file mode 100644 index 0000000..01d6333 --- /dev/null +++ b/spec/fixtures/production/combined_process_settings-20.yml @@ -0,0 +1,47 @@ +--- +# +# Don't edit this file directly! It was generated by combine_process_settings from the files in staging/settings/. +# +- filename: honeypot.yml + settings: + honeypot: + max_recording_seconds: 600 + answer_odds: 100 + status_change_min_days: +- filename: regex_target.yml + target: + service: !ruby/regexp /frontend/ + settings: + test_setting: 100 +- filename: telecom/log_level.yml + target: + app: telecom + settings: + logging: + level: debug +- filename: telecom/stop_incoming_requests.yml + target: + app: telecom + region: west + settings: + incoming_requests: 0 +- filename: telecom/debug_sip_private_caller_id.yml + target: + app: telecom + region: west + caller_id: + - "+18053334444" + - "+12755554321" + - "+18052223344" + settings: + log_stream: + sip: caller_id_privacy +- filename: cca/tech-1234_call_counts_drift_investigation.yml + target: + app: ccn + settings: + call_counts: + complete_sync_seconds: 60 +- meta: + version: 20 + END: true diff --git a/spec/fixtures/production/settings/regex_target.yml b/spec/fixtures/production/settings/regex_target.yml new file mode 100644 index 0000000..153cc9b --- /dev/null +++ b/spec/fixtures/production/settings/regex_target.yml @@ -0,0 +1,5 @@ +--- +target: + service: !ruby/regexp /frontend/ +settings: + test_setting: 100 diff --git a/spec/lib/process_settings/target_spec.rb b/spec/lib/process_settings/target_spec.rb index 82080b4..672f8c0 100644 --- a/spec/lib/process_settings/target_spec.rb +++ b/spec/lib/process_settings/target_spec.rb @@ -146,8 +146,8 @@ } end - context "with target value that has a slash at the start and end" do - let(:target_hash) { { 'service' => '/telecom/' } } + context "with target value is a regular expression" do + let(:target_hash) { { 'service' => /telecom/ } } context "when context hash value matches" do let(:service) { 'telecom-1' } @@ -166,23 +166,8 @@ end end - context "when target value only has a leading slash" do - let(:target_hash) { { 'service' => '/telecom' } } - - context "when context hash value has the string but not the slash" do - let(:service) { 'telecom' } - - it { is_expected.to be_falsey } - end - - context "when context hash value exactly matches target value" do - let(:service) { '/telecom' } - it { is_expected.to be_truthy } - end - end - - context "when target value only has a trailing slash" do - let(:target_hash) { { 'service' => 'telecom/' } } + context "when target value is a regex as a string" do + let(:target_hash) { { 'service' => '/telecom/' } } context "when context hash value has the string but not the slash" do let(:service) { 'telecom' } @@ -190,28 +175,14 @@ it { is_expected.to be_falsey } end - context "when context hash value exactly matches target value" do - let(:service) { 'telecom/' } - it { is_expected.to be_truthy } - end - end - - context "when target value has embedded slashes (not at the front or back)" do - let(:target_hash) { { 'service' => 'tmp/dir/log' } } - - context "when context hash value is the target value except the first and last character" do - let(:service) { 'mp/dir/lo' } - it { is_expected.to be_falsey } - end - - context "when context hash value exactly matches target value" do - let(:service) { 'tmp/dir/log' } + context "when context hash value exactly matches the string target value" do + let(:service) { '/telecom/' } it { is_expected.to be_truthy } end end context "when target value is valid and also has embedded slashes" do - let(:target_hash) { { 'service' => '/tmp/dir/log/'} } + let(:target_hash) { { 'service' => /tmp\/dir\/log/ } } context "when context hash value matches the target" do let(:service) { 'tmp/dir/log/service-log.txt' } @@ -223,19 +194,6 @@ it { is_expected.to be_falsey } end end - - context "when target value is two slashes and nothing else" do - let(:target_hash) { { 'service' => '//' } } - context "when context hash value exactly matches" do - let(:service) {'//' } - it { is_expected.to be_truthy } - end - - context "when context hash value is empty" do - let(:service) {'' } - it { is_expected.to be_falsey } - end - end end end diff --git a/spec/lib/process_settings/targeted_settings_spec.rb b/spec/lib/process_settings/targeted_settings_spec.rb index eb1d835..085b972 100644 --- a/spec/lib/process_settings/targeted_settings_spec.rb +++ b/spec/lib/process_settings/targeted_settings_spec.rb @@ -78,6 +78,21 @@ end end + context "with ruby's special regular expression keyword" do + let(:file_path) { File.expand_path("../../fixtures/production/combined_process_settings-20.yml", __dir__) } + + describe ".from_file" do + it "reads from yaml file and properly converts the special keyword and expression in the file into a ruby Regexp object" do + targeted_settings = described_class.from_file(file_path) + + regex_target_setting = targeted_settings.targeted_settings_array[1] + expect(regex_target_setting.filename).to eq("regex_target.yml") + expect(regex_target_setting.target.json_doc).to eq({ "service" => /frontend/ }) + expect(regex_target_setting.settings.json_doc).to eq({ "test_setting" => 100 }) + end + end + end + describe ".from_array" do it "delegates" do target_and_settings = described_class.from_array(TARGETED_SETTINGS) From c6d10fe6e7ad91bcc878a5489c345d7817cc3d4e Mon Sep 17 00:00:00 2001 From: Tristan Starck Date: Fri, 25 Mar 2022 13:43:32 -0700 Subject: [PATCH 6/7] use safe_load_file with only Regexp as permitted class --- CHANGELOG.md | 2 ++ lib/process_settings/targeted_settings.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adb8a6a..631036a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0 ## [0.20.0] - Unreleased ### Added - Added regular expressions capabilities to targeting. See [README.md](README.md#Regexp-Targeting) for usage examples. +### Fixed +- Use `Pysch.safe_load_file` over `Pysch.load_file` with `Regexp` as only permitted class. ## [0.19.0] - 2021-07-09 ### Fixed diff --git a/lib/process_settings/targeted_settings.rb b/lib/process_settings/targeted_settings.rb index 5032fe6..f489902 100644 --- a/lib/process_settings/targeted_settings.rb +++ b/lib/process_settings/targeted_settings.rb @@ -73,7 +73,7 @@ def from_array(settings_array, only_meta: false) end def from_file(file_path, only_meta: false) - json_doc = Psych.load_file(file_path) + json_doc = Psych.safe_load_file(file_path, permitted_classes: [Regexp]) from_array(json_doc, only_meta: only_meta) end end From 9809f61fc857812928a11e5cc6106a0e91e3efc0 Mon Sep 17 00:00:00 2001 From: Tristan Starck Date: Tue, 29 Mar 2022 10:29:01 -0700 Subject: [PATCH 7/7] update static_context_hash in target to use regex as well --- Gemfile.lock | 2 +- lib/process_settings/target.rb | 12 +++- lib/process_settings/version.rb | 2 +- spec/lib/process_settings/target_spec.rb | 89 ++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 92b5582..2193d1f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - process_settings (0.20.0.pre.1) + process_settings (0.20.0.pre.2) activesupport (>= 4.2, < 7) json listen (~> 3.0) diff --git a/lib/process_settings/target.rb b/lib/process_settings/target.rb index 257dcd7..79b3097 100644 --- a/lib/process_settings/target.rb +++ b/lib/process_settings/target.rb @@ -38,6 +38,12 @@ def with_static_context(target_value, static_context_hash) with_static_context_hash(target_value, static_context_hash) when true, false !target_value == !static_context_hash + when Regexp + if static_context_hash.is_a?(String) + static_context_hash.match?(target_value) + else + static_context_hash == target_value + end else target_value == static_context_hash end @@ -91,7 +97,11 @@ def target_key_matches?(target_value, context_hash) when true, false target_value when Regexp - context_hash.match?(target_value) + if context_hash.is_a?(String) + context_hash.match?(target_value) + else + context_hash == target_value + end else target_value == context_hash end diff --git a/lib/process_settings/version.rb b/lib/process_settings/version.rb index 4314e89..759ccbf 100644 --- a/lib/process_settings/version.rb +++ b/lib/process_settings/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ProcessSettings - VERSION = '0.20.0.pre.1' + VERSION = '0.20.0.pre.2' end diff --git a/spec/lib/process_settings/target_spec.rb b/spec/lib/process_settings/target_spec.rb index 672f8c0..40fb122 100644 --- a/spec/lib/process_settings/target_spec.rb +++ b/spec/lib/process_settings/target_spec.rb @@ -194,6 +194,20 @@ it { is_expected.to be_falsey } end end + + context "when context hash and target hash don't match keys" do + let(:context_hash) do + { + 'service' => { 'name' => service }, + 'region' => 'east', + 'cdr' => { 'caller' => '+18056807000' } + } + end + let(:target_hash) { { 'service' => /telecom/ } } + let(:service) { 'telecom-1' } + + it { is_expected.to be_falsey } + end end end @@ -394,6 +408,81 @@ it { should eq(target_hash) } end end + + describe "for regex matching" do + subject { process_target.with_static_context(context_hash).json_doc } + let(:process_target) { described_class.new(target_hash) } + let(:context_hash) do + { + 'service' => service, + 'region' => 'east', + 'cdr' => { 'caller' => '+18056807000' } + } + end + + context "with target value is a regular expression" do + let(:target_hash) { { 'service' => /telecom/ } } + + context "when context hash value matches" do + let(:service) { 'telecom-1' } + + it { is_expected.to be_truthy } + end + + context "with an empty context hash" do + let(:context_hash) { {} } + it { is_expected.to eq(target_hash) } + end + + context "with a non-matching context value" do + let(:service) { 'tele' } + it { is_expected.to be_falsey } + end + end + + context "when target value is a regex as a string" do + let(:target_hash) { { 'service' => '/telecom/' } } + + context "when context hash value has the string but not the slash" do + let(:service) { 'telecom' } + + it { is_expected.to be_falsey } + end + + context "when context hash value exactly matches the string target value" do + let(:service) { '/telecom/' } + it { is_expected.to be_truthy } + end + end + + context "when target value is valid and also has embedded slashes" do + let(:target_hash) { { 'service' => /tmp\/dir\/log/ } } + + context "when context hash value matches the target" do + let(:service) { 'tmp/dir/log/service-log.txt' } + it { is_expected.to be_truthy } + end + + context "when context hash only has whats between the embedded slashes" do + let(:service) { 'dir' } + it { is_expected.to be_falsey } + end + end + + context "when context hash and target hash don't match keys" do + let(:context_hash) do + { + 'service' => { 'name' => service }, + 'region' => 'east', + 'cdr' => { 'caller' => '+18056807000' } + } + end + let(:target_hash) { { 'service' => /telecom/ } } + let(:service) { 'telecom-1' } + + it { is_expected.to be_falsey } + end + end end describe "class methods" do