ddr-antivirus 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 07356afadfc5b20e33d7d3ca999de568da15066a
4
+ data.tar.gz: d9647a4763966736db61d308ac23a7c8288c500e
5
+ SHA512:
6
+ metadata.gz: 345204eb970ad8926c7931c67a2c049be6b886a0281378c6796bd2af60539f4c2fe0bf5f3e020aacc72114f68d6e8782929e76afc04fb0e9cd38ee9b5b0286e2
7
+ data.tar.gz: ebf82da16aa825f54c55e9de6a1e1048dd25989f4eea8515f5a51b5dafb0a3b3c22dfee5e63ce9c7851a0e8260087cf894ce2b4ff61b042371e3a53ef04cc620
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ before_install:
3
+ - sudo apt-get update -qq
4
+ - sudo apt-get install -y libclamav-dev clamav clamav-freshclam
5
+ - sudo freshclam
6
+ rvm:
7
+ - 2.1
8
+ cache:
9
+ - bundler
10
+ - apt
11
+ notifications:
12
+ email:
13
+ - lib-drs@duke.edu
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ddr-antivirus.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,12 @@
1
+ Copyright (c) Duke University Libraries.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+
8
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9
+
10
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # Ddr::Antivirus
2
+
3
+ Antivirus scanner for Ruby applications.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'ddr-antivirus'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install ddr-antivirus
18
+
19
+ ## ClamAV Dependencies
20
+
21
+ For system dependencies, see https://github.com/eagleas/clamav.
22
+
23
+ Ddr::Antivirus intentionally does *not* include `clamav` as a runtime dependency. Rather you should add to you application's Gemfile:
24
+
25
+ gem 'clamav'
26
+
27
+ Ddr::Antivirus will use an adapter class for ClamAV if the Ruby gem is installed.
28
+
29
+ ## Usage
30
+
31
+ ### Scanning ###
32
+
33
+ ```ruby
34
+ require "ddr-antivirus"
35
+
36
+ result = Ddr::Antivirus::Scanner.scan(path)
37
+
38
+ Ddr::Antivirus::Scanner.new do |scanner|
39
+ result = scanner.scan(path)
40
+ end
41
+ ```
42
+
43
+ ### Results
44
+
45
+ ```ruby
46
+ >> require "ddr-antivirus"
47
+ => true
48
+
49
+ >> result = Ddr::Antivirus::Scanner.scan("/path/to/blue-devil.png")
50
+ => #<Ddr::Antivirus::Adapters::ClamavScannerAdapter::ClamavScanResult:0x007f98fb169cc0 ...
51
+
52
+ # Was there a virus?
53
+ >> result.has_virus?
54
+ => false
55
+
56
+ # Was there an error?
57
+ >> result.error?
58
+ => false
59
+
60
+ # Success? (no virus or error)
61
+ >> result.ok?
62
+ => true
63
+
64
+ # What did the scanner adapter return?
65
+ >> result.raw
66
+ => 0 # ClamAV example
67
+
68
+ # String representation
69
+ >> puts result.to_s
70
+ Virus scan: OK - /path/to/blue-devil.png (ClamAV 0.98.3/19559/Thu Oct 30 06:39:46 2014)
71
+ ```
72
+
73
+ ### The NullScannerAdapter
74
+
75
+ In order to avoid the overhead of ClamAV in test and/or development environments, the package provides a no-op adapter that logs a message and returns a normal scan result (instance of Ddr::Antivirus::ScanResult).
76
+
77
+ ```ruby
78
+ >> Ddr::Antivirus.scanner_adapter = :null
79
+ => :null
80
+ >> Ddr::Antivirus::Scanner.scan("/path/to/blue-devil.png")
81
+ W, [2014-10-30T16:21:24.349542 #76244] WARN -- : File not scanned -- using :null scanner adapter.
82
+ I, [2014-10-30T16:21:24.350582 #76244] INFO -- : #<Ddr::Antivirus::ScanResult:0x007ff6c98d0500 @raw="File not scanned -- using :null scanner adapter.", @file_path="/path/to/blue-devil.png", @scanned_at=2014-10-30 20:21:24 UTC, @version="ddr-antivirus 1.0.0.rc1">
83
+ ```
84
+
85
+ ## Contributing
86
+
87
+ 1. Fork it ( https://github.com/[my-github-username]/ddr-antivirus/fork )
88
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
89
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
90
+ 4. Push to the branch (`git push origin my-new-feature`)
91
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ desc "Run all specs in spec directory"
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ddr/antivirus/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ddr-antivirus"
8
+ spec.version = Ddr::Antivirus::VERSION
9
+ spec.authors = ["David Chandek-Stark"]
10
+ spec.email = ["dchandekstark@gmail.com"]
11
+ spec.summary = %q{Antivirus scanning service.}
12
+ spec.description = %q{Antivirus scanning service.}
13
+ spec.homepage = "https://github.com/duke-libraries/ddr-antivirus"
14
+ spec.license = "BSD-3-Clause"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activesupport", "~> 4.0"
22
+ spec.add_development_dependency "bundler", "~> 1.6"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "clamav"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ end
@@ -0,0 +1 @@
1
+ require "ddr/antivirus"
@@ -0,0 +1,43 @@
1
+ require "ddr/antivirus/version"
2
+ require "active_support/core_ext/module/attribute_accessors"
3
+ require "active_support/dependencies/autoload"
4
+ require "logger"
5
+
6
+ module Ddr
7
+ module Antivirus
8
+ extend ActiveSupport::Autoload
9
+
10
+ class VirusFoundError < ::StandardError; end
11
+
12
+ def self.clamav_installed?
13
+ begin
14
+ require 'clamav'
15
+ rescue LoadError
16
+ false
17
+ else
18
+ true
19
+ end
20
+ end
21
+
22
+ def self.configure
23
+ yield self
24
+ end
25
+
26
+ autoload :Scanner
27
+ autoload :ScanResult
28
+ autoload :Adapters
29
+
30
+ # Custom logger
31
+ # Defaults to Rails logger if Rails is loaded; otherwise logs to STDERR.
32
+ mattr_accessor :logger do
33
+ defined?(Rails) ? Rails.logger : Logger.new(STDERR)
34
+ end
35
+
36
+ # Scanner adapter
37
+ # Defaults to :clamav adapter if ClamAV is installed; otherwise uses the :null adapter
38
+ mattr_accessor :scanner_adapter do
39
+ clamav_installed? ? :clamav : :null
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,23 @@
1
+ require "active_support/dependencies/autoload"
2
+
3
+ module Ddr
4
+ module Antivirus
5
+ module Adapters
6
+ extend ActiveSupport::Autoload
7
+
8
+ autoload :ScannerAdapter
9
+ autoload :NullScannerAdapter
10
+ autoload :ClamavScannerAdapter if Ddr::Antivirus.clamav_installed?
11
+
12
+ def self.get_adapter
13
+ klass = self.const_get(adapter_name.to_sym, false)
14
+ klass.new
15
+ end
16
+
17
+ def self.adapter_name
18
+ "#{Ddr::Antivirus.scanner_adapter.to_s.capitalize}ScannerAdapter"
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,48 @@
1
+ require 'clamav'
2
+
3
+ module Ddr
4
+ module Antivirus
5
+ module Adapters
6
+ class ClamavScannerAdapter < ScannerAdapter
7
+
8
+ def scan(path)
9
+ reload!
10
+ raw = engine.scanfile(path)
11
+ ClamavScanResult.new(raw, path)
12
+ end
13
+
14
+ def reload!
15
+ # ClamAV is supposed to reload the database if changed (1 = successful, 0 = unnecessary)
16
+ # but operation only succeeds when unneccesary and raises RuntimeError when the db needs
17
+ # to be reloaded, in which case, loaddb must be called.
18
+ engine.loaddb unless engine.reload == 0
19
+ rescue RuntimeError
20
+ engine.loaddb
21
+ end
22
+
23
+ def engine
24
+ ClamAV.instance
25
+ end
26
+
27
+ class ClamavScanResult < Ddr::Antivirus::ScanResult
28
+
29
+ def virus_found
30
+ raw if raw.is_a?(String)
31
+ end
32
+
33
+ def error?
34
+ raw == 1
35
+ end
36
+
37
+ def default_version
38
+ # Engine and database versions
39
+ # E.g., ClamAV 0.98.3/19010/Tue May 20 21:46:01 2014
40
+ `sigtool --version`.strip
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,19 @@
1
+ module Ddr
2
+ module Antivirus
3
+ module Adapters
4
+ #
5
+ # The NullScannerAdapter provides a no-op adapter, primarily for testing and development.
6
+ #
7
+ class NullScannerAdapter < ScannerAdapter
8
+
9
+ RESULT = "File not scanned -- using :null scanner adapter."
10
+
11
+ def scan(path)
12
+ Ddr::Antivirus.logger.warn(RESULT)
13
+ Ddr::Antivirus::ScanResult.new(RESULT, path)
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ module Ddr
2
+ module Antivirus
3
+ module Adapters
4
+ #
5
+ # Abstract class for scanner adapters.
6
+ #
7
+ class ScannerAdapter
8
+
9
+ def scan(path)
10
+ raise NotImplementedError
11
+ end
12
+
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,67 @@
1
+ module Ddr
2
+ module Antivirus
3
+ #
4
+ # Default scan result implementation
5
+ #
6
+ class ScanResult
7
+
8
+ attr_reader :raw, :file_path, :scanned_at, :version
9
+
10
+ def initialize(raw, file_path, opts={})
11
+ @raw = raw
12
+ @file_path = file_path
13
+ @scanned_at = opts.fetch(:scanned_at, default_time)
14
+ @version = opts.fetch(:version, default_version)
15
+ end
16
+
17
+ def default_time
18
+ Time.now.utc
19
+ end
20
+
21
+ def default_version
22
+ "ddr-antivirus #{Ddr::Antivirus::VERSION}"
23
+ end
24
+
25
+ # Subclasses may override to provide description of virus found.
26
+ # Should return nil if no virus found.
27
+ def virus_found; end
28
+
29
+ def has_virus?
30
+ !virus_found.nil?
31
+ end
32
+
33
+ def status
34
+ return status_found if has_virus?
35
+ return status_error if error?
36
+ status_ok
37
+ end
38
+
39
+ def ok?
40
+ !(has_virus? || error?)
41
+ end
42
+
43
+ # Subclasses may implement to indicate an error condition (not necessarily an exception).
44
+ def error?
45
+ false
46
+ end
47
+
48
+ def status_error
49
+ "ERROR"
50
+ end
51
+
52
+ def status_ok
53
+ "OK"
54
+ end
55
+
56
+ def status_found
57
+ "FOUND #{virus_found}"
58
+ end
59
+
60
+ def to_s
61
+ "Virus scan: #{status} - #{file_path} (#{version})"
62
+ end
63
+
64
+ end
65
+ end
66
+ end
67
+
@@ -0,0 +1,36 @@
1
+ require "active_support/core_ext/class/attribute"
2
+
3
+ module Ddr
4
+ module Antivirus
5
+ class Scanner
6
+
7
+ # Instance of scanner adapter
8
+ attr_reader :adapter
9
+
10
+ def self.scan(path)
11
+ new { |scanner| return scanner.scan(path) }
12
+ end
13
+
14
+ def initialize
15
+ @adapter = Ddr::Antivirus::Adapters.get_adapter
16
+ yield self if block_given?
17
+ end
18
+
19
+ def scan(path)
20
+ result = adapter.scan(path)
21
+ raise Ddr::Antivirus::VirusFoundError, result if result.has_virus?
22
+ logger.error("Antivirus scanner error (#{result.version})") if result.error?
23
+ logger.info(result)
24
+ result
25
+ end
26
+
27
+ private
28
+
29
+ def logger
30
+ Ddr::Antivirus.logger
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,5 @@
1
+ module Ddr
2
+ module Antivirus
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,48 @@
1
+ shared_examples "a scan result" do
2
+ it "should have a raw result" do
3
+ expect(subject.raw).not_to be_nil
4
+ end
5
+ it "should have a version" do
6
+ expect(subject.version).not_to be_nil
7
+ end
8
+ it "should have a scanned_at time" do
9
+ expect(subject.scanned_at).to be_a(Time)
10
+ end
11
+ it "should have a string representation" do
12
+ expect(subject.to_s).to match(/^Virus scan:/)
13
+ end
14
+ end
15
+
16
+ shared_examples "a successful scan result" do
17
+ it "should not have a virus" do
18
+ expect(subject.virus_found).to be_nil
19
+ expect(subject).not_to have_virus
20
+ end
21
+ it "should not have an error" do
22
+ expect(subject).not_to be_error
23
+ end
24
+ it "should be ok" do
25
+ expect(subject).to be_ok
26
+ end
27
+ it "should have OK status" do
28
+ expect(subject.status).to eq "OK"
29
+ end
30
+ end
31
+
32
+ shared_examples "an error scan result" do
33
+ it "should have ERROR status" do
34
+ expect(subject.status).to eq("ERROR")
35
+ end
36
+ it "should have an error" do
37
+ expect(subject).to be_error
38
+ end
39
+ end
40
+
41
+ shared_examples "a virus scan result" do
42
+ it "should have FOUND status" do
43
+ expect(subject.status).to match(/^FOUND/)
44
+ end
45
+ it "shoud have a virus" do
46
+ expect(subject).to have_virus
47
+ end
48
+ end
@@ -0,0 +1,81 @@
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 this
4
+ # file to always be loaded, without a need to explicitly require it in any files.
5
+ #
6
+ # Given that it is always loaded, you are encouraged to keep this file as
7
+ # light-weight as possible. Requiring heavyweight dependencies from this file
8
+ # will add to the boot time of your test suite on EVERY test run, even for an
9
+ # individual file that may not need all of that loaded. Instead, make a
10
+ # separate helper file that requires this one and then use it only in the specs
11
+ # that actually need it.
12
+ #
13
+ # The `.rspec` file also contains a few flags that are not defaults but that
14
+ # users commonly want.
15
+ #
16
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
+
18
+ require 'ddr/antivirus'
19
+
20
+ RSpec.configure do |config|
21
+ # The settings below are suggested to provide a good initial experience
22
+ # with RSpec, but feel free to customize to your heart's content.
23
+
24
+ # These two settings work together to allow you to limit a spec run
25
+ # to individual examples or groups you care about by tagging them with
26
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
27
+ # get run.
28
+ config.filter_run :focus
29
+ config.run_all_when_everything_filtered = true
30
+
31
+ # Many RSpec users commonly either run the entire suite or an individual
32
+ # file, and it's useful to allow more verbose output when running an
33
+ # individual spec file.
34
+ if config.files_to_run.one?
35
+ # Use the documentation formatter for detailed output,
36
+ # unless a formatter has already been configured
37
+ # (e.g. via a command-line flag).
38
+ config.default_formatter = 'doc'
39
+ end
40
+
41
+ # Print the 10 slowest examples and example groups at the
42
+ # end of the spec run, to help surface which specs are running
43
+ # particularly slow.
44
+ config.profile_examples = 10
45
+
46
+ # Run specs in random order to surface order dependencies. If you find an
47
+ # order dependency and want to debug it, you can fix the order by providing
48
+ # the seed, which is printed after each run.
49
+ # --seed 1234
50
+ config.order = :random
51
+
52
+ # Seed global randomization in this process using the `--seed` CLI option.
53
+ # Setting this allows you to use `--seed` to deterministically reproduce
54
+ # test failures related to randomization by passing the same `--seed` value
55
+ # as the one that triggered the failure.
56
+ Kernel.srand config.seed
57
+
58
+ # rspec-expectations config goes here. You can use an alternate
59
+ # assertion/expectation library such as wrong or the stdlib/minitest
60
+ # assertions if you prefer.
61
+ config.expect_with :rspec do |expectations|
62
+ # Enable only the newer, non-monkey-patching expect syntax.
63
+ # For more details, see:
64
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
65
+ expectations.syntax = :expect
66
+ end
67
+
68
+ # rspec-mocks config goes here. You can use an alternate test double
69
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
70
+ config.mock_with :rspec do |mocks|
71
+ # Enable only the newer, non-monkey-patching expect syntax.
72
+ # For more details, see:
73
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
74
+ mocks.syntax = :expect
75
+
76
+ # Prevents you from mocking or stubbing a method that does not exist on
77
+ # a real object. This is generally recommended.
78
+ mocks.verify_partial_doubles = true
79
+ end
80
+
81
+ end
@@ -0,0 +1,64 @@
1
+ require 'shared_examples_for_scan_results'
2
+
3
+ module Ddr
4
+ module Antivirus
5
+ module Adapters
6
+ RSpec.describe ClamavScannerAdapter do
7
+
8
+ let(:path) { File.expand_path(File.join("..", "fixtures", "blue-devil.png"), __FILE__) }
9
+
10
+ describe "#scan" do
11
+ context "when the db is already loaded" do
12
+ before { subject.engine.loaddb }
13
+ it "should reload the db" do
14
+ expect(subject.engine).to receive(:reload).and_call_original
15
+ expect(subject.engine).not_to receive(:loaddb)
16
+ subject.scan(path)
17
+ end
18
+ end
19
+ context "when the db is not already loaded" do
20
+ before { allow(subject.engine).to receive(:reload).and_raise(RuntimeError) }
21
+ it "should load the db" do
22
+ expect(subject.engine).to receive(:loaddb).and_call_original
23
+ subject.scan(path)
24
+ end
25
+ end
26
+ context "when the db is not reloaded successfully" do
27
+ before { allow(subject.engine).to receive(:reload) { 2 } }
28
+ it "should load the db" do
29
+ expect(subject.engine).to receive(:loaddb).and_call_original
30
+ subject.scan(path)
31
+ end
32
+ end
33
+
34
+ describe "result" do
35
+ subject { adapter.scan(path) }
36
+ let(:adapter) { described_class.new }
37
+ it "should be a scan result" do
38
+ expect(subject).to be_a(Ddr::Antivirus::ScanResult)
39
+ end
40
+ context "when a virus is found" do
41
+ before { allow(adapter.engine).to receive(:scanfile).with(path) { "Bad boy 35" } }
42
+ it "the raw result should be the virus description" do
43
+ expect(subject.raw).to eq "Bad boy 35"
44
+ expect(subject.virus_found).to eq "Bad boy 35"
45
+ end
46
+ it_should_behave_like "a virus scan result"
47
+ end
48
+ context "when there is an error" do
49
+ before { allow(adapter.engine).to receive(:scanfile).with(path) { 1 } }
50
+ it "should not have a virus" do
51
+ expect(subject).not_to have_virus
52
+ end
53
+ it_should_behave_like "an error scan result"
54
+ end
55
+ context "success" do
56
+ before { allow(adapter.engine).to receive(:scanfile).with(path) { 0 } }
57
+ it_should_behave_like "a successful scan result"
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,25 @@
1
+ require 'shared_examples_for_scan_results'
2
+
3
+ module Ddr
4
+ module Antivirus
5
+ RSpec.describe ScanResult do
6
+ subject { described_class.new("Raw result", "/tmp/foo") }
7
+
8
+ it_should_behave_like "a scan result"
9
+
10
+ describe "success" do
11
+ it_should_behave_like "a successful scan result"
12
+ end
13
+
14
+ describe "error" do
15
+ before { allow(subject).to receive(:error?) { true } }
16
+ it_should_behave_like "an error scan result"
17
+ end
18
+
19
+ describe "virus found" do
20
+ before { allow(subject).to receive(:virus_found) { "Bad boy 35" } }
21
+ it_should_behave_like "a virus scan result"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,54 @@
1
+ module Ddr
2
+ module Antivirus
3
+ RSpec.describe Scanner do
4
+
5
+ shared_examples "a scanner" do
6
+ describe "when a virus is found" do
7
+ before do
8
+ allow_any_instance_of(ScanResult).to receive(:has_virus?) { true }
9
+ end
10
+ it "should raise an execption" do
11
+ expect { subject.scan("/tmp/foo") }.to raise_error
12
+ end
13
+ end
14
+ describe "when a virus is not found" do
15
+ before do
16
+ allow_any_instance_of(ScanResult).to receive(:has_virus?) { false }
17
+ end
18
+ it "should return the scan result" do
19
+ expect(subject.scan("/tmp/foo")).to be_a(ScanResult)
20
+ end
21
+ end
22
+ describe "when an error occurs in the scanner" do
23
+ before do
24
+ allow_any_instance_of(ScanResult).to receive(:error?) { true }
25
+ end
26
+ it "should log an error" do
27
+ expect(Ddr::Antivirus.logger).to receive(:error)
28
+ subject.scan("/tmp/foo")
29
+ end
30
+ end
31
+ end
32
+
33
+ before do
34
+ @original_adapter = Ddr::Antivirus.scanner_adapter
35
+ Ddr::Antivirus.scanner_adapter = :null
36
+ end
37
+
38
+ after do
39
+ Ddr::Antivirus.scanner_adapter = @original_adapter
40
+ end
41
+
42
+ describe ".scan" do
43
+ subject { described_class }
44
+ it_behaves_like "a scanner"
45
+ end
46
+
47
+ describe "#scan" do
48
+ subject { described_class.new }
49
+ it_behaves_like "a scanner"
50
+ end
51
+
52
+ end
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ddr-antivirus
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - David Chandek-Stark
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: clamav
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ description: Antivirus scanning service.
84
+ email:
85
+ - dchandekstark@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - Gemfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - ddr-antivirus.gemspec
98
+ - lib/ddr-antivirus.rb
99
+ - lib/ddr/antivirus.rb
100
+ - lib/ddr/antivirus/adapters.rb
101
+ - lib/ddr/antivirus/adapters/clamav_scanner_adapter.rb
102
+ - lib/ddr/antivirus/adapters/null_scanner_adapter.rb
103
+ - lib/ddr/antivirus/adapters/scanner_adapter.rb
104
+ - lib/ddr/antivirus/scan_result.rb
105
+ - lib/ddr/antivirus/scanner.rb
106
+ - lib/ddr/antivirus/version.rb
107
+ - spec/shared_examples_for_scan_results.rb
108
+ - spec/spec_helper.rb
109
+ - spec/unit/clamav_scanner_adapter_spec.rb
110
+ - spec/unit/scan_result_spec.rb
111
+ - spec/unit/scanner_spec.rb
112
+ homepage: https://github.com/duke-libraries/ddr-antivirus
113
+ licenses:
114
+ - BSD-3-Clause
115
+ metadata: {}
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 2.2.2
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: Antivirus scanning service.
136
+ test_files:
137
+ - spec/shared_examples_for_scan_results.rb
138
+ - spec/spec_helper.rb
139
+ - spec/unit/clamav_scanner_adapter_spec.rb
140
+ - spec/unit/scan_result_spec.rb
141
+ - spec/unit/scanner_spec.rb