spandx 0.13.1 → 0.14.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -2
- data/exe/spandx +0 -1
- data/ext/spandx/spandx.c +6 -4
- data/lib/spandx.rb +1 -1
- data/lib/spandx/cli.rb +2 -1
- data/lib/spandx/cli/commands/scan.rb +15 -32
- data/lib/spandx/cli/main.rb +3 -3
- data/lib/spandx/cli/printer.rb +27 -0
- data/lib/spandx/cli/printers/csv.rb +17 -0
- data/lib/spandx/cli/printers/json.rb +17 -0
- data/lib/spandx/cli/printers/table.rb +41 -0
- data/lib/spandx/core/dependency.rb +48 -13
- data/lib/spandx/core/git.rb +6 -8
- data/lib/spandx/core/guess.rb +12 -1
- data/lib/spandx/core/http.rb +7 -7
- data/lib/spandx/core/index_file.rb +2 -0
- data/lib/spandx/core/license_plugin.rb +15 -4
- data/lib/spandx/core/parser.rb +10 -3
- data/lib/spandx/core/path_traversal.rb +4 -13
- data/lib/spandx/core/plugin.rb +6 -0
- data/lib/spandx/core/thread_pool.rb +11 -11
- data/lib/spandx/dotnet/nuget_gateway.rb +1 -1
- data/lib/spandx/dotnet/parsers/csproj.rb +7 -7
- data/lib/spandx/dotnet/parsers/packages_config.rb +7 -7
- data/lib/spandx/dotnet/parsers/sln.rb +10 -13
- data/lib/spandx/dotnet/project_file.rb +3 -3
- data/lib/spandx/java/parsers/maven.rb +7 -7
- data/lib/spandx/js/parsers/npm.rb +8 -8
- data/lib/spandx/js/parsers/yarn.rb +7 -7
- data/lib/spandx/js/yarn_pkg.rb +1 -1
- data/lib/spandx/os/parsers/apk.rb +51 -0
- data/lib/spandx/php/packagist_gateway.rb +1 -1
- data/lib/spandx/php/parsers/composer.rb +7 -7
- data/lib/spandx/python/parsers/pipfile_lock.rb +4 -4
- data/lib/spandx/python/pypi.rb +19 -9
- data/lib/spandx/python/source.rb +13 -1
- data/lib/spandx/ruby/gateway.rb +1 -1
- data/lib/spandx/ruby/parsers/gemfile_lock.rb +10 -9
- data/lib/spandx/spdx/catalogue.rb +1 -1
- data/lib/spandx/version.rb +1 -1
- data/spandx.gemspec +5 -3
- metadata +43 -14
- data/lib/spandx/core/concurrent.rb +0 -40
- data/lib/spandx/core/line_io.rb +0 -23
- data/lib/spandx/core/report.rb +0 -60
- data/lib/spandx/core/table.rb +0 -29
data/lib/spandx/core/guess.rb
CHANGED
@@ -10,7 +10,14 @@ module Spandx
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def license_for(raw)
|
13
|
-
|
13
|
+
case raw
|
14
|
+
when Hash
|
15
|
+
from_hash(raw)
|
16
|
+
when Array
|
17
|
+
from_array(raw)
|
18
|
+
else
|
19
|
+
from_string(raw)
|
20
|
+
end
|
14
21
|
end
|
15
22
|
|
16
23
|
private
|
@@ -21,6 +28,10 @@ module Spandx
|
|
21
28
|
unknown(hash[:name] || hash[:url])
|
22
29
|
end
|
23
30
|
|
31
|
+
def from_array(array)
|
32
|
+
from_string(array.join(' AND '))
|
33
|
+
end
|
34
|
+
|
24
35
|
def from_string(raw)
|
25
36
|
return if raw.nil?
|
26
37
|
|
data/lib/spandx/core/http.rb
CHANGED
@@ -27,7 +27,7 @@ module Spandx
|
|
27
27
|
client.get(escape ? Addressable::URI.escape(uri) : uri)
|
28
28
|
end
|
29
29
|
end
|
30
|
-
rescue *Net::Hippie::CONNECTION_ERRORS
|
30
|
+
rescue *Net::Hippie::CONNECTION_ERRORS, URI::InvalidURIError
|
31
31
|
default
|
32
32
|
end
|
33
33
|
|
@@ -36,12 +36,12 @@ module Spandx
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def self.default_driver
|
39
|
-
@default_driver ||= Net::Hippie::Client.new
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
@default_driver ||= Net::Hippie::Client.new(
|
40
|
+
follow_redirects: 3,
|
41
|
+
logger: Spandx.logger,
|
42
|
+
open_timeout: 1,
|
43
|
+
read_timeout: 5
|
44
|
+
)
|
45
45
|
end
|
46
46
|
|
47
47
|
private
|
@@ -8,7 +8,8 @@ module Spandx
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def enhance(dependency)
|
11
|
-
|
11
|
+
package_manager = package_manager_for(dependency)
|
12
|
+
return dependency unless known?(package_manager)
|
12
13
|
return enhance_from_metadata(dependency) if available_in?(dependency.meta)
|
13
14
|
|
14
15
|
licenses_for(dependency).each do |text|
|
@@ -25,12 +26,14 @@ module Spandx
|
|
25
26
|
end
|
26
27
|
|
27
28
|
def cache_for(dependency, git: Spandx.git)
|
28
|
-
|
29
|
-
|
29
|
+
package_manager = package_manager_for(dependency)
|
30
|
+
git = git[package_manager.to_sym] || git[:cache]
|
31
|
+
key = key_for(package_manager)
|
32
|
+
Spandx::Core::Cache.new(key, root: "#{git.root}/.index")
|
30
33
|
end
|
31
34
|
|
32
35
|
def known?(package_manager)
|
33
|
-
%i[nuget maven rubygems npm yarn pypi composer].include?(package_manager)
|
36
|
+
%i[nuget maven rubygems npm yarn pypi composer apk].include?(package_manager)
|
34
37
|
end
|
35
38
|
|
36
39
|
def gateway_for(dependency)
|
@@ -49,6 +52,14 @@ module Spandx
|
|
49
52
|
end
|
50
53
|
dependency
|
51
54
|
end
|
55
|
+
|
56
|
+
def key_for(package_manager)
|
57
|
+
package_manager == :yarn ? :npm : package_manager
|
58
|
+
end
|
59
|
+
|
60
|
+
def package_manager_for(dependency)
|
61
|
+
dependency.package_manager
|
62
|
+
end
|
52
63
|
end
|
53
64
|
end
|
54
65
|
end
|
data/lib/spandx/core/parser.rb
CHANGED
@@ -9,8 +9,8 @@ module Spandx
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
raise ::Spandx::Error, :
|
12
|
+
def match?(_path)
|
13
|
+
raise ::Spandx::Error, :match?
|
14
14
|
end
|
15
15
|
|
16
16
|
def parse(_dependency)
|
@@ -20,8 +20,15 @@ module Spandx
|
|
20
20
|
class << self
|
21
21
|
include Registerable
|
22
22
|
|
23
|
+
def parse(path)
|
24
|
+
self.for(path).parse(path)
|
25
|
+
end
|
26
|
+
|
23
27
|
def for(path)
|
24
|
-
|
28
|
+
path = Pathname.new(path)
|
29
|
+
return UNKNOWN if !path.exist? || path.zero?
|
30
|
+
|
31
|
+
find { |x| x.match?(path) } || UNKNOWN
|
25
32
|
end
|
26
33
|
end
|
27
34
|
end
|
@@ -6,7 +6,7 @@ module Spandx
|
|
6
6
|
attr_reader :root
|
7
7
|
|
8
8
|
def initialize(root, recursive: true)
|
9
|
-
@root = root
|
9
|
+
@root = Pathname.new(root)
|
10
10
|
@recursive = recursive
|
11
11
|
end
|
12
12
|
|
@@ -14,27 +14,18 @@ module Spandx
|
|
14
14
|
each_file_in(root, &block)
|
15
15
|
end
|
16
16
|
|
17
|
-
def to_enum
|
18
|
-
Enumerator.new do |yielder|
|
19
|
-
each do |item|
|
20
|
-
yielder.yield item
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
17
|
private
|
26
18
|
|
27
19
|
def recursive?
|
28
20
|
@recursive
|
29
21
|
end
|
30
22
|
|
31
|
-
def each_file_in(
|
32
|
-
files =
|
23
|
+
def each_file_in(path, &block)
|
24
|
+
files = path.directory? ? path.children : [path]
|
33
25
|
files.each do |file|
|
34
|
-
if
|
26
|
+
if file.directory?
|
35
27
|
each_file_in(file, &block) if recursive?
|
36
28
|
else
|
37
|
-
Spandx.logger.debug(file)
|
38
29
|
block.call(file)
|
39
30
|
end
|
40
31
|
end
|
data/lib/spandx/core/plugin.rb
CHANGED
@@ -3,14 +3,14 @@
|
|
3
3
|
module Spandx
|
4
4
|
module Core
|
5
5
|
class ThreadPool
|
6
|
-
def initialize(size:
|
6
|
+
def initialize(size: 1)
|
7
7
|
@size = size
|
8
8
|
@queue = Queue.new
|
9
|
-
@pool = size.times.map { start_worker_thread }
|
9
|
+
@pool = size.times.map { start_worker_thread(@queue) }
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
@queue.enq([
|
12
|
+
def run(*args, &job)
|
13
|
+
@queue.enq([job, args])
|
14
14
|
end
|
15
15
|
|
16
16
|
def done?
|
@@ -19,14 +19,14 @@ module Spandx
|
|
19
19
|
|
20
20
|
def shutdown
|
21
21
|
@size.times do
|
22
|
-
|
22
|
+
run { throw :exit }
|
23
23
|
end
|
24
24
|
|
25
25
|
@pool.map(&:join)
|
26
26
|
end
|
27
27
|
|
28
|
-
def self.open
|
29
|
-
pool = new
|
28
|
+
def self.open(**args)
|
29
|
+
pool = new(**args)
|
30
30
|
yield pool
|
31
31
|
ensure
|
32
32
|
pool.shutdown
|
@@ -34,12 +34,12 @@ module Spandx
|
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
|
-
def start_worker_thread
|
38
|
-
Thread.new do
|
37
|
+
def start_worker_thread(queue)
|
38
|
+
Thread.new(queue) do |q|
|
39
39
|
catch(:exit) do
|
40
40
|
loop do
|
41
|
-
job, args =
|
42
|
-
job.call(
|
41
|
+
job, args = q.deq
|
42
|
+
job.call(args)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -4,22 +4,22 @@ module Spandx
|
|
4
4
|
module Dotnet
|
5
5
|
module Parsers
|
6
6
|
class Csproj < ::Spandx::Core::Parser
|
7
|
-
def
|
8
|
-
['.csproj', '.props'].include?(
|
7
|
+
def match?(path)
|
8
|
+
['.csproj', '.props'].include?(path.extname)
|
9
9
|
end
|
10
10
|
|
11
|
-
def parse(
|
11
|
+
def parse(path)
|
12
12
|
ProjectFile
|
13
|
-
.new(
|
13
|
+
.new(path)
|
14
14
|
.package_references
|
15
|
-
.map { |x| map_from(x) }
|
15
|
+
.map { |x| map_from(path, x) }
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
19
19
|
|
20
|
-
def map_from(package_reference)
|
20
|
+
def map_from(path, package_reference)
|
21
21
|
::Spandx::Core::Dependency.new(
|
22
|
-
|
22
|
+
path: path,
|
23
23
|
name: package_reference.name,
|
24
24
|
version: package_reference.version,
|
25
25
|
meta: package_reference
|
@@ -4,22 +4,22 @@ module Spandx
|
|
4
4
|
module Dotnet
|
5
5
|
module Parsers
|
6
6
|
class PackagesConfig < ::Spandx::Core::Parser
|
7
|
-
def
|
8
|
-
|
7
|
+
def match?(path)
|
8
|
+
path.basename.fnmatch?('packages.config')
|
9
9
|
end
|
10
10
|
|
11
|
-
def parse(
|
12
|
-
Nokogiri::XML(
|
11
|
+
def parse(path)
|
12
|
+
Nokogiri::XML(path.read)
|
13
13
|
.search('//package')
|
14
|
-
.map { |node| map_from(node) }
|
14
|
+
.map { |node| map_from(path, node) }
|
15
15
|
end
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
-
def map_from(node)
|
19
|
+
def map_from(path, node)
|
20
20
|
name = attribute_for('id', node)
|
21
21
|
version = attribute_for('version', node)
|
22
|
-
::Spandx::Core::Dependency.new(
|
22
|
+
::Spandx::Core::Dependency.new(name: name, version: version, path: path)
|
23
23
|
end
|
24
24
|
|
25
25
|
def attribute_for(key, node)
|
@@ -4,29 +4,26 @@ module Spandx
|
|
4
4
|
module Dotnet
|
5
5
|
module Parsers
|
6
6
|
class Sln < ::Spandx::Core::Parser
|
7
|
-
def
|
8
|
-
|
7
|
+
def match?(path)
|
8
|
+
path.extname == '.sln'
|
9
9
|
end
|
10
10
|
|
11
|
-
def parse(
|
12
|
-
project_paths_from(
|
13
|
-
::Spandx::Core::Parser
|
14
|
-
.for(path)
|
15
|
-
.parse(path)
|
11
|
+
def parse(path)
|
12
|
+
project_paths_from(path).map do |project_path|
|
13
|
+
::Spandx::Core::Parser.parse(project_path)
|
16
14
|
end.flatten
|
17
15
|
end
|
18
16
|
|
19
17
|
private
|
20
18
|
|
21
|
-
def project_paths_from(
|
22
|
-
|
19
|
+
def project_paths_from(path)
|
20
|
+
path.each_line.map do |line|
|
23
21
|
next unless project_line?(line)
|
24
22
|
|
25
|
-
|
26
|
-
next unless
|
23
|
+
project_path = project_path_from(line)
|
24
|
+
next unless project_path
|
27
25
|
|
28
|
-
path
|
29
|
-
Pathname.new(path).cleanpath.to_path
|
26
|
+
path.dirname.join(project_path).cleanpath.to_path
|
30
27
|
end.compact
|
31
28
|
end
|
32
29
|
|
@@ -6,9 +6,9 @@ module Spandx
|
|
6
6
|
attr_reader :catalogue, :document, :nuget
|
7
7
|
|
8
8
|
def initialize(path)
|
9
|
-
@path = path
|
10
|
-
@dir =
|
11
|
-
@document = Nokogiri::XML(
|
9
|
+
@path = Pathname(path)
|
10
|
+
@dir = @path.dirname
|
11
|
+
@document = Nokogiri::XML(@path.read).tap(&:remove_namespaces!)
|
12
12
|
end
|
13
13
|
|
14
14
|
def package_references
|
@@ -4,26 +4,26 @@ module Spandx
|
|
4
4
|
module Java
|
5
5
|
module Parsers
|
6
6
|
class Maven < ::Spandx::Core::Parser
|
7
|
-
def
|
8
|
-
|
7
|
+
def match?(path)
|
8
|
+
path.basename.fnmatch?('pom.xml')
|
9
9
|
end
|
10
10
|
|
11
|
-
def parse(
|
12
|
-
document = Nokogiri.XML(
|
11
|
+
def parse(path)
|
12
|
+
document = Nokogiri.XML(path.read).tap(&:remove_namespaces!)
|
13
13
|
document.search('//project/dependencies/dependency').map do |node|
|
14
|
-
map_from(node)
|
14
|
+
map_from(path, node)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
19
19
|
|
20
|
-
def map_from(node)
|
20
|
+
def map_from(path, node)
|
21
21
|
artifact_id = node.at_xpath('./artifactId').text
|
22
22
|
group_id = node.at_xpath('./groupId').text
|
23
23
|
version = node.at_xpath('./version').text
|
24
24
|
|
25
25
|
::Spandx::Core::Dependency.new(
|
26
|
-
|
26
|
+
path: path,
|
27
27
|
name: "#{group_id}:#{artifact_id}",
|
28
28
|
version: version
|
29
29
|
)
|
@@ -4,30 +4,30 @@ module Spandx
|
|
4
4
|
module Js
|
5
5
|
module Parsers
|
6
6
|
class Npm < ::Spandx::Core::Parser
|
7
|
-
def
|
7
|
+
def match?(filename)
|
8
8
|
File.basename(filename) == 'package-lock.json'
|
9
9
|
end
|
10
10
|
|
11
|
-
def parse(
|
11
|
+
def parse(path)
|
12
12
|
items = Set.new
|
13
|
-
each_metadata(
|
14
|
-
items.add(map_from(metadata))
|
13
|
+
each_metadata(path) do |metadata|
|
14
|
+
items.add(map_from(path, metadata))
|
15
15
|
end
|
16
16
|
items
|
17
17
|
end
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
|
-
def each_metadata(
|
22
|
-
package_lock =
|
21
|
+
def each_metadata(path)
|
22
|
+
package_lock = Oj.load(path.read)
|
23
23
|
package_lock['dependencies'].each do |name, metadata|
|
24
24
|
yield metadata.merge('name' => name)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
def map_from(metadata)
|
28
|
+
def map_from(path, metadata)
|
29
29
|
Spandx::Core::Dependency.new(
|
30
|
-
|
30
|
+
path: path,
|
31
31
|
name: metadata['name'],
|
32
32
|
version: metadata['version'],
|
33
33
|
meta: metadata
|
@@ -4,21 +4,21 @@ module Spandx
|
|
4
4
|
module Js
|
5
5
|
module Parsers
|
6
6
|
class Yarn < ::Spandx::Core::Parser
|
7
|
-
def
|
8
|
-
|
7
|
+
def match?(filename)
|
8
|
+
filename.basename.fnmatch?('yarn.lock')
|
9
9
|
end
|
10
10
|
|
11
|
-
def parse(
|
12
|
-
YarnLock.new(
|
13
|
-
memo << map_from(metadata)
|
11
|
+
def parse(path)
|
12
|
+
YarnLock.new(path).each_with_object(Set.new) do |metadata, memo|
|
13
|
+
memo << map_from(path, metadata)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
-
def map_from(metadata)
|
19
|
+
def map_from(path, metadata)
|
20
20
|
::Spandx::Core::Dependency.new(
|
21
|
-
|
21
|
+
path: path,
|
22
22
|
name: metadata['name'],
|
23
23
|
version: metadata['version'],
|
24
24
|
meta: metadata
|