veracode 1.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/veracode +81 -0
- data/lib/veracode.rb +739 -0
- data/lib/veracode/version.rb +3 -0
- metadata +60 -0
data/bin/veracode
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
5
|
+
$:.unshift Dir.pwd
|
6
|
+
|
7
|
+
unless File.exists?("script/rails")
|
8
|
+
$stderr.puts "Current directory #{File.basename(Dir.pwd).dump} does not appear to be a Rails 3 application."
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
APP_PATH = File.expand_path('config/application')
|
12
|
+
APP_NAME = File.basename(Dir.pwd)
|
13
|
+
COMMAND = "#{$0} #{ARGV.join(' ')}"
|
14
|
+
|
15
|
+
require 'veracode'
|
16
|
+
|
17
|
+
$options = {
|
18
|
+
:phase1 => false,
|
19
|
+
:phase2 => false,
|
20
|
+
:phase3 => true,
|
21
|
+
:archive_source => true,
|
22
|
+
:include_inherited => false,
|
23
|
+
:jruby => false,
|
24
|
+
}
|
25
|
+
|
26
|
+
subcommand = ARGV.shift
|
27
|
+
case subcommand
|
28
|
+
when "prepare", "prep"
|
29
|
+
OptionParser.new do |opts|
|
30
|
+
opts.banner = "Usage: veracode prepare [options]"
|
31
|
+
|
32
|
+
opts.on("-v", "--verbose", "Run verbosely") do
|
33
|
+
$options[:verbose] = true
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.on("-a", "--all", "Archive objects at all stages") do
|
37
|
+
$options[:phase1] = true
|
38
|
+
$options[:phase2] = true
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on("-f", "--file", "Disassemble .rb files") do
|
42
|
+
$options[:disasm] = true
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on("-j", "--jruby", "Force JRuby mode") do
|
46
|
+
$options[:jruby] = true
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on("--[no-]source", "[Don't] Include source code in archive") do |s|
|
50
|
+
$options[:archive_source] = s
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on("-D", "--debug", "Enable debug output") do
|
54
|
+
$DEBUG = true
|
55
|
+
end
|
56
|
+
|
57
|
+
end.parse!
|
58
|
+
|
59
|
+
Veracode.prepare
|
60
|
+
|
61
|
+
when "help", nil
|
62
|
+
ARGV.clear
|
63
|
+
ARGV.unshift "--help"
|
64
|
+
|
65
|
+
OptionParser.new do |opts|
|
66
|
+
opts.banner = "Usage: veracode prepare [options]"
|
67
|
+
end.parse!
|
68
|
+
|
69
|
+
else
|
70
|
+
$stderr.puts "#{subcommand.dump} is not a valid subcommand"
|
71
|
+
|
72
|
+
ARGV.clear
|
73
|
+
ARGV.unshift "--help"
|
74
|
+
|
75
|
+
OptionParser.new do |opts|
|
76
|
+
opts.banner = "Usage: veracode prepare [options]"
|
77
|
+
end.parse!
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
|
data/lib/veracode.rb
ADDED
@@ -0,0 +1,739 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
require 'zip/zip'
|
3
|
+
require "veracode/version"
|
4
|
+
|
5
|
+
module Veracode
|
6
|
+
@run_id = nil
|
7
|
+
|
8
|
+
# Metadata and method disassemblies for all Modules (.txt.gz)
|
9
|
+
@disasmlog = nil
|
10
|
+
@disasmlog_filename = "disasm.txt.gz"
|
11
|
+
|
12
|
+
# Error log including capture of STDERR and any errors generated by the gem (.log)
|
13
|
+
@errorlog = nil
|
14
|
+
@errorlog_filename = "error.log"
|
15
|
+
|
16
|
+
# Index file containing the names of files present in the application directory (.txt)
|
17
|
+
@index_filename = "index.txt"
|
18
|
+
|
19
|
+
# Manifest file containing original names of all files in archive (.txt)
|
20
|
+
@manifest = []
|
21
|
+
@manifest_filename = "manifest.txt"
|
22
|
+
|
23
|
+
# The final archive that will be uploaded to Veracode for analysis (.zip)
|
24
|
+
@archive = nil
|
25
|
+
@archive_filename = nil
|
26
|
+
@archive_dirname = nil
|
27
|
+
|
28
|
+
|
29
|
+
def self.init
|
30
|
+
@run_id = Time.now.strftime("%Y%m%d%H%M%S")
|
31
|
+
@archive_dirname = File.join("tmp","veracode-#{@run_id}")
|
32
|
+
|
33
|
+
if !Dir.exists?("tmp")
|
34
|
+
begin
|
35
|
+
Dir.mkdir("tmp")
|
36
|
+
rescue Exception => e
|
37
|
+
$stderr.puts "Directory 'tmp' does not exist and cannot be created: #{e.message}"
|
38
|
+
exit
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
while Dir.exists?(@archive_dirname)
|
43
|
+
@run_id = Time.now.strftime("%Y%m%d%H%M%S")
|
44
|
+
@archive_dirname = File.join("tmp","veracode-#{@run_id}")
|
45
|
+
end
|
46
|
+
|
47
|
+
begin
|
48
|
+
Dir.mkdir(@archive_dirname)
|
49
|
+
rescue Exception => e
|
50
|
+
$stderr.puts "Unable to make directory #{@archive_dirname}: #{e.message}"
|
51
|
+
exit
|
52
|
+
end
|
53
|
+
|
54
|
+
@archive_filename = File.join("tmp","veracode-#{APP_NAME}-#{@run_id}.zip")
|
55
|
+
|
56
|
+
@errorlog_filename = File.join(@archive_dirname, @errorlog_filename)
|
57
|
+
@disasmlog_filename = File.join(@archive_dirname, @disasmlog_filename)
|
58
|
+
@index_filename = File.join(@archive_dirname, @index_filename)
|
59
|
+
@manifest_filename = File.join(@archive_dirname, @manifest_filename)
|
60
|
+
|
61
|
+
# Try touching each of the files to be written
|
62
|
+
[@disasmlog_filename, @errorlog_filename, @index_filename, @manifest_filename].each {|f|
|
63
|
+
begin
|
64
|
+
File.open(f, "wb") {}
|
65
|
+
rescue Exception => e
|
66
|
+
$stderr.puts "Unable to create file #{f}: #{e.message}"
|
67
|
+
exit
|
68
|
+
else
|
69
|
+
@manifest << f
|
70
|
+
end
|
71
|
+
}
|
72
|
+
|
73
|
+
begin
|
74
|
+
@errorlog = File.open(@errorlog_filename, "wb")
|
75
|
+
log_error "COMMAND: #{COMMAND}"
|
76
|
+
log_error "RUBY_DESCRIPTION: #{RUBY_DESCRIPTION}"
|
77
|
+
log_error "RAILS_VERSION: " + `rails --version`.chomp
|
78
|
+
log_error "GEM_VERSION: #{Veracode::VERSION}"
|
79
|
+
log_error "PWD: #{Dir.pwd.to_s.dump}"
|
80
|
+
log_error "APP_NAME: #{APP_NAME.dump}"
|
81
|
+
log_error "RUNID: #{@run_id}"
|
82
|
+
rescue Exception => e
|
83
|
+
$stderr.puts "Unable to create errorlog #{@errorlog_filename}: #{e.message}"
|
84
|
+
@errorlog = $stderr
|
85
|
+
else
|
86
|
+
STDERR.reopen(@errorlog)
|
87
|
+
end
|
88
|
+
|
89
|
+
index_application
|
90
|
+
|
91
|
+
@manifest += Dir.glob("*").keep_if {|f| File.file?(f)}
|
92
|
+
|
93
|
+
# {app config db doc lib log public script test tmp vendor}
|
94
|
+
%w{app config lib log public script vendor}.each {|dirname|
|
95
|
+
@manifest += Dir[File.join(dirname, "**", "*")].keep_if {|f| File.file?(f)}
|
96
|
+
}
|
97
|
+
@manifest += Dir[File.join("db", "**", "*.rb")]
|
98
|
+
|
99
|
+
if $options[:archive_source]
|
100
|
+
# Add any other ruby files not already added
|
101
|
+
@manifest |= Dir[File.join("**","*.rb")]
|
102
|
+
# Add any other erb files not already added
|
103
|
+
@manifest |= Dir[File.join("**","*.erb")]
|
104
|
+
# Add any other haml files not already added
|
105
|
+
@manifest |= Dir[File.join("**","*.haml")]
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.index_application
|
111
|
+
File.open(@index_filename, "wb") {|index_file|
|
112
|
+
Dir[File.join("**","*")].keep_if {|f| File.file?(f)}.sort.each {|f|
|
113
|
+
index_file.puts f.dump
|
114
|
+
}
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.pack_manifest
|
119
|
+
|
120
|
+
puts "Archiving disassembly and source files"
|
121
|
+
|
122
|
+
begin
|
123
|
+
File.open(@manifest_filename, "wb") { |mf|
|
124
|
+
@manifest.sort.each { |f|
|
125
|
+
mf.puts f.to_s.dump
|
126
|
+
}
|
127
|
+
}
|
128
|
+
rescue Exception => e
|
129
|
+
log_error e.message
|
130
|
+
$stderr.puts "Unable to write manifest file #{@manifest_filename}: #{e.message}"
|
131
|
+
end
|
132
|
+
|
133
|
+
@errorlog.flush
|
134
|
+
|
135
|
+
begin
|
136
|
+
Zip::ZipFile.open(@archive_filename, Zip::ZipFile::CREATE) { |zf|
|
137
|
+
@manifest.each {|file|
|
138
|
+
|
139
|
+
if file.start_with?(@archive_dirname)
|
140
|
+
name_in_archive = file.sub(/^#{@archive_dirname + File::SEPARATOR}/,"")
|
141
|
+
else
|
142
|
+
name_in_archive = File.join(APP_NAME, file)
|
143
|
+
end
|
144
|
+
|
145
|
+
puts "Adding #{file} to archive as #{name_in_archive}" if $options[:verbose]
|
146
|
+
zf.add(name_in_archive, file)
|
147
|
+
}
|
148
|
+
}
|
149
|
+
rescue Exception => e
|
150
|
+
$stderr.puts "Unable to create archive #{@manifest_filename}: #{e.message}"
|
151
|
+
exit
|
152
|
+
end
|
153
|
+
|
154
|
+
puts "Please upload #{@archive_filename}"
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.cleanup
|
158
|
+
[@disasmlog_filename, @errorlog_filename, @index_filename, @manifest_filename].each {|f|
|
159
|
+
begin
|
160
|
+
File.delete(f)
|
161
|
+
rescue Exception => e
|
162
|
+
log_error "Unable to delete #{f.to_s.dump} (#{e.message})"
|
163
|
+
end
|
164
|
+
}
|
165
|
+
|
166
|
+
begin
|
167
|
+
Dir.delete(@archive_dirname)
|
168
|
+
rescue Exception => e
|
169
|
+
puts "Unable to remove #{@archive_dirname.to_s.dump} (#{e.message})"
|
170
|
+
log_error "Unable to remove #{@archive_dirname.to_s.dump} (#{e.message})"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.baseline
|
175
|
+
self.update
|
176
|
+
@baseline_objects = @objects
|
177
|
+
@baseline_modules = @modules
|
178
|
+
@baseline_classes = @classes
|
179
|
+
end
|
180
|
+
|
181
|
+
def self.rebaseline
|
182
|
+
self.baseline
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.update
|
186
|
+
@objects = ObjectSpace.each_object.to_a
|
187
|
+
@modules = ObjectSpace.each_object(Module).to_a
|
188
|
+
@classes = ObjectSpace.each_object(Class).to_a
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.stats
|
192
|
+
puts "#{ObjectSpace.each_object.count.to_s} objects"
|
193
|
+
puts "#{ObjectSpace.each_object(Module).count.to_s} modules"
|
194
|
+
puts "#{ObjectSpace.each_object(Class).count.to_s} classes"
|
195
|
+
puts
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
##############################################################################
|
200
|
+
# Helpers
|
201
|
+
def self.glob_require(files)
|
202
|
+
Dir.glob(files) do |f|
|
203
|
+
print "Requiring #{f.to_s} " if $options[:verbose]
|
204
|
+
|
205
|
+
begin
|
206
|
+
require File.expand_path(f)
|
207
|
+
rescue Exception => e
|
208
|
+
puts "(failed: #{e.message})" if $options[:verbose]
|
209
|
+
log_error "Unable to require #{File.expand_path(f).to_s.dump} (#{e.message})"
|
210
|
+
else
|
211
|
+
puts "(OK)" if $options[:verbose]
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.safe_name(o)
|
218
|
+
case
|
219
|
+
when o == ActiveSupport::TimeWithZone
|
220
|
+
"ActiveSupport::TimeWithZone"
|
221
|
+
when o.is_a?(Module)
|
222
|
+
( o.name.nil? ? o.to_s : o.name )
|
223
|
+
when o.is_a?(Method), o.is_a?(UnboundMethod)
|
224
|
+
o.name.to_s
|
225
|
+
else
|
226
|
+
o.to_s
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.quote(o)
|
231
|
+
o.to_s.dump
|
232
|
+
end
|
233
|
+
|
234
|
+
def self.quote_if_string(o)
|
235
|
+
( o.is_a?(String) ? o.dump : o.inspect )
|
236
|
+
end
|
237
|
+
|
238
|
+
def self.good_type?(o)
|
239
|
+
%w{
|
240
|
+
Array
|
241
|
+
Bignum
|
242
|
+
Class
|
243
|
+
FalseClass
|
244
|
+
Fixnum
|
245
|
+
Float
|
246
|
+
Hash
|
247
|
+
Module
|
248
|
+
NilClass
|
249
|
+
Range
|
250
|
+
Rational
|
251
|
+
Regexp
|
252
|
+
String
|
253
|
+
Symbol
|
254
|
+
Time
|
255
|
+
TrueClass
|
256
|
+
}.include?(o.class.to_s)
|
257
|
+
end
|
258
|
+
|
259
|
+
def self.safe_inspect(o)
|
260
|
+
if o.is_a?(Array)
|
261
|
+
"[" +
|
262
|
+
o.map {|i| safe_inspect(i) }.join(", ") +
|
263
|
+
"]"
|
264
|
+
elsif o.is_a?(Hash)
|
265
|
+
"{" +
|
266
|
+
o.map {|k,v| "#{safe_inspect(k)}=>#{safe_inspect(v)}" }.join(", ") +
|
267
|
+
"}"
|
268
|
+
elsif o.is_a?(Module)
|
269
|
+
safe_name(o)
|
270
|
+
elsif good_type?(o)
|
271
|
+
quote_if_string(o)
|
272
|
+
else
|
273
|
+
":veracode_nil" # not a white-listed type
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def self.log_error(data)
|
278
|
+
@errorlog.printf "veracode [%s] %s\n", Time.now.to_s, data.to_s.chomp
|
279
|
+
end
|
280
|
+
|
281
|
+
|
282
|
+
##############################################################################
|
283
|
+
# Archiving
|
284
|
+
def self.prepare_archive
|
285
|
+
@disasmlog = Zlib::GzipWriter.new(File.open(@disasmlog_filename, "wb"), nil, nil)
|
286
|
+
@disasmlog.puts "#{RUBY_ENGINE}-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
|
287
|
+
@disasmlog.puts "# " + `rails --version`.chomp
|
288
|
+
@disasmlog.puts
|
289
|
+
end
|
290
|
+
|
291
|
+
def self.finalize_archive
|
292
|
+
@disasmlog.close unless @disasmlog.nil?
|
293
|
+
end
|
294
|
+
|
295
|
+
def self.add_to_archive(data)
|
296
|
+
if @disasmlog.nil?
|
297
|
+
prepare_archive
|
298
|
+
end
|
299
|
+
@disasmlog.write(data)
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
def self.format_method(m, kind, with_disasm=true)
|
304
|
+
return "" unless ((m.is_a? Method ) || (m.is_a? UnboundMethod))
|
305
|
+
|
306
|
+
puts " #{kind}_method #{quote(safe_name(m))}" if $options[:verbose]
|
307
|
+
|
308
|
+
formatted = "#{kind}_method #{quote(safe_name(m))} #{m.parameters.to_s}\n"
|
309
|
+
|
310
|
+
if with_disasm
|
311
|
+
insns = RubyVM::InstructionSequence.disassemble(m)
|
312
|
+
formatted += ( (insns.nil? || insns.empty?) ?
|
313
|
+
"== disasm\n== end disasm\n" :
|
314
|
+
"#{insns}== end disasm\n"
|
315
|
+
)
|
316
|
+
end
|
317
|
+
|
318
|
+
formatted
|
319
|
+
end
|
320
|
+
|
321
|
+
def self.format_variable(v_symbol, v, kind)
|
322
|
+
puts " #{quote(kind)} variable #{quote(v_symbol)}" if $options[:verbose]
|
323
|
+
|
324
|
+
"#{kind}_variable %s %s%s\n" %
|
325
|
+
[quote(v.class), quote(v_symbol), ( good_type?(v) ? " = #{safe_inspect(v)}" : "")]
|
326
|
+
end
|
327
|
+
|
328
|
+
def self.format_constant(c_symbol, c)
|
329
|
+
puts " constant #{quote(c_symbol)}" if $options[:verbose]
|
330
|
+
|
331
|
+
"constant %s %s%s\n" %
|
332
|
+
[quote(c.class), quote(c_symbol), ( good_type?(c) ? " = #{safe_inspect(c)}" : "")]
|
333
|
+
end
|
334
|
+
|
335
|
+
|
336
|
+
##############################################################################
|
337
|
+
# Archiving Headers
|
338
|
+
def self.class_header(c)
|
339
|
+
return "" unless c.is_a? Class
|
340
|
+
|
341
|
+
puts " class header" if $options[:verbose]
|
342
|
+
|
343
|
+
case
|
344
|
+
when c.superclass.nil? # this should only happen for BasicObject
|
345
|
+
return ""
|
346
|
+
when c.superclass.name.nil? # in case the parent is anonymous
|
347
|
+
name = c.superclass.to_s.dump
|
348
|
+
else
|
349
|
+
name = c.superclass.name.dump
|
350
|
+
end
|
351
|
+
|
352
|
+
"superclass #{name}\n"
|
353
|
+
end
|
354
|
+
|
355
|
+
def self.module_header(m)
|
356
|
+
return "" unless m.is_a? Module
|
357
|
+
|
358
|
+
puts " module header" if $options[:verbose]
|
359
|
+
|
360
|
+
( m.included_modules.count > 0 ?
|
361
|
+
m.included_modules.map {|m| "include #{m.inspect.dump}\n" }.join :
|
362
|
+
""
|
363
|
+
) +
|
364
|
+
( m.singleton_class.included_modules.count > 0 ?
|
365
|
+
m.singleton_class.included_modules.map {|m| "extend #{m.inspect.dump}\n" }.join :
|
366
|
+
""
|
367
|
+
)
|
368
|
+
end
|
369
|
+
|
370
|
+
|
371
|
+
##############################################################################
|
372
|
+
# Archiving Contents
|
373
|
+
def self.module_contents(m, with_disasm=true)
|
374
|
+
return "" unless m.is_a? Module
|
375
|
+
|
376
|
+
puts " module contents" if $options[:verbose]
|
377
|
+
|
378
|
+
formatted_contents = ""
|
379
|
+
|
380
|
+
m.constants($options[:include_inherited]).each do |c_symbol|
|
381
|
+
begin
|
382
|
+
c = m.const_get(c_symbol) if m.const_defined? c_symbol
|
383
|
+
formatted_contents += format_constant(c_symbol, c)
|
384
|
+
rescue Exception => e
|
385
|
+
log_error "Error archiving constant #{c_symbol.to_s.dump}: #{e.message}"
|
386
|
+
formatted_contents += format_constant(c_symbol, :veracode_nil)
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
m.class_variables.each do |v_symbol|
|
391
|
+
begin
|
392
|
+
v = m.class_variable_get(v_symbol)
|
393
|
+
formatted_contents += format_variable(v_symbol, v, "class")
|
394
|
+
rescue Exception => e
|
395
|
+
log_error "Error archiving class variable #{v_symbol.to_s.dump}: #{e.message}"
|
396
|
+
formatted_contents += format_variable(v_symbol, :veracode_nil, "class")
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
if m.respond_to?(:global_variables)
|
401
|
+
m.global_variables.each do |v_symbol|
|
402
|
+
begin
|
403
|
+
v = eval(v_symbol.to_s)
|
404
|
+
formatted_contents += format_variable(v_symbol, v, "global")
|
405
|
+
rescue Exception => e
|
406
|
+
log_error "Error archiving global variable #{v_symbol.to_s.dump}: #{e.message}"
|
407
|
+
formatted_contents += format_variable(v_symbol, :veracode_nil, "global")
|
408
|
+
end
|
409
|
+
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
%w[ public protected private ].each {|p|
|
414
|
+
get_methods = (p + "_instance_methods").to_sym
|
415
|
+
if m.respond_to?(get_methods) && m.send(get_methods, $options[:include_inherited]).count > 0
|
416
|
+
m.send(get_methods, $options[:include_inherited]).each do |m_symbol|
|
417
|
+
begin
|
418
|
+
method = m.instance_method(m_symbol)
|
419
|
+
formatted_contents += format_method(method, "#{p.to_s}_instance", with_disasm)
|
420
|
+
rescue Exception => e
|
421
|
+
log_error "Error archiving #{p.to_s} instance method #{m_symbol.to_s.dump}: #{e.message}"
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
}
|
426
|
+
|
427
|
+
formatted_contents
|
428
|
+
end
|
429
|
+
|
430
|
+
def self.object_contents(o, with_disasm=true)
|
431
|
+
return "" unless o.is_a? Object
|
432
|
+
|
433
|
+
puts " object contents" if $options[:verbose]
|
434
|
+
|
435
|
+
formatted_contents = ""
|
436
|
+
|
437
|
+
if o.respond_to?(:instance_variables) && o.instance_variables.count > 0
|
438
|
+
o.instance_variables.each do |v_symbol|
|
439
|
+
begin
|
440
|
+
v = o.instance_variable_get(v_symbol)
|
441
|
+
formatted_contents += format_variable(v_symbol, v, "instance")
|
442
|
+
rescue Exception => e
|
443
|
+
log_error "Error archiving instance variable #{v_symbol.to_s.dump}: #{e.message}"
|
444
|
+
formatted_contents += format_variable(v_symbol, :veracode_nil, "instance")
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
if o.respond_to?(:singleton_methods) && o.singleton_methods($options[:include_inherited]).count > 0
|
450
|
+
o.singleton_methods($options[:include_inherited]).each do |m_symbol|
|
451
|
+
begin
|
452
|
+
m = o.method(m_symbol)
|
453
|
+
formatted_contents += format_method(m, "singleton", with_disasm)
|
454
|
+
rescue Exception => e
|
455
|
+
log_error "Error archiving singleton method #{m_symbol.to_s.dump}: #{e.message}"
|
456
|
+
end
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
formatted_contents
|
461
|
+
end
|
462
|
+
|
463
|
+
|
464
|
+
##############################################################################
|
465
|
+
# Archiving Objects
|
466
|
+
def self.archive(objects, with_disasm=true)
|
467
|
+
|
468
|
+
objects = objects - [Veracode]
|
469
|
+
|
470
|
+
if $options[:verbose]
|
471
|
+
puts "Archiving #{objects.count.to_s} objects" + (with_disasm ? " with disassembly" : "")
|
472
|
+
puts
|
473
|
+
end
|
474
|
+
|
475
|
+
objects.sort_by {|o| safe_name(o) }.each do |o|
|
476
|
+
|
477
|
+
puts "archiving #{o.class.to_s.downcase} #{quote(safe_name(o))}" if $options[:verbose]
|
478
|
+
|
479
|
+
add_to_archive "#{o.class.to_s.downcase} #{quote(safe_name(o))}\n" +
|
480
|
+
|
481
|
+
( o.is_a?(Class) ? class_header(o) : "") + # superclass
|
482
|
+
( o.is_a?(Module) ? module_header(o) : "") + # included modules
|
483
|
+
|
484
|
+
( o.is_a?(Object) ? object_contents(o, with_disasm) : "") +
|
485
|
+
( o.is_a?(Module) ? module_contents(o, with_disasm) : "") +
|
486
|
+
|
487
|
+
"end#{o.class.to_s.downcase}\n" +
|
488
|
+
"\n"
|
489
|
+
end
|
490
|
+
|
491
|
+
end
|
492
|
+
|
493
|
+
|
494
|
+
def self.compile_erb_templates
|
495
|
+
|
496
|
+
# Rails 3 has wrapped Erubis to handle block helpers in ERB templates
|
497
|
+
# a little differently, e.g.:
|
498
|
+
# <%= form_for ... do %>
|
499
|
+
# vs the normal ERB:
|
500
|
+
# <% form_for ... do %>
|
501
|
+
#
|
502
|
+
# This means if Rails 3 erb templates are compiled with ERB or Erubis
|
503
|
+
# the resulting ruby source code will contain syntax errors.
|
504
|
+
# To avoid this, use the ActionView templates and handlers
|
505
|
+
|
506
|
+
view_paths = []
|
507
|
+
view_paths += ActionController::Base.view_paths.to_a.map(&:to_s)
|
508
|
+
view_paths |= [File.expand_path("app/views")]
|
509
|
+
|
510
|
+
puts "Looking for erb templates in #{view_paths.join(", ")}" if $options[:verbose]
|
511
|
+
|
512
|
+
templates = view_paths.map { |vp|
|
513
|
+
Dir[File.join(vp, "**", "*.erb")]
|
514
|
+
}.flatten
|
515
|
+
|
516
|
+
return unless templates.count > 0
|
517
|
+
|
518
|
+
puts "Found #{templates.count} erb templates" if $options[:verbose]
|
519
|
+
|
520
|
+
templates.each {|template|
|
521
|
+
|
522
|
+
puts "Compiling template #{template}" if $options[:verbose]
|
523
|
+
|
524
|
+
begin
|
525
|
+
|
526
|
+
t = ActionView::Template.new(
|
527
|
+
File.read(template),
|
528
|
+
template,
|
529
|
+
ActionView::Template::Handlers::ERB,
|
530
|
+
:virtual_path => template
|
531
|
+
)
|
532
|
+
|
533
|
+
case t.method(:compile).arity
|
534
|
+
when 2 # Rails 3.1.0+
|
535
|
+
t.send(:compile, ActionView::Base.new, ActionView::CompiledTemplates)
|
536
|
+
when 3
|
537
|
+
t.send(:compile, {}, ActionView::Base.new, ActionView::CompiledTemplates)
|
538
|
+
end
|
539
|
+
|
540
|
+
rescue Exception => e
|
541
|
+
puts "Unable to compile template #{template}"
|
542
|
+
log_error "Unable to compile template #{template} (#{e.message})"
|
543
|
+
end
|
544
|
+
|
545
|
+
}
|
546
|
+
|
547
|
+
puts "Compiled templates: " + ActionView::CompiledTemplates.instance_methods.count.to_s if $options[:verbose]
|
548
|
+
|
549
|
+
end
|
550
|
+
|
551
|
+
def self.compile_haml_templates
|
552
|
+
|
553
|
+
view_paths = []
|
554
|
+
view_paths += ActionController::Base.view_paths.to_a.map(&:to_s)
|
555
|
+
view_paths |= [File.expand_path("app/views")]
|
556
|
+
|
557
|
+
puts "Looking for haml templates in #{view_paths.join(", ")}" if $options[:verbose]
|
558
|
+
|
559
|
+
templates = view_paths.map {|vp|
|
560
|
+
Dir[File.join(vp, "**", "*.haml")]
|
561
|
+
}.flatten
|
562
|
+
|
563
|
+
return unless templates.count > 0
|
564
|
+
|
565
|
+
begin
|
566
|
+
require 'action_view'
|
567
|
+
require 'haml'
|
568
|
+
require 'haml/template/plugin'
|
569
|
+
rescue Exception => e
|
570
|
+
log_error "Unable to satisfy haml dependencies (#{e.message})"
|
571
|
+
return
|
572
|
+
end
|
573
|
+
|
574
|
+
puts "Found #{templates.count} haml templates" if $options[:verbose]
|
575
|
+
|
576
|
+
templates.each {|template|
|
577
|
+
|
578
|
+
puts "Compiling template #{template}" if $options[:verbose]
|
579
|
+
|
580
|
+
begin
|
581
|
+
|
582
|
+
t = ActionView::Template.new(
|
583
|
+
File.read(template),
|
584
|
+
template,
|
585
|
+
Haml::Plugin,
|
586
|
+
:virtual_path => template
|
587
|
+
)
|
588
|
+
|
589
|
+
case t.method(:compile).arity
|
590
|
+
when 2 # Rails 3.1.0+
|
591
|
+
t.send(:compile, ActionView::Base.new, ActionView::CompiledTemplates)
|
592
|
+
when 3
|
593
|
+
t.send(:compile, {}, ActionView::Base.new, ActionView::CompiledTemplates)
|
594
|
+
end
|
595
|
+
|
596
|
+
rescue Exception => e
|
597
|
+
puts "Unable to compile template #{template}"
|
598
|
+
log_error "Unable to compile template #{template} (#{e.message})"
|
599
|
+
end
|
600
|
+
|
601
|
+
}
|
602
|
+
|
603
|
+
puts "Compiled templates: " + ActionView::CompiledTemplates.instance_methods.count.to_s if $options[:verbose]
|
604
|
+
|
605
|
+
end
|
606
|
+
|
607
|
+
|
608
|
+
|
609
|
+
|
610
|
+
################################################################################
|
611
|
+
# Subcommands
|
612
|
+
def self.prepare
|
613
|
+
|
614
|
+
init
|
615
|
+
|
616
|
+
puts "Preparing Ruby on Rails application #{APP_NAME.dump} for Veracode upload"
|
617
|
+
puts "Source code will be included in the archive" if $options[:archive_source]
|
618
|
+
|
619
|
+
if $options[:verbose]
|
620
|
+
puts Dir.pwd.to_s.dump
|
621
|
+
puts
|
622
|
+
end
|
623
|
+
|
624
|
+
if $options[:disasm]
|
625
|
+
rbfiles = File.join("**", "*.rb")
|
626
|
+
Dir[rbfiles].each do |f|
|
627
|
+
puts RubyVM::InstructionSequence.compile_file(f).disasm
|
628
|
+
puts
|
629
|
+
end
|
630
|
+
exit
|
631
|
+
end
|
632
|
+
|
633
|
+
prepare_archive
|
634
|
+
|
635
|
+
################################################################
|
636
|
+
## phase 1 - Create baseline
|
637
|
+
self.baseline
|
638
|
+
|
639
|
+
puts "Phase 1 - Initial State" if $options[:verbose]
|
640
|
+
self.stats if $options[:verbose]
|
641
|
+
|
642
|
+
if $options[:phase1]
|
643
|
+
puts "Processing and disassembling Ruby standard classes and modules"
|
644
|
+
archive(@modules)
|
645
|
+
end
|
646
|
+
## /phase 1 - Create baseline
|
647
|
+
################################################################
|
648
|
+
|
649
|
+
|
650
|
+
|
651
|
+
################################################################
|
652
|
+
## phase 2 - Require rails
|
653
|
+
|
654
|
+
puts "Phase 2 - Load Rails" if $options[:verbose]
|
655
|
+
begin
|
656
|
+
require "rails"
|
657
|
+
rescue Exception => e
|
658
|
+
puts "Unable to require rails: #{e.message}"
|
659
|
+
log_error "Unable to require rails: #{e.message}"
|
660
|
+
exit
|
661
|
+
else
|
662
|
+
puts "Required rails" if $options[:verbose]
|
663
|
+
end
|
664
|
+
|
665
|
+
self.update
|
666
|
+
|
667
|
+
self.stats if $options[:verbose]
|
668
|
+
|
669
|
+
if $options[:phase2]
|
670
|
+
puts "Processing and disassembling Rails classes and modules"
|
671
|
+
archive(@modules)
|
672
|
+
end
|
673
|
+
|
674
|
+
self.rebaseline
|
675
|
+
## /phase 2 - Require rails
|
676
|
+
################################################################
|
677
|
+
|
678
|
+
|
679
|
+
|
680
|
+
################################################################
|
681
|
+
# phase 3 - require app
|
682
|
+
|
683
|
+
puts "Phase 3 - Imitate Rails" if $options[:verbose]
|
684
|
+
|
685
|
+
## Imitate script/rails
|
686
|
+
# APP_PATH = File.expand_path('config/application')
|
687
|
+
# APP_PATH is already set in bin/veracode
|
688
|
+
#require File.expand_path('../../config/boot', __FILE__)
|
689
|
+
glob_require "config/boot.rb"
|
690
|
+
#require 'rails/commands'
|
691
|
+
# this will trigger the console to be launched
|
692
|
+
# ARGV.clear
|
693
|
+
# ARGV << 'console'
|
694
|
+
# ARGV << '--sandbox'
|
695
|
+
# require 'rails/commands'
|
696
|
+
|
697
|
+
## Imitate rails/commands when console
|
698
|
+
glob_require 'rails/commands/console'
|
699
|
+
# require APP_PATH # => config/application.rb
|
700
|
+
|
701
|
+
glob_require "config/application.rb"
|
702
|
+
|
703
|
+
Rails.application.require_environment! unless $options[:jruby]
|
704
|
+
# Following line will actually kick off IRB
|
705
|
+
# Rails::Console.start(Rails.application)
|
706
|
+
|
707
|
+
# Imitate Rails::Console.initialize_console
|
708
|
+
# require "pp"
|
709
|
+
glob_require "rails/console/app"
|
710
|
+
glob_require "rails/console/helpers"
|
711
|
+
|
712
|
+
glob_require "app/models/**/*.rb"
|
713
|
+
glob_require "app/helpers/**/*.rb"
|
714
|
+
glob_require "app/controllers/application_controller.rb"
|
715
|
+
glob_require "app/controllers/**/*.rb"
|
716
|
+
|
717
|
+
compile_erb_templates
|
718
|
+
compile_haml_templates
|
719
|
+
|
720
|
+
self.update
|
721
|
+
self.stats if $options[:verbose]
|
722
|
+
|
723
|
+
if $options[:phase3]
|
724
|
+
puts "Processing and disassembling #{APP_NAME} classes and modules"
|
725
|
+
archive(@baseline_modules, false)
|
726
|
+
archive(@modules - @baseline_modules, true)
|
727
|
+
end
|
728
|
+
|
729
|
+
## /phase 3 - require app
|
730
|
+
################################################################
|
731
|
+
|
732
|
+
finalize_archive
|
733
|
+
|
734
|
+
pack_manifest
|
735
|
+
cleanup
|
736
|
+
|
737
|
+
end # self.prepare
|
738
|
+
|
739
|
+
end
|
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: veracode
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.alpha
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Veracode
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rubyzip
|
16
|
+
requirement: &70257511683960 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70257511683960
|
25
|
+
description: Prepares your Ruby on Rails app for submission to Veracode.
|
26
|
+
email: devcontact@veracode.com
|
27
|
+
executables:
|
28
|
+
- veracode
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- bin/veracode
|
33
|
+
- lib/veracode.rb
|
34
|
+
- lib/veracode/version.rb
|
35
|
+
homepage: http://veracode.com/
|
36
|
+
licenses: []
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 1.9.3.0
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>'
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.3.1
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 1.8.10
|
56
|
+
signing_key:
|
57
|
+
specification_version: 3
|
58
|
+
summary: Command line tool for preparing your Ruby on Rails app for submission to
|
59
|
+
Veracode
|
60
|
+
test_files: []
|