spandx 0.13.3 → 0.15.1
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 +37 -2
- data/exe/spandx +0 -1
- data/ext/spandx/spandx.c +7 -3
- data/lib/spandx.rb +1 -1
- data/lib/spandx/cli.rb +2 -2
- data/lib/spandx/cli/commands/pull.rb +33 -4
- data/lib/spandx/cli/commands/scan.rb +19 -22
- 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 +42 -0
- data/lib/spandx/core/dependency.rb +48 -13
- data/lib/spandx/core/git.rb +6 -6
- data/lib/spandx/core/http.rb +6 -6
- data/lib/spandx/core/license_plugin.rb +10 -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 +49 -0
- 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 +1 -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 -4
- metadata +38 -20
- data/lib/spandx/core/report.rb +0 -60
- data/lib/spandx/core/spinner.rb +0 -51
- 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: 120ae97e54f2a138b7d1053d9e71c8b702174cf70fbac0fc861b8971f4aec0bd
|
4
|
+
data.tar.gz: c89d3ffe76d00d0a6fb18e91b5cdd3ef1487a826047213dd264be3d59796d188
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab85f497f8ce4fe46a03b31d25ffa07816975dcbcb91a1438cf09bcd38f857ed652a1003569e2a8cbb091c5fb5b5b88a52043f4a61eec71337eff58107c75737
|
7
|
+
data.tar.gz: e73a923228358065c7d67bdfa8aaea328657269758f2c2d664621b5e6dd6da449b1d585655ae351e0edd99dbd155ef2efa24f0e37c95cd24c75f85da517503af
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Version 0.
|
1
|
+
Version 0.15.1
|
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.1] - 2020-11-18
|
13
|
+
### Fixed
|
14
|
+
- Rebuild index after pulling latest cache.
|
15
|
+
|
16
|
+
## [0.15.0] - 2020-11-18
|
17
|
+
### Added
|
18
|
+
- Parse `/var/lib/dpkg/status` file.
|
19
|
+
|
20
|
+
## [0.14.0] - 2020-11-14
|
21
|
+
### Added
|
22
|
+
- Parse `/lib/apk/db/installed` file.
|
23
|
+
|
24
|
+
## [0.13.5] - 2020-05-26
|
25
|
+
### Fixed
|
26
|
+
- Process PyPI package urls with single digit versions.
|
27
|
+
- Remove unsupported `hash` report from help text.
|
28
|
+
|
29
|
+
### Changed
|
30
|
+
- Stream output to output stream as soon as results are available.
|
31
|
+
- Switch to `Oj` for JSON parsing.
|
32
|
+
- Run spinner on background thread.
|
33
|
+
|
34
|
+
## [0.13.4] - 2020-05-26
|
35
|
+
### Added
|
36
|
+
- Add detected file path to report output.
|
37
|
+
|
38
|
+
### Changed
|
39
|
+
- Use `Pathname` instead of `String` to represent file paths.
|
40
|
+
- Scan current directory when a path is not specified.
|
41
|
+
|
12
42
|
## [0.13.3] - 2020-05-19
|
13
43
|
### Fixed
|
14
44
|
- Ignore invalid URLs during scan.
|
@@ -181,7 +211,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
181
211
|
### Added
|
182
212
|
- Provide ruby API to the latest SPDX catalogue.
|
183
213
|
|
184
|
-
[Unreleased]: https://github.com/spandx/spandx/compare/v0.
|
214
|
+
[Unreleased]: https://github.com/spandx/spandx/compare/v0.15.1...HEAD
|
215
|
+
[0.15.1]: https://github.com/spandx/spandx/compare/v0.15.0...v0.15.1
|
216
|
+
[0.15.0]: https://github.com/spandx/spandx/compare/v0.14.0...v0.15.0
|
217
|
+
[0.14.0]: https://github.com/spandx/spandx/compare/v0.13.5...v0.14.0
|
218
|
+
[0.13.5]: https://github.com/spandx/spandx/compare/v0.13.4...v0.13.5
|
219
|
+
[0.13.4]: https://github.com/spandx/spandx/compare/v0.13.3...v0.13.4
|
185
220
|
[0.13.3]: https://github.com/spandx/spandx/compare/v0.13.2...v0.13.3
|
186
221
|
[0.13.2]: https://github.com/spandx/spandx/compare/v0.13.1...v0.13.2
|
187
222
|
[0.13.1]: https://github.com/spandx/spandx/compare/v0.13.0...v0.13.1
|
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;
|
@@ -50,4 +52,6 @@ void Init_spandx(void)
|
|
50
52
|
rb_mCore = rb_define_module_under(rb_mSpandx, "Core");
|
51
53
|
rb_mCsvParser = rb_define_module_under(rb_mCore, "CsvParser");
|
52
54
|
rb_define_module_function(rb_mCsvParser, "parse", parse, 1);
|
55
|
+
|
56
|
+
rb_gc_register_mark_object(rb_mCsvParser);
|
53
57
|
}
|
data/lib/spandx.rb
CHANGED
data/lib/spandx/cli.rb
CHANGED
@@ -8,12 +8,41 @@ module Spandx
|
|
8
8
|
@options = options
|
9
9
|
end
|
10
10
|
|
11
|
-
def execute(output: $
|
11
|
+
def execute(output: $stderr)
|
12
|
+
sync(output)
|
13
|
+
build(output, ::Spandx::Core::Dependency::PACKAGE_MANAGERS.values.uniq)
|
14
|
+
output.puts 'OK'
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def sync(output)
|
12
20
|
Spandx.git.each_value do |db|
|
13
|
-
|
14
|
-
|
21
|
+
with_spinner("Updating #{db.url}...", output: output) do
|
22
|
+
db.update!
|
23
|
+
end
|
15
24
|
end
|
16
|
-
|
25
|
+
end
|
26
|
+
|
27
|
+
def build(output, sources)
|
28
|
+
index_path = Spandx.git[:cache].root.join('.index')
|
29
|
+
|
30
|
+
with_spinner('Rebuilding index...', output: output) do
|
31
|
+
sources.each do |source|
|
32
|
+
Spandx::Core::Cache
|
33
|
+
.new(source, root: index_path)
|
34
|
+
.rebuild_index
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def with_spinner(message, output:)
|
40
|
+
spinner = TTY::Spinner.new("[:spinner] #{message}", output: output)
|
41
|
+
spinner.auto_spin
|
42
|
+
yield
|
43
|
+
spinner.success('(done)')
|
44
|
+
ensure
|
45
|
+
spinner.stop
|
17
46
|
end
|
18
47
|
end
|
19
48
|
end
|
@@ -4,52 +4,49 @@ module Spandx
|
|
4
4
|
module Cli
|
5
5
|
module Commands
|
6
6
|
class Scan
|
7
|
-
|
7
|
+
include Spandx::Core
|
8
|
+
attr_reader :scan_path
|
8
9
|
|
9
10
|
def initialize(scan_path, options)
|
10
11
|
@scan_path = ::Pathname.new(scan_path)
|
11
12
|
@options = options
|
12
|
-
@spinner = options[:show_progress] ? ::Spandx::Core::Spinner.new : ::Spandx::Core::Spinner::NULL
|
13
13
|
require(options[:require]) if options[:require]
|
14
14
|
end
|
15
15
|
|
16
16
|
def execute(output: $stdout)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
each_dependency_from(file) do |dependency|
|
21
|
-
spinner.spin(file)
|
22
|
-
report.add(dependency)
|
17
|
+
with_printer(output) do |printer|
|
18
|
+
each_dependency do |dependency|
|
19
|
+
printer.print_line(Plugin.enhance(dependency), output)
|
23
20
|
end
|
24
21
|
end
|
25
|
-
spinner.stop
|
26
|
-
output.puts(format(report.to(@options[:format])))
|
27
22
|
end
|
28
23
|
|
29
24
|
private
|
30
25
|
|
31
26
|
def each_file
|
32
|
-
|
33
|
-
.new(scan_path, recursive: @options[
|
27
|
+
PathTraversal
|
28
|
+
.new(scan_path, recursive: @options[:recursive])
|
34
29
|
.each { |file| yield file }
|
35
30
|
end
|
36
31
|
|
37
|
-
def
|
38
|
-
|
39
|
-
.
|
40
|
-
|
41
|
-
|
42
|
-
|
32
|
+
def each_dependency
|
33
|
+
each_file do |file|
|
34
|
+
Parser.parse(file).each do |dependency|
|
35
|
+
yield dependency
|
36
|
+
end
|
37
|
+
end
|
43
38
|
end
|
44
39
|
|
45
40
|
def format(output)
|
46
41
|
Array(output).map(&:to_s)
|
47
42
|
end
|
48
43
|
|
49
|
-
def
|
50
|
-
::Spandx::
|
51
|
-
|
52
|
-
|
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)
|
53
50
|
end
|
54
51
|
end
|
55
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,42 @@
|
|
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(output: $stderr)
|
10
|
+
@spinner = TTY::Spinner.new('[:spinner] Scanning...', output: output, clear: true, format: :dots)
|
11
|
+
@spinner.auto_spin
|
12
|
+
end
|
13
|
+
|
14
|
+
def match?(format)
|
15
|
+
format.to_sym == :table
|
16
|
+
end
|
17
|
+
|
18
|
+
def print_header(_io)
|
19
|
+
@dependencies = SortedSet.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def print_line(dependency, _io)
|
23
|
+
@dependencies << dependency
|
24
|
+
end
|
25
|
+
|
26
|
+
def print_footer(io)
|
27
|
+
@spinner.stop
|
28
|
+
@spinner.reset
|
29
|
+
io.puts(to_table(@dependencies.map(&:to_a)))
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def to_table(rows)
|
35
|
+
Terminal::Table.new(headings: HEADINGS) do |table|
|
36
|
+
rows.each { |row| table.add_row(row) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
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
|