roboscott 0.0.1
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/bin/roboscott +55 -0
- data/lib/roboscott.rb +144 -0
- metadata +46 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 5c681267a2332eebb783cce94b68ceb1757f5cc8
|
|
4
|
+
data.tar.gz: 8d3cb169844fa3afbcbfa5f0b4a606c141043d44
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 08c304cccbd1c4d19eadf8870463811acd1891e1636b4ddf7c4c35b2346df0f35af9ac8fd87edfa86e6e83dd179679b9a47489c303647ccad4aabee69d687953
|
|
7
|
+
data.tar.gz: 205c6ff996af23354b5939ac5df33950b04afd12e8469f6e28655acc8f20198551ce3050181ae9edd3f6aa6e734a8027146ca24962e6fbc3d985094372455dcc
|
data/bin/roboscott
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'getoptlong'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
|
|
6
|
+
begin
|
|
7
|
+
require 'roboscott'
|
|
8
|
+
rescue LoadError
|
|
9
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
10
|
+
require 'roboscott'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
opts = GetoptLong.new(
|
|
14
|
+
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
|
15
|
+
[ '--unredacted', '-u', GetoptLong::NO_ARGUMENT ]
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
config = {}
|
|
19
|
+
|
|
20
|
+
opts.each do |opt, arg|
|
|
21
|
+
case opt
|
|
22
|
+
when '--help'
|
|
23
|
+
puts <<-EOF
|
|
24
|
+
roboscott [OPTION] ... <DIR|Files>
|
|
25
|
+
|
|
26
|
+
-h, --help:
|
|
27
|
+
show help
|
|
28
|
+
|
|
29
|
+
-u, --unredacted:
|
|
30
|
+
log all found suspicious passwords to the console
|
|
31
|
+
|
|
32
|
+
DIR|Files: The directory or files to parse
|
|
33
|
+
EOF
|
|
34
|
+
when '--unredacted'
|
|
35
|
+
puts 'Running in unredacted mode'
|
|
36
|
+
config[:unredacted] = true
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if ARGV.length < 1
|
|
41
|
+
puts "Missing dir argument. Running on current directory (try --help if this isn't intendted)"
|
|
42
|
+
dir = ['.']
|
|
43
|
+
else
|
|
44
|
+
dir = ARGV
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
failed = 0
|
|
48
|
+
|
|
49
|
+
# Okay, enough setting up, let's check some files
|
|
50
|
+
ARGV.each do|file|
|
|
51
|
+
lint = RoboScott.new(file, config)
|
|
52
|
+
failed = failed + lint.do_lint
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
exit failed
|
data/lib/roboscott.rb
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
module Logging
|
|
6
|
+
ESCAPES = { :green => "\033[32m",
|
|
7
|
+
:yellow => "\033[33m",
|
|
8
|
+
:red => "\033[31m",
|
|
9
|
+
:reset => "\033[0m" }
|
|
10
|
+
|
|
11
|
+
def error(message)
|
|
12
|
+
emit(:message => message, :color => :red)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def emit(opts={})
|
|
16
|
+
color = opts[:color]
|
|
17
|
+
message = opts[:message]
|
|
18
|
+
print ESCAPES[color]
|
|
19
|
+
print message
|
|
20
|
+
print ESCAPES[:reset]
|
|
21
|
+
print "\n"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class RoboScott
|
|
26
|
+
include Logging
|
|
27
|
+
|
|
28
|
+
def initialize(file, config={})
|
|
29
|
+
@file = file
|
|
30
|
+
@config = config
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def do_lint
|
|
34
|
+
unless File.exists? @file
|
|
35
|
+
error "File #{@file} does not exist"
|
|
36
|
+
return 0
|
|
37
|
+
else
|
|
38
|
+
if File.directory? @file
|
|
39
|
+
return self.parse_directory @file
|
|
40
|
+
else
|
|
41
|
+
return self.parse_file @file
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def parse_directory(directory)
|
|
47
|
+
Dir.glob("#{directory}/*").inject(0) do |mem, fdir|
|
|
48
|
+
if File.directory? fdir
|
|
49
|
+
mem + parse_directory(fdir)
|
|
50
|
+
else
|
|
51
|
+
mem + parse_file(fdir)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def parse_file(file)
|
|
57
|
+
if (not File.extname(file) =~ /.(yaml|yml)$/) && (not @config[:nocheckfileext])
|
|
58
|
+
# Instead of logging an error, just silently move on. Helps us scan a repo
|
|
59
|
+
return 1
|
|
60
|
+
end
|
|
61
|
+
begin
|
|
62
|
+
yaml = YAML.load_file(file)
|
|
63
|
+
rescue Exception => err
|
|
64
|
+
# Not a yaml file, move on, nothing to see here
|
|
65
|
+
return 1
|
|
66
|
+
else
|
|
67
|
+
traverse(file, yaml ) do |node|
|
|
68
|
+
#puts node
|
|
69
|
+
end
|
|
70
|
+
return 0
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def has_keys?(yaml)
|
|
75
|
+
has_fails = false
|
|
76
|
+
yaml.each do |key, value|
|
|
77
|
+
puts "Key: #{key}"
|
|
78
|
+
if key_looks_important?(key) and value_looks_sensitive?(value)
|
|
79
|
+
has_fails = true
|
|
80
|
+
report_fail(key, value)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
return has_fails
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def key_looks_important?(key)
|
|
87
|
+
if key.class != String
|
|
88
|
+
return false
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# TODO - move bad_words to a config value
|
|
92
|
+
bad_words = ['SECRET', 'TOKEN', 'PASSWORD', 'KEY']
|
|
93
|
+
bad_words.each do |baddy|
|
|
94
|
+
if key.upcase.include? baddy
|
|
95
|
+
return true
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
return false
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def value_looks_sensitive?(val)
|
|
102
|
+
if val == nil or val == ''
|
|
103
|
+
return false
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# TODO - move okay_vals to a config value
|
|
107
|
+
okay_vals = ['ENV', 'DUMMY']
|
|
108
|
+
okay_vals.each do |ok|
|
|
109
|
+
if val.upcase.include? ok
|
|
110
|
+
return false
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
rescue
|
|
114
|
+
return false
|
|
115
|
+
return true
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def report_fail(file, key, value, redacted=true)
|
|
119
|
+
value = 'REDACTED' unless @config[:unredacted]
|
|
120
|
+
|
|
121
|
+
error "File #{file} - The value '#{value}' for key '#{key}' looks sensitive"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def traverse(filename, obj, &blk)
|
|
125
|
+
case obj
|
|
126
|
+
when Hash
|
|
127
|
+
obj.each {|key, val|
|
|
128
|
+
if val.class == Hash
|
|
129
|
+
traverse(filename, val, &blk)
|
|
130
|
+
else
|
|
131
|
+
# In this case the value should be a leaf node (not another hash)
|
|
132
|
+
if key_looks_important?(key) and value_looks_sensitive?(val)
|
|
133
|
+
has_fails = true
|
|
134
|
+
report_fail(filename, key, val)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
}
|
|
138
|
+
when Array
|
|
139
|
+
obj.each {|v| traverse(filename, v, &blk) }
|
|
140
|
+
else
|
|
141
|
+
blk.call(obj)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: roboscott
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Elliot Rushton
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2017-11-20 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Check if YAML files contain secrets that should be in ENV
|
|
14
|
+
email: elliot.rushton@gmail.com
|
|
15
|
+
executables:
|
|
16
|
+
- roboscott
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- bin/roboscott
|
|
21
|
+
- lib/roboscott.rb
|
|
22
|
+
homepage: https://github.com/elliotrushton/roboscott
|
|
23
|
+
licenses:
|
|
24
|
+
- MIT
|
|
25
|
+
metadata: {}
|
|
26
|
+
post_install_message:
|
|
27
|
+
rdoc_options: []
|
|
28
|
+
require_paths:
|
|
29
|
+
- lib
|
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: '0'
|
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
requirements: []
|
|
41
|
+
rubyforge_project:
|
|
42
|
+
rubygems_version: 2.4.5.1
|
|
43
|
+
signing_key:
|
|
44
|
+
specification_version: 4
|
|
45
|
+
summary: Simple secret linter
|
|
46
|
+
test_files: []
|