dradis-plugins 4.7.0 → 4.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a55255c245e1ce6009d032fab79a582b05e760af0942ae7893ee7bb42af99dc
4
- data.tar.gz: 350e48e4f5c7021339e0d542d7d9776bafaf44f78e23b3feae5e7f8e8d8e6d4f
3
+ metadata.gz: 76e20a999e5f8a6309b837043fc488dc8d7f8f6bafae273482f9f1027078aa04
4
+ data.tar.gz: aa7c0068193b07f847ea8f0ddb6b7a8f2fb4705922ebb3da01df2859837fe4f7
5
5
  SHA512:
6
- metadata.gz: 91ee0fb58cc17d416a403dd60b9eeae6c106f16fdc4badeda6816f171f5154da7443b0c0b9d96964bf06d32a1f7b41f94db5e7d5c15f7bf3cb4c6ee0a773b643
7
- data.tar.gz: 04af89b9742efb8803f8e8d9c934aea5fa9b38c0fa7dcf16fe0f1d23a270167ef1f2c2e46af93d9e00c47c20618467e07b862b03fb4765e799d45dbcbec8ed8b
6
+ metadata.gz: efcd0183333ddf9271c3ecca1a7c4793bb864c7e6172d46bc1f335e543ecbbfcedc640953230d976c5ba9e052df2988a5077921f78a61f95e6fa188782f44357
7
+ data.tar.gz: 0c73436e1dd6d733a37fe4ccf10519f0d710137eab88eb6170fc44756d993c142372751e7f41dbc3ca5798ae6c2494d6d1829e9ba5d68cd4b1ed341fa7c92467
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ v4.9.0 (June 2023)
2
+ - Fix deduplication of findings
3
+ - Store engine settings encrypted
4
+
5
+ v4.8.0 (April 2023)
6
+ - Add support for issue and content block states
7
+
1
8
  v4.7.0 (February 2023)
2
9
  - No changes
3
10
 
@@ -2,15 +2,18 @@ module Dradis
2
2
  module Plugins
3
3
  module Export
4
4
  class BaseController < Rails.application.config.dradis.base_export_controller_class_name.to_s.constantize
5
+ before_action :validate_scope
5
6
 
6
7
  protected
7
8
 
8
- # Protected: allows export plugins to access the options sent from the
9
- # framework via the session object (see Export#create).
10
- #
11
- # Returns a Hash with indifferent access.
12
- def export_options
13
- @export_options ||= session[:export_manager].with_indifferent_access
9
+ def export_params
10
+ params.permit(:project_id, :scope, :template)
11
+ end
12
+
13
+ def validate_scope
14
+ unless Dradis::Plugins::ContentService::Base::VALID_SCOPES.include?(params[:scope])
15
+ raise 'Something fishy is going on...'
16
+ end
14
17
  end
15
18
  end
16
19
  end
@@ -20,12 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
21
21
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
22
 
23
- spec.add_development_dependency 'bundler', '~> 1.6'
24
- spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.add_development_dependency 'bundler'
24
+ spec.add_development_dependency 'rake'
25
25
  spec.add_development_dependency 'rspec-rails'
26
-
27
- # By not including Rails as a dependency, we can use the gem with different
28
- # versions of Rails (a sure recipe for disaster, I'm sure), which is needed
29
- # until we bump Dradis Pro to 4.1.
30
- # s.add_dependency 'rails', '~> 4.1.1'
31
26
  end
@@ -3,14 +3,19 @@ module Dradis::Plugins
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  module ClassMethods
6
- delegate :settings, to: :instance
6
+ delegate :encrypted_settings, :settings, to: :instance
7
7
 
8
8
  def settings_namespace
9
- @settings_namespace || plugin_name
9
+ @settings_namespace ||= plugin_name
10
+ end
11
+
12
+ def addon_encrypted_settings(namespace = nil, &block)
13
+ @settings_namespace = namespace
14
+ yield self if block_given?
10
15
  end
11
16
 
12
17
  def addon_settings(namespace = nil, &block)
13
- @settings_namespace = namespace if namespace
18
+ @settings_namespace = namespace
14
19
  yield self if block_given?
15
20
  end
16
21
 
@@ -19,8 +24,12 @@ module Dradis::Plugins
19
24
  end
20
25
  end
21
26
 
27
+ def encrypted_settings
28
+ @encrypted_settings ||= Dradis::Plugins::Settings.new(self.class.settings_namespace, adapter: :encrypted_configuration)
29
+ end
30
+
22
31
  def settings
23
- @settings ||= Dradis::Plugins::Settings.new(self.class.settings_namespace)
32
+ @settings ||= Dradis::Plugins::Settings.new(self.class.settings_namespace, adapter: :db)
24
33
  end
25
34
  end
26
35
  end
@@ -10,6 +10,8 @@ require 'dradis/plugins/content_service/properties'
10
10
 
11
11
  module Dradis::Plugins::ContentService
12
12
  class Base
13
+ VALID_SCOPES = %w[all published].freeze
14
+
13
15
  include Core
14
16
 
15
17
  include Boards
@@ -3,23 +3,34 @@ module Dradis::Plugins::ContentService
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  def all_content_blocks
6
- project.content_blocks
6
+ case scope
7
+ when :all
8
+ project.content_blocks
9
+ when :published
10
+ project.content_blocks.published
11
+ else
12
+ raise 'Unsupported scope!'
13
+ end
7
14
  end
8
15
 
9
16
  def create_content_block(args={})
10
17
  block_group = args.fetch(:block_group, default_content_block_group)
11
18
  content = args.fetch(:content, default_content_block_content)
19
+ state = args.fetch(:state, :published)
12
20
  user_id = args.fetch(:user_id)
13
21
 
14
22
  content_block = ContentBlock.new(
15
23
  content: content,
16
24
  block_group: block_group,
17
25
  project_id: project.id,
26
+ state: state,
18
27
  user_id: user_id
19
28
  )
20
29
 
21
30
  if content_block.valid?
22
31
  content_block.save
32
+
33
+ return content_block
23
34
  else
24
35
  try_rescue_from_length_validation(
25
36
  model: content_block,
@@ -3,7 +3,7 @@ module Dradis::Plugins::ContentService
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- attr_accessor :logger, :plugin, :project
6
+ attr_accessor :logger, :plugin, :project, :scope
7
7
  end
8
8
 
9
9
  # ----------------------------------------------------------- Initializer
@@ -12,9 +12,11 @@ module Dradis::Plugins::ContentService
12
12
  # @option plugin [Class] the 'wrapper' module of a plugin, e.g.
13
13
  # Dradis::Plugins::Nessus
14
14
  def initialize(args={})
15
- @logger = args.fetch(:logger, Rails.logger)
16
- @plugin = args.fetch(:plugin)
15
+ @logger = args.fetch(:logger, Rails.logger)
16
+ @plugin = args.fetch(:plugin)
17
17
  @project = args[:project]
18
+ @scope = args.fetch(:scope, :published)
19
+ @state = args[:state]
18
20
  end
19
21
 
20
22
  private
@@ -3,7 +3,17 @@ module Dradis::Plugins::ContentService
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  def all_issues
6
- project.issues.where(category_id: default_issue_category.id)
6
+ issues =
7
+ case scope
8
+ when :all
9
+ project.issues
10
+ when :published
11
+ project.issues.published
12
+ else
13
+ raise 'Unsupported scope!'
14
+ end
15
+
16
+ issues.where(category_id: default_issue_category.id)
7
17
  end
8
18
 
9
19
  def create_issue(args={})
@@ -11,6 +21,7 @@ module Dradis::Plugins::ContentService
11
21
  # NOTE that ID is the unique issue identifier assigned by the plugin,
12
22
  # and is not to be confused with the Issue#id primary key
13
23
  id = args.fetch(:id, default_issue_id)
24
+ state = args.fetch(:state, @state)
14
25
 
15
26
  # Bail if we already have this issue in the cache
16
27
  uuid = [plugin::Engine::plugin_name, id]
@@ -25,9 +36,10 @@ module Dradis::Plugins::ContentService
25
36
  text << plugin_details
26
37
 
27
38
  issue = Issue.new(text: text) do |i|
28
- i.author = default_author
29
- i.node = project.issue_library
39
+ i.author = default_author
40
+ i.node = project.issue_library
30
41
  i.category = default_issue_category
42
+ i.state = state
31
43
  end
32
44
 
33
45
  if issue.valid?
@@ -64,7 +76,7 @@ module Dradis::Plugins::ContentService
64
76
  # the issue library cache has been initialized.
65
77
  def issue_cache
66
78
  @issue_cache ||= begin
67
- issues_map = all_issues.map do |issue|
79
+ issues_map = project.issues.map do |issue|
68
80
  cache_key = [
69
81
  issue.fields['plugin'],
70
82
  issue.fields['plugin_id']
@@ -5,7 +5,7 @@ module Dradis
5
5
  module Plugins
6
6
  module Export
7
7
  class Base
8
- attr_accessor :content_service, :logger, :options, :plugin, :project
8
+ attr_accessor :content_service, :logger, :options, :plugin, :project, :scope
9
9
 
10
10
  def initialize(args={})
11
11
  # Save everything just in case the implementing class needs any of it.
@@ -15,6 +15,7 @@ module Dradis
15
15
  @logger = args.fetch(:logger, Rails.logger)
16
16
  @plugin = args[:plugin] || default_plugin
17
17
  @project = args.key?(:project_id) ? Project.find(args[:project_id]) : nil
18
+ @scope = args.fetch(:scope, :published).to_sym
18
19
 
19
20
  @content_service = args.fetch(:content_service, default_content_service)
20
21
 
@@ -34,7 +35,8 @@ module Dradis
34
35
  @content ||= Dradis::Plugins::ContentService::Base.new(
35
36
  logger: logger,
36
37
  plugin: plugin,
37
- project: project
38
+ project: project,
39
+ scope: scope
38
40
  )
39
41
  end
40
42
 
@@ -7,7 +7,7 @@ module Dradis
7
7
 
8
8
  module VERSION
9
9
  MAJOR = 4
10
- MINOR = 7
10
+ MINOR = 9
11
11
  TINY = 0
12
12
  PRE = nil
13
13
 
@@ -0,0 +1,30 @@
1
+ module Dradis::Plugins::Settings::Adapters
2
+ class Db
3
+ def initialize(namespace)
4
+ @namespace = namespace.to_s
5
+ end
6
+
7
+ def delete(key)
8
+ Configuration.find_by(name: namespaced_key(key)).destroy
9
+ end
10
+
11
+ def exists?(key)
12
+ Configuration.exists?(name: namespaced_key(key))
13
+ end
14
+
15
+ def read(key)
16
+ Configuration.find_by(name: namespaced_key(key))&.value
17
+ end
18
+
19
+ def write(key, value)
20
+ db_setting = Configuration.find_or_create_by(name: namespaced_key(key))
21
+ db_setting.update_attribute(:value, value)
22
+ end
23
+
24
+ private
25
+
26
+ def namespaced_key(key)
27
+ [@namespace, key.to_s.underscore].join(':')
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,58 @@
1
+ module Dradis::Plugins::Settings::Adapters
2
+ class EncryptedConfiguration
3
+ attr_writer :config_path
4
+
5
+ def initialize(namespace)
6
+ @namespace = namespace
7
+ end
8
+
9
+ def delete(key)
10
+ if exists?(key)
11
+ configuration.config[@namespace].delete(key)
12
+ configuration.write(configuration.config.to_yaml)
13
+ end
14
+ end
15
+
16
+ def exists?(key)
17
+ !!configuration.config[@namespace]&.key?(key)
18
+ end
19
+
20
+ def read(key)
21
+ configuration.config.fetch(@namespace, {}).fetch(key, nil)
22
+ end
23
+
24
+ def write(key, value)
25
+ configuration.config[@namespace] ||= {}
26
+ configuration.config[@namespace][key] = value
27
+ configuration.write(configuration.config.to_yaml)
28
+ end
29
+
30
+ def key_path=(string_or_pathname)
31
+ @key_path = Pathname.new(string_or_pathname)
32
+ end
33
+
34
+ private
35
+ def config_path
36
+ @config_path ||= Rails.root.join('config', 'shared', 'dradis-plugins.yml.enc')
37
+ end
38
+
39
+ def configuration
40
+ @configuration ||= begin
41
+ create_key unless key_path.exist?
42
+
43
+ ActiveSupport::EncryptedConfiguration.new(
44
+ config_path: config_path, key_path: key_path,
45
+ env_key: 'RAILS_MASTER_KEY', raise_if_missing_key: true
46
+ )
47
+ end
48
+ end
49
+
50
+ def create_key
51
+ File.write(key_path, ActiveSupport::EncryptedConfiguration.generate_key)
52
+ end
53
+
54
+ def key_path
55
+ @key_path ||= Rails.root.join('config', 'shared', 'dradis-plugins.key')
56
+ end
57
+ end
58
+ end
@@ -2,10 +2,11 @@ module Dradis::Plugins
2
2
  class Settings
3
3
  attr_reader :namespace
4
4
 
5
- def initialize(namespace)
5
+ def initialize(namespace, adapter: :db)
6
6
  @namespace = namespace
7
7
  @dirty_options ||= {}
8
8
  @default_options ||= { enabled: true }.with_indifferent_access
9
+ assign_adapter(adapter)
9
10
  end
10
11
 
11
12
  def respond_to?(name)
@@ -16,14 +17,18 @@ module Dradis::Plugins
16
17
  @default_options.except(:enabled).map do |key, value|
17
18
  {
18
19
  name: key.to_sym,
19
- value: value = dirty_or_db_setting_or_default(key.to_sym),
20
+ value: value = dirty_or_stored_or_default(key.to_sym),
20
21
  default: is_default?(key, value)
21
22
  }
22
23
  end.sort_by{ |o| o[:name] }
23
24
  end
24
25
 
25
26
  def save
26
- @dirty_options.reject{ |k, v| v.present? && v == db_setting(k) }.each{ |k, v| write_to_db(k, v) }
27
+ @dirty_options.reject do |k, v|
28
+ v.present? && v == read(k)
29
+ end.each do |k, v|
30
+ write(k, v)
31
+ end
27
32
  end
28
33
 
29
34
  def update_settings(opts = {})
@@ -36,7 +41,7 @@ module Dradis::Plugins
36
41
  def reset_defaults!
37
42
  @dirty_options = {}
38
43
  @default_options.each do |key, value|
39
- Configuration.where(name: namespaced_key(key)).each(&:destroy)
44
+ delete(key) if exists?(key)
40
45
  end
41
46
  end
42
47
 
@@ -45,6 +50,8 @@ module Dradis::Plugins
45
50
  end
46
51
 
47
52
  private
53
+ attr_reader :adapter
54
+ delegate :delete, :exists?, :read, :write, to: :adapter
48
55
 
49
56
  # ---------------------------------------------------- Method missing magic
50
57
  def method_missing(name, *args, &blk)
@@ -53,39 +60,33 @@ module Dradis::Plugins
53
60
  elsif name.to_s =~ /=$/
54
61
  @dirty_options[$`.to_sym] = args.first
55
62
  elsif @default_options.key?(name)
56
- dirty_or_db_setting_or_default(name)
63
+ dirty_or_stored_or_default(name)
57
64
  else
58
65
  super
59
66
  end
60
67
  end
61
68
  # --------------------------------------------------- /Method missing magic
62
69
 
63
- def write_to_db(key, value)
64
- db_setting = Configuration.find_or_create_by(name: namespaced_key(key))
65
- db_setting.update_attribute(:value, value)
66
- end
67
-
68
-
69
- def db_setting(key)
70
- Configuration.where(name: namespaced_key(key)).first.value rescue nil
70
+ def assign_adapter(name)
71
+ adapters = { db: Adapters::Db, encrypted_configuration: Adapters::EncryptedConfiguration }
72
+ if adapters.key?(name)
73
+ @adapter = adapters[name].new(namespace)
74
+ else
75
+ raise ArgumentError
76
+ end
71
77
  end
72
78
 
73
79
  # This method looks up in the configuration repository DB to see if the
74
80
  # user has provided a value for the given setting. If not, the default
75
81
  # value is returned.
76
- def dirty_or_db_setting_or_default(key)
82
+ def dirty_or_stored_or_default(key)
77
83
  if @dirty_options.key?(key)
78
84
  @dirty_options[key]
79
- elsif Configuration.exists?(name: namespaced_key(key))
80
- db_setting(key)
85
+ elsif exists?(key)
86
+ read(key)
81
87
  else
82
88
  @default_options[key]
83
89
  end
84
90
  end
85
-
86
- # Builds namespaced key
87
- def namespaced_key(key)
88
- [self.namespace.to_s, key.to_s.underscore].join(":")
89
- end
90
91
  end
91
92
  end
@@ -9,7 +9,7 @@ module Dradis
9
9
  end
10
10
 
11
11
  def task_options
12
- @task_options ||= { logger: logger }
12
+ @task_options ||= { logger: logger, state: :published }
13
13
  end
14
14
 
15
15
  def logger
@@ -12,6 +12,7 @@ module Dradis
12
12
  :options,
13
13
  :plugin,
14
14
  :project,
15
+ :state,
15
16
  :template_service
16
17
  )
17
18
 
@@ -22,10 +23,11 @@ module Dradis
22
23
  def initialize(args={})
23
24
  @options = args
24
25
 
25
- @logger = args.fetch(:logger, Rails.logger)
26
- @plugin = args[:plugin] || default_plugin
27
- @project = args.key?(:project_id) ? Project.find(args[:project_id]) : nil
28
26
  @default_user_id = args[:default_user_id] || -1
27
+ @logger = args.fetch(:logger, Rails.logger)
28
+ @plugin = args[:plugin] || default_plugin
29
+ @project = args.key?(:project_id) ? Project.find(args[:project_id]) : nil
30
+ @state = args.fetch(:state, :published)
29
31
 
30
32
  @content_service = args.fetch(:content_service, default_content_service)
31
33
  @template_service = args.fetch(:template_service, default_template_service)
@@ -46,7 +48,8 @@ module Dradis
46
48
  @content ||= Dradis::Plugins::ContentService::Base.new(
47
49
  logger: logger,
48
50
  plugin: plugin,
49
- project: project
51
+ project: project,
52
+ state: state
50
53
  )
51
54
  end
52
55
 
@@ -84,6 +84,8 @@ require 'dradis/plugins/upload'
84
84
  # Common functionality
85
85
  require 'dradis/plugins/configurable'
86
86
  require 'dradis/plugins/settings'
87
+ require 'dradis/plugins/settings/adapters/db'
88
+ require 'dradis/plugins/settings/adapters/encrypted_configuration'
87
89
  require 'dradis/plugins/templates'
88
90
  require 'dradis/plugins/thor'
89
91
  require 'dradis/plugins/thor_helper'
data/spec/engine_spec.rb CHANGED
@@ -13,11 +13,14 @@ describe Dradis::Plugins::Base do
13
13
 
14
14
  describe '#enabled?' do
15
15
  it 'returns default value' do
16
- expect(TestEngine.enabled?).to eq(false)
16
+ expect(TestEngine.enabled?).to eq(true)
17
17
  end
18
18
  end
19
19
  describe '#enable!' do
20
20
  it 'sets enabled to true' do
21
+ TestEngine.settings.enabled = false
22
+ TestEngine.settings.save
23
+
21
24
  expect { TestEngine.enable! }.to change {
22
25
  TestEngine.enabled?
23
26
  }.from(false).to(true)
@@ -25,7 +28,9 @@ describe Dradis::Plugins::Base do
25
28
  end
26
29
  describe '#disable!' do
27
30
  it 'sets enabled to false' do
28
- TestEngine.enable!
31
+ TestEngine.settings.enabled = true
32
+ TestEngine.settings.save
33
+
29
34
  expect { TestEngine.disable! }.to change {
30
35
  TestEngine.enabled?
31
36
  }.from(true).to(false)
@@ -20,7 +20,7 @@ describe Dradis::Plugins::ContentService::Boards do
20
20
  node = create(:node, project: project)
21
21
  node_board = create(:board, node: node, project: project)
22
22
 
23
- boards = service.all_boards
23
+ boards = service.project_boards
24
24
 
25
25
  expect(boards).to include(board)
26
26
  expect(boards).to_not include(node_board)
@@ -0,0 +1,29 @@
1
+ require 'rails_helper'
2
+
3
+ # To run, execute from Dradis Pro main app folder:
4
+ # bin/rspec [dradis-plugins path]/spec/lib/dradis/plugins/content_service/content_blocks_spec.rb
5
+
6
+ describe 'Content Block content service' do
7
+ let(:plugin) { Dradis::Plugins::Nessus }
8
+ let(:plugin_id) { '111' }
9
+ let(:project) { create(:project) }
10
+ let(:service) do
11
+ Dradis::Plugins::ContentService::Base.new(
12
+ plugin: plugin,
13
+ logger: Rails.logger,
14
+ project: project
15
+ )
16
+ end
17
+
18
+ describe '#all_content_blocks' do
19
+ before do
20
+ @draft_content = create_list(:content_block, 10, project: project, state: :draft)
21
+ @review_content = create_list(:content_block, 10, project: project, state: :ready_for_review)
22
+ @published_content = create_list(:content_block, 10, project: project, state: :published)
23
+ end
24
+
25
+ it 'returns only the published content blocks' do
26
+ expect(service.all_content_blocks.to_a).to match_array(@published_content)
27
+ end
28
+ end
29
+ end
@@ -1,11 +1,11 @@
1
1
  require 'rails_helper'
2
2
 
3
- # These specs are coming from engines/dradispro-rules/spec/content_service_spec.rb
4
3
  # To run, execute from Dradis main app folder:
5
4
  # bin/rspec [dradis-plugins path]/spec/lib/dradis/plugins/content_service/issues_spec.rb
6
5
 
7
- describe Dradis::Plugins::ContentService::Base do
8
- let(:plugin) { Dradis::Plugins::Nessus }
6
+ describe 'Issues content service' do
7
+ let(:plugin) { Dradis::Plugins::Nessus }
8
+ let(:plugin_id) { '111' }
9
9
  let(:project) { create(:project) }
10
10
  let(:service) do
11
11
  Dradis::Plugins::ContentService::Base.new(
@@ -17,47 +17,39 @@ describe Dradis::Plugins::ContentService::Base do
17
17
 
18
18
  describe 'Issues' do
19
19
  let(:create_issue) do
20
- service.create_issue_without_callback(id: plugin_id)
20
+ service.create_issue(text: "#[Title]#\nTest Issue\n", id: plugin_id, state: :ready_for_review)
21
21
  end
22
22
 
23
- # Remember: even though we're calling create_issue_without_callback,
24
- # that method will still call issue_cache_with_callback internally.
25
- # So when we store an issue in the issue_cache/finding_cache below,
26
- # it's being stored within an instance of FindingCache, which
27
- # automatically wraps Issues in Findings.
28
-
29
23
  describe 'when the issue already exists in the cache' do
30
- let(:existing_issue) { create(:issue, text: cached_issue_text) }
31
- before { cache.store(existing_issue) }
32
-
33
- it "doesn't create a new issue" do
34
- expect{create_issue}.not_to change{Issue.count}
24
+ before do
25
+ issue = create(:issue, text: "#[Title]#\nTest Issue\n", id: plugin_id)
26
+ service.issue_cache.store("nessus-#{plugin_id}", issue)
35
27
  end
36
28
 
37
- it 'returns the cached issue encapsulated in a finding' do
38
- finding = create_issue
39
- expect(finding).to be_a(Finding)
40
- expect(finding).to eq Finding.from_issue(existing_issue)
29
+ it 'does not create a new issue' do
30
+ expect { create_issue }.not_to change { Issue.count }
41
31
  end
42
32
  end
43
33
 
44
34
  describe "when the issue doesn't already exist in the cache" do
45
35
  it "creates a new Issue containing 'plugin' and 'plugin_id'" do
46
36
  new_issue = nil
47
- expect{new_issue = create_issue}.to change{Issue.count}.by(1)
48
- expect(new_issue.body).to match(/#\[plugin\]#\n*#{plugin_name}/)
49
- expect(new_issue.body).to match(/#\[plugin_id\]#\n*#{plugin_id}/)
37
+ plugin_name = "#{plugin}::Engine".constantize.plugin_name
38
+ expect { new_issue = create_issue }.to change { Issue.count }.by(1)
39
+ expect(new_issue.text).to match(/#\[plugin\]#\n*#{plugin_name}/)
40
+ expect(new_issue.text).to match(/#\[plugin_id\]#\n*#{plugin_id}/)
50
41
  end
42
+ end
51
43
 
52
- it 'returns the new Issue encapsulated in a Finding' do
53
- finding = create_issue
54
- expect(finding).to be_a(Finding)
55
- expect(finding).to eq Finding.from_issue(Issue.last)
44
+ describe '#all_issues' do
45
+ before do
46
+ @draft_issues = create_list(:issue, 10, project: project, state: :draft)
47
+ @review_issues = create_list(:issue, 10, project: project, state: :ready_for_review)
48
+ @published_issues = create_list(:issue, 10, project: project, state: :published)
56
49
  end
57
50
 
58
- it 'adds the new Finding to the cache' do
59
- finding = create_issue
60
- expect(cache[cache_key]).to eq finding
51
+ it 'returns only the published issues' do
52
+ expect(service.all_issues.to_a).to match_array(@published_issues)
61
53
  end
62
54
  end
63
55
  end
@@ -0,0 +1,112 @@
1
+ #
2
+ # This spec must be run from Dradis root dir.
3
+ #
4
+ # Configuration init from:
5
+ # https://github.com/rails/rails/blob/main/activesupport/test/encrypted_configuration_test.rb
6
+ #
7
+ require 'rails_helper'
8
+
9
+ describe Dradis::Plugins::Settings::Adapters::EncryptedConfiguration do
10
+
11
+ subject do
12
+ ec = Dradis::Plugins::Settings::Adapters::EncryptedConfiguration.new(:rspec)
13
+ ec.config_path = @credentials_config_path
14
+ ec.key_path = @credentials_key_path
15
+ ec
16
+ end
17
+
18
+ context 'With an empty config file' do
19
+ before(:all) do
20
+ @tmpdir = Dir.mktmpdir('config-')
21
+ @credentials_config_path = File.join(@tmpdir, 'empty.yml.enc')
22
+ @credentials_key_path = File.join(@tmpdir, 'empty.key')
23
+ end
24
+
25
+ describe '#delete' do
26
+ it 'becomes a no-op' do
27
+ expect { subject.delete(:key) }.to_not raise_error
28
+ end
29
+ end
30
+
31
+ describe '#exists' do
32
+ it 'is always false' do
33
+ expect(subject.exists?(:key)).to be(false)
34
+ expect(subject.exists?(:key2)).to be(false)
35
+ end
36
+ end
37
+
38
+ describe '#read' do
39
+ it 'always returns nil' do
40
+ expect(subject.read(:key)).to eq(nil)
41
+ expect(subject.read(:key2)).to eq(nil)
42
+ end
43
+ end
44
+
45
+ describe '#write' do
46
+ it 'inits the namespace and stores the setting' do
47
+ expect { subject.write(:key, :value) }.to_not raise_error
48
+ expect(File.size(@credentials_config_path)).to_not be(0)
49
+
50
+ File.unlink @credentials_config_path
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'With a working config file' do
56
+ DEFAULT_CONFIG = { rspec: { key: :lorem_ipsum, key2: :dolor_sit } }.to_yaml.freeze
57
+
58
+ before(:all) do
59
+ @tmpdir = Dir.mktmpdir('config-')
60
+ @credentials_config_path = File.join(@tmpdir, 'credentials.yml.enc')
61
+ @credentials_key_path = File.join(@tmpdir, 'master.key')
62
+
63
+ File.write(@credentials_key_path, ActiveSupport::EncryptedConfiguration.generate_key)
64
+
65
+ @credentials = ActiveSupport::EncryptedConfiguration.new(
66
+ config_path: @credentials_config_path, key_path: @credentials_key_path,
67
+ env_key: 'RAILS_MASTER_KEY', raise_if_missing_key: true
68
+ )
69
+
70
+ @credentials.write(DEFAULT_CONFIG)
71
+ end
72
+
73
+ after(:all) do
74
+ FileUtils.rm_rf @tmpdir
75
+ end
76
+
77
+ describe '#delete' do
78
+ it 'removes a value from disk' do
79
+ subject.delete(:key2)
80
+
81
+ @credentials.instance_variable_set('@config', nil)
82
+ expect(@credentials.config[:rspec].key?(:key)).to be(true)
83
+ expect(@credentials.config[:rspec].key?(:key2)).to be(false)
84
+ @credentials.write(DEFAULT_CONFIG)
85
+ end
86
+ end
87
+
88
+ describe '#exists' do
89
+ it 'finds an existing value' do
90
+ expect(subject.exists?(:key)).to be(true)
91
+ end
92
+ it 'detects an inexisting value' do
93
+ expect(subject.exists?(:key3)).to be(false)
94
+ end
95
+ end
96
+
97
+ describe '#read' do
98
+ it 'loads an already existing value' do
99
+ expect(subject.read(:key)).to eq(:lorem_ipsum)
100
+ end
101
+ end
102
+
103
+ describe '#write' do
104
+ it 'stores a value on disk' do
105
+ subject.write(:new_key, :new_value)
106
+ @credentials.instance_variable_set('@config', nil)
107
+ expect(@credentials.config[:rspec][:new_key]).to eq(:new_value)
108
+ @credentials.write(DEFAULT_CONFIG)
109
+ end
110
+ end
111
+ end
112
+ end
@@ -19,7 +19,6 @@ describe Dradis::Plugins::Settings do
19
19
  end
20
20
 
21
21
  it "sets and return default values" do
22
- expect(TestEngine::settings.enabled).to eq(false)
23
22
  expect(TestEngine::settings.host).to eq('localhost')
24
23
  expect(TestEngine::settings.port).to eq(80)
25
24
  end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dradis-plugins
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.0
4
+ version: 4.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Martin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-20 00:00:00.000000000 Z
11
+ date: 2023-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.6'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.6'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec-rails
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,8 @@ files:
94
94
  - lib/dradis/plugins/import/filters/base.rb
95
95
  - lib/dradis/plugins/import/result.rb
96
96
  - lib/dradis/plugins/settings.rb
97
+ - lib/dradis/plugins/settings/adapters/db.rb
98
+ - lib/dradis/plugins/settings/adapters/encrypted_configuration.rb
97
99
  - lib/dradis/plugins/template_service.rb
98
100
  - lib/dradis/plugins/templates.rb
99
101
  - lib/dradis/plugins/thor.rb
@@ -106,7 +108,9 @@ files:
106
108
  - spec/engine_spec.rb
107
109
  - spec/internal/log/test.log
108
110
  - spec/lib/dradis/plugins/content_service/boards_spec.rb
111
+ - spec/lib/dradis/plugins/content_service/content_blocks_spec.rb
109
112
  - spec/lib/dradis/plugins/content_service/issues_spec.rb
113
+ - spec/lib/dradis/plugins/settings/adapters/encrypted_configuration_spec.rb
110
114
  - spec/settings_spec.rb
111
115
  - spec/spec_helper.rb
112
116
  homepage: http://dradisframework.org
@@ -136,6 +140,8 @@ test_files:
136
140
  - spec/engine_spec.rb
137
141
  - spec/internal/log/test.log
138
142
  - spec/lib/dradis/plugins/content_service/boards_spec.rb
143
+ - spec/lib/dradis/plugins/content_service/content_blocks_spec.rb
139
144
  - spec/lib/dradis/plugins/content_service/issues_spec.rb
145
+ - spec/lib/dradis/plugins/settings/adapters/encrypted_configuration_spec.rb
140
146
  - spec/settings_spec.rb
141
147
  - spec/spec_helper.rb