bundler-security 0.0.1 → 0.1.0

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