bibliothecary 10.2.0 → 10.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 593043fd2afa0c57546f1947d788d7d4882cc398b36ebcc5774cb89446ba07d1
4
- data.tar.gz: fcf4b7b67a9b0d6de622d6bf4390bf20b64f6c015e13253ffad21257bd142f81
3
+ metadata.gz: 7dfc5b2b87a91e11a42997699093f41438d326c32bb5f9e1d1a6f0fe53e14273
4
+ data.tar.gz: b913696a04f7cbc09e8c8f9fbf257f695ca9024e91714860b0da9e656ff111df
5
5
  SHA512:
6
- metadata.gz: 9b6922980540f62a05e27a46c612937dc165c4815dab3ca8462ad137e1cb4905ac9a015a7a47777126336eefa5a50794027696d1be9340e88206b71885c6893a
7
- data.tar.gz: b283d69564bbd69f8684cd4ac530551c42c5ab1c174da3edaa84f9ca4ee9750abc26cd1d6a977ccf69709fe52cb8d821d7875f6821c456ac5727b1a196dbd060
6
+ metadata.gz: c9b0b9fda708eee583ffe0a41e18b6cb3e50c723038f51d1320bc8b175be36737cf0df3c77bc98baa8cb0c220ad2b07d84e2d5d77306ac933c8029190bee3a79
7
+ data.tar.gz: 86d1f61c7ed98652aba0e36938ddfb5d39970358f7f4564cd35a1e4cf83560d3879732c4d5ee62f05a50f57b8d71e974c8079db87568a9e3cf444e0ce2f15b92
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.0.7
1
+ 3.0.7
data/CHANGELOG.md CHANGED
@@ -13,11 +13,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13
13
 
14
14
  ### Removed
15
15
 
16
+ ## [10.2.2] - 2024-09-25
17
+
18
+ ### Added
19
+
20
+ - Support parsing *.spdx.json files
21
+
16
22
  ## [10.2.0] - 2024-08-27
17
23
 
18
24
  ### Changed
19
25
 
20
- - `Bibliothecary::Dependency#requirement` now defaults to all versions (`"*"`) instead of `nil` if no version range is specified for the dependency,
26
+ - `Bibliothecary::Dependency#requirement` now defaults to all versions (`"*"`) instead of `nil` if no version range is specified for the dependency.
21
27
 
22
28
  ## [10.1.0] - 2024-07-23
23
29
 
data/Gemfile CHANGED
@@ -1,8 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- # Temporarily pegging to HEAD until 0.2.1 is released: https://github.com/piotrmurach/strings-ansi/pull/2
4
- gem "strings-ansi", ref: "35d0c9430cf0a8022dc12bdab005bce296cb9f00", git: "git@github.com:piotrmurach/strings-ansi.git"
5
-
6
3
  # Specify your gem's dependencies in bibliothecary.gemspec
7
4
  gemspec
8
5
 
data/README.md CHANGED
@@ -97,6 +97,11 @@ All available config options are in: https://github.com/librariesio/bibliothecar
97
97
  - JSON as cyclonedx.json
98
98
  - Note that CycloneDX manifests can contain information on multiple
99
99
  package manager's packages!
100
+ - SPDX
101
+ - tag:value as *.spdx
102
+ - JSON as *.spdx.json
103
+ - Note that SPDX manifests can contain information on multiple
104
+ package manager's packages!
100
105
  - Bower
101
106
  - bower.json
102
107
  - CPAN
@@ -25,8 +25,6 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency "deb_control"
26
26
  spec.add_dependency "sdl4r"
27
27
  spec.add_dependency "commander"
28
- spec.add_dependency "strings-ansi" # NB this is also pegged to a git sha in Gemfile temporarily.
29
- spec.add_dependency "strings"
30
28
  spec.add_dependency "packageurl-ruby"
31
29
 
32
30
  spec.add_development_dependency "pry"
@@ -29,12 +29,12 @@ module Bibliothecary
29
29
  end
30
30
 
31
31
  def <<(purl)
32
- mapping = Bibliothecary::PURL_TYPE_MAPPING[purl.type]
32
+ mapping = PurlUtil::PURL_TYPE_MAPPING[purl.type]
33
33
  return unless mapping
34
34
 
35
35
  @manifests[mapping] ||= Set.new
36
36
  @manifests[mapping] << Dependency.new(
37
- name: self.class.full_name_for_purl(purl),
37
+ name: PurlUtil.full_name(purl),
38
38
  requirement: purl.version,
39
39
  type: "lockfile",
40
40
  )
@@ -60,18 +60,6 @@ module Bibliothecary
60
60
  def [](key)
61
61
  @manifests[key]&.to_a
62
62
  end
63
-
64
- # @return [String] The properly namespaced package name
65
- def self.full_name_for_purl(purl)
66
- parts = [purl.namespace, purl.name].compact
67
-
68
- case purl.type
69
- when "maven"
70
- parts.join(":")
71
- else
72
- parts.join("/")
73
- end
74
- end
75
63
  end
76
64
 
77
65
  def self.mapping
@@ -18,7 +18,7 @@ module Bibliothecary
18
18
  PACKAGE_NAME_REGEXP = /^\s*PackageName:\s*(.*)/
19
19
 
20
20
  # e.g. 'PackageVersion:' (allowing for excessive whitespace)
21
- PACKAGE_VERSION_REGEXP =/^\s*PackageVersion:\s*(.*)/
21
+ PACKAGE_VERSION_REGEXP = /^\s*PackageVersion:\s*(.*)/
22
22
 
23
23
  # e.g. "ExternalRef: PACKAGE-MANAGER purl (allowing for excessive whitespace)
24
24
  PURL_REGEXP = /^\s*ExternalRef:\s*PACKAGE[-|_]MANAGER\s*purl\s*(.*)/
@@ -33,6 +33,11 @@ module Bibliothecary
33
33
  parser: :parse_spdx_tag_value,
34
34
  ungroupable: true,
35
35
  },
36
+ match_extension(".spdx.json") => {
37
+ kind: "lockfile",
38
+ parser: :parse_spdx_json,
39
+ ungroupable: true,
40
+ },
36
41
  }
37
42
  end
38
43
 
@@ -46,53 +51,93 @@ module Bibliothecary
46
51
  entries[platform_name.to_sym]
47
52
  end
48
53
 
49
- def get_platform(purl_string)
50
- platform = PackageURL.parse(purl_string).type
51
-
52
- Bibliothecary::PURL_TYPE_MAPPING[platform]
53
- end
54
-
55
54
  def parse_spdx_tag_value_file_contents(file_contents)
56
55
  entries = {}
56
+ spdx_name = spdx_version = platform = purl_name = purl_version = nil
57
57
 
58
- package_name = nil
59
- package_version = nil
60
- platform = nil
61
-
62
- file_contents.split("\n").each do |line|
58
+ file_contents.each_line do |line|
63
59
  stripped_line = line.strip
60
+ next if skip_tag_value_line?(stripped_line)
64
61
 
65
- next if skip_line?(stripped_line)
66
-
67
- raise MalformedFile unless stripped_line.match(WELLFORMED_LINE_REGEXP)
62
+ raise MalformedFile unless stripped_line.match?(WELLFORMED_LINE_REGEXP)
68
63
 
69
64
  if (match = stripped_line.match(PACKAGE_NAME_REGEXP))
70
- package_name = match[1]
65
+ # Per the spec:
66
+ # > A new package Information section is denoted by the package name (7.1) field.
67
+ add_entry(entries: entries, platform: platform, purl_name: purl_name,
68
+ spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version)
69
+
70
+ # reset for this new package
71
+ spdx_name = spdx_version = platform = purl_name = purl_version = nil
72
+
73
+ # capture the new package's name
74
+ spdx_package_name = match[1]
71
75
  elsif (match = stripped_line.match(PACKAGE_VERSION_REGEXP))
72
- package_version = match[1]
76
+ spdx_version = match[1]
73
77
  elsif (match = stripped_line.match(PURL_REGEXP))
74
- platform ||= get_platform(match[1])
78
+ purl = PackageURL.parse(match[1])
79
+ platform ||= PurlUtil::PURL_TYPE_MAPPING[purl.type]
80
+ purl_name ||= PurlUtil.full_name(purl)
81
+ purl_version ||= purl.version
75
82
  end
83
+ end
76
84
 
77
- unless package_name.nil? || package_version.nil? || platform.nil?
78
- entries[platform.to_sym] ||= []
79
- entries[platform.to_sym] << Dependency.new(
80
- name: package_name,
81
- requirement: package_version,
82
- type: "lockfile",
83
- )
85
+ add_entry(entries: entries, platform: platform, purl_name: purl_name,
86
+ spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version)
84
87
 
85
- package_name = package_version = platform = nil
86
- end
88
+ entries
89
+ end
90
+
91
+ def skip_tag_value_line?(stripped_line)
92
+ # Ignore blank lines and comments
93
+ stripped_line.empty? || stripped_line.start_with?("#")
94
+ end
95
+
96
+ def parse_spdx_json(file_contents, options: {})
97
+ entries = try_cache(options, options[:filename]) do
98
+ parse_spdx_json_file_contents(file_contents)
99
+ end
100
+
101
+ raise NoEntries if entries.empty?
102
+
103
+ entries[platform_name.to_sym]
104
+ end
105
+
106
+ def parse_spdx_json_file_contents(file_contents)
107
+ entries = {}
108
+ manifest = JSON.parse(file_contents)
109
+
110
+ manifest["packages"]&.each do |package|
111
+ spdx_name = package["name"]
112
+ spdx_version = package["versionInfo"]
113
+
114
+ first_purl_string = package.dig("externalRefs")&.find { |ref| ref["referenceType"] == "purl" }&.dig("referenceLocator")
115
+ purl = first_purl_string && PackageURL.parse(first_purl_string)
116
+ platform = PurlUtil::PURL_TYPE_MAPPING[purl&.type]
117
+ purl_name = PurlUtil.full_name(purl)
118
+ purl_version = purl&.version
119
+
120
+ add_entry(entries: entries, platform: platform, purl_name: purl_name,
121
+ spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version)
87
122
  end
88
123
 
89
124
  entries
90
125
  end
91
126
 
92
- def skip_line?(stripped_line)
93
- # Ignore blank lines and comments
94
- stripped_line == "" || stripped_line[0] == "#"
127
+ def add_entry(entries:, platform:, purl_name:, spdx_name:, purl_version:, spdx_version:)
128
+ package_name = purl_name || spdx_name
129
+ package_version = purl_version || spdx_version
130
+
131
+ if platform && package_name && package_version
132
+ entries[platform.to_sym] ||= []
133
+ entries[platform.to_sym] << Dependency.new(
134
+ name: package_name,
135
+ requirement: package_version,
136
+ type: "lockfile"
137
+ )
138
+ end
95
139
  end
140
+
96
141
  end
97
142
  end
98
143
  end
@@ -1,5 +1,4 @@
1
1
  require "ox"
2
- require "strings-ansi"
3
2
 
4
3
  # Known shortcomings and unimplemented Maven features:
5
4
  # pom.xml
@@ -57,6 +56,27 @@ module Bibliothecary
57
56
  # e.g. "[info] "
58
57
  SBT_IGNORE_REGEXP = /^\[info\]\s*$/
59
58
 
59
+
60
+ # Copied from the "strings-ansi" gem, because it seems abandoned: https://github.com/piotrmurach/strings-ansi/pull/2
61
+ # From: https://github.com/piotrmurach/strings-ansi/blob/35d0c9430cf0a8022dc12bdab005bce296cb9f00/lib/strings/ansi.rb#L14-L29
62
+ # License: MIT
63
+ # The regex to match ANSI codes
64
+ ANSI_MATCHER = %r{
65
+ (?>\033(
66
+ \[[\[?>!]?\d*(;\d+)*[ ]?[a-zA-Z~@$^\]_\{\\] # graphics
67
+ |
68
+ \#?\d # cursor modes
69
+ |
70
+ [)(%+\-*/. ](\d|[a-zA-Z@=%]|) # character sets
71
+ |
72
+ O[p-xA-Z] # special keys
73
+ |
74
+ [a-zA-Z=><~\}|] # cursor movement
75
+ |
76
+ \]8;[^;]*;.*?(\033\\|\07) # hyperlink
77
+ ))
78
+ }x.freeze
79
+
60
80
  def self.mapping
61
81
  {
62
82
  match_filename("ivy.xml", case_insensitive: true) => {
@@ -218,7 +238,8 @@ module Bibliothecary
218
238
  end
219
239
 
220
240
  def self.parse_maven_resolved(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
221
- Strings::ANSI.sanitize(file_contents)
241
+ file_contents
242
+ .gsub(ANSI_MATCHER, "")
222
243
  .split("\n")
223
244
  .map(&method(:parse_resolved_dep_line))
224
245
  .compact
@@ -226,7 +247,8 @@ module Bibliothecary
226
247
  end
227
248
 
228
249
  def self.parse_maven_tree(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
229
- captures = Strings::ANSI.sanitize(file_contents)
250
+ captures = file_contents
251
+ .gsub(ANSI_MATCHER, "")
230
252
  .gsub(/\r\n?/, "\n")
231
253
  .scan(/^\[INFO\](?:(?:\+-)|\||(?:\\-)|\s)+((?:[\w\.-]+:)+[\w\.\-${}]+)/)
232
254
  .flatten
@@ -1,21 +1,39 @@
1
1
  module Bibliothecary
2
- # If a purl type (key) exists, it will be used in a manifest for
3
- # the key's value. If not, it's ignored.
4
- #
5
- # https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst
6
- PURL_TYPE_MAPPING = {
7
- "golang" => :go,
8
- "maven" => :maven,
9
- "npm" => :npm,
10
- "cargo" => :cargo,
11
- "composer" => :packagist,
12
- "conda" => :conda,
13
- "cran" => :cran,
14
- "gem" => :rubygems,
15
- "hackage" => :hackage,
16
- "hex" => :hex,
17
- "nuget" => :nuget,
18
- "pypi" => :pypi,
19
- "swift" => :swift_pm,
20
- }.freeze
2
+ class PurlUtil
3
+ # If a purl type (key) exists, it will be used in a manifest for
4
+ # the key's value. If not, it's ignored.
5
+ #
6
+ # https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst
7
+ PURL_TYPE_MAPPING = {
8
+ "golang" => :go,
9
+ "maven" => :maven,
10
+ "npm" => :npm,
11
+ "cargo" => :cargo,
12
+ "composer" => :packagist,
13
+ "conda" => :conda,
14
+ "cran" => :cran,
15
+ "gem" => :rubygems,
16
+ "hackage" => :hackage,
17
+ "hex" => :hex,
18
+ "nuget" => :nuget,
19
+ "pypi" => :pypi,
20
+ "swift" => :swift_pm,
21
+ }.freeze
22
+
23
+
24
+ # @param purl [PackageURL]
25
+ # @return [String] The properly namespaced package name
26
+ def self.full_name(purl)
27
+ return nil if purl.nil?
28
+
29
+ parts = [purl.namespace, purl.name].compact
30
+
31
+ case purl.type
32
+ when "maven"
33
+ parts.join(":")
34
+ else
35
+ parts.join("/")
36
+ end
37
+ end
38
+ end
21
39
  end
@@ -1,3 +1,3 @@
1
1
  module Bibliothecary
2
- VERSION = "10.2.0"
2
+ VERSION = "10.2.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bibliothecary
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.2.0
4
+ version: 10.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Nesbitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-27 00:00:00.000000000 Z
11
+ date: 2024-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tomlrb
@@ -108,34 +108,6 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: strings-ansi
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :runtime
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: strings
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :runtime
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
111
  - !ruby/object:Gem::Dependency
140
112
  name: packageurl-ruby
141
113
  requirement: !ruby/object:Gem::Requirement
@@ -266,7 +238,6 @@ files:
266
238
  - ".rubocop.yml"
267
239
  - ".ruby-version"
268
240
  - ".tidelift.yml"
269
- - ".travis.yml"
270
241
  - CHANGELOG.md
271
242
  - CODE_OF_CONDUCT.md
272
243
  - Gemfile
@@ -277,7 +248,6 @@ files:
277
248
  - bin/bibliothecary
278
249
  - bin/console
279
250
  - bin/setup
280
- - dependencyci.yml
281
251
  - lib/bibliothecary.rb
282
252
  - lib/bibliothecary/analyser.rb
283
253
  - lib/bibliothecary/analyser/analysis.rb
data/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.6.6
4
- cache: bundler
5
- before_install:
6
- - gem update --system
7
- - gem install bundler
8
- script:
9
- - bundle exec rake spec && bundle exec codeclimate-test-reporter
10
- notifications:
11
- slack:
12
- secure: MkuDOE57uFrypxJGB7fy6Mq7uT77SzC3ApXVbdpx8k+4ihwLK+7Gyn0IzJ0f24B9PprH2RzmFoHk6XPjSjVCAEoCHvuv2ntHPX3FqxkBXdkb3NjKjOvV1+rRt9D+3sG6IEY5M5ak7j34W0FGgczNQs3+IOGCs3NIJP/h2mAL02w8oZFU2LMGYY6gX7LL+z4q65Ag5mDMwN9kslmWELO7k8xLPunlCh9jRWbZpxzFKwsHC4HtygejWwijNlSAt6Rk2XaPJ4jR8PO8uvWR1+iXxOVFErZ/nriybYMdThpLUdLWWHn6n+a3lu9vpo0KtnMrVq/E5KSaM1bilKxTuFR35AU9kbMv2L9cs65sRz1rSa2CnfN+788icesDyePh6ZjDOb+5zvxOViDvoEc9cIogf6JJT8hDpvF0zDqEuU+CTvh+3AqRGS7yjlsviQZofB8Fr/VMjZzuHL45T1+4O46eryO1PZpNYlq9svLRgpkdmu5A+SFwlM2K7Zc4ND5GSlCnWdGx1ThBp1u1lFYvw2IMeU5bylS+ak4xt+S2YH5Hmc0y7F0nvB54mmap8T7GGc7dFhLaLTaTTijHF70HJgsDKCnPsRqk5Bt2h7grBMT6t9AG+6Hg0QVFJ4ZSfnM2IBb57naVhUpMFjYT9fnLrjIAg9rY1GW6kkowFdoj6mvFhAM=
data/dependencyci.yml DELETED
@@ -1,9 +0,0 @@
1
- platforms:
2
- NPM:
3
- jade:
4
- tests:
5
- deprecated: skip
6
- NuGet:
7
- tests:
8
- unlicensed: skip
9
- removed: skip