bundler-organization_audit 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
data/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
2
  gemspec
3
3
 
4
4
  gem "bump"
5
5
  gem "rake"
6
6
  gem "rspec", "~>2"
7
- gem "bundler-audit"
7
+ gem "bundler-audit", :github => "grosser/bundler-audit", :branch => "ignore-version", :submodules => true
data/Gemfile.lock CHANGED
@@ -1,15 +1,22 @@
1
+ GIT
2
+ remote: git://github.com/grosser/bundler-audit.git
3
+ revision: a2d65124650460f525f62c7302629fee4d697413
4
+ branch: ignore-version
5
+ submodules: true
6
+ specs:
7
+ bundler-audit (0.1.3)
8
+ bundler (~> 1.2)
9
+
1
10
  PATH
2
11
  remote: .
3
12
  specs:
4
- bundler-organization_audit (0.1.0)
13
+ bundler-organization_audit (0.1.2)
5
14
  json
6
15
 
7
16
  GEM
8
- remote: http://rubygems.org/
17
+ remote: https://rubygems.org/
9
18
  specs:
10
19
  bump (0.3.9)
11
- bundler-audit (0.1.2)
12
- bundler (~> 1.2)
13
20
  diff-lcs (1.1.3)
14
21
  json (1.7.7)
15
22
  rake (10.0.3)
@@ -27,7 +34,7 @@ PLATFORMS
27
34
 
28
35
  DEPENDENCIES
29
36
  bump
30
- bundler-audit
37
+ bundler-audit!
31
38
  bundler-organization_audit!
32
39
  rake
33
40
  rspec (~> 2)
data/Readme.md CHANGED
@@ -1,7 +1,14 @@
1
1
  Audit all Gemfiles of a user/organization on Github for unpatched versions
2
2
 
3
+ # simple
3
4
  gem install bundler-organization_audit
4
5
 
6
+ # if you want --ignore-cve
7
+ git clone git://github.com/grosser/bundler-organization_audit.git
8
+ cd bundler-organization_audit
9
+ bundle update bundler-audit # get new advisories
10
+ bundle exec ./bin/bundle-organization-audit ... options ...
11
+
5
12
  Usage
6
13
  =====
7
14
 
@@ -27,10 +34,10 @@ Title: Rack Rack::Session::Cookie Function Timing Attack Remote Code Execution
27
34
  Patched Versions: ~> 1.1.6, ~> 1.2.8, ~> 1.3.10, ~> 1.4.5, >= 1.5.2
28
35
 
29
36
  Vulnerable:
30
- https://github.com/grosser/rails_example_app
37
+ https://github.com/grosser/rails_example_app -- Peter Last Committer <peter@last-commit-email.com>
31
38
  ```
32
39
 
33
- For someone elese
40
+ For someone else
34
41
  ```Bash
35
42
  bundle-organization-audit --user grosser
36
43
  ```
@@ -40,16 +47,20 @@ Ignore gems (ignores repos that have a %{repo}.gemspec)
40
47
  bundle-organization-audit --ignore-gems
41
48
  ```
42
49
 
43
- For pipe -> only show vulnerable repos
50
+ Silent: only show vulnerable repos
44
51
  ```
45
52
  bundle-organization-audit 2>/dev/null
46
53
  ```
47
54
 
48
- Use for CI -> ignore old/unmaintained proejcts
55
+ CI: ignore old/unmaintained proejcts, unfixable/unimportant cves and gems
49
56
  ```
50
57
  bundle-organization-audit \
51
58
  --ignore https://github.com/xxx/a \
52
59
  --ignore https://github.com/xxx/b \
60
+ --ignore-cve 2013-0269@1.5.3 \
61
+ --ignore-cve '2013-0123@~>3.2.10' \
62
+ --ignore-cve 2013-0234 \
63
+ --ignore-gems \
53
64
  --organization xxx \
54
65
  --token yyy
55
66
  ```
@@ -64,8 +75,13 @@ enter your password -> TOKEN
64
75
  bundle-organization-audit --user your-user --token TOKEN --organization your-organization
65
76
  ```
66
77
 
67
- Dev
68
- ===
78
+ Related
79
+ =======
80
+ - [holepicker](https://github.com/jsuder/holepicker) does the same check for local projects and running servers
81
+ - [bundler-audit](https://github.com/postmodern/bundler-audit) check a single local project for vulerabilities
82
+
83
+ Development
84
+ ===========
69
85
  - test private repo fetching via `cp spec/private{.example,}.yml` and filling it out
70
86
 
71
87
  Author
@@ -12,6 +12,7 @@ end
12
12
 
13
13
  options = {
14
14
  :ignore => [],
15
+ :ignore_cves => [],
15
16
  :user => git_config("github.user")
16
17
  }
17
18
  OptionParser.new do |opts|
@@ -27,6 +28,7 @@ BANNER
27
28
  opts.on("--user USER", "Use user") { |user| options[:user] = user }
28
29
  opts.on("--ignore REPO_URL", "Ignore given repo urls (use multiple times)") { |repo_url| options[:ignore] << repo_url }
29
30
  opts.on("--ignore-gems", "Ignore repos that have a %{repo}.gemspec") { options[:ignore_gems] = true }
31
+ opts.on("--ignore-cve CVE_NUMBER", "Ignore CVE that you do not want to get warned about just number or number@gem-version") { |cve| options[:ignore_cves] << cve }
30
32
  opts.on("--organization ORGANIZATION", "Use user") { |organization| options[:organization] = organization }
31
33
  opts.on("-h", "--help", "Show this.") { puts opts; exit }
32
34
  opts.on("-v", "--version", "Show Version"){ puts Bundler::OrganizationAudit::VERSION; exit}
@@ -9,8 +9,13 @@ Gem::Specification.new name, Bundler::OrganizationAudit::VERSION do |s|
9
9
  s.homepage = "http://github.com/grosser/#{name}"
10
10
  s.files = `git ls-files`.split("\n")
11
11
  s.license = "MIT"
12
- s.signing_key = File.expand_path("~/.ssh/gem-private_key.pem")
12
+ key = File.expand_path("~/.ssh/gem-private_key.pem")
13
+ if File.exist?(key)
14
+ s.signing_key = key
15
+ s.cert_chain = ["gem-public_cert.pem"]
16
+ else
17
+ puts "No signature"
18
+ end
13
19
  s.executables = ["bundle-organization-audit"]
14
- s.cert_chain = ["gem-public_cert.pem"]
15
20
  s.add_runtime_dependency "json"
16
21
  end
@@ -6,8 +6,7 @@ module Bundler
6
6
  module OrganizationAudit
7
7
  class << self
8
8
  def run(options)
9
- vulnerable = find_vulnerable(options).map(&:url)
10
- vulnerable -= (options[:ignore] || [])
9
+ vulnerable = find_vulnerable(options)
11
10
  if vulnerable.size == 0
12
11
  0
13
12
  else
@@ -19,13 +18,14 @@ module Bundler
19
18
 
20
19
  private
21
20
 
22
- def download_file(repo, file, options)
23
- return unless content = repo.content(file, options)
21
+ def download_file(repo, file)
22
+ return unless content = repo.content(file)
24
23
  File.open(file, "w") { |f| f.write content }
25
24
  end
26
25
 
27
26
  def find_vulnerable(options)
28
27
  Repo.all(options).select do |repo|
28
+ next if (options[:ignore] || []).include? repo.url
29
29
  audit_repo(repo, options)
30
30
  end
31
31
  end
@@ -34,11 +34,15 @@ module Bundler
34
34
  success = false
35
35
  $stderr.puts repo.project
36
36
  in_temp_dir do
37
- if download_file(repo, "Gemfile.lock", options)
38
- if options[:ignore_gems] && repo.gem?(options)
37
+ if download_file(repo, "Gemfile.lock")
38
+ if options[:ignore_gems] && repo.gem?
39
39
  $stderr.puts "Ignored because it's a gem"
40
40
  else
41
- success = !sh("bundle-audit")
41
+ command = "bundle-audit"
42
+ if options[:ignore_cves] && options[:ignore_cves].any?
43
+ command << " --ignore #{options[:ignore_cves].map { |cve| "'CVE-#{cve}'" }.join(" ")}"
44
+ end
45
+ success = !sh(command)
42
46
  end
43
47
  else
44
48
  $stderr.puts "No Gemfile.lock found"
@@ -7,18 +7,22 @@ module Bundler
7
7
  class Repo
8
8
  HOST = "https://api.github.com"
9
9
 
10
- def initialize(data)
10
+ def initialize(data, token=nil)
11
11
  @data = data
12
+ @token = token
12
13
  end
13
14
 
14
- def gem?(options={})
15
- !!content("#{project}.gemspec", options)
15
+ def gem?
16
+ !!content("#{project}.gemspec")
16
17
  end
17
18
 
18
19
  def url
19
20
  api_url.sub("api.", "").sub("/repos", "")
20
21
  end
21
- alias_method :to_s, :url
22
+
23
+ def to_s
24
+ "#{url} -- #{last_commiter}"
25
+ end
22
26
 
23
27
  def project
24
28
  api_url.split("/").last
@@ -34,12 +38,13 @@ module Bundler
34
38
  end
35
39
  url = File.join(HOST, user, "repos")
36
40
 
37
- download_all_pages(url, headers(options[:token])).map { |data| Repo.new(data) }
41
+ token = options[:token]
42
+ download_all_pages(url, headers(token)).map { |data| Repo.new(data, token) }
38
43
  end
39
44
 
40
- def content(file, options={})
45
+ def content(file)
41
46
  if private?
42
- download_content_via_api(file, options)
47
+ download_content_via_api(file)
43
48
  else
44
49
  download_content_via_raw(file)
45
50
  end
@@ -51,13 +56,22 @@ module Bundler
51
56
  @data["private"]
52
57
  end
53
58
 
59
+ def last_commiter
60
+ response = call_api("commits/#{branch}")
61
+ committer = response["commit"]["committer"]
62
+ "#{committer["name"]} <#{committer["email"]}>"
63
+ end
64
+
54
65
  private
55
66
 
56
67
  def self.download_all_pages(url, headers)
57
68
  results = []
58
69
  page = 1
59
70
  loop do
60
- result = JSON.parse(open("#{url}?page=#{page}", headers).read)
71
+ response = decorate_errors do
72
+ open("#{url}?page=#{page}", headers).read
73
+ end
74
+ result = JSON.parse(response)
61
75
  if result.size == 0
62
76
  break
63
77
  else
@@ -81,13 +95,25 @@ module Bundler
81
95
  end
82
96
 
83
97
  # increases api rate limit
84
- def download_content_via_api(file, options)
85
- url = File.join(api_url, "contents", file, "?ref=#{branch}")
86
- content = open(url, self.class.headers(options.fetch(:token))).read
87
- content = JSON.load(content)["content"]
98
+ def download_content_via_api(file)
99
+ content = call_api("contents/#{file}?branch=#{branch}")["content"]
88
100
  Base64.decode64(content)
89
101
  end
90
102
 
103
+ def call_api(path)
104
+ content = self.class.decorate_errors do
105
+ open(File.join(api_url, path), self.class.headers(@token)).read
106
+ end
107
+ JSON.load(content)
108
+ end
109
+
110
+ def self.decorate_errors
111
+ yield
112
+ rescue OpenURI::HTTPError => e
113
+ e.message << " -- body: " << e.io.read
114
+ raise e
115
+ end
116
+
91
117
  # unlimited
92
118
  def download_content_via_raw(file)
93
119
  open(File.join(raw_url, branch, file)).read
@@ -1,5 +1,5 @@
1
1
  module Bundler
2
2
  module OrganizationAudit
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  end
@@ -28,6 +28,12 @@ describe Bundler::OrganizationAudit::Repo do
28
28
  end
29
29
  end
30
30
 
31
+ describe "#last_commiter" do
32
+ it "returns nice info" do
33
+ repo.last_commiter.should == "grosser <grosser.michael@gmail.com>"
34
+ end
35
+ end
36
+
31
37
  describe "#content" do
32
38
  it "can download a public file" do
33
39
  repo.content("Gemfile.lock").should include('rspec (2')
@@ -37,9 +43,9 @@ describe Bundler::OrganizationAudit::Repo do
37
43
  it "can download a private file" do
38
44
  url = "https://api.github.com/repos/#{config["organization"]}/#{config["expected_organization"]}"
39
45
  repo = Bundler::OrganizationAudit::Repo.new(
40
- "url" => url, "private" => true
46
+ {"url" => url, "private" => true}, config["token"]
41
47
  )
42
- content = repo.content("Gemfile.lock", :token => config["token"], :user => config["user"])
48
+ content = repo.content("Gemfile.lock")
43
49
  content.should include('i18n (0.')
44
50
  end
45
51
  end
@@ -64,7 +64,7 @@ describe Bundler::OrganizationAudit do
64
64
 
65
65
  it "only shows failed projects on stdout" do
66
66
  result = audit("--user user-with-unpatched-apps 2>/dev/null", :fail => true, :keep_output => true)
67
- result.should == "https://github.com/user-with-unpatched-apps/unpatched\n"
67
+ result.should == "https://github.com/user-with-unpatched-apps/unpatched -- grosser <grosser.michael@gmail.com>\n"
68
68
  end
69
69
 
70
70
  it "ignores projects in --ignore" do
@@ -72,6 +72,11 @@ describe Bundler::OrganizationAudit do
72
72
  result.should == ""
73
73
  end
74
74
 
75
+ it "ignores CVEs via --ignore-cve" do
76
+ result = audit("--user user-with-unpatched-apps --ignore-cve 2013-0269 2>/dev/null", :keep_output => true)
77
+ result.should == ""
78
+ end
79
+
75
80
  it "shows --version" do
76
81
  audit("--version").should include(Bundler::OrganizationAudit::VERSION)
77
82
  end
data/spec/spec_helper.rb CHANGED
@@ -1 +1,2 @@
1
1
  require "bundler/organization_audit"
2
+ require "yaml"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler-organization_audit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -36,7 +36,7 @@ cert_chain:
36
36
  VHNmKzZNYWVud0FNa0FnSGRzd0dzSnp0T25ObkJhM0YKeTBrQ1NXbUs2RCt4
37
37
  L1NiZlM2cjdLZTA3TVJxemlKZEI5R3VFMSswY0lSdUZoOEVRK0xONkhYQ0tN
38
38
  NXBvbi9HVQp5Y3dNWGZsMAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
39
- date: 2013-02-18 00:00:00.000000000 Z
39
+ date: 2013-03-22 00:00:00.000000000 Z
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: json
@@ -92,7 +92,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
92
92
  version: '0'
93
93
  segments:
94
94
  - 0
95
- hash: 75415256473976345
95
+ hash: -3883081273091798118
96
96
  required_rubygems_version: !ruby/object:Gem::Requirement
97
97
  none: false
98
98
  requirements:
@@ -101,10 +101,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
101
  version: '0'
102
102
  segments:
103
103
  - 0
104
- hash: 75415256473976345
104
+ hash: -3883081273091798118
105
105
  requirements: []
106
106
  rubyforge_project:
107
- rubygems_version: 1.8.24
107
+ rubygems_version: 1.8.25
108
108
  signing_key:
109
109
  specification_version: 3
110
110
  summary: Audit all Gemfiles of a user/organization on github for unpatched versions
metadata.gz.sig CHANGED
Binary file