clamby 1.4.0 → 1.5.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: d8a7e48c2bd0285d60fe7ece07fd72bca337e33fefb86d5304b6278132047d44
4
- data.tar.gz: d2489bc3655ecf95667fa41f9aa39e104404fb9d0eccbbf5447dd6cd9e78b307
3
+ metadata.gz: 14e5489bd2c961059e2642dfcd7e472a838c449d114ba7ce7849eb4a7d8a2ae9
4
+ data.tar.gz: a0e7743a75f54442325af1773d923eb3ead7342efb6fd147733020c2ad85551b
5
5
  SHA512:
6
- metadata.gz: 1a505ca85b244f599a0270a9e94e46305b1230fb2502eebbffbc441e86e78d7e668ab534fb39a2f086eb14a330c68706bd15104a387aec2e518108e9e4f912e3
7
- data.tar.gz: 2401278d0d3721113268156994ed39eed440619b90f1e25dd42b62db99681eeeaa3aa23c9d5d7c7c59477ccd1875f93192f052a350ea9d83d3836517ec5ff724
6
+ metadata.gz: ec80ea427e309f396664d599e28e742ddbf1913f1f4c5a58e3be43557bd9ad0f85276827e58511d2132ce4c89e6ab577082d0e7dcc471dfea92cf3c08b448e44
7
+ data.tar.gz: '079f33a665afff1f99e6df4e8c6c7be877b5bade43d8d2fc4270976b77de7b84fc2cdeec8f1791c19b8c79b8ac921cd90e6974a448af0db6c96a2bac28601654'
@@ -1,3 +1,9 @@
1
+ # v1.5.0
2
+ - Exceptions are now raised under Clamby module - could be breaking change
3
+ - [szajbus](https://github.com/kobaltz/clamby/commits?author=szajbus) fixed specs! and updated README
4
+ - [broder](https://github.com/kobaltz/clamby/commits?author=broder) added path for config file to address strange clamscan situations
5
+ - [tilsammans](https://github.com/kobaltz/clamby/commits?author=tilsammans) added queit, verbose and Command class
6
+
1
7
  # v1.4.0
2
8
  - [emilong](https://github.com/kobaltz/clamby/commits/master?author=emilong) added `:error_clamscan_client_error => false` option to prevent error from missing running daemon or clamscan.
3
9
 
data/README.md CHANGED
@@ -66,32 +66,51 @@ It's good to note that Clamby will not by default delete files which had a virus
66
66
 
67
67
  # Configuration
68
68
 
69
- Configuration is rather limited right now. You can exclude the check if `clamscan` exists which will save a bunch of time for scanning your files. However, for development purposes, your machine may not have `clamscan` installed and you may wonder why it's not working properly. This is just to give you a reminder to install `clamscan` on your development machine and production machine. You can add the following to a config file, `clamby_setup.rb` to your initializers directory.
69
+ Configuration is rather limited right now. You can exclude the check if `clamscan` exists which will save a bunch of time for scanning your files. However, for development purposes, your machine may not have `clamscan` installed and you may wonder why it's not working properly. This is just to give you a reminder to install `clamscan` on your development machine and production machine. You can add the following to an initializer, for example `config/initializers/clamby.rb`:
70
+
71
+ ```ruby
72
+ Clamby.configure({
73
+ :check => false,
74
+ :daemonize => false,
75
+ :config_file => nil,
76
+ :error_clamscan_missing => true,
77
+ :error_clamscan_client_error => false,
78
+ :error_file_missing => true,
79
+ :error_file_virus => false,
80
+ :fdpass => false,
81
+ :stream => false,
82
+ :output => 'medium' # one of 'off', 'low', 'medium', 'high'
83
+ })
84
+ ```
85
+
86
+ #### Daemonize
87
+
88
+ I highly recommend using the `daemonize` set to `true`. This will allow for clamscan to remain in memory and will not have to load for each virus scan. It will save several seconds per request.
89
+
90
+ To specify a config file for clamdscan to use, you can set `config_file` with the relevant path. See [this page](https://linux.die.net/man/5/clamd.conf) for more information about the config file.
91
+
92
+ #### Error suppression
70
93
 
71
94
  There has been added additional functionality where you can override exceptions. If you set the exceptions below to false, then there will not be a hard exception generated. Instead, it will post to your log that an error had occured. By default each one of these configuration options are set to true. You may want to set these to false in your production environment.
72
95
 
96
+ #### Pass file descriptor permissions to clamd
97
+
73
98
  Setting the `fdpass` configuration option to `true` will pass the `--fdpass` option to clamscan. This might be useful if you are encountering permissions problems between clamscan and files being created by your application. From the clamscan man page:
74
99
 
75
100
  `--fdpass : Pass the file descriptor permissions to clamd. This is useful if clamd is running as a different user as it is faster than streaming the file to clamd. Only available if connected to clamd via local(unix) socket.`
76
101
 
102
+ #### Force streaming files to clamd
103
+
77
104
  Setting the `stream` configuration option will stream the file to the daemon. This may be useful for forcing streaming as a test for local development. Only works when also specifying `daemonize`. From the clamdscan man page:
78
105
 
79
106
  `--stream : Forces file streaming to clamd. This is generally not needed as clamdscan detects automatically if streaming is required. This option only exists for debugging and testing purposes, in all other cases --fdpass is preferred.`
80
107
 
81
- ```ruby
82
- Clamby.configure({
83
- :check => false,
84
- :daemonize => false,
85
- :error_clamscan_missing => false,
86
- :error_file_missing => false,
87
- :error_file_virus => false,
88
- :fdpass => false,
89
- :silence_output => false,
90
- :stream => false
91
- })
92
- ```
108
+ #### Output levels
93
109
 
94
- I highly recommend using the `daemonize` set to true. This will allow for clamscan to remain in memory and will not have to load for each virus scan. It will save several seconds per request.
110
+ - *off*: suppress all output
111
+ - *low*: show errors, but nothing else
112
+ - *medium*: show errors and briefly what happened _(default)_
113
+ - *high*: as verbose as possible
95
114
 
96
115
  # Dependencies
97
116
 
@@ -102,7 +121,7 @@ I highly recommend using the `daemonize` set to true. This will allow for clamsc
102
121
  Note, `clamav-daemon` is optional but recommended. It's needed if you wish to
103
122
  run ClamAV in daemon mode.
104
123
 
105
- ***Apple***
124
+ ***macOS***
106
125
 
107
126
  `brew install clamav`
108
127
 
@@ -1,25 +1,38 @@
1
1
  require "English"
2
+ require "clamby/command"
3
+ require "clamby/error"
2
4
  require "clamby/version"
3
- require "clamby/exception"
5
+
4
6
  module Clamby
5
7
  DEFAULT_CONFIG = {
6
8
  :check => true,
7
9
  :daemonize => false,
10
+ :config_file => nil,
8
11
  :error_clamscan_missing => true,
9
12
  :error_clamscan_client_error => false,
10
13
  :error_file_missing => true,
11
14
  :error_file_virus => false,
12
15
  :fdpass => false,
13
- :silence_output => false,
14
- :stream => false
16
+ :stream => false,
17
+ :output_level => 'medium'
15
18
  }.freeze
16
19
 
17
20
  @config = DEFAULT_CONFIG.dup
18
21
 
19
22
  @valid_config_keys = @config.keys
20
23
 
24
+ class << self
25
+ attr_reader :config
26
+ attr_reader :valid_config_keys
27
+ end
28
+
21
29
  def self.configure(opts = {})
22
- opts.each {|k,v| @config[k.to_sym] = v if @valid_config_keys.include? k.to_sym}
30
+ if opts.delete(:silence_output)
31
+ warn ':silence_output config is deprecated. Use :output_level => "off" instead.'
32
+ opts[:output_level] = 'off'
33
+ end
34
+
35
+ opts.each {|k,v| config[k.to_sym] = v if valid_config_keys.include? k.to_sym}
23
36
  end
24
37
 
25
38
  def self.safe?(path)
@@ -28,79 +41,26 @@ module Clamby
28
41
  ! value
29
42
  end
30
43
 
31
- # Assemble the system command to be called, including optional flags
32
- # @param [String] path path to the file being scanned
33
- # @return [String] command to be executed
34
- def self.system_command(path)
35
- command = [].tap do |cmd|
36
- cmd << clamd_executable_name
37
- cmd << '--fdpass' if @config[:fdpass]
38
- cmd << '--stream' if @config[:stream] && @config[:daemonize]
39
- cmd << path
40
- cmd << '--no-summary'
41
- cmd << { out: File::NULL } if @config[:silence_output]
42
- end
43
- command
44
- end
45
-
46
44
  def self.virus?(path)
47
45
  return nil unless scanner_exists?
48
- return nil unless file_exists?(path)
49
- system(*system_command(path))
50
-
51
- case $CHILD_STATUS.exitstatus
52
- when 0
53
- return false
54
- when 2
55
- # clamdscan returns 2 whenever error other than a detection happens
56
- if @config[:error_clamscan_client_error] && @config[:daemonize]
57
- raise Exceptions::ClamscanClientError.new("Clamscan client error")
58
- end
59
-
60
- # returns true to maintain legacy behavior
61
- return true
62
- else
63
- return true unless @config[:error_file_virus]
64
-
65
- raise Exceptions::VirusDetected.new("VIRUS DETECTED on #{Time.now}: #{path}")
66
- end
46
+ Command.scan path
67
47
  end
68
48
 
69
49
  def self.scanner_exists?
70
- return true unless @config[:check]
71
- scanner = system(clamd_executable_name, '-V', @config[:silence_output] ? { out: File::NULL } : {})
50
+ return true unless config[:check]
51
+ scanner = Command.clamscan_version
72
52
 
73
53
  return true if scanner
74
- return false unless @config[:error_clamscan_missing]
75
-
76
- raise Exceptions::ClamscanMissing.new("#{clamd_executable_name} application not found. Check your installation and path.")
77
- end
78
-
79
- def self.file_exists?(path)
80
- return false if path.nil?
81
- return true if File.file?(path)
54
+ return false unless config[:error_clamscan_missing]
82
55
 
83
- if @config[:error_file_missing]
84
- raise Exceptions::FileNotFound.new("File not found: #{path}")
85
- else
86
- puts "FILE NOT FOUND on #{Time.now}: #{path}"
87
- return false
88
- end
56
+ raise Clamby::ClamscanMissing.new("#{Command.scan_executable} not found. Check your installation and path.")
89
57
  end
90
58
 
91
59
  def self.update
92
- system("freshclam", @config[:silence_output] ? { out: File::NULL } : {})
93
- end
94
-
95
- def self.config
96
- @config
97
- end
98
-
99
- def self.clamd_executable_name(daemonize: false)
100
- daemonize? ? "clamdscan" : "clamscan"
60
+ Command.freshclam
101
61
  end
102
62
 
103
63
  def self.daemonize?
104
- !! @config[:daemonize]
64
+ !! config[:daemonize]
105
65
  end
106
66
  end
@@ -0,0 +1,102 @@
1
+ module Clamby
2
+ # Interface with the system. Builds and runs the command.
3
+ class Command
4
+ EXECUTABLES = %w(clamscan clamdscan freshclam)
5
+
6
+ # Array containing the complete command line.
7
+ attr_accessor :command
8
+
9
+ # Returns the appropriate scan executable, based on clamd being used.
10
+ def self.scan_executable
11
+ return 'clamdscan' if Clamby.config[:daemonize]
12
+ return 'clamscan'
13
+ end
14
+
15
+ # Perform a ClamAV scan on the given path.
16
+ def self.scan(path)
17
+ return nil unless file_exists?(path)
18
+
19
+ args = [path, '--no-summary']
20
+
21
+ if Clamby.config[:daemonize]
22
+ args << '--fdpass' if Clamby.config[:fdpass]
23
+ args << '--stream' if Clamby.config[:stream]
24
+ args << "--config-file=#{Clamby.config[:config_file]}" if Clamby.config[:config_file] && Clamby.config[:daemonize]
25
+ end
26
+
27
+ new.run scan_executable, *args
28
+
29
+ case $CHILD_STATUS.exitstatus
30
+ when 0
31
+ return false
32
+ when 2
33
+ # clamdscan returns 2 whenever error other than a detection happens
34
+ if Clamby.config[:error_clamscan_client_error] && Clamby.config[:daemonize]
35
+ raise Clamby::ClamscanClientError.new("Clamscan client error")
36
+ end
37
+
38
+ # returns true to maintain legacy behavior
39
+ return true
40
+ else
41
+ return true unless Clamby.config[:error_file_virus]
42
+
43
+ raise Clamby::VirusDetected.new("VIRUS DETECTED on #{Time.now}: #{path}")
44
+ end
45
+ end
46
+
47
+ # Update the virus definitions.
48
+ def self.freshclam
49
+ new.run 'freshclam'
50
+ end
51
+
52
+ # Show the ClamAV version. Also acts as a quick check if ClamAV functions.
53
+ def self.clamscan_version
54
+ new.run 'clamscan', '--version'
55
+ end
56
+
57
+ # Run the given commands via a system call.
58
+ # The executable must be one of the permitted ClamAV executables.
59
+ # The arguments will be combined with default arguments if needed.
60
+ # The arguments are sorted alphabetically before being passed to the system.
61
+ #
62
+ # Examples:
63
+ # run('clamscan', file, '--verbose')
64
+ # run('clamscan', '-V')
65
+ def run(executable, *args)
66
+ raise "`#{executable}` is not permitted" unless EXECUTABLES.include?(executable)
67
+ self.command = args | default_args
68
+ self.command = command.sort.unshift(executable)
69
+
70
+ system(*self.command, system_options)
71
+ end
72
+
73
+ private
74
+
75
+ def default_args
76
+ args = []
77
+ args << '--quiet' if Clamby.config[:output_level] == 'low'
78
+ args << '--verbose' if Clamby.config[:output_level] == 'high'
79
+ args
80
+ end
81
+
82
+ # This applies to the `system` call itself; does not end up in the command.
83
+ def system_options
84
+ if Clamby.config[:output_level] == 'off'
85
+ { out: File::NULL }
86
+ else
87
+ {}
88
+ end
89
+ end
90
+
91
+ def self.file_exists?(path)
92
+ return true if File.file?(path)
93
+
94
+ if Clamby.config[:error_file_missing]
95
+ raise Clamby::FileNotFound.new("File not found: #{path}")
96
+ else
97
+ puts "FILE NOT FOUND on #{Time.now}: #{path}"
98
+ return false
99
+ end
100
+ end
101
+ end
102
+ end
@@ -1,5 +1,6 @@
1
- module Exceptions
1
+ module Clamby
2
2
  class Error < StandardError; end
3
+
3
4
  class VirusDetected < Error; end
4
5
  class ClamscanMissing < Error; end
5
6
  class ClamscanClientError < Error; end
@@ -1,3 +1,3 @@
1
1
  module Clamby
2
- VERSION = "1.4.0"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+ require 'support/shared_context'
3
+
4
+ describe Clamby::Command do
5
+ before { Clamby.configure(Clamby::DEFAULT_CONFIG.dup) }
6
+
7
+ describe 'ClamAV version' do
8
+ it 'returns true' do
9
+ command = described_class.clamscan_version
10
+ expect(command).to be true
11
+ end
12
+ end
13
+
14
+ describe 'scan' do
15
+ include_context 'paths'
16
+
17
+ let(:runner){ instance_double(described_class) }
18
+
19
+ describe 'exceptions' do
20
+ it "can be configured to raise exception when file is missing" do
21
+ Clamby.configure({:error_file_missing => true})
22
+
23
+ expect do
24
+ described_class.scan(bad_path)
25
+ end.to raise_exception(Clamby::FileNotFound)
26
+ end
27
+ it 'can be configured to return nil when file is missing' do
28
+ Clamby.configure({:error_file_missing => false})
29
+ command = described_class.scan(bad_path)
30
+
31
+ expect(command).to be(nil)
32
+ end
33
+ end
34
+
35
+ describe 'passing file descriptor' do
36
+ it 'does not include fdpass in the command by default' do
37
+ Clamby.configure(fdpass: false)
38
+ expect(runner).to receive(:run).with('clamscan', good_path, '--no-summary')
39
+ allow(described_class).to receive(:new).and_return(runner)
40
+
41
+ described_class.scan(good_path)
42
+ end
43
+
44
+ it 'omits the fdpass option when invoking clamscan if it is set, but daemonize isn\'t' do
45
+ Clamby.configure(fdpass: true)
46
+ expect(runner).to receive(:run).with('clamscan', good_path, '--no-summary')
47
+ allow(described_class).to receive(:new).and_return(runner)
48
+
49
+ described_class.scan(good_path)
50
+ end
51
+
52
+ it 'passes the fdpass option when invoking clamscan if it is set with daemonize' do
53
+ Clamby.configure(fdpass: true, daemonize: true)
54
+ expect(runner).to receive(:run).with('clamdscan', good_path, '--no-summary', '--fdpass')
55
+ allow(described_class).to receive(:new).and_return(runner)
56
+
57
+ described_class.scan(good_path)
58
+ end
59
+ end
60
+
61
+ describe 'streaming files to clamd' do
62
+ it 'does not include stream in the command by default' do
63
+ Clamby.configure(stream: false)
64
+ expect(runner).to receive(:run).with('clamscan', good_path, '--no-summary')
65
+ allow(described_class).to receive(:new).and_return(runner)
66
+
67
+ described_class.scan(good_path)
68
+ end
69
+
70
+ it 'omits the stream option when invoking clamscan if it is set, but daemonize isn\'t' do
71
+ Clamby.configure(stream: true)
72
+ expect(runner).to receive(:run).with('clamscan', good_path, '--no-summary')
73
+ allow(described_class).to receive(:new).and_return(runner)
74
+
75
+ described_class.scan(good_path)
76
+ end
77
+
78
+ it 'passes the stream option when invoking clamscan if it is set with daemonize' do
79
+ Clamby.configure(stream: true, daemonize: true)
80
+ expect(runner).to receive(:run).with('clamdscan', good_path, '--no-summary', '--stream')
81
+ allow(described_class).to receive(:new).and_return(runner)
82
+
83
+ described_class.scan(good_path)
84
+ end
85
+ end
86
+
87
+ describe 'specifying config-file' do
88
+ it 'does not include the parameter in the clamscan command by default' do
89
+ Clamby.configure(daemonize: false, stream: false, fdpass: false)
90
+ expect(runner).to receive(:run).with('clamscan', good_path, '--no-summary')
91
+ allow(described_class).to receive(:new).and_return(runner)
92
+
93
+ described_class.scan(good_path)
94
+ end
95
+ it 'does not include the parameter in the clamdscan command by default' do
96
+ Clamby.configure(daemonize: true, stream: false, fdpass: false)
97
+ expect(runner).to receive(:run).with('clamdscan', good_path, '--no-summary')
98
+ allow(described_class).to receive(:new).and_return(runner)
99
+
100
+ described_class.scan(good_path)
101
+ end
102
+ it 'omits the parameter when invoking clamscan if it is set' do
103
+ Clamby.configure(daemonize: false, stream: false, fdpass: false, config_file: 'clamd.conf')
104
+ expect(runner).to receive(:run).with('clamscan', good_path, '--no-summary')
105
+ allow(described_class).to receive(:new).and_return(runner)
106
+
107
+ described_class.scan(good_path)
108
+ end
109
+ it 'passes the parameter when invoking clamdscan if it is set' do
110
+ Clamby.configure(daemonize: true, stream: false, fdpass: false, config_file: 'clamd.conf')
111
+ expect(runner).to receive(:run).with('clamdscan', good_path, '--no-summary', '--config-file=clamd.conf')
112
+ allow(described_class).to receive(:new).and_return(runner)
113
+
114
+ described_class.scan(good_path)
115
+ end
116
+ end
117
+ end
118
+ end
@@ -1,26 +1,15 @@
1
1
  require 'spec_helper'
2
-
3
- good_path = 'README.md'
4
- bad_path = 'BAD_FILE.md'
2
+ require 'support/shared_context'
5
3
 
6
4
  describe Clamby do
7
- before { Clamby.configure(Clamby::DEFAULT_CONFIG.dup) }
5
+ include_context 'paths'
8
6
 
9
- it "should find files." do
10
- expect(Clamby.file_exists?(good_path)).to be true
11
- end
7
+ before { Clamby.configure(Clamby::DEFAULT_CONFIG.dup) }
12
8
 
13
9
  it "should find clamscan" do
14
10
  expect(Clamby.scanner_exists?).to be true
15
11
  end
16
12
 
17
- it "should not find files." do
18
- Clamby.configure({:error_file_missing => true})
19
- expect{Clamby.file_exists?(bad_path)}.to raise_exception(Exceptions::FileNotFound)
20
- Clamby.configure({:error_file_missing => false})
21
- expect(Clamby.file_exists?(bad_path)).to be false
22
- end
23
-
24
13
  it "should scan file as safe" do
25
14
  expect(Clamby.safe?(good_path)).to be true
26
15
  expect(Clamby.virus?(good_path)).to be false
@@ -33,21 +22,20 @@ describe Clamby do
33
22
  end
34
23
 
35
24
  it "should scan file as dangerous" do
36
- `which wget`
37
-
38
- if $?.success?
39
- `wget http://www.eicar.org/download/eicar.com`
40
- else
41
- `curl http://www.eicar.org/download/eicar.com > eicar.com`
25
+ begin
26
+ file = download('https://secure.eicar.org/eicar.com')
27
+ rescue SocketError => error
28
+ pending("Skipped because reasons: #{error}")
42
29
  end
43
- `chmod 644 eicar.com`
30
+
31
+ dangerous = file.path
44
32
  Clamby.configure({:error_file_virus => true})
45
- expect{Clamby.safe?('eicar.com')}.to raise_exception(Exceptions::VirusDetected)
46
- expect{Clamby.virus?('eicar.com')}.to raise_exception(Exceptions::VirusDetected)
33
+ expect{Clamby.safe?(dangerous)}.to raise_exception(Clamby::VirusDetected)
34
+ expect{Clamby.virus?(dangerous)}.to raise_exception(Clamby::VirusDetected)
47
35
  Clamby.configure({:error_file_virus => false})
48
- expect(Clamby.safe?('eicar.com')).to be false
49
- expect(Clamby.virus?('eicar.com')).to be true
50
- File.delete('eicar.com')
36
+ expect(Clamby.safe?(dangerous)).to be false
37
+ expect(Clamby.virus?(dangerous)).to be true
38
+ File.delete(dangerous)
51
39
  end
52
40
 
53
41
  # From the clamscan man page:
@@ -62,14 +50,6 @@ describe Clamby do
62
50
  Clamby.configure(fdpass: true)
63
51
  expect(Clamby.config[:fdpass]).to eq true
64
52
  end
65
- it 'does not include fdpass in the command by default' do
66
- Clamby.configure(fdpass: false)
67
- expect(Clamby.system_command(good_path)).to eq ["clamscan", good_path, "--no-summary"]
68
- end
69
- it 'passes the fdpass option when invoking clamscan if it is set' do
70
- Clamby.configure(fdpass: true)
71
- expect(Clamby.system_command(good_path)).to eq ["clamscan", "--fdpass", good_path, "--no-summary"]
72
- end
73
53
  end
74
54
 
75
55
  # From the clamscan man page:
@@ -84,18 +64,6 @@ describe Clamby do
84
64
  Clamby.configure(stream: true)
85
65
  expect(Clamby.config[:stream]).to eq true
86
66
  end
87
- it 'does not include stream in the command by default' do
88
- Clamby.configure(stream: false)
89
- expect(Clamby.system_command(good_path)).to eq ["clamscan", good_path, "--no-summary"]
90
- end
91
- it 'omits the stream option when invoking clamscan if it is set, but daemonize isn\'t' do
92
- Clamby.configure(stream: true)
93
- expect(Clamby.system_command(good_path)).to eq ["clamscan", good_path, "--no-summary"]
94
- end
95
- it 'passes the stream option when invoking clamscan if it is set with daemonize' do
96
- Clamby.configure(stream: true, daemonize: true)
97
- expect(Clamby.system_command(good_path)).to eq ["clamdscan", "--stream", good_path, "--no-summary"]
98
- end
99
67
  end
100
68
 
101
69
  context 'error_clamscan_client_error option' do
@@ -131,7 +99,7 @@ describe Clamby do
131
99
 
132
100
  it 'virus? raises when the daemonized client exits with status 2' do
133
101
  Clamby.configure(daemonize: true)
134
- expect { Clamby.virus?(good_path) }.to raise_error(Exceptions::ClamscanClientError)
102
+ expect { Clamby.virus?(good_path) }.to raise_error(Clamby::ClamscanClientError)
135
103
  end
136
104
  it 'returns true when the client exits with status 2' do
137
105
  Clamby.configure(daemonize: false)
@@ -0,0 +1,2 @@
1
+ This is a virus-free file.
2
+ It is used by automated tests.
@@ -1,8 +1,30 @@
1
1
  require 'bundler/setup'
2
2
  Bundler.setup
3
3
 
4
+ require 'open-uri'
5
+ require 'tempfile'
6
+
4
7
  require 'clamby' # and any other gems you need
5
8
 
6
9
  RSpec.configure do |config|
7
- # some (optional) config here
8
- end
10
+ config.mock_with :rspec do |mocks|
11
+ # so that Command can keep doing what it always does.
12
+ mocks.verify_partial_doubles = true
13
+ end
14
+
15
+ def download(url)
16
+ file = open(url)
17
+ file.is_a?(StringIO) ? to_tempfile(file) : file
18
+ end
19
+
20
+ # OpenURI returns either Tempfile or StringIO depending of the size of
21
+ # the response. We want to unify this and always return Tempfile.
22
+ def to_tempfile(io)
23
+ tempfile = Tempfile.new('tmp')
24
+ tempfile.binmode
25
+ ::OpenURI::Meta.init(tempfile, io)
26
+ tempfile << io.string
27
+ tempfile.rewind
28
+ tempfile
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ RSpec.shared_context 'paths' do
2
+ let(:good_path) { File.expand_path('../../fixtures/safe.txt', __FILE__) }
3
+ let(:bad_path) { File.expand_path("not-here/#{rand 10e6}.txt", __FILE__) }
4
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clamby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - kobaltz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-24 00:00:00.000000000 Z
11
+ date: 2018-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -73,11 +73,15 @@ files:
73
73
  - clamby.gemspec
74
74
  - clamby_logo.png
75
75
  - lib/clamby.rb
76
- - lib/clamby/exception.rb
76
+ - lib/clamby/command.rb
77
+ - lib/clamby/error.rb
77
78
  - lib/clamby/version.rb
78
79
  - spec/.DS_Store
80
+ - spec/clamby/command_spec.rb
79
81
  - spec/clamby_spec.rb
82
+ - spec/fixtures/safe.txt
80
83
  - spec/spec_helper.rb
84
+ - spec/support/shared_context.rb
81
85
  homepage: ''
82
86
  licenses:
83
87
  - MIT
@@ -98,11 +102,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
102
  version: '0'
99
103
  requirements: []
100
104
  rubyforge_project:
101
- rubygems_version: 2.7.6
105
+ rubygems_version: 2.7.7
102
106
  signing_key:
103
107
  specification_version: 4
104
108
  summary: Scan file uploads with ClamAV
105
109
  test_files:
106
110
  - spec/.DS_Store
111
+ - spec/clamby/command_spec.rb
107
112
  - spec/clamby_spec.rb
113
+ - spec/fixtures/safe.txt
108
114
  - spec/spec_helper.rb
115
+ - spec/support/shared_context.rb