bundler-organization_audit 0.1.0 → 0.1.2

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.
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