hakiri 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +2 -1
- data/README.md +21 -3
- data/bin/hakiri +31 -1
- data/hakiri.gemspec +1 -0
- data/lib/hakiri.rb +3 -0
- data/lib/hakiri/cli/gemfile.rb +140 -0
- data/lib/hakiri/cli/system.rb +4 -4
- data/lib/hakiri/http_client.rb +2 -2
- data/lib/hakiri/stack.rb +34 -0
- data/lib/hakiri/version.rb +1 -1
- metadata +19 -2
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Secure Rails with Hakiri
|
2
2
|
|
3
|
-
Hakiri is a command line interface (CLI) for the Hakiri platform. It allows Ruby on Rails developers to automate version scraping of servers, databases and other technologies used in their stacks. For each technology Hakiri shows CVE vulnerabilities. Here is a snippet of how it works:
|
3
|
+
Hakiri is a command line interface (CLI) for the Hakiri platform. It allows Ruby on Rails developers to automate version scraping of Ruby gems, servers, databases and other technologies used in their stacks. For each technology Hakiri shows CVE vulnerabilities. Here is a snippet of how it works:
|
4
4
|
|
5
5
|
~~~
|
6
6
|
$ hakiri system:scan
|
@@ -82,14 +82,32 @@ $ hakiri system:scan -m ../my_stack.json
|
|
82
82
|
|
83
83
|
You can learn more about configuring the manifest in [Hakiri docs](https://www.hakiriup.com/docs/manifest-file).
|
84
84
|
|
85
|
+
## Test Your Gemfile
|
86
|
+
|
87
|
+
Hakiri supports vulnerability detection for a collection of gems listed in [the docs](https://www.hakiriup.com/docs/supported-gems). To scan a `Gemfile.lock` for vulnerabilities in the current directory do the following:
|
88
|
+
|
89
|
+
~~~
|
90
|
+
$ hakiri gemfile:scan
|
91
|
+
~~~
|
92
|
+
|
93
|
+
To scan a specific `Gemfile.lock` add the `-m` parameter at the end:
|
94
|
+
|
95
|
+
~~~
|
96
|
+
$ hakiri gemfile:scan -m ../Gemfile.lock
|
97
|
+
~~~
|
98
|
+
|
99
|
+
This will scan your `Gemfile.lock` and check with the server whether it has any vulnerable gems. It only checks gems that are [supported by Hakiri]((https://www.hakiriup.com/docs/manifest-file)).
|
100
|
+
|
101
|
+
You can also [sync your gems]((https://www.hakiriup.com/docs/syncing-with-the-cloud)) with the cloud and get notified when new vulnerabilities come out.
|
102
|
+
|
85
103
|
## Advanced Usage
|
86
104
|
|
87
105
|
We just went through the most basic Hakiri use case. Here are links to docs describing how to do more:
|
88
106
|
|
89
107
|
- [Learn about](https://www.hakiriup.com/docs/manifest-file) advanced manifest file options.
|
90
108
|
- [Setup your](https://www.hakiriup.com/docs/authentication-token) authentication token.
|
91
|
-
- [Sync your
|
92
|
-
- [Check out technologies](https://www.hakiriup.com/docs/technologies-version-formats) the
|
109
|
+
- [Sync your technologies and gems](https://www.hakiriup.com/docs/syncing-with-the-cloud) with the cloud and get notified when new vulnerabilities come out.
|
110
|
+
- [Check out technologies](https://www.hakiriup.com/docs/technologies-version-formats) the list of supported technologies and version formats.
|
93
111
|
|
94
112
|
## Contribute
|
95
113
|
|
data/bin/hakiri
CHANGED
@@ -35,7 +35,7 @@ end
|
|
35
35
|
|
36
36
|
command 'system:sync' do |c|
|
37
37
|
c.syntax = 'hakiri system:sync [options]'
|
38
|
-
c.summary = 'Sync your system\'s software versions with the
|
38
|
+
c.summary = 'Sync your system\'s software versions with the cloud.'
|
39
39
|
c.description = 'This command grabs your custom stack JSON file, and syncs it with your project on www.hakiriup.com.'
|
40
40
|
c.option '--manifest STRING', String, 'Path to your manifest JSON file stack'
|
41
41
|
c.option '--project INTEGER', Integer, 'Your project ID.'
|
@@ -58,4 +58,34 @@ command 'system:steps' do |c|
|
|
58
58
|
cli = Hakiri::System.new(args, options)
|
59
59
|
cli.steps
|
60
60
|
end
|
61
|
+
end
|
62
|
+
|
63
|
+
command 'gemfile:scan' do |c|
|
64
|
+
c.syntax = 'hakiri gemfile:scan [options]'
|
65
|
+
c.summary = 'Check if Gemfile.lock has any vulnerabilities.'
|
66
|
+
c.description = 'This command grabs your Gemfile.lock file and shows vulnerabilities in it.'
|
67
|
+
c.option '--gemfile STRING', String, 'Path to your Gemfile.lock'
|
68
|
+
|
69
|
+
c.action do |args, options|
|
70
|
+
options.default :gemfile => './Gemfile.lock'
|
71
|
+
|
72
|
+
cli = Hakiri::Gemfile.new(args, options)
|
73
|
+
cli.scan
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
command 'gemfile:sync' do |c|
|
78
|
+
c.syntax = 'hakiri gemfile:sync [options]'
|
79
|
+
c.summary = 'Sync your system\'s Gemfile.lock gem versions with the cloud.'
|
80
|
+
c.description = 'This command grabs your Gemfile.lock file, and syncs it with your project on www.hakiriup.com.'
|
81
|
+
c.option '--gemfile STRING', String, 'Path to your Gemfile.lock'
|
82
|
+
c.option '--project INTEGER', Integer, 'Your project ID.'
|
83
|
+
c.option '--force', 'Force syncing without asking for it first.'
|
84
|
+
|
85
|
+
c.action do |args, options|
|
86
|
+
options.default :gemfile => './Gemfile.lock'
|
87
|
+
options.default :project => nil
|
88
|
+
cli = Hakiri::Gemfile.new(args, options)
|
89
|
+
cli.sync
|
90
|
+
end
|
61
91
|
end
|
data/hakiri.gemspec
CHANGED
data/lib/hakiri.rb
CHANGED
@@ -5,10 +5,13 @@ end
|
|
5
5
|
require 'terminal-table'
|
6
6
|
require 'open-uri'
|
7
7
|
require 'json'
|
8
|
+
require 'bundler'
|
9
|
+
require 'bundler/lockfile_parser'
|
8
10
|
|
9
11
|
require 'hakiri/cli/cli'
|
10
12
|
require 'hakiri/cli/system'
|
11
13
|
require 'hakiri/cli/manifest'
|
14
|
+
require 'hakiri/cli/gemfile'
|
12
15
|
|
13
16
|
require 'hakiri/stack'
|
14
17
|
require 'hakiri/version'
|
@@ -0,0 +1,140 @@
|
|
1
|
+
class Hakiri::Gemfile < Hakiri::Cli
|
2
|
+
#
|
3
|
+
# Walks the user through Gemfile scanning process.
|
4
|
+
#
|
5
|
+
def scan
|
6
|
+
if File.exist? @options.gemfile
|
7
|
+
@stack.build_from_gemfile(@options.gemfile)
|
8
|
+
|
9
|
+
if @stack.technologies.empty?
|
10
|
+
say ' No gems were found in your Gemfile.lock...'
|
11
|
+
else
|
12
|
+
@stack.technologies.each do |technology_slug, payload|
|
13
|
+
say " Found #{payload[:name]} #{payload[:version]}"
|
14
|
+
end
|
15
|
+
|
16
|
+
# GETTING VULNERABILITIES
|
17
|
+
say '-----> Searching for vulnerabilities...'
|
18
|
+
params = ({ :technologies => @stack.technologies }.to_param)
|
19
|
+
response = @http_client.get_issues(params)
|
20
|
+
|
21
|
+
if response[:errors]
|
22
|
+
response[:errors].each do |error|
|
23
|
+
say "! Server Error: #{error}"
|
24
|
+
end
|
25
|
+
else
|
26
|
+
authenticated = response[:meta][:authenticated]
|
27
|
+
|
28
|
+
if response[:technologies].empty?
|
29
|
+
say ' No vulnerabilities found. Keep it up!'
|
30
|
+
else
|
31
|
+
response[:technologies].each do |technology|
|
32
|
+
unless technology[:issues_count] == 0
|
33
|
+
say "! Found #{technology[:issues_count].to_i} #{'vulnerability'.pluralize if technology[:issues_count].to_i != 1} in #{technology[:name]} #{technology[:version]}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
if agree 'Show all of them? (yes or no) '
|
38
|
+
puts ' '
|
39
|
+
response[:technologies].each do |technology|
|
40
|
+
technology[:issues].each do |issue|
|
41
|
+
say issue[:name]
|
42
|
+
say issue[:description]
|
43
|
+
puts ' '
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
unless authenticated
|
49
|
+
say '****** Signup on www.hakiriup.com to get notified when new vulnerabilities come out.'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
else
|
55
|
+
say '! You have to either have a Gemfile.lock in the current directory or setup a parameter `-p` with a path to it.'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Walks the user through Gemfile syncing process.
|
61
|
+
#
|
62
|
+
def sync
|
63
|
+
if @http_client.auth_token
|
64
|
+
@stack.build_from_gemfile(@options.gemfile)
|
65
|
+
|
66
|
+
# GETTING VERSIONS
|
67
|
+
|
68
|
+
if @stack.technologies.empty?
|
69
|
+
say ' No gems were found in your Gemfile.lock...'
|
70
|
+
else
|
71
|
+
@stack.technologies.each do |technology_name, payload|
|
72
|
+
say " Found #{payload[:name]} #{payload[:version]}"
|
73
|
+
end
|
74
|
+
|
75
|
+
# CHECK VERSIONS ON THE SERVER
|
76
|
+
params = { :project_id => @options.project, :technologies => @stack.technologies }
|
77
|
+
say '-----> Checking software versions on www.hakiriup.com...'
|
78
|
+
response = @http_client.check_versions_diff(params)
|
79
|
+
|
80
|
+
if response[:errors]
|
81
|
+
response[:errors].each do |error|
|
82
|
+
say "! Server Error: #{error}"
|
83
|
+
end
|
84
|
+
else
|
85
|
+
if response[:diffs].any?
|
86
|
+
@stack.technologies = {}
|
87
|
+
response[:diffs].each do |diff|
|
88
|
+
if diff[:success]
|
89
|
+
@stack.technologies[diff[:technology][:slug]] = { :version => diff[:system_version] }
|
90
|
+
|
91
|
+
if diff[:hakiri_version]
|
92
|
+
if diff[:system_version_newer]
|
93
|
+
say " System version of #{diff[:technology][:name]} is newer (#{diff[:system_version]} > #{diff[:hakiri_version]})"
|
94
|
+
else
|
95
|
+
say " System version of #{diff[:technology][:name]} is older (#{diff[:system_version]} < #{diff[:hakiri_version]})"
|
96
|
+
end
|
97
|
+
else
|
98
|
+
say " New gem detected: #{diff[:technology][:name]} #{diff[:system_version]}"
|
99
|
+
end
|
100
|
+
else
|
101
|
+
say "! Error in #{diff[:technology][:name]}: #{diff[:errors][:value][0]}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# UPDATE VERSIONS ON THE SERVER
|
106
|
+
unless @options.force
|
107
|
+
update = agree "Do you want to update \"#{response[:project][:name]}\" with system versions? (yes or no) "
|
108
|
+
end
|
109
|
+
|
110
|
+
if update or @options.force
|
111
|
+
say '-----> Syncing versions with www.hakiriup.com...'
|
112
|
+
params = ({ :project_id => @options.project, :technologies => @stack.technologies }.to_param)
|
113
|
+
response = @http_client.sync_project_versions(response[:project][:id], params)
|
114
|
+
|
115
|
+
if response[:errors]
|
116
|
+
response[:errors].each do |error|
|
117
|
+
say "! Server Error: #{error}"
|
118
|
+
end
|
119
|
+
else
|
120
|
+
if response[:updated].any?
|
121
|
+
response[:updated].each do |update|
|
122
|
+
if update[:success]
|
123
|
+
say " #{update[:technology][:name]} was updated to #{update[:new_version]}"
|
124
|
+
else
|
125
|
+
say "! Error syncing #{update[:technology][:name]}: #{update[:errors][:value][0]}"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
else
|
132
|
+
say ' No differences were found. Everything is up to date.'
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
else
|
137
|
+
say '! You have to setup HAKIRI_AUTH_TOKEN environmental variable with your Hakiri authentication token.'
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
data/lib/hakiri/cli/system.rb
CHANGED
@@ -64,10 +64,10 @@ class Hakiri::System < Hakiri::Cli
|
|
64
64
|
# Walks the user through the version syncing process.
|
65
65
|
#
|
66
66
|
def sync
|
67
|
-
@stack.build_from_json_file(@options.manifest)
|
68
|
-
@stack.fetch_versions
|
69
|
-
|
70
67
|
if @http_client.auth_token
|
68
|
+
@stack.build_from_json_file(@options.manifest)
|
69
|
+
@stack.fetch_versions
|
70
|
+
|
71
71
|
# GETTING VERSIONS
|
72
72
|
say '-----> Scanning system for software versions...'
|
73
73
|
|
@@ -79,7 +79,7 @@ class Hakiri::System < Hakiri::Cli
|
|
79
79
|
end
|
80
80
|
|
81
81
|
# CHECK VERSIONS ON THE SERVER
|
82
|
-
params =
|
82
|
+
params = { :project_id => @options.project, :technologies => @stack.technologies }
|
83
83
|
say '-----> Checking software versions on www.hakiriup.com...'
|
84
84
|
response = @http_client.check_versions_diff(params)
|
85
85
|
|
data/lib/hakiri/http_client.rb
CHANGED
@@ -24,7 +24,7 @@ class Hakiri::HttpClient
|
|
24
24
|
# { |response, request, result, &block|
|
25
25
|
# JSON.parse(.to_str, symbolize_names: true)
|
26
26
|
# "! Server Error: #{response.code}"
|
27
|
-
RestClient.
|
27
|
+
RestClient.post "#{@api_url}/issues.json?auth_token=#{@auth_token}", params do |response, request, result, &block|
|
28
28
|
case response.code
|
29
29
|
when 200
|
30
30
|
JSON.parse(response.to_str, :symbolize_names => true)
|
@@ -44,7 +44,7 @@ class Hakiri::HttpClient
|
|
44
44
|
# Returns a hash of differences between technologies.
|
45
45
|
#
|
46
46
|
def check_versions_diff(params)
|
47
|
-
RestClient.
|
47
|
+
RestClient.post "#{@api_url}/versions/diffs.json?auth_token=#{@auth_token}", params do |response, request, result, &block|
|
48
48
|
case response.code
|
49
49
|
when 200
|
50
50
|
JSON.parse(response.to_str, :symbolize_names => true)
|
data/lib/hakiri/stack.rb
CHANGED
@@ -22,6 +22,40 @@ class Hakiri::Stack
|
|
22
22
|
@technologies = JSON.parse(IO.read(json_file))
|
23
23
|
end
|
24
24
|
|
25
|
+
#
|
26
|
+
# Parses a supplied Gemfile.lock and sets stack technologies.
|
27
|
+
#
|
28
|
+
# @param [String] gemfile
|
29
|
+
# Gemfile.lock file.
|
30
|
+
#
|
31
|
+
def build_from_gemfile(gemfile)
|
32
|
+
begin
|
33
|
+
lockfile = Bundler::LockfileParser.new(IO.read(gemfile))
|
34
|
+
|
35
|
+
lockfile.sources.map do |source|
|
36
|
+
case source
|
37
|
+
when Bundler::Source::Git
|
38
|
+
case source.uri
|
39
|
+
when /^git:/, /^http:/
|
40
|
+
say "! Insecure Source: #{source.uri}"
|
41
|
+
end
|
42
|
+
when Bundler::Source::Rubygems
|
43
|
+
source.remotes.each do |uri|
|
44
|
+
if uri.scheme == 'http'
|
45
|
+
say "! Insecure Source: #{uri.to_s}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
lockfile.specs.each do |gem|
|
52
|
+
@technologies[gem.name] = { name: gem.name, version: gem.version.to_s, type: 'gem' }
|
53
|
+
end
|
54
|
+
rescue Exception => e
|
55
|
+
say "! Couldn\'t parse your Gemfile.lock: #{e}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
25
59
|
#
|
26
60
|
# This method analyzes user input from the Hakiri gem and sets up
|
27
61
|
# default commands to retrieve versions.
|
data/lib/hakiri/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hakiri
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-07-
|
12
|
+
date: 2013-07-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !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: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: rake
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -141,6 +157,7 @@ files:
|
|
141
157
|
- hakiri.gemspec
|
142
158
|
- lib/hakiri.rb
|
143
159
|
- lib/hakiri/cli/cli.rb
|
160
|
+
- lib/hakiri/cli/gemfile.rb
|
144
161
|
- lib/hakiri/cli/manifest.json
|
145
162
|
- lib/hakiri/cli/manifest.rb
|
146
163
|
- lib/hakiri/cli/system.rb
|