s3-antivirus 0.1.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 +7 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +6 -0
- data/Guardfile +19 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/Rakefile +14 -0
- data/exe/s3-antivirus +14 -0
- data/lib/s3-antivirus.rb +1 -0
- data/lib/s3_antivirus/autoloader.rb +22 -0
- data/lib/s3_antivirus/aws_services.rb +18 -0
- data/lib/s3_antivirus/cli.rb +29 -0
- data/lib/s3_antivirus/command.rb +82 -0
- data/lib/s3_antivirus/completer/script.rb +6 -0
- data/lib/s3_antivirus/completer/script.sh +10 -0
- data/lib/s3_antivirus/completer.rb +159 -0
- data/lib/s3_antivirus/conf.rb +11 -0
- data/lib/s3_antivirus/config.rb +29 -0
- data/lib/s3_antivirus/help/completion.md +20 -0
- data/lib/s3_antivirus/help/completion_script.md +3 -0
- data/lib/s3_antivirus/help/scan.md +24 -0
- data/lib/s3_antivirus/help.rb +9 -0
- data/lib/s3_antivirus/logger.rb +7 -0
- data/lib/s3_antivirus/notifier.rb +35 -0
- data/lib/s3_antivirus/s3_record.rb +39 -0
- data/lib/s3_antivirus/scan.rb +142 -0
- data/lib/s3_antivirus/tagger.rb +28 -0
- data/lib/s3_antivirus/tee.rb +32 -0
- data/lib/s3_antivirus/version.rb +3 -0
- data/lib/s3_antivirus.rb +13 -0
- data/s3-antivirus.gemspec +49 -0
- data/spec/fixtures/home/.s3-antivirus.conf +8 -0
- data/spec/fixtures/sqs-event.json +38 -0
- data/spec/lib/cli_spec.rb +8 -0
- data/spec/lib/scan_spec.rb +36 -0
- data/spec/spec_helper.rb +32 -0
- metadata +284 -0
@@ -0,0 +1,142 @@
|
|
1
|
+
require "aws-sdk-sqs"
|
2
|
+
require "json"
|
3
|
+
require "securerandom"
|
4
|
+
require "syslog/logger"
|
5
|
+
require "uri"
|
6
|
+
require "yaml"
|
7
|
+
|
8
|
+
module S3Antivirus
|
9
|
+
class Scan
|
10
|
+
extend Memoist
|
11
|
+
include AwsServices
|
12
|
+
include Logger
|
13
|
+
include Conf
|
14
|
+
|
15
|
+
def initialize(options={})
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
logger.info "Polling SQS queue for S3 antivirus findings. Started #{Time.now}..."
|
21
|
+
return if @options[:noop]
|
22
|
+
|
23
|
+
poller = Aws::SQS::QueuePoller.new(conf['queue'])
|
24
|
+
poller.poll do |msg|
|
25
|
+
begin
|
26
|
+
body = JSON.parse(msg.body)
|
27
|
+
|
28
|
+
logger.debug "body #{body}"
|
29
|
+
if body.key?('Records')
|
30
|
+
body['Records'].each do |record|
|
31
|
+
# Instance variables change on each iteration
|
32
|
+
@s3_record = S3Record.new(record)
|
33
|
+
@notifier = Notifier.new(@s3_record)
|
34
|
+
@tagger = Tagger.new(@s3_record)
|
35
|
+
|
36
|
+
logger.info("Checking #{@s3_record.human_key}")
|
37
|
+
within_size_limit = check_file_size
|
38
|
+
next unless within_size_limit # continue to next file because oversized
|
39
|
+
filename = "/tmp/#{SecureRandom.uuid}"
|
40
|
+
success = download_file(filename)
|
41
|
+
next unless success # continue to next file because unable to download
|
42
|
+
scan_file(filename)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
rescue Exception => e
|
46
|
+
logger.error "message failed: #{e.inspect} #{msg.inspect}"
|
47
|
+
raise e
|
48
|
+
end
|
49
|
+
# Sometimes stdout doesnt get shown but the message is processed file.
|
50
|
+
# Know this because the SNS message gets sent.
|
51
|
+
# Even this $stdout.flush doesn't seem to be enough.
|
52
|
+
$stdout.flush
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def scan_file(filename)
|
58
|
+
logger.info "Scanning #{human_key}..."
|
59
|
+
sh("clamdscan #{filename}")
|
60
|
+
exitstatus = $?.exitstatus
|
61
|
+
if exitstatus == 0 # No virus found.
|
62
|
+
clean_file_found
|
63
|
+
elsif exitstatus == 1 # Virus(es) found.
|
64
|
+
virus_found
|
65
|
+
else # An error occured.
|
66
|
+
raise "#{human_key} could not be scanned, clamdscan exit status was #{exitstatus}, retry"
|
67
|
+
end
|
68
|
+
ensure
|
69
|
+
system("rm #{filename}")
|
70
|
+
end
|
71
|
+
|
72
|
+
def clean_file_found
|
73
|
+
if conf['tag_files']
|
74
|
+
logger.info "#{human_key} is clean (tagging)"
|
75
|
+
@tagger.tag("clean");
|
76
|
+
else
|
77
|
+
logger.info "#{human_key} is clean"
|
78
|
+
end
|
79
|
+
if conf['report_clean']
|
80
|
+
@notifier.notify(status: "clean", action: "no");
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def virus_found
|
85
|
+
if conf['delete']
|
86
|
+
logger.info "#{human_key} is infected (deleting)"
|
87
|
+
s3.delete_object(
|
88
|
+
bucket: @s3_record.bucket,
|
89
|
+
key: @s3_record.key,
|
90
|
+
)
|
91
|
+
@notifier.notify(status: "infected", action: "delete");
|
92
|
+
elsif conf['tag_files']
|
93
|
+
logger.info "#{human_key} is infected (tagging)"
|
94
|
+
@tagger.tag("infected");
|
95
|
+
@notifier.notify(status: "infected", action: "tag");
|
96
|
+
else
|
97
|
+
logger.info "#{human_key} is infected"
|
98
|
+
@notifier.notify(status: "infected", action: "no");
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def human_key
|
103
|
+
@s3_record.human_key
|
104
|
+
end
|
105
|
+
|
106
|
+
def download_file(filename)
|
107
|
+
logger.info "Downloading #{@s3_record.human_key} to #{filename}..."
|
108
|
+
params = {
|
109
|
+
response_target: filename,
|
110
|
+
bucket: @s3_record.bucket,
|
111
|
+
key: @s3_record.key,
|
112
|
+
}
|
113
|
+
params[:version_id] = @s3_record.version if @s3_record.version
|
114
|
+
|
115
|
+
begin
|
116
|
+
s3.get_object(params)
|
117
|
+
rescue Aws::S3::Errors::NoSuchKey
|
118
|
+
logger.info "#{@s3_record.human_key} no longer exist, skipping."
|
119
|
+
return false
|
120
|
+
end
|
121
|
+
true # successful download
|
122
|
+
end
|
123
|
+
|
124
|
+
def check_file_size
|
125
|
+
within_size_limit = true
|
126
|
+
if @s3_record.oversized?
|
127
|
+
logger.info "#{@s3_record.human_key} is too large. Bigger than half of the EBS volume, skipping."
|
128
|
+
if conf['tag_files']
|
129
|
+
@tagger.tag("oversized")
|
130
|
+
end
|
131
|
+
@notifier.notify(status: "oversized", action: "no")
|
132
|
+
within_size_limit = false
|
133
|
+
end
|
134
|
+
within_size_limit
|
135
|
+
end
|
136
|
+
|
137
|
+
def sh(command)
|
138
|
+
logger.info("=> #{command}")
|
139
|
+
system(command)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module S3Antivirus
|
2
|
+
class Tagger
|
3
|
+
include AwsServices
|
4
|
+
include Conf
|
5
|
+
|
6
|
+
def initialize(s3_record)
|
7
|
+
@s3_record = s3_record
|
8
|
+
@bucket, @key, @version = s3_record.bucket, s3_record.key, s3_record.version
|
9
|
+
@tag_key = conf['tag_key']
|
10
|
+
end
|
11
|
+
|
12
|
+
# Different tag values:
|
13
|
+
#
|
14
|
+
# clean
|
15
|
+
# inflected
|
16
|
+
# oversized
|
17
|
+
#
|
18
|
+
def tag(value)
|
19
|
+
params = {
|
20
|
+
bucket: @bucket,
|
21
|
+
key: @key,
|
22
|
+
tagging: {tag_set: [{key: @tag_key, value: value}]}
|
23
|
+
}
|
24
|
+
params[:version_id] = @version if @version
|
25
|
+
s3.put_object_tagging(params)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "syslog/logger"
|
2
|
+
|
3
|
+
module S3Antivirus
|
4
|
+
class Tee
|
5
|
+
extend Memoist
|
6
|
+
|
7
|
+
def initialize(path, options={})
|
8
|
+
@path, @options = path, options
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(name, message, &block)
|
12
|
+
if logger.respond_to?(name)
|
13
|
+
# Interesting note about level mapping: http://bit.ly/2PP5Y6Z
|
14
|
+
# Messages from Ruby applications are not considered as critical as messages
|
15
|
+
# from other system daemons using syslog(3), so most messages are reduced by one level.
|
16
|
+
#
|
17
|
+
# Will mimic behavior for puts stdout.
|
18
|
+
# Interestingly, the default logger.level is ::Logger::DEBUG which is 0.
|
19
|
+
# So can't check against that, so will check against the method name.
|
20
|
+
puts message unless name == :debug
|
21
|
+
logger.send(name, message, &block)
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def logger
|
28
|
+
Syslog::Logger.new(@path)
|
29
|
+
end
|
30
|
+
memoize :logger
|
31
|
+
end
|
32
|
+
end
|
data/lib/s3_antivirus.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
$stdout.sync = true unless ENV["S3_ANTIVIRUS_STDOUT_SYNC"] == "0"
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path("../", __FILE__))
|
4
|
+
require "memoist"
|
5
|
+
require "rainbow/ext/string"
|
6
|
+
require "s3_antivirus/version"
|
7
|
+
|
8
|
+
require "s3_antivirus/autoloader"
|
9
|
+
S3Antivirus::Autoloader.setup
|
10
|
+
|
11
|
+
module S3Antivirus
|
12
|
+
class Error < StandardError; end
|
13
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "s3_antivirus/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "s3-antivirus"
|
8
|
+
spec.version = S3Antivirus::VERSION
|
9
|
+
spec.authors = ["Tung Nguyen"]
|
10
|
+
spec.email = ["tongueroo@gmail.com"]
|
11
|
+
spec.summary = "Detects if files uploaded to s3 contain a virus with ClamAV and auto-deletes or tags them"
|
12
|
+
spec.homepage = "https://github.com/tongueroo/s3-antivirus"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.bindir = "exe"
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |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"
|
22
|
+
spec.add_dependency "aws-sdk-s3"
|
23
|
+
spec.add_dependency "aws-sdk-sns"
|
24
|
+
spec.add_dependency "aws-sdk-sqs"
|
25
|
+
spec.add_dependency "memoist"
|
26
|
+
spec.add_dependency "rainbow"
|
27
|
+
spec.add_dependency "recursive-open-struct"
|
28
|
+
spec.add_dependency "thor"
|
29
|
+
spec.add_dependency "zeitwerk"
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler"
|
32
|
+
spec.add_development_dependency "byebug"
|
33
|
+
spec.add_development_dependency "cli_markdown"
|
34
|
+
spec.add_development_dependency "rake"
|
35
|
+
spec.add_development_dependency "rspec"
|
36
|
+
|
37
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
38
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
39
|
+
if spec.respond_to?(:metadata)
|
40
|
+
# spec.metadata["allowed_push_host"] = ""
|
41
|
+
|
42
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
43
|
+
|
44
|
+
# spec.metadata["source_code_uri"] = ""
|
45
|
+
# spec.metadata["changelog_uri"] = ""
|
46
|
+
else
|
47
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
delete: true
|
2
|
+
report_clean: true
|
3
|
+
tag_files: true
|
4
|
+
tag_key: clamav-status
|
5
|
+
region: us-west-2
|
6
|
+
queue: https://sqs.us-west-2.amazonaws.com/112233445566/s3-ScanQueue-1BRQO2VOPIUM8
|
7
|
+
topic: arn:aws:sns:us-west-2:112233445566:s3-FindingsTopic-J1E10FB4G914
|
8
|
+
volume_size: 8
|
@@ -0,0 +1,38 @@
|
|
1
|
+
{
|
2
|
+
"Records": [
|
3
|
+
{
|
4
|
+
"eventVersion": "2.1",
|
5
|
+
"eventSource": "aws:s3",
|
6
|
+
"awsRegion": "us-west-2",
|
7
|
+
"eventTime": "2019-12-14T22:56:24.066Z",
|
8
|
+
"eventName": "ObjectCreated:Put",
|
9
|
+
"userIdentity": {
|
10
|
+
"principalId": "AWS:AIDAJTCD6O457QEXAMPLE"
|
11
|
+
},
|
12
|
+
"requestParameters": {
|
13
|
+
"sourceIPAddress": "52.33.148.151"
|
14
|
+
},
|
15
|
+
"responseElements": {
|
16
|
+
"x-amz-request-id": "C6044CD6DEXAMPLE",
|
17
|
+
"x-amz-id-2": "V1wa7UVBCDXAFHPwoS6+I02H4idFtO4A5omkL2AeCfTsbz8/JWMVYgGzdE5+uhe1kWYYAEXAMPLE"
|
18
|
+
},
|
19
|
+
"s3": {
|
20
|
+
"s3SchemaVersion": "1.0",
|
21
|
+
"configurationId": "s3-antivirus",
|
22
|
+
"bucket": {
|
23
|
+
"name": "fake-bucket",
|
24
|
+
"ownerIdentity": {
|
25
|
+
"principalId": "AYC6O1EXAMPLE"
|
26
|
+
},
|
27
|
+
"arn": "arn:aws:s3:::fake-bucket"
|
28
|
+
},
|
29
|
+
"object": {
|
30
|
+
"key": "a.txt",
|
31
|
+
"size": 2,
|
32
|
+
"eTag": "60b725f10c9c85c70d97880dfEXAMPLE",
|
33
|
+
"sequencer": "005DF568980EXAMPLE"
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
]
|
38
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "aws-sdk-sqs"
|
2
|
+
require "recursive-open-struct"
|
3
|
+
require "ostruct"
|
4
|
+
require "json"
|
5
|
+
class Aws::SQS::QueuePoller
|
6
|
+
@@msg = nil
|
7
|
+
def self.msg=(val)
|
8
|
+
@@msg = val
|
9
|
+
end
|
10
|
+
|
11
|
+
def poll
|
12
|
+
yield(@@msg)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe S3Antivirus::Scan do
|
17
|
+
before(:each) do
|
18
|
+
Aws::SQS::QueuePoller.msg = RecursiveOpenStruct.new(body: body)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Pretty causal test. Mocked out most of the methods.
|
22
|
+
let(:null) { double(:null).as_null_object }
|
23
|
+
let(:scan) do
|
24
|
+
scan = S3Antivirus::Scan.new
|
25
|
+
allow(scan).to receive(:download_file).and_return(true)
|
26
|
+
allow(scan).to receive(:scan_file)
|
27
|
+
scan
|
28
|
+
end
|
29
|
+
let(:body) { IO.read("spec/fixtures/sqs-event.json") }
|
30
|
+
|
31
|
+
describe "Scan" do
|
32
|
+
it "run" do
|
33
|
+
scan.run
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
ENV["S3_ANTIVIRUS_TEST"] = "1"
|
2
|
+
# Ensures aws api never called. Fixture home folder does not contain ~/.aws/credentials
|
3
|
+
ENV['HOME'] = File.join(Dir.pwd,'spec/fixtures/home')
|
4
|
+
ENV['AWS_REGION'] = "us-west-2"
|
5
|
+
|
6
|
+
# CodeClimate test coverage: https://docs.codeclimate.com/docs/configuring-test-coverage
|
7
|
+
# require 'simplecov'
|
8
|
+
# SimpleCov.start
|
9
|
+
|
10
|
+
require "pp"
|
11
|
+
require "byebug"
|
12
|
+
root = File.expand_path("../", File.dirname(__FILE__))
|
13
|
+
require "#{root}/lib/s3-antivirus"
|
14
|
+
|
15
|
+
module Helper
|
16
|
+
def execute(cmd)
|
17
|
+
puts "Running: #{cmd}" if show_command?
|
18
|
+
out = `#{cmd}`
|
19
|
+
puts out if show_command?
|
20
|
+
out
|
21
|
+
end
|
22
|
+
|
23
|
+
# Added SHOW_COMMAND because DEBUG is also used by other libraries like
|
24
|
+
# bundler and it shows its internal debugging logging also.
|
25
|
+
def show_command?
|
26
|
+
ENV['DEBUG'] || ENV['SHOW_COMMAND']
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
RSpec.configure do |c|
|
31
|
+
c.include Helper
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,284 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: s3-antivirus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tung Nguyen
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-12-15 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: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: aws-sdk-s3
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: aws-sdk-sns
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
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: aws-sdk-sqs
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
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: memoist
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rainbow
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: recursive-open-struct
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: thor
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: zeitwerk
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: bundler
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: byebug
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: cli_markdown
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: rake
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: rspec
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
209
|
+
description:
|
210
|
+
email:
|
211
|
+
- tongueroo@gmail.com
|
212
|
+
executables:
|
213
|
+
- s3-antivirus
|
214
|
+
extensions: []
|
215
|
+
extra_rdoc_files: []
|
216
|
+
files:
|
217
|
+
- ".gitignore"
|
218
|
+
- ".rspec"
|
219
|
+
- CHANGELOG.md
|
220
|
+
- Gemfile
|
221
|
+
- Guardfile
|
222
|
+
- LICENSE.txt
|
223
|
+
- README.md
|
224
|
+
- Rakefile
|
225
|
+
- exe/s3-antivirus
|
226
|
+
- lib/s3-antivirus.rb
|
227
|
+
- lib/s3_antivirus.rb
|
228
|
+
- lib/s3_antivirus/autoloader.rb
|
229
|
+
- lib/s3_antivirus/aws_services.rb
|
230
|
+
- lib/s3_antivirus/cli.rb
|
231
|
+
- lib/s3_antivirus/command.rb
|
232
|
+
- lib/s3_antivirus/completer.rb
|
233
|
+
- lib/s3_antivirus/completer/script.rb
|
234
|
+
- lib/s3_antivirus/completer/script.sh
|
235
|
+
- lib/s3_antivirus/conf.rb
|
236
|
+
- lib/s3_antivirus/config.rb
|
237
|
+
- lib/s3_antivirus/help.rb
|
238
|
+
- lib/s3_antivirus/help/completion.md
|
239
|
+
- lib/s3_antivirus/help/completion_script.md
|
240
|
+
- lib/s3_antivirus/help/scan.md
|
241
|
+
- lib/s3_antivirus/logger.rb
|
242
|
+
- lib/s3_antivirus/notifier.rb
|
243
|
+
- lib/s3_antivirus/s3_record.rb
|
244
|
+
- lib/s3_antivirus/scan.rb
|
245
|
+
- lib/s3_antivirus/tagger.rb
|
246
|
+
- lib/s3_antivirus/tee.rb
|
247
|
+
- lib/s3_antivirus/version.rb
|
248
|
+
- s3-antivirus.gemspec
|
249
|
+
- spec/fixtures/home/.s3-antivirus.conf
|
250
|
+
- spec/fixtures/sqs-event.json
|
251
|
+
- spec/lib/cli_spec.rb
|
252
|
+
- spec/lib/scan_spec.rb
|
253
|
+
- spec/spec_helper.rb
|
254
|
+
homepage: https://github.com/tongueroo/s3-antivirus
|
255
|
+
licenses:
|
256
|
+
- MIT
|
257
|
+
metadata:
|
258
|
+
homepage_uri: https://github.com/tongueroo/s3-antivirus
|
259
|
+
post_install_message:
|
260
|
+
rdoc_options: []
|
261
|
+
require_paths:
|
262
|
+
- lib
|
263
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
264
|
+
requirements:
|
265
|
+
- - ">="
|
266
|
+
- !ruby/object:Gem::Version
|
267
|
+
version: '0'
|
268
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
269
|
+
requirements:
|
270
|
+
- - ">="
|
271
|
+
- !ruby/object:Gem::Version
|
272
|
+
version: '0'
|
273
|
+
requirements: []
|
274
|
+
rubygems_version: 3.0.6
|
275
|
+
signing_key:
|
276
|
+
specification_version: 4
|
277
|
+
summary: Detects if files uploaded to s3 contain a virus with ClamAV and auto-deletes
|
278
|
+
or tags them
|
279
|
+
test_files:
|
280
|
+
- spec/fixtures/home/.s3-antivirus.conf
|
281
|
+
- spec/fixtures/sqs-event.json
|
282
|
+
- spec/lib/cli_spec.rb
|
283
|
+
- spec/lib/scan_spec.rb
|
284
|
+
- spec/spec_helper.rb
|