dockscan 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 +9 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE +340 -0
- data/README.md +52 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/dockscan.gemspec +27 -0
- data/docs/dockscan.png +0 -0
- data/exe/dockscan +107 -0
- data/lib/dockscan/modules/audit/container-filesystem-diff.rb +41 -0
- data/lib/dockscan/modules/audit/container-filesystem-shadow.rb +37 -0
- data/lib/dockscan/modules/audit/container-number-process.rb +36 -0
- data/lib/dockscan/modules/audit/container-sshd-process.rb +33 -0
- data/lib/dockscan/modules/audit/docker-experimental-build.rb +27 -0
- data/lib/dockscan/modules/audit/docker-insecure-registries.rb +53 -0
- data/lib/dockscan/modules/audit/docker-limits.rb +34 -0
- data/lib/dockscan/modules/audit/docker-networking-forwarding.rb +27 -0
- data/lib/dockscan/modules/audit/docker-registry-mirror.rb +41 -0
- data/lib/dockscan/modules/audit/docker-storage-driver-aufs.rb +28 -0
- data/lib/dockscan/modules/audit.rb +32 -0
- data/lib/dockscan/modules/discover/get-containers.rb +14 -0
- data/lib/dockscan/modules/discover/get-docker-info.rb +17 -0
- data/lib/dockscan/modules/discover/get-docker-version.rb +14 -0
- data/lib/dockscan/modules/discover/get-images.rb +16 -0
- data/lib/dockscan/modules/discover/get-run-containers.rb +14 -0
- data/lib/dockscan/modules/discover.rb +16 -0
- data/lib/dockscan/modules/genmodule.rb +17 -0
- data/lib/dockscan/modules/report/html.rb +182 -0
- data/lib/dockscan/modules/report/stdout.rb +36 -0
- data/lib/dockscan/modules/report/txt.rb +36 -0
- data/lib/dockscan/modules/report.rb +75 -0
- data/lib/dockscan/scan/issue.rb +18 -0
- data/lib/dockscan/scan/manage.rb +172 -0
- data/lib/dockscan/scan/plugin.rb +14 -0
- data/lib/dockscan/version.rb +3 -0
- data/lib/dockscan.rb +7 -0
- metadata +141 -0
@@ -0,0 +1,182 @@
|
|
1
|
+
class ReportHTML < Dockscan::Modules::ReportModule
|
2
|
+
|
3
|
+
def info
|
4
|
+
return 'This plugin produces HTML reports'
|
5
|
+
end
|
6
|
+
|
7
|
+
def file_extension
|
8
|
+
return ".html"
|
9
|
+
end
|
10
|
+
|
11
|
+
def format
|
12
|
+
return "html"
|
13
|
+
end
|
14
|
+
|
15
|
+
def htmlhead
|
16
|
+
htmlout = ""
|
17
|
+
htmlout << "<HTML><HEAD><TITLE>dockscan Report</TITLE>\n"
|
18
|
+
htmlout << '<style>'
|
19
|
+
htmlout << '.Vulnerability {
|
20
|
+
margin:0px;padding:0px;
|
21
|
+
width:100%;
|
22
|
+
border:0px solid #000000;
|
23
|
+
|
24
|
+
-moz-border-radius-bottomleft:0px;
|
25
|
+
-webkit-border-bottom-left-radius:0px;
|
26
|
+
border-bottom-left-radius:0px;
|
27
|
+
|
28
|
+
-moz-border-radius-bottomright:0px;
|
29
|
+
-webkit-border-bottom-right-radius:0px;
|
30
|
+
border-bottom-right-radius:0px;
|
31
|
+
|
32
|
+
-moz-border-radius-topright:0px;
|
33
|
+
-webkit-border-top-right-radius:0px;
|
34
|
+
border-top-right-radius:0px;
|
35
|
+
|
36
|
+
-moz-border-radius-topleft:0px;
|
37
|
+
-webkit-border-top-left-radius:0px;
|
38
|
+
border-top-left-radius:0px;
|
39
|
+
}.Vulnerability table{
|
40
|
+
border-collapse: collapse;
|
41
|
+
border-spacing: 0;
|
42
|
+
width:100%;
|
43
|
+
height:100%;
|
44
|
+
margin:0px;padding:0px;
|
45
|
+
}.Vulnerability tr:last-child td:last-child {
|
46
|
+
-moz-border-radius-bottomright:0px;
|
47
|
+
-webkit-border-bottom-right-radius:0px;
|
48
|
+
border-bottom-right-radius:0px;
|
49
|
+
}
|
50
|
+
.Vulnerability table tr:first-child td:first-child {
|
51
|
+
-moz-border-radius-topleft:0px;
|
52
|
+
-webkit-border-top-left-radius:0px;
|
53
|
+
border-top-left-radius:0px;
|
54
|
+
}
|
55
|
+
.Vulnerability table tr:first-child td:last-child {
|
56
|
+
-moz-border-radius-topright:0px;
|
57
|
+
-webkit-border-top-right-radius:0px;
|
58
|
+
border-top-right-radius:0px;
|
59
|
+
}.Vulnerability tr:last-child td:first-child{
|
60
|
+
-moz-border-radius-bottomleft:0px;
|
61
|
+
-webkit-border-bottom-left-radius:0px;
|
62
|
+
border-bottom-left-radius:0px;
|
63
|
+
}.Vulnerability tr:hover td{
|
64
|
+
background-color:#ffffff;
|
65
|
+
}
|
66
|
+
.Vulnerability td{
|
67
|
+
vertical-align:middle;
|
68
|
+
|
69
|
+
background-color:#ffffff;
|
70
|
+
|
71
|
+
border:0px solid #000000;
|
72
|
+
border-width:0px 1px 1px 0px;
|
73
|
+
text-align:left;
|
74
|
+
padding:7px;
|
75
|
+
font-size:10px;
|
76
|
+
font-family:Arial;
|
77
|
+
font-weight:normal;
|
78
|
+
color:#000000;
|
79
|
+
}.Vulnerability tr:last-child td{
|
80
|
+
border-width:0px 0px 0px 0px;
|
81
|
+
}.Vulnerability tr td:last-child{
|
82
|
+
border-width:0px 0px 0px 0px;
|
83
|
+
}.Vulnerability tr:last-child td:last-child{
|
84
|
+
border-width:0px 0px 0px 0px;
|
85
|
+
}
|
86
|
+
.Vulnerability tr:first-child td{
|
87
|
+
border:0px solid #000000;
|
88
|
+
text-align:left;
|
89
|
+
border-width:0px 0px 0px 0px;
|
90
|
+
font-size:14px;
|
91
|
+
font-family:Arial;
|
92
|
+
font-weight:bold;
|
93
|
+
color:#000000;
|
94
|
+
}
|
95
|
+
.Vulnerability tr:first-child:hover td{
|
96
|
+
}
|
97
|
+
.Vulnerability tr:first-child td:first-child{
|
98
|
+
border-width:0px 0px 0px 0px;
|
99
|
+
}
|
100
|
+
.Vulnerability tr:first-child td:last-child{
|
101
|
+
border-width:0px 0px 0px 0px;
|
102
|
+
}
|
103
|
+
|
104
|
+
.VulnerabilityBLACK tr:first-child td{
|
105
|
+
background-color:#000000;
|
106
|
+
color:#FFFFFF;
|
107
|
+
}
|
108
|
+
|
109
|
+
.VulnerabilityRED tr:first-child td{
|
110
|
+
background-color:#ff0000;
|
111
|
+
color:#ffffff;
|
112
|
+
}
|
113
|
+
|
114
|
+
.VulnerabilityORANGE tr:first-child td{
|
115
|
+
background-color:#ff9966;
|
116
|
+
color:#000000;
|
117
|
+
}
|
118
|
+
|
119
|
+
.VulnerabilityYELLOW tr:first-child td{
|
120
|
+
background-color:#ffff00;
|
121
|
+
color:#000000;
|
122
|
+
}
|
123
|
+
|
124
|
+
.VulnerabilityGRAY tr:first-child td{
|
125
|
+
background-color:#d0d0d0;
|
126
|
+
color:#000000;
|
127
|
+
}
|
128
|
+
'
|
129
|
+
htmlout << '</style>'
|
130
|
+
htmlout << "</HEAD>\n"
|
131
|
+
htmlout << "<BODY>\n"
|
132
|
+
htmlout << '<img width="220" height="169" title="" alt="" src="data:image/png;base64,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" />'
|
133
|
+
return htmlout
|
134
|
+
end
|
135
|
+
|
136
|
+
def htmlfoot
|
137
|
+
htmlout = ""
|
138
|
+
htmlout << "</BODY>\n"
|
139
|
+
htmlout << "</HTML>\n"
|
140
|
+
return htmlout
|
141
|
+
end
|
142
|
+
|
143
|
+
def report(opts)
|
144
|
+
output=""
|
145
|
+
output << htmlhead
|
146
|
+
output << "<h2>dockscan Report<h2>"
|
147
|
+
issues = sortvulns
|
148
|
+
7.downto(3) do |sev|
|
149
|
+
if issues.key?(sev)
|
150
|
+
output << "<h3>" << sev2word(sev) << " vulnerabilities</h3>\n"
|
151
|
+
issues[sev].each do |v|
|
152
|
+
if sev >= 7 then
|
153
|
+
output << '<TABLE CLASS="Vulnerability VulnerabilityBLACK">'
|
154
|
+
elsif sev == 6 then
|
155
|
+
output << '<TABLE CLASS="Vulnerability VulnerabilityRED">'
|
156
|
+
elsif sev == 5
|
157
|
+
output << '<TABLE CLASS="Vulnerability VulnerabilityORANGE">'
|
158
|
+
elsif sev == 4
|
159
|
+
output << '<TABLE CLASS="Vulnerability VulnerabilityYELLOW">'
|
160
|
+
elsif sev == 3
|
161
|
+
output << '<TABLE CLASS="Vulnerability VulnerabilityGRAY">'
|
162
|
+
else
|
163
|
+
output << '<TABLE CLASS="Vulnerability">'
|
164
|
+
end
|
165
|
+
output << "<TR>\n"
|
166
|
+
output << "<TD COLSPAN=2>" << v.vuln.title << "</TD>\n"
|
167
|
+
output << "<TD>" << sev2word(v.vuln.severity) << "</TD>\n"
|
168
|
+
output << "</TR>\n"
|
169
|
+
output << "<TR><TD COLSPAN=3>" << v.vuln.description << "</TD></TR>\n"
|
170
|
+
output << "<TR><TD COLSPAN=3><PRE>" << v.output << "</PRE></TD></TR>\n"
|
171
|
+
output << "<TR><TD COLSPAN=3>" << v.vuln.solution << "</TD></TR>\n"
|
172
|
+
output << "<TR><TD>CVSS: " << getkey(v.vuln.risk,"cvss").to_s << "</TD><TD>State: " << v.state << "</TD><TD></TD></TR>\n"
|
173
|
+
output << "</TABLE>\n\n"
|
174
|
+
end
|
175
|
+
output << "<P></P>\n"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
return output
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class ReportStdout < Dockscan::Modules::ReportModule
|
2
|
+
|
3
|
+
def info
|
4
|
+
return 'This plugin produces brief stdout reports'
|
5
|
+
end
|
6
|
+
|
7
|
+
def format
|
8
|
+
return "stdout"
|
9
|
+
end
|
10
|
+
|
11
|
+
def file_extension
|
12
|
+
return "-stdout.txt"
|
13
|
+
end
|
14
|
+
|
15
|
+
def report(opts)
|
16
|
+
output=""
|
17
|
+
output << "Dockscan Report\n\n"
|
18
|
+
|
19
|
+
issues = sortvulns
|
20
|
+
7.downto(3) do |sev|
|
21
|
+
if issues.key?(sev)
|
22
|
+
output << sev2word(sev) << "\n"
|
23
|
+
issues[sev].each do |v|
|
24
|
+
# output << k << ": "
|
25
|
+
output << v.vuln.title << ": "
|
26
|
+
output << v.vuln.solution
|
27
|
+
# output << v.output
|
28
|
+
output << "\n"
|
29
|
+
end
|
30
|
+
output << "\n"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return output
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class ReportText < Dockscan::Modules::ReportModule
|
2
|
+
|
3
|
+
def info
|
4
|
+
return 'This plugin produces text reports'
|
5
|
+
end
|
6
|
+
|
7
|
+
def format
|
8
|
+
return "txt"
|
9
|
+
end
|
10
|
+
|
11
|
+
def file_extension
|
12
|
+
return ".txt"
|
13
|
+
end
|
14
|
+
|
15
|
+
def report(opts)
|
16
|
+
output=""
|
17
|
+
output << "Dockscan Report\n\n"
|
18
|
+
|
19
|
+
issues = sortvulns
|
20
|
+
7.downto(3) do |sev|
|
21
|
+
if issues.key?(sev)
|
22
|
+
output << "-[ " << sev2word(sev) << " ]-\n"
|
23
|
+
issues[sev].each do |v|
|
24
|
+
output << "=" << v.vuln.title << "=\n"
|
25
|
+
output << "Description:\n" << v.vuln.description << "\n"
|
26
|
+
output << "Output:\n" << v.output << "\n"
|
27
|
+
output << "Solution:\n" << v.vuln.solution << "\n"
|
28
|
+
output << "\n"
|
29
|
+
end
|
30
|
+
output << "\n"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return output
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Dockscan
|
2
|
+
module Modules
|
3
|
+
|
4
|
+
class ReportModule < GenericModule
|
5
|
+
attr_accessor :scandata
|
6
|
+
|
7
|
+
def info
|
8
|
+
raise "#{self.class.name} doesn't implement `handle_command`!"
|
9
|
+
end
|
10
|
+
|
11
|
+
def desc(item)
|
12
|
+
if item.vuln.description
|
13
|
+
return item.vuln.description
|
14
|
+
else
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def sortvulns
|
20
|
+
severity_sorted=Hash.new
|
21
|
+
scandata.each do |classname,scanissue|
|
22
|
+
if scanissue.state == "vulnerable" or scanissue.state=="info" then
|
23
|
+
severity_sorted[scanissue.vuln.severity] ||= []
|
24
|
+
severity_sorted[scanissue.vuln.severity] << scanissue
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return severity_sorted
|
28
|
+
end
|
29
|
+
|
30
|
+
def format
|
31
|
+
return "unknown"
|
32
|
+
end
|
33
|
+
|
34
|
+
def file_extension
|
35
|
+
return ".unknown"
|
36
|
+
end
|
37
|
+
|
38
|
+
def getkey(hsh,hkey)
|
39
|
+
if hsh.has_key?(hkey) then
|
40
|
+
return hsh[hkey]
|
41
|
+
else
|
42
|
+
return ''
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def sev2word(sev)
|
47
|
+
case sev
|
48
|
+
when 7
|
49
|
+
return "Critical"
|
50
|
+
when 6
|
51
|
+
return "High"
|
52
|
+
when 5
|
53
|
+
return "Medium"
|
54
|
+
when 4
|
55
|
+
return "Low"
|
56
|
+
when 3
|
57
|
+
return "Info"
|
58
|
+
when 2
|
59
|
+
return "Verbose"
|
60
|
+
when 1
|
61
|
+
return "Inspect"
|
62
|
+
when 0
|
63
|
+
return "Debug"
|
64
|
+
else
|
65
|
+
return "DebugMiss"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def report(opts)
|
70
|
+
raise "#{self.class.name} doesn't implement `handle_command`!"
|
71
|
+
end
|
72
|
+
end # Class
|
73
|
+
|
74
|
+
end # Module
|
75
|
+
end # Dockscan
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Dockscan
|
2
|
+
module Scan
|
3
|
+
class Issue
|
4
|
+
attr_accessor :severity, :description, :solution, :title, :tags, :references, :risk, :reflinks
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
severity=0
|
8
|
+
description="Forgot to add description"
|
9
|
+
solution="Information only."
|
10
|
+
title="Forgot to add title"
|
11
|
+
tags=Hash.new
|
12
|
+
references=Hash.new
|
13
|
+
risk=Hash.new
|
14
|
+
reflinks=Hash.new
|
15
|
+
end
|
16
|
+
end # Issue
|
17
|
+
end # Scan
|
18
|
+
end # Dockscan
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'docker'
|
2
|
+
|
3
|
+
require 'dockscan/modules/genmodule'
|
4
|
+
require 'dockscan/modules/discover'
|
5
|
+
require 'dockscan/modules/audit'
|
6
|
+
require 'dockscan/modules/report'
|
7
|
+
|
8
|
+
require 'dockscan/scan/plugin'
|
9
|
+
|
10
|
+
require 'pp'
|
11
|
+
|
12
|
+
module Dockscan
|
13
|
+
module Scan
|
14
|
+
class Manage
|
15
|
+
|
16
|
+
attr_accessor :log
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@auditoutput=Hash.new
|
20
|
+
@log=Logger.new MultiDelegator.delegate(:write, :close).to(STDERR)
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_connection
|
24
|
+
@log.info("Validating version specified: "+Docker.url)
|
25
|
+
begin
|
26
|
+
Docker.validate_version!
|
27
|
+
rescue
|
28
|
+
@log.error("Error connecting or validating Docker version")
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
|
34
|
+
def scan (url, opts, logger)
|
35
|
+
failed=Array.new
|
36
|
+
|
37
|
+
if url != nil then
|
38
|
+
Docker.url = url
|
39
|
+
end
|
40
|
+
|
41
|
+
@log=logger
|
42
|
+
|
43
|
+
if not check_connection then
|
44
|
+
return
|
45
|
+
end
|
46
|
+
|
47
|
+
moduledirs=Array.new
|
48
|
+
if moduledirs.empty? then
|
49
|
+
moduledirs.push File.expand_path("../modules", File.dirname(__FILE__))
|
50
|
+
end
|
51
|
+
|
52
|
+
@log.info("Loading discovery modules...")
|
53
|
+
moduledirs.each do |moduledir|
|
54
|
+
@log.debug("Loading dir: #{moduledir}")
|
55
|
+
Dir["#{moduledir}/discover/*.rb"].each do |f|
|
56
|
+
@log.info("Loading discovery module: #{f}")
|
57
|
+
begin
|
58
|
+
require f
|
59
|
+
rescue SyntaxError => se
|
60
|
+
@log.info("Error loading audit module: #{f}")
|
61
|
+
@log.debug("Error executing audit module: #{se.backtrace}")
|
62
|
+
failed << f
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
@log.info("Running discovery modules...")
|
68
|
+
Dockscan::Modules::DiscoverModule.modules.each do |modclass|
|
69
|
+
@log.info("Running discovery module: #{modclass.name}")
|
70
|
+
begin
|
71
|
+
mod=modclass.new
|
72
|
+
mod.scandata=@auditoutput
|
73
|
+
@auditoutput[mod.class.name]=mod.run
|
74
|
+
rescue Exception => e
|
75
|
+
@log.info("Error executing audit module: #{modclass.name}")
|
76
|
+
@log.debug("Error executing audit module: #{e.backtrace}")
|
77
|
+
failed << modclass.name
|
78
|
+
end
|
79
|
+
# pp @auditoutput[mod.class.name]
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
@log.info("Loading audit modules...")
|
84
|
+
moduledirs.each do |moduledir|
|
85
|
+
@log.debug("Loading dir: #{moduledir}")
|
86
|
+
Dir["#{moduledir}/audit/*.rb"].each do |f|
|
87
|
+
@log.info("Loading audit module: #{f}")
|
88
|
+
begin
|
89
|
+
require f
|
90
|
+
rescue SyntaxError => se
|
91
|
+
@log.info("Error loading audit module: #{f}")
|
92
|
+
@log.debug("Error executing audit module: #{se.backtrace}")
|
93
|
+
failed << f
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
@log.info("Running audit modules...")
|
99
|
+
Dockscan::Modules::AuditModule.modules.each do |modclass|
|
100
|
+
@log.info("Running audit module: #{modclass.name}")
|
101
|
+
begin
|
102
|
+
mod=modclass.new
|
103
|
+
mod.scandata=@auditoutput
|
104
|
+
@auditoutput[mod.class.name]=mod.check('test')
|
105
|
+
rescue Exception => e
|
106
|
+
@log.info("Error executing audit module: #{modclass.name}")
|
107
|
+
@log.debug("Error executing audit module: #{e.to_s} #{e.backtrace}")
|
108
|
+
failed << modclass.name
|
109
|
+
end
|
110
|
+
# pp @auditoutput[mod.class.name]
|
111
|
+
end
|
112
|
+
|
113
|
+
@log.info("Loading report modules...")
|
114
|
+
moduledirs.each do |moduledir|
|
115
|
+
Dir["#{moduledir}/report/*.rb"].each do |f|
|
116
|
+
@log.info("Loading report #{f}")
|
117
|
+
begin
|
118
|
+
require f
|
119
|
+
rescue SyntaxError => se
|
120
|
+
@log.info("Error loading report module: #{f}")
|
121
|
+
@log.debug("Error executing report module: #{se.backtrace}")
|
122
|
+
failed << f
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
@log.info("Running report modules...")
|
128
|
+
Dockscan::Modules::ReportModule.modules.each do |modclass|
|
129
|
+
@log.info("Running report module: #{modclass.name}")
|
130
|
+
mod=modclass.new
|
131
|
+
if opts.key?("report") then
|
132
|
+
formats=opts["report"].split(",")
|
133
|
+
else
|
134
|
+
formats=['stdout']
|
135
|
+
end
|
136
|
+
formats.each do |fmt|
|
137
|
+
if fmt==mod.format then
|
138
|
+
begin
|
139
|
+
mod.scandata=@auditoutput
|
140
|
+
output=mod.report(nil)
|
141
|
+
if opts.key?("output") then
|
142
|
+
reportfilename = opts["output"]
|
143
|
+
reportfilename << mod.file_extension
|
144
|
+
File.open(reportfilename, 'w') { |file| file.write(output) }
|
145
|
+
else
|
146
|
+
puts output
|
147
|
+
end
|
148
|
+
rescue Exception => e
|
149
|
+
@log.info("Error executing report module: #{modclass.name}")
|
150
|
+
@log.debug("Error executing report module: #{e.to_s} #{e.backtrace}")
|
151
|
+
failed << modclass.name
|
152
|
+
end
|
153
|
+
@log.debug(output)
|
154
|
+
else
|
155
|
+
@log.debug("Skipping report module: #{modclass.name}");
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
if failed.count > 0
|
161
|
+
failedstr=""
|
162
|
+
failed.each do |f|
|
163
|
+
failedstr = f + " "
|
164
|
+
end
|
165
|
+
@log.warn("Following modules failed: #{failedstr}")
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end # Class
|
170
|
+
end # Scan
|
171
|
+
end # Dockscan
|
172
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'dockscan/scan/issue'
|
2
|
+
|
3
|
+
module Dockscan
|
4
|
+
module Scan
|
5
|
+
class Plugin
|
6
|
+
attr_accessor :state, :output, :obj, :vuln, :cname
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
state="untested"
|
10
|
+
vuln = Dockscan::Scan::Issue.new
|
11
|
+
end
|
12
|
+
end # Plugin
|
13
|
+
end # Scan
|
14
|
+
end # Dockscan
|