fluent-plugin-jfrog-siem 0.1.8 → 2.0.1

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,56 @@
1
+ [
2
+ File.join(File.dirname(__FILE__), '..'),
3
+ File.join(File.dirname(__FILE__), '..', 'lib/fluent/plugin'),
4
+ File.join(File.dirname(__FILE__), '..', 'spec'),
5
+ ].each do |dir|
6
+ $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir)
7
+ end
8
+
9
+ require 'position_file'
10
+ require 'date'
11
+ require 'rspec'
12
+
13
+
14
+ RSpec.describe PositionFile do
15
+ describe "#processed?" do
16
+ let(:violation){ { "created": Date.parse(Date.today.to_s).strftime("%Y-%m-%dT%H:%M:%SZ"), "watch_name": "watch1", "issue_id": "55444"} }
17
+
18
+ pos_file_date = DateTime.parse(Date.today.to_s).strftime("%Y-%m-%d")
19
+ temp_pos_file = "jfrog_siem_log_#{pos_file_date}.pos"
20
+
21
+ it "returns false when a violation has not been processed" do
22
+ pos_file = PositionFile.new(`pwd`)
23
+ allow(File).to receive(:open).and_yield []
24
+
25
+ expect(pos_file.processed?(JSON.parse(violation.to_json))).to be_falsey
26
+ end
27
+
28
+ it "returns true when a violation was found in the pos file" do
29
+ pos_file = PositionFile.new(`pwd`)
30
+
31
+ matching_violation = [violation[:created], violation[:watch_name], violation[:issue_id]].join(',')
32
+ another_violation = [violation[:created], "watch2", "12345"].join(',')
33
+ allow(File).to receive(:exist?).and_return true
34
+ allow(File).to receive(:open).and_yield [matching_violation, another_violation]
35
+
36
+ expect(pos_file.processed?(JSON.parse(violation.to_json))).to be_truthy
37
+ end
38
+
39
+ end
40
+
41
+ describe "#write" do
42
+ let(:violation){ { "created": Date.parse(Date.today.to_s).strftime("%Y-%m-%dT%H:%M:%SZ"), "watch_name": "watch1", "issue_id": "55444"} }
43
+
44
+ it "returns false when a violation has not been processed" do
45
+ pos_file = PositionFile.new(`pwd`)
46
+
47
+ result = []
48
+ allow(File).to receive(:open).and_yield result
49
+
50
+ pos_file.write(JSON.parse(violation.to_json))
51
+
52
+ matching_violation = [violation[:created], violation[:watch_name], violation[:issue_id]].join(',')
53
+ expect(result.include? matching_violation).to be_truthy
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,111 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
+
17
+ [
18
+ File.join(File.dirname(__FILE__), '..'),
19
+ File.join(File.dirname(__FILE__), '..', 'lib/fluent/plugin'),
20
+ File.join(File.dirname(__FILE__), '..', 'spec'),
21
+ ].each do |dir|
22
+ $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir)
23
+ end
24
+
25
+ require 'xray'
26
+
27
+ RSpec.configure do |config|
28
+ # rspec-expectations config goes here. You can use an alternate
29
+ # assertion/expectation library such as wrong or the stdlib/minitest
30
+ # assertions if you prefer.
31
+ config.expect_with :rspec do |expectations|
32
+ # This option will default to `true` in RSpec 4. It makes the `description`
33
+ # and `failure_message` of custom matchers include text for helper methods
34
+ # defined using `chain`, e.g.:
35
+ # be_bigger_than(2).and_smaller_than(4).description
36
+ # # => "be bigger than 2 and smaller than 4"
37
+ # ...rather than:
38
+ # # => "be bigger than 2"
39
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
40
+ end
41
+
42
+ # rspec-mocks config goes here. You can use an alternate test double
43
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
44
+ config.mock_with :rspec do |mocks|
45
+ # Prevents you from mocking or stubbing a method that does not exist on
46
+ # a real object. This is generally recommended, and will default to
47
+ # `true` in RSpec 4.
48
+ mocks.verify_partial_doubles = true
49
+ end
50
+
51
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
52
+ # have no way to turn it off -- the option exists only for backwards
53
+ # compatibility in RSpec 3). It causes shared context metadata to be
54
+ # inherited by the metadata hash of host groups and examples, rather than
55
+ # triggering implicit auto-inclusion in groups with matching metadata.
56
+ config.shared_context_metadata_behavior = :apply_to_host_groups
57
+
58
+ # The settings below are suggested to provide a good initial experience
59
+ # with RSpec, but feel free to customize to your heart's content.
60
+ =begin
61
+ # This allows you to limit a spec run to individual examples or groups
62
+ # you care about by tagging them with `:focus` metadata. When nothing
63
+ # is tagged with `:focus`, all examples get run. RSpec also provides
64
+ # aliases for `it`, `describe`, and `context` that include `:focus`
65
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
66
+ config.filter_run_when_matching :focus
67
+
68
+ # Allows RSpec to persist some state between runs in order to support
69
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
70
+ # you configure your source control system to ignore this file.
71
+ config.example_status_persistence_file_path = "spec/examples.txt"
72
+
73
+ # Limits the available syntax to the non-monkey patched syntax that is
74
+ # recommended. For more details, see:
75
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
76
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
77
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
78
+ config.disable_monkey_patching!
79
+
80
+ # This setting enables warnings. It's recommended, but in some cases may
81
+ # be too noisy due to issues in dependencies.
82
+ config.warnings = true
83
+
84
+ # Many RSpec users commonly either run the entire suite or an individual
85
+ # file, and it's useful to allow more verbose output when running an
86
+ # individual spec file.
87
+ if config.files_to_run.one?
88
+ # Use the documentation formatter for detailed output,
89
+ # unless a formatter has already been configured
90
+ # (e.g. via a command-line flag).
91
+ config.default_formatter = "doc"
92
+ end
93
+
94
+ # Print the 10 slowest examples and example groups at the
95
+ # end of the spec run, to help surface which specs are running
96
+ # particularly slow.
97
+ config.profile_examples = 10
98
+
99
+ # Run specs in random order to surface order dependencies. If you find an
100
+ # order dependency and want to debug it, you can fix the order by providing
101
+ # the seed, which is printed after each run.
102
+ # --seed 1234
103
+ config.order = :random
104
+
105
+ # Seed global randomization in this process using the `--seed` CLI option.
106
+ # Setting this allows you to use `--seed` to deterministically reproduce
107
+ # test failures related to randomization by passing the same `--seed` value
108
+ # as the one that triggered the failure.
109
+ Kernel.srand config.seed
110
+ =end
111
+ end
data/spec/xray_spec.rb ADDED
@@ -0,0 +1,135 @@
1
+ [
2
+ File.join(File.dirname(__FILE__), '..'),
3
+ File.join(File.dirname(__FILE__), '..', 'lib/fluent/plugin'),
4
+ File.join(File.dirname(__FILE__), '..', 'spec'),
5
+ ].each do |dir|
6
+ $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir)
7
+ end
8
+
9
+ require 'xray'
10
+ require 'date'
11
+ require 'rspec'
12
+ require 'rest-client'
13
+
14
+
15
+ RSpec.describe Xray do
16
+ describe "#violation_details" do
17
+
18
+ let(:violation1){ { "created": Date.parse(Date.today.to_s).strftime("%Y-%m-%dT%H:%M:%SZ"),
19
+ "watch_name": "watch1",
20
+ "issue_id": "55444",
21
+ "violation_details_url": "http://www.com"}
22
+ }
23
+ let(:violation2){ { "created": Date.parse(Date.today.to_s).strftime("%Y-%m-%dT%H:%M:%SZ"),
24
+ "watch_name": "watch2",
25
+ "issue_id": "55443",
26
+ "violation_details_url": "http://www.com"}
27
+ }
28
+
29
+ let(:violations) { Concurrent::Array.new }
30
+
31
+ it "creates a future for every violation" do
32
+ xray = Xray.new(@jpd_url, @username, @apikey, @wait_interval, @batch_size, @pos_file_path, @router, @tag)
33
+
34
+ (1..5).each do |i|
35
+ violations << i
36
+ end
37
+
38
+ promises = class_double("Concurrent::Promises").as_stubbed_const(:transfer_nested_constants => true)
39
+ expect(promises).to receive(:future).exactly(5).times
40
+
41
+ xray.violation_details(violations)
42
+ end
43
+
44
+ it "updates pos file for every violation (cannot do exactly tests since stubs with Concurrent ruby are broken)" do
45
+ router = double('router')
46
+ pos_file_path = `pwd`
47
+ xray = Xray.new(@jpd_url, @username, @apikey, @wait_interval, @batch_size, pos_file_path, router, @tag)
48
+
49
+ violations << JSON.parse(violation1.to_json)
50
+ violations << JSON.parse(violation2.to_json)
51
+
52
+ promises = class_double("Concurrent::Promises").as_stubbed_const(:transfer_nested_constants => true)
53
+ allow(promises).to receive(:future).and_yield(violation1).and_yield(violation2)
54
+
55
+ rest_client = double("RestClient::Request")
56
+ allow(RestClient::Request).to receive(:new).and_return rest_client
57
+ allow(rest_client).to receive(:execute).and_return(JSON.parse({'impacted_artifacts': []}.to_json))
58
+
59
+ pos_file = double(PositionFile)
60
+ allow(PositionFile).to receive(:new).and_return pos_file
61
+ allow(pos_file).to receive(:write)
62
+
63
+ fluent = class_double("Fluent::Engine").as_stubbed_const(:transfer_nested_constants => true)
64
+ allow(fluent).to receive(:now).and_return(DateTime.now)
65
+ allow(router).to receive(:emit)
66
+
67
+ xray.violation_details(JSON.parse(violations.to_json))
68
+ end
69
+ end
70
+
71
+ describe "#violations" do
72
+ it "runs a timer task to process violations periodically" do
73
+ batch_size = 25
74
+ pos_file_path = `pwd`
75
+ router = double('router')
76
+ xray = Xray.new(@jpd_url, @username, @apikey, @wait_interval, batch_size, pos_file_path, router, @tag)
77
+
78
+ channel = double(Concurrent::Channel)
79
+ expect(Concurrent::Channel).to receive(:new).with(capacity: batch_size).and_return(channel)
80
+
81
+ timer_task = double(Concurrent::TimerTask)
82
+ expect(Concurrent::TimerTask).to receive(:new).and_return timer_task
83
+
84
+ expect(timer_task).to receive(:execute)
85
+ xray.violations(Date.today)
86
+ end
87
+
88
+ end
89
+
90
+ describe "#process" do
91
+ let(:violation1){ { "created": Date.parse(Date.today.to_s).strftime("%Y-%m-%dT%H:%M:%SZ"),
92
+ "watch_name": "watch1",
93
+ "issue_id": "55444",
94
+ "violation_details_url": "http://www.com"}
95
+ }
96
+ let(:violation2){ { "created": Date.parse(Date.today.to_s).strftime("%Y-%m-%dT%H:%M:%SZ"),
97
+ "watch_name": "watch2",
98
+ "issue_id": "55443",
99
+ "violation_details_url": "http://www.com"}
100
+ }
101
+
102
+ let(:violations_channel) { Concurrent::Array.new }
103
+
104
+ it "skips processed violation" do
105
+ pos_file_path = `pwd`
106
+ xray = Xray.new(@jpd_url, @username, @apikey, @wait_interval, @batch_size, @pos_file_path, @router, @tag)
107
+
108
+ violations_channel << violation1
109
+
110
+ pos_file = double(PositionFile)
111
+ allow(PositionFile).to receive(:new).and_return pos_file
112
+ allow(pos_file).to receive(:processed?).and_return true
113
+
114
+ xray.process(violation1, violations_channel)
115
+
116
+ expect(violations_channel.size).to eq 1
117
+ end
118
+
119
+ it "adds unprocessed violation to the channel" do
120
+ pos_file_path = `pwd`
121
+ xray = Xray.new(@jpd_url, @username, @apikey, @wait_interval, @batch_size, @pos_file_path, @router, @tag)
122
+
123
+ violations_channel << violation1
124
+
125
+ pos_file = double(PositionFile)
126
+ allow(PositionFile).to receive(:new).and_return pos_file
127
+ allow(pos_file).to receive(:processed?).and_return false
128
+
129
+ xray.process(violation2, violations_channel)
130
+
131
+ expect(violations_channel.size).to eq 2
132
+ end
133
+ end
134
+
135
+ end
data/test/helper.rb CHANGED
@@ -4,5 +4,6 @@ require "fluent/test"
4
4
  require "fluent/test/driver/input"
5
5
  require "fluent/test/helpers"
6
6
 
7
+
7
8
  Test::Unit::TestCase.include(Fluent::Test::Helpers)
8
9
  Test::Unit::TestCase.extend(Fluent::Test::Helpers)
@@ -12,12 +12,15 @@ class JfrogSiemInputTest < Test::Unit::TestCase
12
12
 
13
13
  # Default configuration for tests
14
14
  CONFIG = %[
15
- tag "test_tag"
16
- jpd_url JPD_URL
17
- username USER
18
- apikey API_KEY
19
- pos_file "test_pos.txt"
20
- ]
15
+ tag "jfrog.xray.siem.vulnerabilities"
16
+ jpd_url "JPDURL"
17
+ username "admin"
18
+ apikey "APIKEY"
19
+ pos_file_path "#{ENV['JF_PRODUCT_DATA_INTERNAL']}/log/"
20
+ wait_interval 10
21
+ from_date "2016-01-01"
22
+ batch_size 25
23
+ ]
21
24
 
22
25
  private
23
26
 
@@ -28,7 +31,11 @@ class JfrogSiemInputTest < Test::Unit::TestCase
28
31
  sub_test_case 'Testing' do
29
32
  test 'Testing plugin in_jfrog_siem' do
30
33
  d = create_driver(CONFIG)
31
- d.run
34
+ begin
35
+ d.run
36
+ rescue => e
37
+ raise "Test failed due to #{e}"
38
+ end
32
39
  end
33
40
  end
34
41
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-jfrog-siem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
- - John Peterson
8
7
  - Mahitha Byreddy
8
+ - Sudhindra Rao
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-05-10 00:00:00.000000000 Z
12
+ date: 2021-08-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -68,33 +68,89 @@ dependencies:
68
68
  - !ruby/object:Gem::Version
69
69
  version: '2.0'
70
70
  - !ruby/object:Gem::Dependency
71
- name: thread
71
+ name: concurrent-ruby
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - "~>"
75
75
  - !ruby/object:Gem::Version
76
- version: 0.2.2
76
+ version: 1.1.8
77
77
  type: :development
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
81
  - - "~>"
82
82
  - !ruby/object:Gem::Version
83
- version: 0.2.2
83
+ version: 1.1.8
84
84
  - !ruby/object:Gem::Dependency
85
- name: thread
85
+ name: concurrent-ruby-edge
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rspec
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: 3.10.0
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: 3.10.0
112
+ - !ruby/object:Gem::Dependency
113
+ name: rest-client
86
114
  requirement: !ruby/object:Gem::Requirement
87
115
  requirements:
88
116
  - - "~>"
89
117
  - !ruby/object:Gem::Version
90
- version: 0.2.2
118
+ version: '2.0'
91
119
  type: :runtime
92
120
  prerelease: false
93
121
  version_requirements: !ruby/object:Gem::Requirement
94
122
  requirements:
95
123
  - - "~>"
96
124
  - !ruby/object:Gem::Version
97
- version: 0.2.2
125
+ version: '2.0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: concurrent-ruby
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - "~>"
131
+ - !ruby/object:Gem::Version
132
+ version: 1.1.8
133
+ type: :runtime
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: 1.1.8
140
+ - !ruby/object:Gem::Dependency
141
+ name: concurrent-ruby-edge
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :runtime
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
98
154
  - !ruby/object:Gem::Dependency
99
155
  name: fluentd
100
156
  requirement: !ruby/object:Gem::Requirement
@@ -118,23 +174,29 @@ dependencies:
118
174
  description: JFrog SIEM fluent input plugin will send the SIEM events from JFrog Xray
119
175
  to Fluentd which can then be delivered to whatever output plugin specified
120
176
  email:
121
- - johnp@jfrog.com
122
177
  - mahithab@jfrog.com
178
+ - sudhindrar@jfrog.com
123
179
  executables: []
124
180
  extensions: []
125
181
  extra_rdoc_files: []
126
182
  files:
183
+ - ".rspec"
127
184
  - Gemfile
185
+ - Gemfile.lock
128
186
  - LICENSE
129
187
  - README.md
130
188
  - Rakefile
131
- - elastic.conf
132
189
  - fluent-plugin-jfrog-siem.gemspec
133
190
  - lib/fluent/plugin/in_jfrog_siem.rb
134
- - splunk.conf
191
+ - lib/fluent/plugin/position_file.rb
192
+ - lib/fluent/plugin/violations.json
193
+ - lib/fluent/plugin/xray.rb
194
+ - spec/position_file_spec.rb
195
+ - spec/spec_helper.rb
196
+ - spec/xray_spec.rb
135
197
  - test/helper.rb
136
198
  - test/plugin/test_in_jfrog_siem.rb
137
- homepage: https://github.com/jfrog/log-analytics
199
+ homepage: https://github.com/jfrog/fluent-plugin-jfrog-siem
138
200
  licenses:
139
201
  - Apache-2.0
140
202
  metadata: {}
@@ -159,5 +221,8 @@ specification_version: 4
159
221
  summary: JFrog SIEM fluent input plugin will send the SIEM events from JFrog Xray
160
222
  to Fluentd
161
223
  test_files:
224
+ - spec/position_file_spec.rb
225
+ - spec/spec_helper.rb
226
+ - spec/xray_spec.rb
162
227
  - test/helper.rb
163
228
  - test/plugin/test_in_jfrog_siem.rb