hakiri 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hakiri (0.3.1)
4
+ hakiri (0.3.2)
5
5
  active_support
6
+ bundler
6
7
  commander
7
8
  i18n
8
9
  json_pure
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 stack technologies](https://www.hakiriup.com/docs/stack-syncing) with the cloud and get notified when new vulnerabilities come out.
92
- - [Check out technologies](https://www.hakiriup.com/docs/technologies-version-formats) the lsit of supported technologies and version formats.
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 server.'
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
@@ -14,6 +14,7 @@ Gem::Specification.new do |s|
14
14
  s.homepage = 'https://www.hakiriup.com'
15
15
  s.license = 'MIT'
16
16
 
17
+ s.add_dependency 'bundler'
17
18
  s.add_dependency 'rake'
18
19
  s.add_dependency 'commander'
19
20
  s.add_dependency 'terminal-table'
@@ -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
@@ -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 = ({ :project_id => @options.project, :technologies => @stack.technologies }.to_param)
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
 
@@ -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.get "#{@api_url}/issues.json?auth_token=#{@auth_token}&#{params}" do |response, request, result, &block|
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.get "#{@api_url}/versions/diffs.json?auth_token=#{@auth_token}&#{params}" do |response, request, result, &block|
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)
@@ -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.
@@ -1,3 +1,3 @@
1
1
  module Hakiri
2
- VERSION = '0.3.2'
2
+ VERSION = '0.4.0'
3
3
  end
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.3.2
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-01 00:00:00.000000000 Z
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