diffend 0.2.29 → 0.2.30

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c978cd44ce6f9c52de63870eea0ccf2534b851a1034318447d60afb08998479
4
- data.tar.gz: 220475fd0f2f47b16ebd3882cd602e45475d0f1dc92cb9cdc21f41996940c305
3
+ metadata.gz: 52618cdf40375202e18c1cdaa481554084f3b92f337fd61c089e147f0027e982
4
+ data.tar.gz: 859f390055e3030d3a357b604067e6c05814f653225a802136563be4bc32f9ee
5
5
  SHA512:
6
- metadata.gz: eb0966e3eecffe872a833ad135004ff177fa3d8e1930dec40533fc62fc71af4047f075512b6df9cb1f898d3654ce2303ce9fcee17c55c1dd1d212da3f27d249d
7
- data.tar.gz: 7d2baad903c1425fdfe8f9f64f2cd741f9de01a504333307e82bab6066d36b968177549d23846e3bca66a87532687058ba39c78b802e8cd3bfc0f3406820c644
6
+ metadata.gz: 9f17436faa3bdabe77c891c930bb9dac01f426ae715d37035d7727112e221526ac003daa44d196dbb056f4c21bca49589a7799e36bef81db6bf8b3c29012adb5
7
+ data.tar.gz: 232310953c6dc8cd500aac54b0fd8d7f9980457b40032021b46bf7753f62c8a7d6167486c3e15e0d2e940101b47b8b8cdd8af67577eca7ba626b2db9706724c6
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## [Unreleased][master]
4
4
 
5
+ ## [0.2.30] (2020-09-21)
6
+ - handle dependencies resolve issues ([#51](https://github.com/diffend-io/diffend-ruby/pull/51))
7
+ - better detection when to start `Diffend::Monitor` ([#50](https://github.com/diffend-io/diffend-ruby/pull/50))
8
+ - cleanup structure ([#47](https://github.com/diffend-io/diffend-ruby/pull/47))
9
+
5
10
  ## [0.2.29] (2020-09-21)
6
11
  - fix command reporting on jruby ([#48](https://github.com/diffend-io/diffend-ruby/pull/48))
7
12
 
@@ -67,7 +72,8 @@
67
72
 
68
73
  - initial release
69
74
 
70
- [master]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.29...HEAD
75
+ [master]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.30...HEAD
76
+ [0.2.30]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.29...v0.2.30
71
77
  [0.2.29]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.28...v0.2.29
72
78
  [0.2.28]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.27...v0.2.28
73
79
  [0.2.27]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.26...v0.2.27
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- diffend (0.2.29)
4
+ diffend (0.2.30)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -2,7 +2,7 @@
2
2
 
3
3
  lib = File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'diffend'
5
+ require 'diffend/version'
6
6
 
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = 'diffend'
@@ -11,8 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.email = ['contact@diffend.io']
12
12
 
13
13
  spec.summary = 'OSS supply chain security and management platform'
14
- spec.summary = 'OSS supply chain security and management platform.'
15
- spec.homepage = Diffend::HOMEPAGE
14
+ spec.homepage = 'https://diffend.io'
16
15
  spec.license = 'Prosperity Public License'
17
16
 
18
17
  if $PROGRAM_NAME.end_with?('gem')
@@ -1,142 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- %w[
4
- bundler
5
- ].each(&method(:require))
6
-
7
- %w[
8
- build_bundler_definition
9
- errors
10
- config/fetcher
11
- config/file_finder
12
- config/validator
13
- commands
14
- handle_errors/messages
15
- handle_errors/build_exception_payload
16
- handle_errors/display_to_stdout
17
- handle_errors/report
18
- request_object
19
- request
20
- voting
21
- track
22
- ].each { |file| require "diffend/#{file}" }
23
-
24
- %w[
25
- versions/local
26
- versions/remote
27
- ].each { |file| require "diffend/voting/#{file}" }
28
-
29
- # Diffend main namespace
30
3
  module Diffend
31
- # Current plugin version
32
- VERSION = '0.2.29'
33
- # Diffend homepage
34
- HOMEPAGE = 'https://diffend.io'
35
-
36
- class << self
37
- # Registers the plugin and add before install all hook
38
- def register
39
- Bundler::Plugin.add_hook('before-install-all') do |_|
40
- execute
41
- end
42
- end
43
-
44
- # Execute diffend plugin
45
- def execute
46
- return unless enabled?
47
-
48
- verify_version
49
-
50
- config = fetch_config
51
-
52
- Diffend::Voting.call(
53
- command,
54
- config,
55
- Diffend::BuildBundlerDefinition.call(
56
- command,
57
- Bundler.default_gemfile,
58
- Bundler.default_lockfile
59
- )
60
- )
61
- rescue Diffend::Errors::HandledException
62
- return if ENV['DIFFEND_IGNORE_ERRORS'] == 'true'
63
-
64
- exit 255
65
- rescue StandardError => e
66
- Diffend::HandleErrors::Report.call(
67
- exception: e,
68
- config: config,
69
- message: :unhandled_exception,
70
- report: true,
71
- raise_exception: false
72
- )
73
-
74
- return if ENV['DIFFEND_IGNORE_ERRORS'] == 'true'
75
-
76
- exit 255
77
- end
78
-
79
- def verify_version
80
- return if ENV['DIFFEND_DEVELOPMENT'] == 'true'
81
- return if installed_version == VERSION
82
-
83
- build_outdated_version_message(installed_version)
84
- .tap(&Bundler.ui.method(:error))
85
-
86
- exit 2
87
- end
88
-
89
- # @return [String] installed plugin version
90
- def installed_version
91
- Bundler::Plugin
92
- .index
93
- .plugin_path('diffend')
94
- .basename
95
- .to_s
96
- .split('-')
97
- .last
98
- end
99
-
100
- # Checks if plugin is enabled
101
- #
102
- # @return [Boolean] true if enabled, false otherwise
103
- def enabled?
104
- Bundler
105
- .default_gemfile
106
- .read
107
- .split("\n")
108
- .reject(&:empty?)
109
- .map(&:strip)
110
- .select { |line| line.start_with?('plugin') }
111
- .any? { |line| line.include?('diffend') }
112
- end
113
-
114
- # @param version [Hash] installed version
115
- #
116
- # @return [String]
117
- def build_outdated_version_message(version)
118
- <<~MSG
119
- \nYou are running an outdated version (#{version}) of the plugin, which will lead to issues.
120
- \nPlease upgrade to the latest one (#{VERSION}) by executing "rm -rf .bundle/plugin".\n
121
- MSG
122
- end
123
-
124
- # Command that was run with bundle
125
- #
126
- # @return [String]
127
- def command
128
- ARGV.first || Bundler.feature_flag.default_cli_command.to_s
129
- end
130
-
131
- # Fetch diffend config file
132
- #
133
- # @return [OpenStruct, nil] configuration object
134
- #
135
- # @raise [Errors::MissingConfigurationFile] when no config file
136
- def fetch_config
137
- Config::Fetcher.call(
138
- File.expand_path('..', Bundler.bin_path)
139
- )
140
- end
141
- end
142
4
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ # Diffend config object
5
+ module Config
6
+ class << self
7
+ # Build diffend config object
8
+ #
9
+ # @return [OpenStruct, nil]
10
+ #
11
+ # @raise [Errors::MissingConfigurationFile] when no config file
12
+ def call
13
+ Diffend::Config::Fetcher.call(
14
+ File.expand_path('..', ::Bundler.bin_path)
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
@@ -23,5 +23,7 @@ module Diffend
23
23
  RequestServerError = Class.new(BaseError)
24
24
  # Raised when we had an exception that we know how to handle
25
25
  HandledException = Class.new(BaseError)
26
+ # Raised when we are unable to resolve dependencies
27
+ DependenciesResolveException = Class.new(BaseError)
26
28
  end
27
29
  end
@@ -1,18 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Diffend
4
- # Verifies voting verdicts for gems
5
- module Voting
4
+ # Executes a check for a given command
5
+ module Execute
6
6
  class << self
7
7
  # Build verdict
8
8
  #
9
9
  # @param command [String] either install or update
10
10
  # @param config [OpenStruct] diffend config
11
- # @param definition [Bundler::Definition] definition for your source
12
- def call(command, config, definition)
13
- Versions::Remote
14
- .call(command, config, definition)
11
+ def call(command, config)
12
+ Diffend::RequestVerdict
13
+ .call(command, config, build_definition(command))
15
14
  .tap { |response| build_message(command, config, response) }
15
+ rescue Diffend::Errors::DependenciesResolveException
16
+ # We are unable to resolve dependencies, no message will be printed
17
+ end
18
+
19
+ # Build bundler definition
20
+ #
21
+ # @return [Bundler::Definition]
22
+ def build_definition(command)
23
+ Diffend::BuildBundlerDefinition.call(
24
+ command,
25
+ Bundler.default_gemfile,
26
+ Bundler.default_lockfile
27
+ )
16
28
  end
17
29
 
18
30
  # @param command [String] either install or update
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ # Module responsible for building local context
5
+ module LocalContext
6
+ class << self
7
+ # Build diffend, host, packages, and platform specific information
8
+ #
9
+ # @param command [String] either install or update
10
+ # @param project_id [String] diffend project_id
11
+ # @param definition [Bundler::Definition] definition for your source
12
+ #
13
+ # @return [Hash] payload for diffend endpoint
14
+ def call(command, project_id, definition)
15
+ {
16
+ 'diffend' => Diffend.call(project_id),
17
+ 'host' => Host.call,
18
+ 'packages' => Packages.call(command, definition),
19
+ 'platform' => Platform.call
20
+ }.freeze
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ # Module responsible for building local context
5
+ module LocalContext
6
+ # Module responsible for building diffend information from local context
7
+ module Diffend
8
+ # API version
9
+ API_VERSION = '0.1'
10
+ # Platform type ruby
11
+ PLATFORM_TYPE = 0
12
+
13
+ private_constant :API_VERSION, :PLATFORM_TYPE
14
+
15
+ class << self
16
+ # Build diffend information
17
+ #
18
+ # @param project_id [String, nil] diffend project_id
19
+ #
20
+ # @return [Hash]
21
+ def call(project_id)
22
+ {
23
+ 'api_version' => API_VERSION,
24
+ 'environment' => ENV['DIFFEND_ENV'],
25
+ 'project_id' => project_id,
26
+ 'type' => PLATFORM_TYPE,
27
+ 'version' => ::Diffend::VERSION
28
+ }.freeze
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'etc'
4
+
5
+ module Diffend
6
+ # Module responsible for building local context
7
+ module LocalContext
8
+ # Module responsible for building host information from local context
9
+ module Host
10
+ class << self
11
+ # Build host information
12
+ #
13
+ # @return [Hash]
14
+ def call
15
+ uname = Etc.uname
16
+
17
+ {
18
+ 'command' => command,
19
+ 'ips' => ips,
20
+ 'name' => uname[:nodename],
21
+ 'system' => {
22
+ 'machine' => uname[:machine],
23
+ 'name' => uname[:sysname],
24
+ 'release' => uname[:release],
25
+ 'version' => uname[:version]
26
+ },
27
+ 'tags' => tags,
28
+ 'user' => Etc.getpwuid(Process.uid).name,
29
+ 'pid' => Process.pid
30
+ }.freeze
31
+ end
32
+
33
+ private
34
+
35
+ # Build host command information
36
+ #
37
+ # @return [Hash]
38
+ def command
39
+ if File.exist?($PROGRAM_NAME)
40
+ if defined?(JRUBY_VERSION)
41
+ name = $PROGRAM_NAME.split('/').last.strip
42
+ command = "#{name} #{ARGV.join(' ')}"
43
+ else
44
+ array = `ps -p #{Process.pid} -o command=`.strip.split(' ')
45
+ array.shift if array.first.end_with?('bin/ruby')
46
+ name = array.shift.split('/').last.strip
47
+ command = "#{name} #{array.join(' ')}"
48
+ end
49
+
50
+ { 'name' => command, 'title' => '' }
51
+ else
52
+ { 'name' => ARGV.join(' '), 'title' => $PROGRAM_NAME }
53
+ end
54
+ end
55
+
56
+ # Build host ips, except localhost and loopback
57
+ #
58
+ # @return [Array<String>]
59
+ def ips
60
+ Socket.ip_address_list.map do |ip|
61
+ next if ip.ipv4_loopback? || ip.ipv6_loopback? || ip.ipv6_linklocal?
62
+
63
+ ip.ip_address
64
+ end.compact
65
+ end
66
+
67
+ # Build host tags
68
+ #
69
+ # @return [Array]
70
+ def tags
71
+ tags = []
72
+
73
+ if ENV.key?('GITHUB_ACTIONS')
74
+ tags << 'ci'
75
+ tags << 'ci-github'
76
+ end
77
+
78
+ if ENV.key?('CIRCLECI')
79
+ tags << 'ci'
80
+ tags << 'ci-circle'
81
+ end
82
+
83
+ tags
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,302 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ # Module responsible for building local context
5
+ module LocalContext
6
+ # Module responsible for building packages information from local context
7
+ class Packages
8
+ # Definition of a local path, if it matches it means that we are the source
9
+ ME_PATH = '.'
10
+ # Sources that we expect to match ourselves too
11
+ ME_SOURCES = [
12
+ Bundler::Source::Gemspec,
13
+ Bundler::Source::Path
14
+ ].freeze
15
+ # List of dependency types
16
+ DEPENDENCIES_TYPES = {
17
+ direct: 0,
18
+ dependency: 1
19
+ }.freeze
20
+ # List of sources types
21
+ SOURCES_TYPES = {
22
+ valid: 0,
23
+ multiple_primary: 1
24
+ }.freeze
25
+ # List of gem sources types
26
+ GEM_SOURCES_TYPES = {
27
+ local: 0,
28
+ gemfile_source: 1,
29
+ gemfile_git: 2,
30
+ gemfile_path: 3
31
+ }.freeze
32
+
33
+ class << self
34
+ # @param command [String] either install or update
35
+ # @param definition [Bundler::Definition] definition for your source
36
+ def call(command, definition)
37
+ Bundler.ui.silence { definition.resolve_remotely! }
38
+
39
+ instance = new(definition)
40
+
41
+ case command
42
+ when Commands::INSTALL, Commands::EXEC then instance.build_install
43
+ when Commands::UPDATE then instance.build_update
44
+ else
45
+ raise ArgumentError, "invalid command: #{command}"
46
+ end
47
+ end
48
+ end
49
+
50
+ # @param definition [Bundler::Definition] definition for your source
51
+ #
52
+ # @return [Hash] local dependencies
53
+ def initialize(definition)
54
+ @definition = definition
55
+ @direct_dependencies = Hash[definition.dependencies.map { |val| [val.name, val] }]
56
+ # Support case without Gemfile.lock
57
+ @locked_specs = @definition.locked_gems ? @definition.locked_gems.specs : []
58
+ end
59
+
60
+ # Build install specification
61
+ #
62
+ # @return [Hash]
63
+ def build_install
64
+ hash = build_main
65
+
66
+ @definition.specs.each do |spec|
67
+ next if skip?(spec.source)
68
+
69
+ locked_spec = @locked_specs.find { |s| s.name == spec.name }
70
+
71
+ hash['dependencies'][spec.name] = {
72
+ 'platform' => build_spec_platform(spec, locked_spec),
73
+ 'source' => build_spec_source(spec),
74
+ 'type' => build_dependency_type(spec.name),
75
+ 'versions' => build_versions(spec, locked_spec)
76
+ }
77
+ end
78
+
79
+ hash
80
+ end
81
+
82
+ # Build update specification
83
+ #
84
+ # @return [Hash]
85
+ def build_update
86
+ hash = build_main
87
+
88
+ @definition.specs.each do |spec|
89
+ next if skip?(spec.source)
90
+
91
+ locked_spec = @locked_specs.find { |s| s.name == spec.name }
92
+
93
+ hash['dependencies'][spec.name] = {
94
+ 'platform' => build_spec_platform(spec, locked_spec),
95
+ 'source' => build_spec_source(spec),
96
+ 'type' => build_dependency_type(spec.name),
97
+ 'versions' => build_versions(spec, locked_spec)
98
+ }
99
+ end
100
+
101
+ hash
102
+ end
103
+
104
+ private
105
+
106
+ # Build default specification
107
+ #
108
+ # @return [Hash]
109
+ def build_main
110
+ {
111
+ 'dependencies' => {},
112
+ 'sources' => build_sources,
113
+ 'plugins' => {},
114
+ 'platforms' => @definition.platforms.map(&:to_s)
115
+ }
116
+ end
117
+
118
+ # Build gem versions
119
+ #
120
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
121
+ # @param locked_spec [Bundler::LazySpecification, Gem::Specification, NilClass]
122
+ #
123
+ # @return [Array<String>]
124
+ def build_versions(spec, locked_spec = nil)
125
+ if locked_spec && locked_spec.version.to_s != spec.version.to_s
126
+ [locked_spec.version.to_s, spec.version.to_s]
127
+ else
128
+ [spec.version.to_s]
129
+ end
130
+ end
131
+
132
+ # @param specs [Array] specs that are direct dependencies
133
+ # @param name [String] spec name
134
+ #
135
+ # @return [Boolean] dependency type
136
+ def build_dependency_type(name)
137
+ if @direct_dependencies.key?(name)
138
+ DEPENDENCIES_TYPES[:direct]
139
+ else
140
+ DEPENDENCIES_TYPES[:dependency]
141
+ end
142
+ end
143
+
144
+ # Build gem platform
145
+ #
146
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
147
+ # @param locked_spec [Bundler::LazySpecification, Gem::Specification, NilClass]
148
+ #
149
+ # @return [String]
150
+ def build_spec_platform(spec, locked_spec)
151
+ parse_platform(
152
+ spec.platform || locked_spec&.platform || spec.send(:generic_local_platform)
153
+ )
154
+ end
155
+
156
+ # Parse gem platform
157
+ #
158
+ # @param platform [String, Gem::Platform]
159
+ #
160
+ # @return [String]
161
+ def parse_platform(platform)
162
+ case platform
163
+ when String then platform
164
+ when Gem::Platform then platform.os
165
+ end
166
+ end
167
+
168
+ # Build gem source type
169
+ #
170
+ # @param source [Bundler::Source] gem source type
171
+ #
172
+ # @return [Integer] internal gem source type
173
+ def build_spec_gem_source_type(source)
174
+ case source
175
+ when Bundler::Source::Metadata
176
+ GEM_SOURCES_TYPES[:local]
177
+ when Bundler::Source::Rubygems, Bundler::Source::Rubygems::Remote
178
+ GEM_SOURCES_TYPES[:gemfile_source]
179
+ when Bundler::Source::Git
180
+ GEM_SOURCES_TYPES[:gemfile_git]
181
+ when Bundler::Source::Path
182
+ GEM_SOURCES_TYPES[:gemfile_path]
183
+ else
184
+ raise ArgumentError, "unknown source #{source.class}"
185
+ end
186
+ end
187
+
188
+ # Build gem source
189
+ #
190
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
191
+ #
192
+ # @return [Hash]
193
+ def build_spec_source(spec)
194
+ source = source_for_spec(spec)
195
+
196
+ {
197
+ 'type' => build_spec_gem_source_type(source),
198
+ 'value' => source_name_from_source(source)
199
+ }
200
+ end
201
+
202
+ # Figure out source for gem
203
+ #
204
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
205
+ #
206
+ # @return [Bundler::Source] gem source type
207
+ def source_for_spec(spec)
208
+ return spec.remote if spec.remote
209
+
210
+ case spec.source
211
+ when Bundler::Source::Rubygems
212
+ spec
213
+ .source
214
+ .send(:remote_specs)
215
+ .search(Bundler::Dependency.new(spec.name, spec.version))
216
+ .last
217
+ .remote
218
+ when Bundler::Source::Metadata, Bundler::Source::Git, Bundler::Source::Path
219
+ spec.source
220
+ else
221
+ raise ArgumentError, "unknown source #{spec.source.class}"
222
+ end
223
+ end
224
+
225
+ # Build gem source name
226
+ #
227
+ # @param source [Bundler::Source] gem source type
228
+ #
229
+ # @return [String]
230
+ def source_name_from_source(source)
231
+ case source
232
+ when Bundler::Source::Metadata
233
+ ''
234
+ when Bundler::Source::Rubygems::Remote
235
+ source_name(source.anonymized_uri)
236
+ when Bundler::Source::Git
237
+ source.instance_variable_get(:@safe_uri)
238
+ when Bundler::Source::Path
239
+ source.path
240
+ else
241
+ raise ArgumentError, "unknown source #{source.class}"
242
+ end
243
+ end
244
+
245
+ # @param uri [Bundler::URI]
246
+ #
247
+ # @return [String]
248
+ def source_name(uri)
249
+ uri.to_s[0...-1]
250
+ end
251
+
252
+ # Build sources used in the Gemfile
253
+ #
254
+ # @return [Array<Hash>]
255
+ def build_sources
256
+ sources = @definition.send(:sources).rubygems_sources
257
+ hash = {}
258
+
259
+ sources.each do |source|
260
+ type = build_source_type(source.remotes)
261
+
262
+ source.remotes.each do |src|
263
+ hash[source_name(src)] = type
264
+ end
265
+ end
266
+
267
+ hash.map { |name, type| { 'name' => name, 'type' => type } }
268
+ end
269
+
270
+ # Build gem source type
271
+ #
272
+ # @param remotes [Array<Bundler::URI>]
273
+ #
274
+ # @return [Integer] internal source type
275
+ def build_source_type(remotes)
276
+ remotes.count > 1 ? SOURCES_TYPES[:multiple_primary] : SOURCES_TYPES[:valid]
277
+ end
278
+
279
+ # Checks if we should skip a source
280
+ #
281
+ # @param source [Bundler::Source] gem source type
282
+ #
283
+ # @return [Boolean] true if we should skip this source, false otherwise
284
+ def skip?(source)
285
+ return true if me?(source)
286
+
287
+ false
288
+ end
289
+
290
+ # Checks if it's a self source, this happens for repositories that are a gem
291
+ #
292
+ # @param source [Bundler::Source] gem source type
293
+ #
294
+ # @return [Boolean] true if it's a self source, false otherwise
295
+ def me?(source)
296
+ return false unless ME_SOURCES.include?(source.class)
297
+
298
+ source.path.to_s == ME_PATH
299
+ end
300
+ end
301
+ end
302
+ end