ddr-antivirus 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bbf8b0276005e8766ca6c985e7a4d4771c1ec2f1
4
- data.tar.gz: 39638ef73883d0ba112cf8d093ed84e9e021d39d
3
+ metadata.gz: 86a232e5b90342f2dd51279b2e589e51d7345a23
4
+ data.tar.gz: e48ae1a5fe0a895d18784a6ba120a0e7dfa892ba
5
5
  SHA512:
6
- metadata.gz: 96ea1c688237f4dfa5f9b6a8c7c5c5c87edd9eeb5a535ed55978680c9850f744bd2d7ba456d37811157d744bf8a2bdda1d2a9c0111d1a411c404ac2cd798f609
7
- data.tar.gz: 5e1c5433a733abdc129bf37893299ec2133b817e7a316613805e973927e13206a673f42f67c7c9671abb2816a68186e3096fecfff925eaa1971f6e71f09a1232
6
+ metadata.gz: 173c325eb8d7369d7823341593334e229ae5a48047938a680fda9afc21a6151d6e34722864a9acda826fd1f11113526b086bc7dc45acdaf7a410c8a70b4e0ee8
7
+ data.tar.gz: 51d17a1ea969fab1d69f86b4bd1f3c870fdcef45d7362f96bebb9387ab95105f2e61e55c79eee1be628a254d5ef15acffd0d894a6a6414bbc7a88e96a52bd3af
data/README.md CHANGED
@@ -24,7 +24,7 @@ Or install it yourself as:
24
24
  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:
25
25
 
26
26
  - If the [clamav](https://github.com/eagleas/clamav) gem is available, it will select the `ClamavScannerAdapter`.
27
- - If the ClamAV Daemon client `clamdscan` is on the user's path, it will select the `ClamdScannerAdapter`.
27
+ - 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.
28
28
  - Otherwise, it will select the [`NullScannerAdapter`](#the-nullscanneradapter).
29
29
 
30
30
  The auto-selection process may be overridden by configuration:
@@ -57,7 +57,7 @@ The scanner raises a `Ddr::Antivirus::VirusFoundError` exception if a virus is f
57
57
 
58
58
  ### Results
59
59
 
60
- Class: `Ddr::Antivirus::ScanResult`
60
+ Class: `Ddr::Antivirus::Adapters::ScanResult`
61
61
 
62
62
  A scanner adapter may subclass the base class to parse the raw result properly.
63
63
 
@@ -66,7 +66,7 @@ A scanner adapter may subclass the base class to parse the raw result properly.
66
66
  => true
67
67
 
68
68
  >> result = Ddr::Antivirus::Scanner.scan("/path/to/blue-devil.png")
69
- => #<Ddr::Antivirus::Adapters::ClamavScannerAdapter::ClamavScanResult:0x007f98fb169cc0 ...
69
+ => #<Ddr::Antivirus::Adapters::ClamavScanResult:0x007f98fb169cc0 ...
70
70
 
71
71
  # Was there a virus?
72
72
  >> result.has_virus?
@@ -85,20 +85,29 @@ A scanner adapter may subclass the base class to parse the raw result properly.
85
85
  => 0 # ClamAV example
86
86
 
87
87
  # String representation (example)
88
- >> puts result.to_s
89
- => /path/to/blue-devil.png: OK (ClamAV 0.98.3/19559/Thu Oct 30 06:39:46 2014)
88
+ >> result.to_s
89
+ => "/path/to/blue-devil.png: OK (ClamAV 0.98.3/19595/Thu Nov 6 11:32:29 2014)"
90
+ ```
91
+
92
+ ### Logging
93
+
94
+ In a Rails application, `Ddr::Antivirus` will log messages to the Rails logger by default. The fallback logger writes to STDERR. You may also explicitly set `Ddr::Antivirus.logger` to any object that supports the Ruby logger API:
95
+
96
+ ```ruby
97
+ require "logger"
98
+ Ddr::Antivirus.logger = Logger.new("/path/to/custom.log")
90
99
  ```
91
100
 
92
101
  ### The NullScannerAdapter
93
102
 
94
- 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 scan result object (instance of Ddr::Antivirus::ScanResult).
103
+ In order to avoid the overhead of ClamAV in test and/or development environments, the package provides a no-op adapter:
95
104
 
96
105
  ```ruby
97
106
  >> Ddr::Antivirus.scanner_adapter = :null
98
107
  => :null
99
108
  >> Ddr::Antivirus::Scanner.scan("/path/to/blue-devil.png")
100
- W, [2014-10-30T16:21:24.349542 #76244] WARN -- : File not scanned -- using :null scanner adapter.
101
- 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">
109
+ I, [2014-11-07T15:58:17.706866 #82651] INFO -- : /path/to/blue-devil.png: NOT SCANNED - using :null scanner adapter. (ddr-antivirus 1.2.0)
110
+ => #<Ddr::Antivirus::Adapters::NullScanResult:0x007f9e2ba1af38 @raw="/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">
102
111
  ```
103
112
 
104
113
  ## Contributing
@@ -1,7 +1,8 @@
1
- require "ddr/antivirus/version"
2
- require "ddr/antivirus/scanner"
3
- require "ddr/antivirus/scan_result"
4
- require "ddr/antivirus/adapters"
1
+ require "logger"
2
+
3
+ require_relative "antivirus/version"
4
+ require_relative "antivirus/scanner"
5
+ require_relative "antivirus/adapters"
5
6
 
6
7
  require "active_support/core_ext/module/attribute_accessors"
7
8
 
@@ -23,7 +24,6 @@ module Ddr
23
24
  if defined?(Rails) && Rails.logger
24
25
  Rails.logger
25
26
  else
26
- require "logger"
27
27
  Logger.new(STDERR)
28
28
  end
29
29
  end
@@ -1,23 +1,14 @@
1
- require_relative "./adapters/scanner_adapter"
2
-
3
1
  module Ddr
4
2
  module Antivirus
5
3
  module Adapters
6
4
 
7
- def self.get_adapter
8
- require_relative adapter_module
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"
9
8
  klass = self.const_get(adapter_name.to_sym, false)
10
9
  klass.new
11
10
  end
12
11
 
13
- def self.adapter_name
14
- "#{Ddr::Antivirus.scanner_adapter.to_s.capitalize}ScannerAdapter"
15
- end
16
-
17
- def self.adapter_module
18
- "./adapters/#{Ddr::Antivirus.scanner_adapter}_scanner_adapter"
19
- end
20
-
21
12
  end
22
13
  end
23
14
  end
@@ -1,8 +1,12 @@
1
- require 'clamav'
1
+ require "clamav"
2
+
3
+ require_relative "scanner_adapter"
4
+ require_relative "scan_result"
2
5
 
3
6
  module Ddr
4
7
  module Antivirus
5
8
  module Adapters
9
+
6
10
  class ClamavScannerAdapter < ScannerAdapter
7
11
 
8
12
  def scan(path)
@@ -31,39 +35,43 @@ module Ddr
31
35
  ClamAV.instance
32
36
  end
33
37
 
34
- class ClamavScanResult < Ddr::Antivirus::ScanResult
38
+ end
35
39
 
36
- def virus_found
37
- raw if has_virus?
38
- end
40
+ #
41
+ # Result of a scan with the ClamavScannerAdapter.
42
+ #
43
+ class ClamavScanResult < ScanResult
39
44
 
40
- def has_virus?
41
- ![0, 1].include?(raw)
42
- end
45
+ def virus_found
46
+ raw if has_virus?
47
+ end
43
48
 
44
- def error?
45
- raw == 1
46
- end
49
+ def has_virus?
50
+ ![0, 1].include?(raw)
51
+ end
47
52
 
48
- def status
49
- return "FOUND #{virus_found}" if has_virus?
50
- return "ERROR" if error?
51
- "OK"
52
- end
53
+ def error?
54
+ raw == 1
55
+ end
53
56
 
54
- def to_s
55
- "#{file_path}: #{status} (#{version})"
56
- end
57
+ def status
58
+ return "FOUND #{virus_found}" if has_virus?
59
+ return "ERROR" if error?
60
+ "OK"
61
+ end
57
62
 
58
- def default_version
59
- # Engine and database versions
60
- # E.g., ClamAV 0.98.3/19010/Tue May 20 21:46:01 2014
61
- `sigtool --version`.strip
62
- end
63
+ def to_s
64
+ "#{file_path}: #{status} (#{version})"
65
+ end
63
66
 
67
+ def default_version
68
+ # Engine and database versions
69
+ # E.g., ClamAV 0.98.3/19010/Tue May 20 21:46:01 2014
70
+ `sigtool --version`.strip
64
71
  end
65
72
 
66
73
  end
74
+
67
75
  end
68
76
  end
69
77
  end
@@ -1,3 +1,6 @@
1
+ require_relative "scanner_adapter"
2
+ require_relative "scan_result"
3
+
1
4
  module Ddr
2
5
  module Antivirus
3
6
  module Adapters
@@ -17,37 +20,41 @@ module Ddr
17
20
  `clamdscan --no-summary #{path}`.strip
18
21
  end
19
22
 
20
- class ClamdScanResult < Ddr::Antivirus::ScanResult
21
-
22
- def virus_found
23
- if m = /: ([^\s]+) FOUND$/.match(raw)
24
- m[1]
25
- end
26
- end
23
+ end
27
24
 
28
- def has_virus?
29
- raw =~ / FOUND$/
25
+ #
26
+ # Result of a scan with the ClamdScannerAdapter
27
+ #
28
+ class ClamdScanResult < ScanResult
29
+
30
+ def virus_found
31
+ if m = /: ([^\s]+) FOUND$/.match(raw)
32
+ m[1]
30
33
  end
34
+ end
31
35
 
32
- def error?
33
- raw =~ / ERROR$/
34
- end
36
+ def has_virus?
37
+ raw =~ / FOUND$/
38
+ end
35
39
 
36
- def ok?
37
- raw =~ / OK$/
38
- end
40
+ def error?
41
+ raw =~ / ERROR$/
42
+ end
39
43
 
40
- def to_s
41
- "#{raw} (#{version})"
42
- end
44
+ def ok?
45
+ raw =~ / OK$/
46
+ end
43
47
 
44
- def default_version
45
- `sigtool --version`.strip
46
- end
48
+ def to_s
49
+ "#{raw} (#{version})"
50
+ end
47
51
 
52
+ def default_version
53
+ `sigtool --version`.strip
48
54
  end
49
55
 
50
56
  end
57
+
51
58
  end
52
59
  end
53
60
  end
@@ -1,3 +1,6 @@
1
+ require_relative "scanner_adapter"
2
+ require_relative "scan_result"
3
+
1
4
  module Ddr
2
5
  module Antivirus
3
6
  module Adapters
@@ -7,10 +10,16 @@ module Ddr
7
10
  class NullScannerAdapter < ScannerAdapter
8
11
 
9
12
  def scan(path)
10
- Ddr::Antivirus::ScanResult.new("#{path}: NOT SCANNED - using :null scanner adapter.", path)
13
+ NullScanResult.new("#{path}: NOT SCANNED - using :null scanner adapter.", path)
11
14
  end
12
15
 
13
16
  end
17
+
18
+ #
19
+ # The result of the scan with the NullScannerAdapter.
20
+ #
21
+ class NullScanResult < ScanResult; end
22
+
14
23
  end
15
24
  end
16
25
  end
@@ -0,0 +1,52 @@
1
+ module Ddr
2
+ module Antivirus
3
+ module Adapters
4
+ #
5
+ # Default scan result implementation
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
+ def default_time
19
+ Time.now.utc
20
+ end
21
+
22
+ def default_version
23
+ "ddr-antivirus #{Ddr::Antivirus::VERSION}"
24
+ end
25
+
26
+ # Subclasses may override to provide description of virus found.
27
+ def virus_found; end
28
+
29
+ # Subclasses should override
30
+ def has_virus?
31
+ !virus_found.nil?
32
+ end
33
+
34
+ # Subclasses may override to indicate an error condition (not necessarily an exception).
35
+ def error?
36
+ false
37
+ end
38
+
39
+ def ok?
40
+ !(has_virus? || error?)
41
+ end
42
+
43
+ # Subclasses may override
44
+ def to_s
45
+ "#{raw} (#{version})"
46
+ end
47
+
48
+ end
49
+ end
50
+ end
51
+ end
52
+
@@ -6,10 +6,15 @@ module Ddr
6
6
  #
7
7
  class ScannerAdapter
8
8
 
9
+ # Scan a file path for viruses - subclasses must implement.
10
+ #
11
+ # @param [String] file path to scan
12
+ # @return [Ddr::Antivirus::ScanResult] the result
9
13
  def scan(path)
10
14
  raise NotImplementedError
11
15
  end
12
16
 
17
+ # Return the adapter configuration options
13
18
  def config
14
19
  Ddr::Antivirus.adapter_config
15
20
  end
@@ -1,5 +1,5 @@
1
1
  module Ddr
2
2
  module Antivirus
3
- VERSION = "1.2.1"
3
+ VERSION = "1.3.0"
4
4
  end
5
5
  end
@@ -35,9 +35,10 @@ module Ddr
35
35
  describe "result" do
36
36
  subject { adapter.scan(path) }
37
37
  let(:adapter) { described_class.new }
38
- it "should be a scan result" do
39
- expect(subject).to be_a(Ddr::Antivirus::ScanResult)
38
+ it "should be a ClamavScanResult" do
39
+ expect(subject).to be_a(ClamavScanResult)
40
40
  end
41
+ it_should_behave_like "a scan result"
41
42
  context "when a virus is found" do
42
43
  before { allow(adapter.engine).to receive(:scanfile).with(path) { "Bad boy 35" } }
43
44
  it "the raw result should be the virus description" do
@@ -12,8 +12,9 @@ module Ddr
12
12
  subject { adapter.scan(path) }
13
13
  let(:adapter) { described_class.new }
14
14
  it "should be a scan result" do
15
- expect(subject).to be_a(Ddr::Antivirus::ScanResult)
15
+ expect(subject).to be_a(ClamdScanResult)
16
16
  end
17
+ it_should_behave_like "a scan result"
17
18
  context "when a virus is found" do
18
19
  before { allow(adapter).to receive(:clamdscan).with(path) { "#{path}: Bad-boy-35 FOUND" } }
19
20
  it "should have a virus_found" do
@@ -0,0 +1,24 @@
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
@@ -2,23 +2,25 @@ require 'shared_examples_for_scan_results'
2
2
 
3
3
  module Ddr
4
4
  module Antivirus
5
- RSpec.describe ScanResult do
6
- subject { described_class.new("Raw result", "/tmp/foo") }
5
+ module Adapters
6
+ RSpec.describe ScanResult do
7
+ subject { described_class.new("Raw result", "/tmp/foo") }
7
8
 
8
- it_should_behave_like "a scan result"
9
+ it_should_behave_like "a scan result"
9
10
 
10
- describe "success" do
11
- it_should_behave_like "a successful scan result"
12
- end
11
+ describe "success" do
12
+ it_should_behave_like "a successful scan result"
13
+ end
13
14
 
14
- describe "error" do
15
- before { allow(subject).to receive(:error?) { true } }
16
- it_should_behave_like "an error scan result"
17
- end
15
+ describe "error" do
16
+ before { allow(subject).to receive(:error?) { true } }
17
+ it_should_behave_like "an error scan result"
18
+ end
18
19
 
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"
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
22
24
  end
23
25
  end
24
26
  end
@@ -1,31 +1,34 @@
1
+ require "ddr/antivirus/adapters/scan_result"
2
+
1
3
  module Ddr
2
4
  module Antivirus
3
5
  RSpec.describe Scanner do
4
6
 
5
7
  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 }
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)
9
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 } }
10
17
  it "should raise an execption" do
11
- expect { subject.scan("/tmp/foo") }.to raise_error
18
+ expect { subject.scan(path) }.to raise_error
12
19
  end
13
20
  end
14
21
  describe "when a virus is not found" do
15
- before do
16
- allow_any_instance_of(ScanResult).to receive(:has_virus?) { false }
17
- end
22
+ before { allow_any_instance_of(Ddr::Antivirus::Adapters::ScanResult).to receive(:has_virus?) { false } }
18
23
  it "should return the scan result" do
19
- expect(subject.scan("/tmp/foo")).to be_a(ScanResult)
24
+ expect(subject.scan(path)).to be_a(Ddr::Antivirus::Adapters::ScanResult)
20
25
  end
21
26
  end
22
27
  describe "when an error occurs in the scanner" do
23
- before do
24
- allow_any_instance_of(ScanResult).to receive(:error?) { true }
25
- end
28
+ before { allow_any_instance_of(Ddr::Antivirus::Adapters::ScanResult).to receive(:error?) { true } }
26
29
  it "should log an error" do
27
30
  expect(Ddr::Antivirus.logger).to receive(:error)
28
- subject.scan("/tmp/foo")
31
+ subject.scan(path)
29
32
  end
30
33
  end
31
34
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ddr-antivirus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Chandek-Stark
@@ -101,8 +101,8 @@ files:
101
101
  - lib/ddr/antivirus/adapters/clamav_scanner_adapter.rb
102
102
  - lib/ddr/antivirus/adapters/clamd_scanner_adapter.rb
103
103
  - lib/ddr/antivirus/adapters/null_scanner_adapter.rb
104
+ - lib/ddr/antivirus/adapters/scan_result.rb
104
105
  - lib/ddr/antivirus/adapters/scanner_adapter.rb
105
- - lib/ddr/antivirus/scan_result.rb
106
106
  - lib/ddr/antivirus/scanner.rb
107
107
  - lib/ddr/antivirus/version.rb
108
108
  - spec/fixtures/blue-devil.png
@@ -110,6 +110,7 @@ files:
110
110
  - spec/spec_helper.rb
111
111
  - spec/unit/clamav_scanner_adapter_spec.rb
112
112
  - spec/unit/clamd_scanner_adapter_spec.rb
113
+ - spec/unit/null_scanner_adapter_spec.rb
113
114
  - spec/unit/scan_result_spec.rb
114
115
  - spec/unit/scanner_spec.rb
115
116
  homepage: https://github.com/duke-libraries/ddr-antivirus
@@ -142,5 +143,6 @@ test_files:
142
143
  - spec/spec_helper.rb
143
144
  - spec/unit/clamav_scanner_adapter_spec.rb
144
145
  - spec/unit/clamd_scanner_adapter_spec.rb
146
+ - spec/unit/null_scanner_adapter_spec.rb
145
147
  - spec/unit/scan_result_spec.rb
146
148
  - spec/unit/scanner_spec.rb
@@ -1,50 +0,0 @@
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
- def virus_found; end
27
-
28
- # Subclasses should override
29
- def has_virus?
30
- !virus_found.nil?
31
- end
32
-
33
- # Subclasses may override to indicate an error condition (not necessarily an exception).
34
- def error?
35
- false
36
- end
37
-
38
- def ok?
39
- !(has_virus? || error?)
40
- end
41
-
42
- # Subclasses may override
43
- def to_s
44
- "#{raw} (#{version})"
45
- end
46
-
47
- end
48
- end
49
- end
50
-