spandx 0.13.2 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -2
- data/exe/spandx +0 -1
- data/ext/spandx/spandx.c +5 -3
- 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 -6
- 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 +9 -4
- 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/os/parsers/dpkg.rb +69 -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 -7
- 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 +44 -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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee3b447710888b33bf24ecf467ce1bf41e3cf6f2c91d2c3c381f256d0fa1ea6f
|
4
|
+
data.tar.gz: cd802eabfd2f0e383ae198217992ce465c28ac7d53587264ca1a2f4746e9e9ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed0fec87962da7ad1576131d6a463324deeaa9ea2b9a6b289dc9c639d1eb9dda98e2bd7aa02df2f9d40526fc4793cedafe3311c9c5fb6c6aedba5594b68fcc1f
|
7
|
+
data.tar.gz: f6bdc294db3b95093c8e3872bb5113879c0a12f9d45ec718557281ff9397f925d0b0a443ba41fad0c5a48e86c77babf95b855b7315d795ec8e869bf8c1dbd6c4
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Version 0.
|
1
|
+
Version 0.15.0
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
@@ -9,6 +9,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
9
9
|
|
10
10
|
## [Unreleased]
|
11
11
|
|
12
|
+
## [0.15.0] - 2020-11-18
|
13
|
+
### Added
|
14
|
+
- Parse `/var/lib/dpkg/status` file.
|
15
|
+
|
16
|
+
## [0.14.0] - 2020-11-14
|
17
|
+
### Added
|
18
|
+
- Parse `/lib/apk/db/installed` file.
|
19
|
+
|
20
|
+
## [0.13.5] - 2020-05-26
|
21
|
+
### Fixed
|
22
|
+
- Process PyPI package urls with single digit versions.
|
23
|
+
- Remove unsupported `hash` report from help text.
|
24
|
+
|
25
|
+
### Changed
|
26
|
+
- Stream output to output stream as soon as results are available.
|
27
|
+
- Switch to `Oj` for JSON parsing.
|
28
|
+
- Run spinner on background thread.
|
29
|
+
|
30
|
+
## [0.13.4] - 2020-05-26
|
31
|
+
### Added
|
32
|
+
- Add detected file path to report output.
|
33
|
+
|
34
|
+
### Changed
|
35
|
+
- Use `Pathname` instead of `String` to represent file paths.
|
36
|
+
- Scan current directory when a path is not specified.
|
37
|
+
|
38
|
+
## [0.13.3] - 2020-05-19
|
39
|
+
### Fixed
|
40
|
+
- Ignore invalid URLs during scan.
|
41
|
+
|
12
42
|
## [0.13.2] - 2020-05-17
|
13
43
|
### Fixed
|
14
44
|
- Detect licenses when provided as an array.
|
@@ -177,7 +207,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
177
207
|
### Added
|
178
208
|
- Provide ruby API to the latest SPDX catalogue.
|
179
209
|
|
180
|
-
[Unreleased]: https://github.com/spandx/spandx/compare/v0.
|
210
|
+
[Unreleased]: https://github.com/spandx/spandx/compare/v0.15.0...HEAD
|
211
|
+
[0.15.0]: https://github.com/spandx/spandx/compare/v0.14.0...v0.15.0
|
212
|
+
[0.14.0]: https://github.com/spandx/spandx/compare/v0.13.5...v0.14.0
|
213
|
+
[0.13.5]: https://github.com/spandx/spandx/compare/v0.13.4...v0.13.5
|
214
|
+
[0.13.4]: https://github.com/spandx/spandx/compare/v0.13.3...v0.13.4
|
215
|
+
[0.13.3]: https://github.com/spandx/spandx/compare/v0.13.2...v0.13.3
|
216
|
+
[0.13.2]: https://github.com/spandx/spandx/compare/v0.13.1...v0.13.2
|
217
|
+
[0.13.1]: https://github.com/spandx/spandx/compare/v0.13.0...v0.13.1
|
181
218
|
[0.13.0]: https://github.com/spandx/spandx/compare/v0.12.3...v0.13.0
|
182
219
|
[0.12.3]: https://github.com/spandx/spandx/compare/v0.12.2...v0.12.3
|
183
220
|
[0.12.2]: https://github.com/spandx/spandx/compare/v0.12.1...v0.12.2
|
data/exe/spandx
CHANGED
data/ext/spandx/spandx.c
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
#include "spandx.h"
|
2
2
|
|
3
|
+
#define NEWLINE 10
|
4
|
+
|
3
5
|
VALUE rb_mSpandx;
|
4
6
|
VALUE rb_mCore;
|
5
7
|
VALUE rb_mCsvParser;
|
@@ -9,7 +11,7 @@ VALUE rb_mCsvParser;
|
|
9
11
|
// "name","version","license"\r
|
10
12
|
// "name","version","license"\r\n
|
11
13
|
// "name","version",""\r\n
|
12
|
-
|
14
|
+
VALUE parse(VALUE self, VALUE line)
|
13
15
|
{
|
14
16
|
if (NIL_P(line)) return Qnil;
|
15
17
|
|
@@ -32,13 +34,13 @@ static VALUE parse(VALUE self, VALUE line)
|
|
32
34
|
s = n;
|
33
35
|
state = open;
|
34
36
|
} else if (state == open) {
|
35
|
-
if (!*n || n == p || *n == ',' || *n ==
|
37
|
+
if (!*n || n == p || *n == ',' || *n == NEWLINE) {
|
36
38
|
rb_ary_push(items, rb_str_new(s, p - s));
|
37
39
|
state = closed;
|
38
40
|
}
|
39
41
|
}
|
40
42
|
}
|
41
|
-
*p
|
43
|
+
*(p++);
|
42
44
|
}
|
43
45
|
|
44
46
|
return items;
|
data/lib/spandx.rb
CHANGED
data/lib/spandx/cli.rb
CHANGED
@@ -4,10 +4,7 @@ module Spandx
|
|
4
4
|
module Cli
|
5
5
|
module Commands
|
6
6
|
class Scan
|
7
|
-
|
8
|
-
def advance(*args); end
|
9
|
-
end.new
|
10
|
-
|
7
|
+
include Spandx::Core
|
11
8
|
attr_reader :scan_path
|
12
9
|
|
13
10
|
def initialize(scan_path, options)
|
@@ -17,32 +14,24 @@ module Spandx
|
|
17
14
|
end
|
18
15
|
|
19
16
|
def execute(output: $stdout)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
each_dependency_from(file, pool) do |dependency|
|
24
|
-
report.add(dependency)
|
25
|
-
end
|
17
|
+
with_printer(output) do |printer|
|
18
|
+
each_dependency do |dependency|
|
19
|
+
printer.print_line(Plugin.enhance(dependency), output)
|
26
20
|
end
|
27
|
-
output.puts(format(report.to(@options[:format])))
|
28
21
|
end
|
29
22
|
end
|
30
23
|
|
31
24
|
private
|
32
25
|
|
33
26
|
def each_file
|
34
|
-
|
35
|
-
.new(scan_path, recursive: @options[
|
27
|
+
PathTraversal
|
28
|
+
.new(scan_path, recursive: @options[:recursive])
|
36
29
|
.each { |file| yield file }
|
37
30
|
end
|
38
31
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
::Spandx::Core::Concurrent
|
43
|
-
.map(dependencies, pool: pool) { |dependency| enhance(dependency) }
|
44
|
-
.each do |dependency|
|
45
|
-
bar.advance(1)
|
32
|
+
def each_dependency
|
33
|
+
each_file do |file|
|
34
|
+
Parser.parse(file).each do |dependency|
|
46
35
|
yield dependency
|
47
36
|
end
|
48
37
|
end
|
@@ -52,18 +41,12 @@ module Spandx
|
|
52
41
|
Array(output).map(&:to_s)
|
53
42
|
end
|
54
43
|
|
55
|
-
def
|
56
|
-
::Spandx::
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
def title_for(file)
|
62
|
-
"#{file} [:bar, :elapsed] :percent"
|
63
|
-
end
|
64
|
-
|
65
|
-
def with_progress(title, total)
|
66
|
-
yield @options[:show_progress] ? TTY::ProgressBar.new(title, total: total) : NULL_BAR
|
44
|
+
def with_printer(output)
|
45
|
+
printer = ::Spandx::Cli::Printer.for(@options[:format])
|
46
|
+
printer.print_header(output)
|
47
|
+
yield printer
|
48
|
+
ensure
|
49
|
+
printer.print_footer(output)
|
67
50
|
end
|
68
51
|
end
|
69
52
|
end
|
data/lib/spandx/cli/main.rb
CHANGED
@@ -8,14 +8,14 @@ module Spandx
|
|
8
8
|
method_option :recursive, aliases: '-R', type: :boolean, desc: 'Perform recursive scan', default: false
|
9
9
|
method_option :airgap, aliases: '-a', type: :boolean, desc: 'Disable network connections', default: false
|
10
10
|
method_option :logfile, aliases: '-l', type: :string, desc: 'Path to a logfile', default: '/dev/null'
|
11
|
-
method_option :format, aliases: '-f', type: :string, desc: 'Format of report', default: 'table'
|
11
|
+
method_option :format, aliases: '-f', type: :string, desc: 'Format of report. (table, csv, json)', default: 'table'
|
12
12
|
method_option :pull, aliases: '-p', type: :boolean, desc: 'Pull the latest cache before the scan', default: false
|
13
13
|
method_option :require, aliases: '-r', type: :string, desc: 'Causes spandx to load the library using require.', default: nil
|
14
|
-
|
15
|
-
def scan(lockfile)
|
14
|
+
def scan(lockfile = Pathname.pwd)
|
16
15
|
if options[:help]
|
17
16
|
invoke :help, ['scan']
|
18
17
|
else
|
18
|
+
Oj.default_options = { mode: :strict }
|
19
19
|
Spandx.airgap = options[:airgap]
|
20
20
|
Spandx.logger = Logger.new(options[:logfile])
|
21
21
|
pull if options[:pull]
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spandx
|
4
|
+
module Cli
|
5
|
+
class Printer
|
6
|
+
def match?(_format)
|
7
|
+
raise ::Spandx::Error, :match?
|
8
|
+
end
|
9
|
+
|
10
|
+
def print_header(io); end
|
11
|
+
|
12
|
+
def print_line(dependency, io)
|
13
|
+
io.puts(dependency.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def print_footer(io); end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
include Core::Registerable
|
20
|
+
|
21
|
+
def for(format)
|
22
|
+
find { |x| x.match?(format) } || new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spandx
|
4
|
+
module Cli
|
5
|
+
module Printers
|
6
|
+
class Csv < Printer
|
7
|
+
def match?(format)
|
8
|
+
format.to_sym == :csv
|
9
|
+
end
|
10
|
+
|
11
|
+
def print_line(dependency, io)
|
12
|
+
io.puts(CSV.generate_line(dependency.to_a))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spandx
|
4
|
+
module Cli
|
5
|
+
module Printers
|
6
|
+
class Json < Printer
|
7
|
+
def match?(format)
|
8
|
+
format.to_sym == :json
|
9
|
+
end
|
10
|
+
|
11
|
+
def print_line(dependency, io)
|
12
|
+
io.puts(Oj.dump(dependency.to_h))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spandx
|
4
|
+
module Cli
|
5
|
+
module Printers
|
6
|
+
class Table < Printer
|
7
|
+
HEADINGS = ['Name', 'Version', 'Licenses', 'Location'].freeze
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@spinner = TTY::Spinner.new(output: $stderr)
|
11
|
+
end
|
12
|
+
|
13
|
+
def match?(format)
|
14
|
+
format.to_sym == :table
|
15
|
+
end
|
16
|
+
|
17
|
+
def print_header(_io)
|
18
|
+
@dependencies = SortedSet.new
|
19
|
+
@spinner.auto_spin
|
20
|
+
end
|
21
|
+
|
22
|
+
def print_line(dependency, _io)
|
23
|
+
@dependencies << dependency
|
24
|
+
end
|
25
|
+
|
26
|
+
def print_footer(io)
|
27
|
+
@spinner.stop
|
28
|
+
io.puts(to_table(@dependencies.map(&:to_a)))
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def to_table(rows)
|
34
|
+
Terminal::Table.new(headings: HEADINGS) do |table|
|
35
|
+
rows.each { |row| table.add_row(row) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -3,46 +3,81 @@
|
|
3
3
|
module Spandx
|
4
4
|
module Core
|
5
5
|
class Dependency
|
6
|
-
|
6
|
+
PACKAGE_MANAGERS = {
|
7
|
+
Spandx::Dotnet::Parsers::Csproj => :nuget,
|
8
|
+
Spandx::Dotnet::Parsers::PackagesConfig => :nuget,
|
9
|
+
Spandx::Dotnet::Parsers::Sln => :nuget,
|
10
|
+
Spandx::Java::Parsers::Maven => :maven,
|
11
|
+
Spandx::Js::Parsers::Npm => :npm,
|
12
|
+
Spandx::Js::Parsers::Yarn => :yarn,
|
13
|
+
Spandx::Php::Parsers::Composer => :composer,
|
14
|
+
Spandx::Python::Parsers::PipfileLock => :pypi,
|
15
|
+
Spandx::Ruby::Parsers::GemfileLock => :rubygems,
|
16
|
+
Spandx::Os::Parsers::Apk => :apk,
|
17
|
+
}.freeze
|
18
|
+
attr_reader :path, :name, :version, :licenses, :meta
|
7
19
|
|
8
|
-
def initialize(
|
9
|
-
@
|
10
|
-
@name = name
|
11
|
-
@version = version
|
12
|
-
@licenses =
|
20
|
+
def initialize(name:, version:, path:, meta: {})
|
21
|
+
@path = Pathname.new(path).realpath
|
22
|
+
@name = name || @path.basename.to_s
|
23
|
+
@version = version || @path.mtime.to_i.to_s
|
24
|
+
@licenses = []
|
13
25
|
@meta = meta
|
14
26
|
end
|
15
27
|
|
16
|
-
def
|
17
|
-
|
28
|
+
def package_manager
|
29
|
+
PACKAGE_MANAGERS[Parser.for(path).class]
|
18
30
|
end
|
19
31
|
|
20
32
|
def <=>(other)
|
21
|
-
|
33
|
+
return 1 if other.nil?
|
34
|
+
|
35
|
+
score = (name <=> other.name)
|
36
|
+
score = score.zero? ? (version <=> other&.version) : score
|
37
|
+
score.zero? ? (path.to_s <=> other&.path.to_s) : score
|
22
38
|
end
|
23
39
|
|
24
40
|
def hash
|
25
41
|
to_s.hash
|
26
42
|
end
|
27
43
|
|
44
|
+
def ==(other)
|
45
|
+
eql?(other)
|
46
|
+
end
|
47
|
+
|
28
48
|
def eql?(other)
|
29
49
|
to_s == other.to_s
|
30
50
|
end
|
31
51
|
|
32
52
|
def to_s
|
33
|
-
@to_s ||= [name, version].compact.join(' ')
|
53
|
+
@to_s ||= [name, version, path].compact.join(' ')
|
34
54
|
end
|
35
55
|
|
36
56
|
def inspect
|
37
|
-
"
|
57
|
+
"#<#{self.class} name=#{name} version=#{version} path=#{relative_path}>"
|
38
58
|
end
|
39
59
|
|
40
60
|
def to_a
|
41
|
-
[name, version,
|
61
|
+
[name, version, license_expression, relative_path.to_s]
|
42
62
|
end
|
43
63
|
|
44
64
|
def to_h
|
45
|
-
{
|
65
|
+
{
|
66
|
+
name: name,
|
67
|
+
version: version,
|
68
|
+
licenses: license_expression,
|
69
|
+
path: relative_path.to_s
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def relative_path(from: Pathname.pwd)
|
76
|
+
path.relative_path_from(from)
|
77
|
+
end
|
78
|
+
|
79
|
+
def license_expression
|
80
|
+
licenses.map(&:id).join(' AND ')
|
46
81
|
end
|
47
82
|
end
|
48
83
|
end
|
data/lib/spandx/core/git.rb
CHANGED
@@ -11,9 +11,8 @@ module Spandx
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def read(path)
|
14
|
-
full_path =
|
15
|
-
|
16
|
-
IO.read(full_path) if File.exist?(full_path)
|
14
|
+
full_path = root.join(path)
|
15
|
+
full_path.read if full_path.exist?
|
17
16
|
end
|
18
17
|
|
19
18
|
def update!
|
@@ -25,15 +24,16 @@ module Spandx
|
|
25
24
|
def path_for(url)
|
26
25
|
uri = URI.parse(url)
|
27
26
|
name = uri.path.gsub(/\.git$/, '')
|
28
|
-
File.expand_path(File.join(Dir.home, '.local', 'share', name))
|
27
|
+
Pathname(File.expand_path(File.join(Dir.home, '.local', 'share', name)))
|
29
28
|
end
|
30
29
|
|
31
30
|
def dotgit?
|
32
|
-
|
31
|
+
root.join('.git').directory?
|
33
32
|
end
|
34
33
|
|
35
34
|
def clone!
|
36
|
-
system('
|
35
|
+
system('rm', '-rf', root.to_s) if root.exist?
|
36
|
+
system('git', 'clone', '--quiet', '--depth=1', '--single-branch', '--branch', 'master', url, root.to_s)
|
37
37
|
end
|
38
38
|
|
39
39
|
def pull!
|