ddr-antivirus 1.3.3 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/.travis.yml +3 -10
- data/Gemfile +0 -2
- data/README.md +41 -53
- data/ddr-antivirus.gemspec +0 -2
- data/lib/ddr/antivirus.rb +40 -34
- data/lib/ddr/antivirus/adapters/clamd_scanner_adapter.rb +66 -51
- data/lib/ddr/antivirus/adapters/null_scanner_adapter.rb +10 -22
- data/lib/ddr/antivirus/scan_result.rb +35 -0
- data/lib/ddr/antivirus/scanner.rb +9 -29
- data/lib/ddr/antivirus/scanner_adapter.rb +29 -0
- data/lib/ddr/antivirus/version.rb +1 -1
- data/spec/spec_helper.rb +2 -20
- data/spec/unit/clamd_scanner_adapter_spec.rb +63 -57
- metadata +6 -46
- data/lib/ddr/antivirus/adapters.rb +0 -14
- data/lib/ddr/antivirus/adapters/clamav_scanner_adapter.rb +0 -82
- data/lib/ddr/antivirus/adapters/scan_result.rb +0 -61
- data/lib/ddr/antivirus/adapters/scanner_adapter.rb +0 -25
- data/spec/shared_examples_for_scan_results.rb +0 -53
- data/spec/unit/clamav_scanner_adapter_spec.rb +0 -66
- data/spec/unit/null_scanner_adapter_spec.rb +0 -24
- data/spec/unit/scan_result_spec.rb +0 -27
- data/spec/unit/scanner_spec.rb +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e16210de6035eef0c49f80ce61c7f2dee7b3fc88
|
4
|
+
data.tar.gz: bb79eb5e1a8aa063773e160855589f28e54f4dfd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d7e101d5f4d85ff8067c2ccc8a98e88cb763cc96df60f719ca6831048058aed7c3b36fa18a68fa4acb65099b78b393ff6fc1b09da5992bbd00e9a9c5d2ff1d5
|
7
|
+
data.tar.gz: 7c48dd3ef7c397e26ac8fa3a0b7860336b6af332ade18327e5be016b1b98b79136f4aa8d445edeb5cdc50a139a3185ae274d9a22e2512baecf751aa283fb0e59
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
@@ -1,15 +1,8 @@
|
|
1
|
+
sudo: false
|
1
2
|
language: ruby
|
2
|
-
before_install:
|
3
|
-
- sudo apt-get update -qq
|
4
|
-
- sudo apt-get install -y libclamav-dev clamav clamav-daemon clamav-freshclam
|
5
|
-
before_script:
|
6
|
-
- sudo freshclam
|
7
|
-
- sudo /etc/init.d/clamav-daemon start
|
8
3
|
rvm:
|
9
4
|
- 2.1
|
5
|
+
- 2.2
|
10
6
|
cache:
|
11
7
|
- bundler
|
12
|
-
|
13
|
-
notifications:
|
14
|
-
email:
|
15
|
-
- lib-drs@duke.edu
|
8
|
+
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -4,8 +4,6 @@ Pluggable antivirus service for Ruby applications.
|
|
4
4
|
|
5
5
|
[![Gem Version](https://badge.fury.io/rb/ddr-antivirus.svg)](http://badge.fury.io/rb/ddr-antivirus)
|
6
6
|
[![Build Status](https://travis-ci.org/duke-libraries/ddr-antivirus.svg?branch=develop)](https://travis-ci.org/duke-libraries/ddr-antivirus)
|
7
|
-
[![Coverage Status](https://coveralls.io/repos/duke-libraries/ddr-antivirus/badge.png?branch=develop)](https://coveralls.io/r/duke-libraries/ddr-antivirus?branch=develop)
|
8
|
-
[![Code Climate](https://codeclimate.com/github/duke-libraries/ddr-antivirus/badges/gpa.svg)](https://codeclimate.com/github/duke-libraries/ddr-antivirus)
|
9
7
|
|
10
8
|
## Installation
|
11
9
|
|
@@ -21,74 +19,57 @@ Or install it yourself as:
|
|
21
19
|
|
22
20
|
$ gem install ddr-antivirus
|
23
21
|
|
24
|
-
## How It Works
|
25
|
-
|
26
|
-
Ddr::Antivirus does *not* provide a virus scanning engine as a runtime dependency. Instead, it will select a scanner adapter class for the software it finds in your environment following this procedure:
|
27
|
-
|
28
|
-
- If the [clamav](https://github.com/eagleas/clamav) gem is available, it will select the `ClamavScannerAdapter`.
|
29
|
-
- If the ClamAV Daemon client `clamdscan` is on the user's path, it will select the `ClamdScannerAdapter`. Ddr::Antivirus *does not* manage clamd -- i.e., checking its status, starting or reloading the database. These tasks must be managed externally.
|
30
|
-
- Otherwise, it will select the [`NullScannerAdapter`](#the-nullscanneradapter).
|
31
|
-
|
32
|
-
The auto-selection process may be overridden by configuration:
|
33
|
-
|
34
|
-
```ruby
|
35
|
-
Ddr::Antivirus.configure do |config|
|
36
|
-
config.scanner_adapter = :clamd # or :clamav, or :null
|
37
|
-
end
|
38
|
-
```
|
39
|
-
|
40
|
-
## Usage
|
41
|
-
|
42
22
|
### Scanning ###
|
43
23
|
|
44
|
-
Class: `Ddr::Antivirus::Scanner`
|
45
|
-
|
46
24
|
```ruby
|
47
25
|
require "ddr-antivirus"
|
48
26
|
|
49
|
-
|
50
|
-
result = Ddr::Antivirus::Scanner.scan(path)
|
27
|
+
result = Ddr::Antivirus.scan(path)
|
51
28
|
|
52
|
-
|
53
|
-
Ddr::Antivirus::Scanner.new do |scanner|
|
29
|
+
Ddr::Antivirus.scanner do |scanner|
|
54
30
|
result = scanner.scan(path)
|
55
31
|
end
|
56
32
|
```
|
57
33
|
|
58
|
-
|
34
|
+
### Exceptions
|
59
35
|
|
60
|
-
|
36
|
+
All exceptions under the `Ddr::Antivirus` namespace.
|
61
37
|
|
62
|
-
|
38
|
+
`Error` - Parent exception class.
|
63
39
|
|
64
|
-
A
|
40
|
+
`VirusFoundError` - A virus was found. The message includes the original output from the scanner.
|
65
41
|
|
66
|
-
|
67
|
-
>> require "ddr-antivirus"
|
68
|
-
=> true
|
42
|
+
`ScannerError` - The scanner encountered an error (e.g., error exit status).
|
69
43
|
|
70
|
-
|
71
|
-
=> #<Ddr::Antivirus::Adapters::ClamavScanResult:0x007f98fb169cc0 ...
|
44
|
+
### Example
|
72
45
|
|
73
|
-
|
74
|
-
|
75
|
-
=>
|
46
|
+
```
|
47
|
+
> require 'ddr/antivirus'
|
48
|
+
=> true
|
49
|
+
|
50
|
+
> Ddr::Antivirus.scanner_adapter = :clamd
|
51
|
+
=> :clamd
|
52
|
+
|
53
|
+
> result = Ddr::Antivirus.scan "/path/to/image.jpg"
|
54
|
+
=> #<Ddr::Antivirus::ScanResult:0x007f98f8b95670 @file_path="/path/to/image.jpg", @output="/path/to/image.jpg: OK\n\n----------- SCAN SUMMARY -----------\nInfected files: 0\nTime: 0.001 sec (0 m 0 s)\n", @scanned_at=2015-09-11 20:41:17 UTC, @version="ClamAV 0.98.7/20903/Fri Sep 11 08:42:07 2015">
|
55
|
+
|
56
|
+
> result.version
|
57
|
+
=> "ClamAV 0.98.7/20903/Fri Sep 11 08:42:07 2015"
|
76
58
|
|
77
|
-
|
78
|
-
|
79
|
-
=> false
|
59
|
+
> result.scanned_at
|
60
|
+
=> 2015-09-11 20:41:17 UTC
|
80
61
|
|
81
|
-
|
82
|
-
|
83
|
-
=> true
|
62
|
+
> result.output
|
63
|
+
=> "/path/to/image.jpg: OK\n\n----------- SCAN SUMMARY -----------\nInfected files: 0\nTime: 0.001 sec (0 m 0 s)\n"
|
84
64
|
|
85
|
-
|
86
|
-
|
87
|
-
=> 0 # ClamAV example
|
65
|
+
> puts result.to_s
|
66
|
+
/path/to/image.jpg: OK
|
88
67
|
|
89
|
-
|
90
|
-
|
91
|
-
|
68
|
+
----------- SCAN SUMMARY -----------
|
69
|
+
Infected files: 0
|
70
|
+
Time: 0.001 sec (0 m 0 s)
|
71
|
+
|
72
|
+
[ClamAV 0.98.7/20903/Fri Sep 11 08:42:07 2015]
|
92
73
|
```
|
93
74
|
|
94
75
|
### Logging
|
@@ -104,12 +85,19 @@ Ddr::Antivirus.logger = Logger.new("/path/to/custom.log")
|
|
104
85
|
|
105
86
|
In order to avoid the overhead of ClamAV in test and/or development environments, the package provides a no-op adapter:
|
106
87
|
|
107
|
-
```
|
88
|
+
```
|
108
89
|
>> Ddr::Antivirus.scanner_adapter = :null
|
109
90
|
=> :null
|
110
91
|
>> Ddr::Antivirus::Scanner.scan("/path/to/blue-devil.png")
|
111
|
-
|
112
|
-
|
92
|
+
=> #<Ddr::Antivirus::NullScanResult:0x007f9e2ba1af38 @output="/path/to/blue-devil.png: NOT SCANNED - using :null scanner adapter.", @file_path="/path/to/blue-devil.png", @scanned_at=2014-11-07 20:58:17 UTC, @version="ddr-antivirus 1.2.0">
|
93
|
+
```
|
94
|
+
|
95
|
+
### Test Mode
|
96
|
+
|
97
|
+
To easily configure `Ddr::Antivirus` to use the `NullScannerAdapter` and log to the null device, turn on test mode:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
Ddr::Antivirus.test_mode!
|
113
101
|
```
|
114
102
|
|
115
103
|
## Contributing
|
data/ddr-antivirus.gemspec
CHANGED
@@ -18,9 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "activesupport", "~> 4.0"
|
22
21
|
spec.add_development_dependency "bundler", "~> 1.6"
|
23
22
|
spec.add_development_dependency "rake"
|
24
|
-
spec.add_development_dependency "clamav"
|
25
23
|
spec.add_development_dependency "rspec", "~> 3.0"
|
26
24
|
end
|
data/lib/ddr/antivirus.rb
CHANGED
@@ -2,50 +2,56 @@ require "logger"
|
|
2
2
|
|
3
3
|
require_relative "antivirus/version"
|
4
4
|
require_relative "antivirus/scanner"
|
5
|
-
require_relative "antivirus/
|
6
|
-
|
7
|
-
|
5
|
+
require_relative "antivirus/scan_result"
|
6
|
+
require_relative "antivirus/scanner_adapter"
|
7
|
+
require_relative "antivirus/adapters/null_scanner_adapter"
|
8
8
|
|
9
9
|
module Ddr
|
10
10
|
module Antivirus
|
11
11
|
|
12
|
-
class
|
12
|
+
class Error < ::StandardError; end
|
13
|
+
class VirusFoundError < Error; end
|
14
|
+
class ScannerError < Error; end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
end
|
16
|
+
class << self
|
17
|
+
attr_accessor :logger, :scanner_adapter
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
if defined?(Rails) && Rails.logger
|
25
|
-
Rails.logger
|
26
|
-
else
|
27
|
-
Logger.new(STDERR)
|
19
|
+
def configure
|
20
|
+
yield self
|
21
|
+
end
|
22
|
+
|
23
|
+
def scan(path)
|
24
|
+
Scanner.scan(path)
|
28
25
|
end
|
29
|
-
end
|
30
26
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
27
|
+
def scanner
|
28
|
+
s = Scanner.new
|
29
|
+
block_given? ? yield(s) : s
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_mode!
|
33
|
+
configure do |config|
|
34
|
+
config.logger = Logger.new(File::NULL)
|
35
|
+
config.scanner_adapter = :null
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Class] the scanner adapter class
|
40
|
+
def get_adapter
|
41
|
+
if scanner_adapter.nil?
|
42
|
+
raise Error, "`Ddr::Antivirus.scanner_adapter` is not configured."
|
43
|
+
end
|
44
|
+
require_relative "antivirus/adapters/#{scanner_adapter}_scanner_adapter"
|
45
|
+
adapter_name = scanner_adapter.to_s.capitalize + "ScannerAdapter"
|
46
|
+
self.const_get(adapter_name, false)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
+
self.logger = if defined?(Rails) && Rails.logger
|
51
|
+
Rails.logger
|
52
|
+
else
|
53
|
+
Logger.new(STDERR)
|
54
|
+
end
|
55
|
+
|
50
56
|
end
|
51
57
|
end
|
@@ -1,69 +1,84 @@
|
|
1
|
+
require "open3"
|
1
2
|
require "fileutils"
|
2
|
-
|
3
|
-
require_relative "scan_result"
|
3
|
+
require "shellwords"
|
4
4
|
|
5
|
-
module Ddr
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
#
|
11
|
-
class ClamdScannerAdapter < ScannerAdapter
|
5
|
+
module Ddr::Antivirus
|
6
|
+
#
|
7
|
+
# Adapter for clamd client (clamdscan)
|
8
|
+
#
|
9
|
+
class ClamdScannerAdapter < ScannerAdapter
|
12
10
|
|
13
|
-
|
14
|
-
raw = clamdscan(path)
|
15
|
-
ClamdScanResult.new(raw, path)
|
16
|
-
end
|
17
|
-
|
18
|
-
def clamdscan(path)
|
19
|
-
original_mode = File.stat(path).mode
|
20
|
-
FileUtils.chmod("a+r", path) unless File.world_readable?(path)
|
21
|
-
result = command(path)
|
22
|
-
FileUtils.chmod(original_mode, path) if File.stat(path).mode != original_mode
|
23
|
-
result
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def command(path)
|
29
|
-
`clamdscan --no-summary "#{path}"`.strip
|
30
|
-
end
|
11
|
+
SCANNER = "clamdscan".freeze
|
31
12
|
|
13
|
+
def scan(path)
|
14
|
+
output, status = clamdscan(path)
|
15
|
+
result = ScanResult.new(path, output, version: version, scanned_at: Time.now.utc)
|
16
|
+
case status.exitstatus
|
17
|
+
when 0
|
18
|
+
result
|
19
|
+
when 1
|
20
|
+
raise VirusFoundError, result.to_s
|
21
|
+
when 2
|
22
|
+
raise ScannerError, result.to_s
|
32
23
|
end
|
24
|
+
end
|
33
25
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
26
|
+
def clamdscan(path)
|
27
|
+
make_readable(path) do
|
28
|
+
command(path)
|
29
|
+
end
|
30
|
+
end
|
38
31
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
32
|
+
def version
|
33
|
+
out, err, status = Open3.capture3(SCANNER, "-V")
|
34
|
+
out.strip
|
35
|
+
end
|
44
36
|
|
45
|
-
|
46
|
-
raw =~ / FOUND$/
|
47
|
-
end
|
37
|
+
private
|
48
38
|
|
49
|
-
|
50
|
-
|
51
|
-
|
39
|
+
def command(path)
|
40
|
+
safe_path = Shellwords.shellescape(path)
|
41
|
+
Open3.capture2e(SCANNER, safe_path)
|
42
|
+
end
|
52
43
|
|
53
|
-
|
54
|
-
|
55
|
-
|
44
|
+
def make_readable(path)
|
45
|
+
changed = false
|
46
|
+
original = File.stat(path).mode # raises Errno::ENOENT
|
47
|
+
if !File.world_readable?(path)
|
48
|
+
changed = FileUtils.chmod("a+r", path)
|
49
|
+
logger.info "File #{path} made world-readable for virus scanning."
|
50
|
+
end
|
51
|
+
result = yield
|
52
|
+
if changed
|
53
|
+
FileUtils.chmod(original, path)
|
54
|
+
logger.info "Mode reset to original #{original} on file #{path}."
|
55
|
+
end
|
56
|
+
result
|
57
|
+
end
|
56
58
|
|
57
|
-
|
58
|
-
"#{raw} (#{version})"
|
59
|
-
end
|
59
|
+
end
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
# Result of a scan with the ClamdScannerAdapter
|
62
|
+
# @api private
|
63
|
+
class ClamdScanResult < ScanResult
|
64
64
|
|
65
|
+
def virus_found
|
66
|
+
if m = /: ([^\s]+) FOUND$/.match(output)
|
67
|
+
m[1]
|
65
68
|
end
|
69
|
+
end
|
66
70
|
|
71
|
+
def ok?
|
72
|
+
status.exitstatus == 0
|
67
73
|
end
|
74
|
+
|
75
|
+
def has_virus?
|
76
|
+
status.exitstatus == 1
|
77
|
+
end
|
78
|
+
|
79
|
+
def error?
|
80
|
+
status.exitstatus == 2
|
81
|
+
end
|
82
|
+
|
68
83
|
end
|
69
84
|
end
|
@@ -1,25 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#
|
9
|
-
#
|
10
|
-
class NullScannerAdapter < ScannerAdapter
|
11
|
-
|
12
|
-
def scan(path)
|
13
|
-
NullScanResult.new("#{path}: NOT SCANNED - using :null scanner adapter.", path)
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
#
|
19
|
-
# The result of the scan with the NullScannerAdapter.
|
20
|
-
#
|
21
|
-
class NullScanResult < ScanResult; end
|
22
|
-
|
1
|
+
module Ddr::Antivirus
|
2
|
+
#
|
3
|
+
# A no-op adapter, primarily for testing and development.
|
4
|
+
#
|
5
|
+
class NullScannerAdapter < ScannerAdapter
|
6
|
+
|
7
|
+
def scan(path)
|
8
|
+
ScanResult.new(path, "#{path}: NOT SCANNED - using :null scanner adapter.")
|
23
9
|
end
|
10
|
+
|
24
11
|
end
|
12
|
+
|
25
13
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Ddr::Antivirus
|
2
|
+
#
|
3
|
+
# The result of a virus scan.
|
4
|
+
#
|
5
|
+
class ScanResult
|
6
|
+
|
7
|
+
attr_reader :file_path, :output, :scanned_at, :version
|
8
|
+
|
9
|
+
def initialize(file_path, output, scanned_at: nil, version: nil)
|
10
|
+
@file_path = file_path
|
11
|
+
@output = output
|
12
|
+
@scanned_at = scanned_at || default_time
|
13
|
+
@version = version || default_version
|
14
|
+
end
|
15
|
+
|
16
|
+
# Default time of virus scan - i.e., now.
|
17
|
+
# @return [Time] the time.
|
18
|
+
def default_time
|
19
|
+
Time.now.utc
|
20
|
+
end
|
21
|
+
|
22
|
+
# Default anti-virus software version information.
|
23
|
+
# @return [String] the version.
|
24
|
+
def default_version
|
25
|
+
"ddr-antivirus #{Ddr::Antivirus::VERSION}"
|
26
|
+
end
|
27
|
+
|
28
|
+
# String representation of the result
|
29
|
+
# @return [String] the representation.
|
30
|
+
def to_s
|
31
|
+
"#{output}\n[#{version}]"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -1,36 +1,16 @@
|
|
1
|
-
require "
|
1
|
+
require "delegate"
|
2
2
|
|
3
|
-
module Ddr
|
4
|
-
|
5
|
-
class Scanner
|
3
|
+
module Ddr::Antivirus
|
4
|
+
class Scanner < SimpleDelegator
|
6
5
|
|
7
|
-
|
8
|
-
|
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.to_s)
|
24
|
-
result
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def logger
|
30
|
-
Ddr::Antivirus.logger
|
31
|
-
end
|
6
|
+
def self.scan(path)
|
7
|
+
new.scan(path)
|
8
|
+
end
|
32
9
|
|
10
|
+
def initialize
|
11
|
+
super Ddr::Antivirus.get_adapter.new
|
33
12
|
end
|
13
|
+
|
34
14
|
end
|
35
15
|
end
|
36
16
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative "scan_result"
|
2
|
+
|
3
|
+
module Ddr::Antivirus
|
4
|
+
#
|
5
|
+
# @abstract Subclass and override {#scan} to implement a scanner adapter.
|
6
|
+
#
|
7
|
+
class ScannerAdapter
|
8
|
+
|
9
|
+
# Scan a file path for viruses.
|
10
|
+
#
|
11
|
+
# @param path [String] file path to scan.
|
12
|
+
# @return [Ddr::Antivirus::Adapters::ScanResult] the result of the scan.
|
13
|
+
def scan(path)
|
14
|
+
raise NotImplementedError, "Adapters must implement the `scan' method."
|
15
|
+
end
|
16
|
+
|
17
|
+
# Return the adapter configuration options
|
18
|
+
def config
|
19
|
+
Ddr::Antivirus.adapter_config
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def logger
|
25
|
+
Ddr::Antivirus.logger
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,25 +1,7 @@
|
|
1
|
-
require "coveralls"
|
2
|
-
Coveralls.wear!
|
3
|
-
|
4
|
-
# This file was generated by the `rspec --init` command. Conventionally, all
|
5
|
-
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
6
|
-
# The generated `.rspec` file contains `--require spec_helper` which will cause this
|
7
|
-
# file to always be loaded, without a need to explicitly require it in any files.
|
8
|
-
#
|
9
|
-
# Given that it is always loaded, you are encouraged to keep this file as
|
10
|
-
# light-weight as possible. Requiring heavyweight dependencies from this file
|
11
|
-
# will add to the boot time of your test suite on EVERY test run, even for an
|
12
|
-
# individual file that may not need all of that loaded. Instead, make a
|
13
|
-
# separate helper file that requires this one and then use it only in the specs
|
14
|
-
# that actually need it.
|
15
|
-
#
|
16
|
-
# The `.rspec` file also contains a few flags that are not defaults but that
|
17
|
-
# users commonly want.
|
18
|
-
#
|
19
|
-
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
20
|
-
|
21
1
|
require 'ddr/antivirus'
|
22
2
|
|
3
|
+
Ddr::Antivirus.test_mode!
|
4
|
+
|
23
5
|
RSpec.configure do |config|
|
24
6
|
# The settings below are suggested to provide a good initial experience
|
25
7
|
# with RSpec, but feel free to customize to your heart's content.
|
@@ -1,66 +1,72 @@
|
|
1
|
-
require "
|
1
|
+
require "tempfile"
|
2
2
|
require "ddr/antivirus/adapters/clamd_scanner_adapter"
|
3
3
|
|
4
|
-
module Ddr
|
5
|
-
|
6
|
-
module Adapters
|
7
|
-
RSpec.describe ClamdScannerAdapter do
|
4
|
+
module Ddr::Antivirus
|
5
|
+
RSpec.describe ClamdScannerAdapter do
|
8
6
|
|
9
|
-
|
10
|
-
let(:adapter) { described_class.new }
|
7
|
+
let(:path) { File.expand_path(File.join("..", "..", "fixtures", "blue-devil.png"), __FILE__) }
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@file.write("Scan me!")
|
16
|
-
@file.close
|
17
|
-
allow(adapter).to receive(:command).with(@file.path) { "#{@file.path}: OK" }
|
18
|
-
end
|
19
|
-
after { @file.unlink }
|
20
|
-
describe "when the file is not world readable" do
|
21
|
-
it "should temporarily change the permissions" do
|
22
|
-
original_mode = File.stat(@file.path).mode
|
23
|
-
expect(FileUtils).to receive(:chmod).with("a+r", @file.path)
|
24
|
-
adapter.scan(@file.path)
|
25
|
-
expect(File.stat(@file.path).mode).to eq(original_mode)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
describe "when the file is world readable" do
|
29
|
-
before { FileUtils.chmod("a+r", @file.path) }
|
30
|
-
it "should not change the permissions" do
|
31
|
-
original_mode = File.stat(@file.path).mode
|
32
|
-
expect(FileUtils).not_to receive(:chmod)
|
33
|
-
adapter.scan(@file.path)
|
34
|
-
expect(File.stat(@file.path).mode).to eq(original_mode)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
9
|
+
before do
|
10
|
+
allow(subject).to receive(:version) { "version" }
|
11
|
+
end
|
38
12
|
|
39
|
-
|
40
|
-
|
13
|
+
describe "permissions" do
|
14
|
+
before do
|
15
|
+
@file = Tempfile.new("test")
|
16
|
+
@file.write("Scan me!")
|
17
|
+
@file.close
|
18
|
+
allow(subject).to receive(:command).with(@file.path) { ["#{@file.path}: OK", double(exitstatus: 0)] }
|
19
|
+
end
|
20
|
+
after { @file.unlink }
|
21
|
+
describe "when the file is not world readable" do
|
22
|
+
it "should temporarily change the permissions" do
|
23
|
+
FileUtils.chmod("a-r", @file.path)
|
24
|
+
original_mode = File.stat(@file.path).mode
|
25
|
+
expect(FileUtils).to receive(:chmod).with("a+r", @file.path)
|
26
|
+
subject.scan(@file.path)
|
27
|
+
expect(File.stat(@file.path).mode).to eq(original_mode)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
describe "when the file is world readable" do
|
31
|
+
before { FileUtils.chmod("a+r", @file.path) }
|
32
|
+
it "should not change the permissions" do
|
33
|
+
original_mode = File.stat(@file.path).mode
|
34
|
+
expect(FileUtils).not_to receive(:chmod)
|
35
|
+
subject.scan(@file.path)
|
36
|
+
expect(File.stat(@file.path).mode).to eq(original_mode)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
41
40
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
41
|
+
describe "result" do
|
42
|
+
before do
|
43
|
+
allow(subject).to receive(:command).with(path) { ["output", status] }
|
44
|
+
end
|
45
|
+
describe "when a virus is found" do
|
46
|
+
let(:status) { double(exitstatus: 1) }
|
47
|
+
it "should raise a VirusFoundError" do
|
48
|
+
expect { subject.scan(path) }.to raise_error(VirusFoundError)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
describe "when there is an error" do
|
52
|
+
let(:status) { double(exitstatus: 2) }
|
53
|
+
it "should raise a ScannerError" do
|
54
|
+
expect { subject.scan(path) }.to raise_error(ScannerError)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
describe "success" do
|
58
|
+
let(:status) { double(exitstatus: 0) }
|
59
|
+
it "should have output" do
|
60
|
+
expect(subject.scan(path).output).to eq("output")
|
61
|
+
end
|
62
|
+
it "should have a scanned_at time" do
|
63
|
+
expect(subject.scan(path).scanned_at).to be_a(Time)
|
64
|
+
end
|
65
|
+
it "should have a version" do
|
66
|
+
expect(subject.scan(path).version).to eq("version")
|
67
|
+
end
|
68
|
+
it "should have the file_path" do
|
69
|
+
expect(subject.scan(path).file_path).to eq(path)
|
64
70
|
end
|
65
71
|
end
|
66
72
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ddr-antivirus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Chandek-Stark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-11 00:00:00.000000000 Z
|
12
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
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: bundler
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,20 +38,6 @@ dependencies:
|
|
52
38
|
- - ">="
|
53
39
|
- !ruby/object:Gem::Version
|
54
40
|
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
41
|
- !ruby/object:Gem::Dependency
|
70
42
|
name: rspec
|
71
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -97,22 +69,15 @@ files:
|
|
97
69
|
- ddr-antivirus.gemspec
|
98
70
|
- lib/ddr-antivirus.rb
|
99
71
|
- lib/ddr/antivirus.rb
|
100
|
-
- lib/ddr/antivirus/adapters.rb
|
101
|
-
- lib/ddr/antivirus/adapters/clamav_scanner_adapter.rb
|
102
72
|
- lib/ddr/antivirus/adapters/clamd_scanner_adapter.rb
|
103
73
|
- lib/ddr/antivirus/adapters/null_scanner_adapter.rb
|
104
|
-
- lib/ddr/antivirus/
|
105
|
-
- lib/ddr/antivirus/adapters/scanner_adapter.rb
|
74
|
+
- lib/ddr/antivirus/scan_result.rb
|
106
75
|
- lib/ddr/antivirus/scanner.rb
|
76
|
+
- lib/ddr/antivirus/scanner_adapter.rb
|
107
77
|
- lib/ddr/antivirus/version.rb
|
108
78
|
- spec/fixtures/blue-devil.png
|
109
|
-
- spec/shared_examples_for_scan_results.rb
|
110
79
|
- spec/spec_helper.rb
|
111
|
-
- spec/unit/clamav_scanner_adapter_spec.rb
|
112
80
|
- spec/unit/clamd_scanner_adapter_spec.rb
|
113
|
-
- spec/unit/null_scanner_adapter_spec.rb
|
114
|
-
- spec/unit/scan_result_spec.rb
|
115
|
-
- spec/unit/scanner_spec.rb
|
116
81
|
homepage: https://github.com/duke-libraries/ddr-antivirus
|
117
82
|
licenses:
|
118
83
|
- BSD-3-Clause
|
@@ -128,9 +93,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
128
93
|
version: '0'
|
129
94
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
95
|
requirements:
|
131
|
-
- - "
|
96
|
+
- - ">"
|
132
97
|
- !ruby/object:Gem::Version
|
133
|
-
version:
|
98
|
+
version: 1.3.1
|
134
99
|
requirements: []
|
135
100
|
rubyforge_project:
|
136
101
|
rubygems_version: 2.4.6
|
@@ -139,10 +104,5 @@ specification_version: 4
|
|
139
104
|
summary: Pluggable antivirus scanning service.
|
140
105
|
test_files:
|
141
106
|
- spec/fixtures/blue-devil.png
|
142
|
-
- spec/shared_examples_for_scan_results.rb
|
143
107
|
- spec/spec_helper.rb
|
144
|
-
- spec/unit/clamav_scanner_adapter_spec.rb
|
145
108
|
- spec/unit/clamd_scanner_adapter_spec.rb
|
146
|
-
- spec/unit/null_scanner_adapter_spec.rb
|
147
|
-
- spec/unit/scan_result_spec.rb
|
148
|
-
- spec/unit/scanner_spec.rb
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module Ddr
|
2
|
-
module Antivirus
|
3
|
-
module Adapters
|
4
|
-
|
5
|
-
def self.get_adapter
|
6
|
-
require_relative "adapters/#{Ddr::Antivirus.scanner_adapter}_scanner_adapter"
|
7
|
-
adapter_name = "#{Ddr::Antivirus.scanner_adapter.to_s.capitalize}ScannerAdapter"
|
8
|
-
klass = self.const_get(adapter_name.to_sym, false)
|
9
|
-
klass.new
|
10
|
-
end
|
11
|
-
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,82 +0,0 @@
|
|
1
|
-
require "clamav"
|
2
|
-
|
3
|
-
require_relative "scanner_adapter"
|
4
|
-
require_relative "scan_result"
|
5
|
-
|
6
|
-
module Ddr
|
7
|
-
module Antivirus
|
8
|
-
module Adapters
|
9
|
-
#
|
10
|
-
# Scanner adapter for the 'clamav' gem (Ruby libclamav bindings).
|
11
|
-
#
|
12
|
-
class ClamavScannerAdapter < ScannerAdapter
|
13
|
-
|
14
|
-
def scan(path)
|
15
|
-
reload!
|
16
|
-
raw = engine.scanfile(path)
|
17
|
-
ClamavScanResult.new(raw, path)
|
18
|
-
end
|
19
|
-
|
20
|
-
# Load or reload the database of virus signatures.
|
21
|
-
def reload!
|
22
|
-
#
|
23
|
-
# ClamAV.instance.reload is supposed to reload the database if changed and return:
|
24
|
-
#
|
25
|
-
# 0 => unnecessary
|
26
|
-
# 1 => successful
|
27
|
-
# 2 => error (undocumented)
|
28
|
-
#
|
29
|
-
# However, reload raises a RuntimeError when the db needs to be reloaded,
|
30
|
-
# in which case, loaddb must be called.
|
31
|
-
#
|
32
|
-
engine.loaddb unless [0, 1].include?(engine.reload)
|
33
|
-
rescue RuntimeError
|
34
|
-
engine.loaddb
|
35
|
-
end
|
36
|
-
|
37
|
-
def engine
|
38
|
-
ClamAV.instance
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
#
|
44
|
-
# Result of a scan with the ClamavScannerAdapter.
|
45
|
-
#
|
46
|
-
class ClamavScanResult < ScanResult
|
47
|
-
|
48
|
-
def virus_found
|
49
|
-
raw if has_virus?
|
50
|
-
end
|
51
|
-
|
52
|
-
def has_virus?
|
53
|
-
![0, 1].include?(raw)
|
54
|
-
end
|
55
|
-
|
56
|
-
def error?
|
57
|
-
raw == 1
|
58
|
-
end
|
59
|
-
|
60
|
-
# A formatted status message (for consistency with clamdscan output).
|
61
|
-
# @return [String] the result status.
|
62
|
-
def status
|
63
|
-
return "FOUND #{virus_found}" if has_virus?
|
64
|
-
return "ERROR" if error?
|
65
|
-
"OK"
|
66
|
-
end
|
67
|
-
|
68
|
-
def to_s
|
69
|
-
"#{file_path}: #{status} (#{version})"
|
70
|
-
end
|
71
|
-
|
72
|
-
def default_version
|
73
|
-
# Engine and database versions
|
74
|
-
# E.g., ClamAV 0.98.3/19010/Tue May 20 21:46:01 2014
|
75
|
-
`sigtool --version`.strip
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
module Ddr
|
2
|
-
module Antivirus
|
3
|
-
module Adapters
|
4
|
-
#
|
5
|
-
# The result of a virus scan.
|
6
|
-
#
|
7
|
-
class ScanResult
|
8
|
-
|
9
|
-
attr_reader :raw, :file_path, :scanned_at, :version
|
10
|
-
|
11
|
-
def initialize(raw, file_path, opts={})
|
12
|
-
@raw = raw
|
13
|
-
@file_path = file_path
|
14
|
-
@scanned_at = opts.fetch(:scanned_at, default_time)
|
15
|
-
@version = opts.fetch(:version, default_version)
|
16
|
-
end
|
17
|
-
|
18
|
-
# Default time of virus scan - i.e., now.
|
19
|
-
# @return [Time] the time.
|
20
|
-
def default_time
|
21
|
-
Time.now.utc
|
22
|
-
end
|
23
|
-
|
24
|
-
# Default anti-virus software version information.
|
25
|
-
# @return [String] the version.
|
26
|
-
def default_version
|
27
|
-
"ddr-antivirus #{Ddr::Antivirus::VERSION}"
|
28
|
-
end
|
29
|
-
|
30
|
-
# the name of virus found.
|
31
|
-
# @return [String] the virus name.
|
32
|
-
def virus_found; end
|
33
|
-
|
34
|
-
# Was a virus found?
|
35
|
-
# @return [true, false] whether a virus was found.
|
36
|
-
def has_virus?
|
37
|
-
!virus_found.nil?
|
38
|
-
end
|
39
|
-
|
40
|
-
# Was there an error (reported by the scanner, not necessarily an exception)?
|
41
|
-
# @return [true, false] whether there was an error.
|
42
|
-
def error?
|
43
|
-
false
|
44
|
-
end
|
45
|
-
|
46
|
-
# Was the result OK - i.e., not an error and virus not found.
|
47
|
-
# @return [true, false] whether the result was OK.
|
48
|
-
def ok?
|
49
|
-
!(has_virus? || error?)
|
50
|
-
end
|
51
|
-
|
52
|
-
# String representation of the result
|
53
|
-
# @return [String] the representation.
|
54
|
-
def to_s
|
55
|
-
"#{raw} (#{version})"
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module Ddr
|
2
|
-
module Antivirus
|
3
|
-
module Adapters
|
4
|
-
#
|
5
|
-
# @abstract Subclass and override {#scan} to implement a scanner adapter.
|
6
|
-
#
|
7
|
-
class ScannerAdapter
|
8
|
-
|
9
|
-
# Scan a file path for viruses.
|
10
|
-
#
|
11
|
-
# @param path [String] file path to scan.
|
12
|
-
# @return [Ddr::Antivirus::Adapters::ScanResult] the result of the scan.
|
13
|
-
def scan(path)
|
14
|
-
raise NotImplementedError, "Adapters must implement the `scan' method."
|
15
|
-
end
|
16
|
-
|
17
|
-
# Return the adapter configuration options
|
18
|
-
def config
|
19
|
-
Ddr::Antivirus.adapter_config
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,53 +0,0 @@
|
|
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).not_to be_nil
|
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
|
-
end
|
28
|
-
|
29
|
-
shared_examples "an error scan result" do
|
30
|
-
it "should have an error" do
|
31
|
-
expect(subject).to be_error
|
32
|
-
end
|
33
|
-
it "shoud not have a virus" do
|
34
|
-
expect(subject.virus_found).to be_nil
|
35
|
-
expect(subject).not_to have_virus
|
36
|
-
end
|
37
|
-
it "should not be ok" do
|
38
|
-
expect(subject).not_to be_ok
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
shared_examples "a virus scan result" do
|
43
|
-
it "shoud have a virus" do
|
44
|
-
expect(subject.virus_found).not_to be_nil
|
45
|
-
expect(subject).to have_virus
|
46
|
-
end
|
47
|
-
it "should not have an error" do
|
48
|
-
expect(subject).not_to be_error
|
49
|
-
end
|
50
|
-
it "should not be ok" do
|
51
|
-
expect(subject).not_to be_ok
|
52
|
-
end
|
53
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
require "shared_examples_for_scan_results"
|
2
|
-
require "ddr/antivirus/adapters/clamav_scanner_adapter"
|
3
|
-
|
4
|
-
module Ddr
|
5
|
-
module Antivirus
|
6
|
-
module Adapters
|
7
|
-
RSpec.describe ClamavScannerAdapter do
|
8
|
-
|
9
|
-
let(:path) { File.expand_path(File.join("..", "..", "fixtures", "blue-devil.png"), __FILE__) }
|
10
|
-
|
11
|
-
describe "#scan" do
|
12
|
-
context "when the db is already loaded" do
|
13
|
-
before { subject.engine.loaddb }
|
14
|
-
it "should reload the db" do
|
15
|
-
expect(subject.engine).to receive(:reload).and_call_original
|
16
|
-
expect(subject.engine).not_to receive(:loaddb)
|
17
|
-
subject.scan(path)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
context "when the db is not already loaded" do
|
21
|
-
before { allow(subject.engine).to receive(:reload).and_raise(RuntimeError) }
|
22
|
-
it "should load the db" do
|
23
|
-
expect(subject.engine).to receive(:loaddb).and_call_original
|
24
|
-
subject.scan(path)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
context "when the db is not reloaded successfully" do
|
28
|
-
before { allow(subject.engine).to receive(:reload) { 2 } }
|
29
|
-
it "should load the db" do
|
30
|
-
expect(subject.engine).to receive(:loaddb).and_call_original
|
31
|
-
subject.scan(path)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
describe "result" do
|
36
|
-
subject { adapter.scan(path) }
|
37
|
-
let(:adapter) { described_class.new }
|
38
|
-
it "should be a ClamavScanResult" do
|
39
|
-
expect(subject).to be_a(ClamavScanResult)
|
40
|
-
end
|
41
|
-
it_should_behave_like "a scan result"
|
42
|
-
context "when a virus is found" do
|
43
|
-
before { allow(adapter.engine).to receive(:scanfile).with(path) { "Bad boy 35" } }
|
44
|
-
it "the raw result should be the virus description" do
|
45
|
-
expect(subject.raw).to eq "Bad boy 35"
|
46
|
-
expect(subject.virus_found).to eq "Bad boy 35"
|
47
|
-
end
|
48
|
-
it_should_behave_like "a virus scan result"
|
49
|
-
end
|
50
|
-
context "when there is an error" do
|
51
|
-
before { allow(adapter.engine).to receive(:scanfile).with(path) { 1 } }
|
52
|
-
it "should not have a virus" do
|
53
|
-
expect(subject).not_to have_virus
|
54
|
-
end
|
55
|
-
it_should_behave_like "an error scan result"
|
56
|
-
end
|
57
|
-
context "success" do
|
58
|
-
before { allow(adapter.engine).to receive(:scanfile).with(path) { 0 } }
|
59
|
-
it_should_behave_like "a successful scan result"
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require "shared_examples_for_scan_results"
|
2
|
-
require "ddr/antivirus/adapters/null_scanner_adapter"
|
3
|
-
|
4
|
-
module Ddr
|
5
|
-
module Antivirus
|
6
|
-
module Adapters
|
7
|
-
RSpec.describe NullScannerAdapter do
|
8
|
-
|
9
|
-
let(:path) { File.expand_path(File.join("..", "..", "fixtures", "blue-devil.png"), __FILE__) }
|
10
|
-
|
11
|
-
describe "result" do
|
12
|
-
subject { adapter.scan(path) }
|
13
|
-
let(:adapter) { described_class.new }
|
14
|
-
it "should be a NullScanResult" do
|
15
|
-
expect(subject).to be_a(NullScanResult)
|
16
|
-
end
|
17
|
-
it_should_behave_like "a scan result"
|
18
|
-
it_should_behave_like "a successful scan result"
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'shared_examples_for_scan_results'
|
2
|
-
|
3
|
-
module Ddr
|
4
|
-
module Antivirus
|
5
|
-
module Adapters
|
6
|
-
RSpec.describe ScanResult do
|
7
|
-
subject { described_class.new("Raw result", "/tmp/foo") }
|
8
|
-
|
9
|
-
it_should_behave_like "a scan result"
|
10
|
-
|
11
|
-
describe "success" do
|
12
|
-
it_should_behave_like "a successful scan result"
|
13
|
-
end
|
14
|
-
|
15
|
-
describe "error" do
|
16
|
-
before { allow(subject).to receive(:error?) { true } }
|
17
|
-
it_should_behave_like "an error scan result"
|
18
|
-
end
|
19
|
-
|
20
|
-
describe "virus found" do
|
21
|
-
before { allow(subject).to receive(:virus_found) { "Bad boy 35" } }
|
22
|
-
it_should_behave_like "a virus scan result"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/spec/unit/scanner_spec.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
require "ddr/antivirus/adapters/scan_result"
|
2
|
-
|
3
|
-
module Ddr
|
4
|
-
module Antivirus
|
5
|
-
RSpec.describe Scanner do
|
6
|
-
|
7
|
-
shared_examples "a scanner" do
|
8
|
-
let(:path) { "/tmp/foo" }
|
9
|
-
describe "logging" do
|
10
|
-
it "should log the result" do
|
11
|
-
expect(Ddr::Antivirus.logger).to receive(:info)
|
12
|
-
subject.scan(path)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
describe "when a virus is found" do
|
16
|
-
before { allow_any_instance_of(Ddr::Antivirus::Adapters::ScanResult).to receive(:has_virus?) { true } }
|
17
|
-
it "should raise an execption" do
|
18
|
-
expect { subject.scan(path) }.to raise_error
|
19
|
-
end
|
20
|
-
end
|
21
|
-
describe "when a virus is not found" do
|
22
|
-
before { allow_any_instance_of(Ddr::Antivirus::Adapters::ScanResult).to receive(:has_virus?) { false } }
|
23
|
-
it "should return the scan result" do
|
24
|
-
expect(subject.scan(path)).to be_a(Ddr::Antivirus::Adapters::ScanResult)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
describe "when an error occurs in the scanner" do
|
28
|
-
before { allow_any_instance_of(Ddr::Antivirus::Adapters::ScanResult).to receive(:error?) { true } }
|
29
|
-
it "should log an error" do
|
30
|
-
expect(Ddr::Antivirus.logger).to receive(:error)
|
31
|
-
subject.scan(path)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
before do
|
37
|
-
@original_adapter = Ddr::Antivirus.scanner_adapter
|
38
|
-
Ddr::Antivirus.scanner_adapter = :null
|
39
|
-
end
|
40
|
-
|
41
|
-
after do
|
42
|
-
Ddr::Antivirus.scanner_adapter = @original_adapter
|
43
|
-
end
|
44
|
-
|
45
|
-
describe ".scan" do
|
46
|
-
subject { described_class }
|
47
|
-
it_behaves_like "a scanner"
|
48
|
-
end
|
49
|
-
|
50
|
-
describe "#scan" do
|
51
|
-
subject { described_class.new }
|
52
|
-
it_behaves_like "a scanner"
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|