fluent-plugin-jfrog-siem 0.1.8 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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