bundler-security 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ module Security
5
+ module Voting
6
+ # Remote policy settings from Coditsu
7
+ RemotePolicy = Struct.new(:type, :threshold) do
8
+ # How many time gem was marked as safe
9
+ #
10
+ # @return [Integer]
11
+ def approved
12
+ threshold['up'].to_i
13
+ end
14
+
15
+ # How many time gem was marked as malicious
16
+ #
17
+ # @return [Integer]
18
+ def rejected
19
+ threshold['down'].to_i
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'openssl'
5
+ require 'json'
6
+
7
+ module Bundler
8
+ module Security
9
+ module Voting
10
+ # Module responsible for doing request to Coditsu differ
11
+ module Request
12
+ # Differ endpoint url
13
+ ENDPOINT_URL = 'https://diff.coditsu.io/api/bundler.json'
14
+ # Request headers
15
+ HEADERS = { 'Content-Type': 'application/json' }.freeze
16
+
17
+ private_constant :ENDPOINT_URL, :HEADERS
18
+
19
+ class << self
20
+ # Execute request to the differ
21
+ #
22
+ # @param config [OpenStruct] Coditsu config
23
+ # @param payload [Hash] with versions to check
24
+ #
25
+ # @return [Net::HTTPResponse] response from Coditsu differ
26
+ def call(config, payload)
27
+ build_http do |http, uri|
28
+ http.request(build_request(uri, config, payload))
29
+ end
30
+ end
31
+
32
+ # Builds http connection object
33
+ def build_http
34
+ uri = URI(differ_url)
35
+
36
+ Net::HTTP.start(
37
+ uri.host,
38
+ uri.port,
39
+ use_ssl: uri.scheme == 'https',
40
+ verify_mode: OpenSSL::SSL::VERIFY_NONE
41
+ ) { |http| yield(http, uri) }
42
+ end
43
+
44
+ # Build http post request and assigns headers and payload
45
+ #
46
+ # @param uri [URI::HTTPS]
47
+ # @param config [OpenStruct] Coditsu config
48
+ # @param payload [Hash] with versions to check
49
+ #
50
+ # @return [Net::HTTP::Post]
51
+ def build_request(uri, config, payload)
52
+ Net::HTTP::Post
53
+ .new(uri.request_uri, HEADERS)
54
+ .tap { |request| assign_auth(request, config) }
55
+ .tap { |request| assign_payload(request, payload) }
56
+ end
57
+
58
+ # Assigns basic authorization if provided in the config
59
+ #
60
+ # @param request [Net::HTTP::Post] prepared http post
61
+ # @param config [OpenStruct] Coditsu config
62
+ def assign_auth(request, config)
63
+ return unless config
64
+ return unless config.api_key
65
+ return unless config.api_secret
66
+
67
+ request.basic_auth(config.api_key, config.api_secret)
68
+ end
69
+
70
+ # Assigns payload as json
71
+ #
72
+ # @param request [Net::HTTP::Post] prepared http post
73
+ # @param payload [Hash] with versions to check
74
+ def assign_payload(request, payload)
75
+ request.body = JSON.dump(payload)
76
+ end
77
+
78
+ # Provides differ endpoint url
79
+ #
80
+ # @return [String]
81
+ def differ_url
82
+ ENV['CODITSU_DIFFER_URL'] || ENDPOINT_URL
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ module Security
5
+ module Voting
6
+ # Module responsible for handling both local and remote gem versions
7
+ module Versions
8
+ # Module responsible for preparing current or current/new versions of gems
9
+ module Local
10
+ class << self
11
+ # Definition of a local path, if it matches it means that we are the source
12
+ ME_PATH = '.'
13
+ # Sources that we expect to match ourselves too
14
+ ME_SOURCES = [
15
+ Bundler::Source::Gemspec,
16
+ Bundler::Source::Path
17
+ ].freeze
18
+
19
+ # @param command [String] either install or update
20
+ # @param definition [Bundler::Definition] definition for your source
21
+ def call(command, definition)
22
+ Bundler.ui.silence { definition.resolve_remotely! }
23
+
24
+ case command
25
+ when Commands::INSTALL then build_install(definition)
26
+ when Commands::UPDATE then build_update(definition)
27
+ else
28
+ raise ArgumentError, "invalid command: #{command}"
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ # @param definition [Bundler::Definition] definition for your source
35
+ def build_install(definition)
36
+ requested_specs = definition.requested_specs
37
+ locked_specs = definition.locked_gems.specs
38
+ introduced = requested_specs.map(&:name) - locked_specs.map(&:name)
39
+ introduced_specs = requested_specs.select { |spec| introduced.include?(spec.name) }
40
+ introduced_specs.concat(locked_specs)
41
+
42
+ introduced_specs.each_with_object({}) do |spec, hash|
43
+ next if skip?(spec.source)
44
+
45
+ hash[spec.name] = ['', spec.version.to_s]
46
+ end
47
+ end
48
+
49
+ # @param definition [Bundler::Definition] definition for your source
50
+ def build_update(definition)
51
+ locked_specs = definition.locked_gems.specs
52
+
53
+ definition.requested_specs.each_with_object({}) do |spec, hash|
54
+ next if skip?(spec.source)
55
+
56
+ locked_spec = locked_specs.find { |s| s.name == spec.name }
57
+
58
+ hash[spec.name] = if locked_spec
59
+ [locked_spec.version.to_s, spec.version.to_s]
60
+ else
61
+ ['', spec.version.to_s]
62
+ end
63
+ end
64
+ end
65
+
66
+ # Checks if we should skip a source
67
+ #
68
+ # @param source [Bundler::Source::Git, Bundler::Source::Rubygems]
69
+ #
70
+ # @return [Boolean] true if we should skip this source, false otherwise
71
+ def skip?(source)
72
+ return true if git?(source)
73
+ return true if me?(source)
74
+
75
+ false
76
+ end
77
+
78
+ # Checks if it's a git source
79
+ #
80
+ # @param source [Bundler::Source::Git, Bundler::Source::Rubygems]
81
+ #
82
+ # @return [Boolean] true if it's a git source, false otherwise
83
+ def git?(source)
84
+ source.instance_of?(Bundler::Source::Git)
85
+ end
86
+
87
+ # Checks if it's a self source, this happens for repositories that are a gem
88
+ #
89
+ # @param source [Bundler::Source::Path,Bundler::Source::Git,Bundler::Source::Rubygems]
90
+ #
91
+ # @return [Boolean] true if it's a self source, false otherwise
92
+ def me?(source)
93
+ return false unless ME_SOURCES.include?(source.class)
94
+
95
+ source.path.to_s == ME_PATH
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Bundler
6
+ module Security
7
+ module Voting
8
+ # Module responsible for handling both local and remote gem versions
9
+ module Versions
10
+ # Module responsible for fetching safe/malicious votes
11
+ # for current or current/new versions of gems
12
+ module Remote
13
+ # Differ bundler url
14
+ ENDPOINT_URL = 'https://diff.coditsu.io/api/bundler.json'
15
+
16
+ private_constant :ENDPOINT_URL
17
+
18
+ class << self
19
+ # @param command [String] either install or update
20
+ # @param definition [Bundler::Definition] definition for your source
21
+ def call(command, definition)
22
+ config = fetch_config
23
+
24
+ Request
25
+ .call(config, payload(command, config&.repository_id, definition))
26
+ .then { |response| JSON.parse(response.body) }
27
+ end
28
+
29
+ # @param command [String] either install or update
30
+ # @param repository_id [String] coditsu repository_id
31
+ # @param definition [Bundler::Definition] definition for your source
32
+ #
33
+ # @return [Hash] payload for differ bundler endpoint
34
+ def payload(command, repository_id, definition)
35
+ Local.call(command, definition).each_with_object({}) do |(name, versions), hash|
36
+ hash[:data] ||= {}
37
+ hash[:data][:repository_id] = repository_id if repository_id
38
+ hash[:data][:gems] ||= {}
39
+ hash[:data][:gems][name] = versions
40
+ end
41
+ end
42
+
43
+ # Fetch coditsu config file
44
+ #
45
+ # @return [OpenStruct, nil] configuration object
46
+ #
47
+ # @raise [Errors::MissingConfigurationFile] when no config file
48
+ def fetch_config
49
+ Config::Fetcher.call(
50
+ File.expand_path('..', Bundler.bin_path)
51
+ )
52
+ rescue Errors::MissingConfigurationFile
53
+ nil
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
data/plugins.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/security'
4
+
5
+ Bundler::Security.register
metadata CHANGED
@@ -1,65 +1,107 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler-security
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
- - Maciej Mensfeld
7
+ - Tomasz Pajor
8
8
  autorequire:
9
- bindir: exe
10
- cert_chain: []
11
- date: 2019-10-24 00:00:00.000000000 Z
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIEODCCAqCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhtYWNp
14
+ ZWovREM9bWVuc2ZlbGQvREM9cGwwHhcNMTkwNzMwMTQ1NDU0WhcNMjAwNzI5MTQ1
15
+ NDU0WjAjMSEwHwYDVQQDDBhtYWNpZWovREM9bWVuc2ZlbGQvREM9cGwwggGiMA0G
16
+ CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC9fCwtaHZG2SyyNXiH8r0QbJQx/xxl
17
+ dkvwWz9QGJO+O8rEx20FB1Ab+MVkfOscwIv5jWpmk1U9whzDPl1uFtIbgu+sk+Zb
18
+ uQlZyK/DPN6c+/BbBL+RryTBRyvkPLoCVwm7uxc/JZ1n4AI6eF4cCZ2ieZ9QgQbU
19
+ MQs2QPqs9hT50Ez/40GnOdadVfiDDGz+NME2C4ms0BriXwZ1tcRTfJIHe2xjIbbb
20
+ y5qRGfsLKcgMzvLQR24olixyX1MR0s4+Wveq3QL/gBhL4veUcv+UABJA8IJR0kyB
21
+ seHHutusiwZ1v3SjjjW1xLLrc2ARV0mgCb0WaK2T4iA3oFTGLh6Ydz8LNl31KQFv
22
+ 94nRd8IhmJxrhQ6dQ/WT9IXoa5S9lfT5lPJeINemH4/6QPABzf9W2IZlCdI9wCdB
23
+ TBaw57MKneGAYZiKjw6OALSy2ltQUCl3RqFl3VP7n8uFy1U987Q5VIIQ3O1UUsQD
24
+ Oe/h+r7GUU4RSPKgPlrwvW9bD/UQ+zF51v8CAwEAAaN3MHUwCQYDVR0TBAIwADAL
25
+ BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFJNIBHdfEUD7TqHqIer2YhWaWhwcMB0GA1Ud
26
+ EQQWMBSBEm1hY2llakBtZW5zZmVsZC5wbDAdBgNVHRIEFjAUgRJtYWNpZWpAbWVu
27
+ c2ZlbGQucGwwDQYJKoZIhvcNAQELBQADggGBAKA4eqko6BTNhlysip6rfBkVTGri
28
+ ZXsL+kRb2hLvsQJS/kLyM21oMlu+LN0aPj3qEFR8mE/YeDD8rLAfruBRTltPNbR7
29
+ xA5eE1gkxY5LfExUtK3b2wPqfmo7mZgfcsMwfYg/tUXw1WpBCnrhAJodpGH6SXmp
30
+ A40qFUZst0vjiOoO+aTblIHPmMJXoZ3K42dTlNKlEiDKUWMRKSgpjjYGEYalFNWI
31
+ hHfCz2r8L2t+dYdMZg1JGbEkq4ADGsAA8ioZIpJd7V4hI17u5TCdi7X5wh/0gN0E
32
+ CgP+nLox3D+l2q0QuQEkayr+auFYkzTCkF+BmEk1D0Ru4mcf3F4CJvEmW4Pzbjqt
33
+ i1tsCWPtJ4E/UUKnKaWKqGbjrjHJ0MuShYzHkodox5IOiCXIQg+1+YSzfXUV6WEK
34
+ KJG/fhg1JV5vVDdVy6x+tv5SQ5ctU0feCsVfESi3rE3zRd+nvzE9HcZ5aXeL1UtJ
35
+ nT5Xrioegu2w1jPyVEgyZgTZC5rvD0nNS5sFNQ==
36
+ -----END CERTIFICATE-----
37
+ date: 2019-11-11 00:00:00.000000000 Z
12
38
  dependencies:
13
39
  - !ruby/object:Gem::Dependency
14
40
  name: bundler
15
41
  requirement: !ruby/object:Gem::Requirement
16
42
  requirements:
17
- - - "~>"
43
+ - - ">="
18
44
  - !ruby/object:Gem::Version
19
- version: '2.0'
45
+ version: '0'
20
46
  type: :development
21
47
  prerelease: false
22
48
  version_requirements: !ruby/object:Gem::Requirement
23
49
  requirements:
24
- - - "~>"
50
+ - - ">="
25
51
  - !ruby/object:Gem::Version
26
- version: '2.0'
52
+ version: '0'
27
53
  - !ruby/object:Gem::Dependency
28
54
  name: rake
29
55
  requirement: !ruby/object:Gem::Requirement
30
56
  requirements:
31
- - - "~>"
57
+ - - ">="
32
58
  - !ruby/object:Gem::Version
33
- version: '10.0'
59
+ version: '0'
34
60
  type: :development
35
61
  prerelease: false
36
62
  version_requirements: !ruby/object:Gem::Requirement
37
63
  requirements:
38
- - - "~>"
64
+ - - ">="
39
65
  - !ruby/object:Gem::Version
40
- version: '10.0'
41
- description: Gem placeholder for gem that is under development.
66
+ version: '0'
67
+ description: Bundler Security
42
68
  email:
43
- - maciej@mensfeld.pl
69
+ - tomek@coditsu.io
44
70
  executables: []
45
71
  extensions: []
46
72
  extra_rdoc_files: []
47
73
  files:
74
+ - ".circleci/config.yml"
75
+ - ".coditsu/ci.yml"
48
76
  - ".gitignore"
77
+ - ".ruby-version"
49
78
  - Gemfile
50
- - LICENSE.txt
79
+ - Gemfile.lock
80
+ - LICENSE
51
81
  - README.md
52
- - Rakefile
53
- - bin/console
54
- - bin/setup
55
82
  - bundler-security.gemspec
83
+ - certs/mensfeld.pem
56
84
  - lib/bundler/security.rb
85
+ - lib/bundler/security/commands.rb
86
+ - lib/bundler/security/config/fetcher.rb
87
+ - lib/bundler/security/config/file_finder.rb
88
+ - lib/bundler/security/errors.rb
57
89
  - lib/bundler/security/version.rb
90
+ - lib/bundler/security/voting.rb
91
+ - lib/bundler/security/voting/build_failure.rb
92
+ - lib/bundler/security/voting/build_success.rb
93
+ - lib/bundler/security/voting/build_unsafe_gem.rb
94
+ - lib/bundler/security/voting/gem_policy.rb
95
+ - lib/bundler/security/voting/remote_policy.rb
96
+ - lib/bundler/security/voting/request.rb
97
+ - lib/bundler/security/voting/versions/local.rb
98
+ - lib/bundler/security/voting/versions/remote.rb
99
+ - plugins.rb
58
100
  homepage: https://diff.coditsu.io
59
101
  licenses:
60
- - LGPL3
102
+ - MIT
61
103
  metadata:
62
- homepage_uri: https://diff.coditsu.io
104
+ allowed_push_host: https://rubygems.org
63
105
  post_install_message:
64
106
  rdoc_options: []
65
107
  require_paths:
@@ -78,5 +120,5 @@ requirements: []
78
120
  rubygems_version: 3.0.3
79
121
  signing_key:
80
122
  specification_version: 4
81
- summary: Gem placeholder
123
+ summary: Bundler Security
82
124
  test_files: []
metadata.gz.sig ADDED
Binary file
data/LICENSE.txt DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2019 Maciej Mensfeld
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
data/Rakefile DELETED
@@ -1,2 +0,0 @@
1
- require "bundler/gem_tasks"
2
- task :default => :spec