license_scout 1.3.17 → 2.0.2

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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +195 -0
  3. data/bin/license_scout +3 -59
  4. data/bin/mix_lock_json +0 -0
  5. data/bin/rebar_lock_json +0 -0
  6. data/lib/license_scout/cli.rb +99 -0
  7. data/lib/license_scout/collector.rb +25 -77
  8. data/lib/license_scout/config.rb +94 -0
  9. data/lib/license_scout/data/dependeny_manifest_v2_schema.json +62 -0
  10. data/lib/license_scout/data/exceptions.json +306 -0
  11. data/lib/license_scout/data/licenses.json +4653 -0
  12. data/lib/license_scout/dependency.rb +79 -7
  13. data/lib/license_scout/dependency_manager/base.rb +74 -42
  14. data/lib/license_scout/dependency_manager/berkshelf.rb +25 -50
  15. data/lib/license_scout/dependency_manager/bundler/_bundler_script.rb +1 -1
  16. data/lib/license_scout/dependency_manager/bundler.rb +47 -69
  17. data/lib/license_scout/dependency_manager/cpanm.rb +62 -112
  18. data/lib/license_scout/dependency_manager/dep.rb +29 -36
  19. data/lib/license_scout/dependency_manager/glide.rb +25 -36
  20. data/lib/license_scout/dependency_manager/godep.rb +27 -26
  21. data/lib/license_scout/dependency_manager/habitat.rb +126 -0
  22. data/lib/license_scout/dependency_manager/mix.rb +105 -0
  23. data/lib/license_scout/dependency_manager/npm.rb +30 -86
  24. data/lib/license_scout/dependency_manager/rebar.rb +26 -45
  25. data/lib/license_scout/dependency_manager.rb +19 -5
  26. data/lib/license_scout/exceptions.rb +2 -43
  27. data/lib/license_scout/license.rb +126 -0
  28. data/lib/license_scout/{license_file_analyzer.rb → log.rb} +4 -6
  29. data/lib/license_scout/reporter.rb +149 -55
  30. data/lib/license_scout/spdx.rb +123 -0
  31. data/lib/license_scout/version.rb +1 -1
  32. data/lib/license_scout.rb +2 -0
  33. data/native_parsers/mix_lock_json/README.md +21 -0
  34. data/native_parsers/mix_lock_json/lib/mix_lock_json.ex +20 -0
  35. data/native_parsers/mix_lock_json/mix.exs +31 -0
  36. data/native_parsers/mix_lock_json/mix.lock +3 -0
  37. data/{erl_src → native_parsers}/rebar_lock_json/rebar.lock +2 -2
  38. metadata +144 -67
  39. data/lib/license_scout/canonical_licenses/BSD-2-Clause.txt +0 -19
  40. data/lib/license_scout/canonical_licenses/BSD-3-Clause.txt +0 -27
  41. data/lib/license_scout/canonical_licenses/BSD-4-Clause.txt +0 -31
  42. data/lib/license_scout/canonical_licenses/Chef-MLSA.txt +0 -5
  43. data/lib/license_scout/canonical_licenses/ISC.txt +0 -14
  44. data/lib/license_scout/canonical_licenses/MIT.txt +0 -20
  45. data/lib/license_scout/dependency_manager/bundler/LICENSE.md +0 -23
  46. data/lib/license_scout/dependency_manager/json/README.md +0 -392
  47. data/lib/license_scout/dependency_manager/manual.rb +0 -67
  48. data/lib/license_scout/license_file_analyzer/any_matcher.rb +0 -37
  49. data/lib/license_scout/license_file_analyzer/definitions.rb +0 -219
  50. data/lib/license_scout/license_file_analyzer/header_matcher.rb +0 -34
  51. data/lib/license_scout/license_file_analyzer/matcher.rb +0 -46
  52. data/lib/license_scout/license_file_analyzer/template.rb +0 -45
  53. data/lib/license_scout/license_file_analyzer/templates/Apache2-short.txt +0 -11
  54. data/lib/license_scout/license_file_analyzer/templates/Apache2.txt +0 -170
  55. data/lib/license_scout/license_file_analyzer/templates/BSD-2-Clause-bullets.txt +0 -18
  56. data/lib/license_scout/license_file_analyzer/templates/BSD-2-Clause.txt +0 -19
  57. data/lib/license_scout/license_file_analyzer/templates/BSD-3-Clause-alt-format.txt +0 -24
  58. data/lib/license_scout/license_file_analyzer/templates/BSD-3-Clause.txt +0 -21
  59. data/lib/license_scout/license_file_analyzer/templates/BSD.txt +0 -24
  60. data/lib/license_scout/license_file_analyzer/templates/Chef-MLSA.txt +0 -5
  61. data/lib/license_scout/license_file_analyzer/templates/EPLICENSE.txt +0 -286
  62. data/lib/license_scout/license_file_analyzer/templates/GPL-2.0.txt +0 -339
  63. data/lib/license_scout/license_file_analyzer/templates/GPL-3.0.txt +0 -674
  64. data/lib/license_scout/license_file_analyzer/templates/ISC.txt +0 -2
  65. data/lib/license_scout/license_file_analyzer/templates/LGPL-3.0.txt +0 -165
  66. data/lib/license_scout/license_file_analyzer/templates/MIT.txt +0 -9
  67. data/lib/license_scout/license_file_analyzer/templates/MPL2.txt +0 -373
  68. data/lib/license_scout/license_file_analyzer/templates/Python-2.0.txt +0 -47
  69. data/lib/license_scout/license_file_analyzer/templates/Ruby.txt +0 -52
  70. data/lib/license_scout/license_file_analyzer/text.rb +0 -46
  71. data/lib/license_scout/net_fetcher.rb +0 -106
  72. data/lib/license_scout/options.rb +0 -47
  73. data/lib/license_scout/overrides.rb +0 -1125
  74. /data/{erl_src → native_parsers}/rebar_lock_json/README.md +0 -0
  75. /data/{erl_src → native_parsers}/rebar_lock_json/rebar.config +0 -0
  76. /data/{erl_src → native_parsers}/rebar_lock_json/src/rebar_lock_json.app.src +0 -0
  77. /data/{erl_src → native_parsers}/rebar_lock_json/src/rebar_lock_json.erl +0 -0
@@ -15,97 +15,191 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
- require "ffi_yajl" unless defined?(FFI_Yajl)
18
+ require "ffi_yajl"
19
+ require "terminal-table"
19
20
 
20
21
  require "license_scout/exceptions"
21
22
 
22
23
  module LicenseScout
23
24
  class Reporter
24
25
 
25
- attr_reader :output_directory
26
-
27
- def initialize(output_directory)
28
- @output_directory = output_directory
29
- end
26
+ class Result
27
+ class << self
28
+ def success(dependency)
29
+ new(dependency, nil, true)
30
+ end
30
31
 
31
- def report
32
- report = []
32
+ def failure(dependency, reason)
33
+ new(dependency, reason, false)
34
+ end
35
+ end
33
36
 
34
- license_manifest_path = find_license_manifest!
37
+ attr_reader :dependency
38
+ attr_reader :reason
35
39
 
36
- license_report = FFI_Yajl::Parser.parse(File.read(license_manifest_path))
40
+ def initialize(dependency, reason, did_succeed)
41
+ @dependency = dependency
42
+ @reason = reason
43
+ @did_succeed = did_succeed
44
+ end
37
45
 
38
- license_report["dependency_managers"].each do |dependency_manager, dependencies|
46
+ def <=>(other)
47
+ dependency.path <=> other.dependency.path
48
+ end
39
49
 
40
- ok_deps, problem_deps = 0, 0
50
+ def succeeded?
51
+ @did_succeed
52
+ end
41
53
 
42
- dependencies.sort_by { |a| a["name"] }.each do |dependency|
43
- dep_ok, problems = license_info_ok?(dependency_manager, dependency)
54
+ def dependency_string
55
+ dependency.uid
56
+ end
44
57
 
45
- if dep_ok
46
- ok_deps += 1
47
- else
48
- problem_deps += 1
49
- report.concat(problems)
50
- end
51
- end
58
+ def license_string
59
+ dependency.license.records.map(&:id).compact.uniq.join(", ")
60
+ end
52
61
 
53
- if problem_deps > 0
54
- report << ">> Found #{dependencies.size} dependencies for #{dependency_manager}. #{ok_deps} OK, #{problem_deps} with problems"
62
+ def reason_string
63
+ case reason
64
+ when :not_allowed
65
+ "Not Allowed"
66
+ when :flagged
67
+ "Flagged"
68
+ when :undetermined
69
+ "Undetermined"
70
+ when :missing
71
+ "Missing"
72
+ else
73
+ "OK"
55
74
  end
56
75
  end
76
+ end
57
77
 
58
- report
78
+ attr_reader :all_dependencies
79
+ attr_reader :results
80
+ attr_reader :dependency_license_manifest
81
+
82
+ def initialize(all_dependencies)
83
+ @all_dependencies = all_dependencies.sort
84
+ @results = {}
85
+ @did_fail = false
86
+ @needs_fallback = false
87
+ @needs_exception = false
59
88
  end
60
89
 
61
- def license_info_ok?(dependency_manager, dependency)
62
- problems = []
63
- if dependency["name"].nil? || dependency["name"].empty?
64
- problems << "There is a dependency with a missing name in '#{dependency_manager}'."
65
- end
90
+ def report
91
+ generate_dependency_license_manifest
92
+ save_manifest_file
93
+ detect_problems
94
+ evaluate_results
95
+ end
66
96
 
67
- if dependency["version"].nil? || dependency["version"].empty?
68
- problems << "Dependency '#{dependency["name"]}' under '#{dependency_manager}' is missing version information."
69
- end
97
+ private
70
98
 
71
- if dependency["license"].nil? || dependency["license"].empty?
72
- problems << "Dependency '#{dependency["name"]}' version '#{dependency["version"]}' under '#{dependency_manager}' is missing license information."
99
+ def save_manifest_file
100
+ LicenseScout::Log.info("[reporter] Writing dependency license manifest written to #{license_manifest_path}")
101
+ File.open(license_manifest_path, "w+") do |file|
102
+ file.print(FFI_Yajl::Encoder.encode(dependency_license_manifest, pretty: true))
73
103
  end
104
+ end
74
105
 
75
- if dependency["license_files"].empty?
76
- problems << "Dependency '#{dependency["name"]}' version '#{dependency["version"]}' under '#{dependency_manager}' is missing license files information."
77
- else
78
- dependency["license_files"].each do |license_file|
79
- unless File.exist?(full_path_for(license_file))
80
- problems << "License file '#{license_file}' for the dependency '#{dependency["name"]}' version '#{dependency["version"]}' under '#{dependency_manager}' is missing."
106
+ def detect_problems
107
+ LicenseScout::Log.info("[reporter] Analyzing dependency's license information against requirements")
108
+
109
+ LicenseScout::Log.info("[reporter] Allowed licenses: #{LicenseScout::Config.allowed_licenses.join(", ")}") unless LicenseScout::Config.allowed_licenses.empty?
110
+ LicenseScout::Log.info("[reporter] Flagged licenses: #{LicenseScout::Config.flagged_licenses.join(", ")}") unless LicenseScout::Config.flagged_licenses.empty?
111
+
112
+ all_dependencies.each do |dependency|
113
+ @results[dependency.type] ||= []
114
+
115
+ if dependency.license.records.empty?
116
+ @results[dependency.type] << Result.failure(dependency, :missing)
117
+ @did_fail = true
118
+ @needs_fallback = true
119
+ elsif dependency.license.undetermined?
120
+ @results[dependency.type] << Result.failure(dependency, :undetermined)
121
+ @did_fail = true
122
+ @needs_fallback = true
123
+ elsif !LicenseScout::Config.allowed_licenses.empty? && !dependency.license.is_allowed?
124
+ unless dependency.has_exception?
125
+ @results[dependency.type] << Result.failure(dependency, :not_allowed)
126
+ @did_fail = true
127
+ @needs_exception = true
128
+ else
129
+ @results[dependency.type] << Result.success(dependency)
81
130
  end
131
+ elsif dependency.license.is_flagged?
132
+ unless dependency.has_exception?
133
+ @results[dependency.type] << Result.failure(dependency, :flagged)
134
+ @did_fail = true
135
+ @needs_exception = true
136
+ else
137
+ @results[dependency.type] << Result.success(dependency)
138
+ end
139
+ else
140
+ @results[dependency.type] << Result.success(dependency)
82
141
  end
83
142
  end
84
-
85
- [ problems.empty?, problems ]
86
143
  end
87
144
 
88
- def find_license_manifest!
89
- unless File.exist?(output_directory)
90
- raise LicenseScout::Exceptions::InvalidOutputReport.new("Output directory '#{output_directory}' does not exist.")
91
- end
145
+ def evaluate_results
146
+ table = Terminal::Table.new
147
+ table.headings = ["Type", "Dependency", "License(s)", "Results"]
148
+ table.style = { border_bottom: false } # the extra :separator will add this
92
149
 
93
- manifests = Dir.glob("#{output_directory}/*-dependency-licenses.json")
150
+ results.each do |type, results_for_type|
151
+ type_in_table = false
94
152
 
95
- if manifests.empty?
96
- raise LicenseScout::Exceptions::InvalidOutputReport.new("Can not find a dependency license manifest under '#{output_directory}'.")
97
- end
153
+ results_for_type.each do |result|
154
+ next if LicenseScout::Config.only_show_failures && result.succeeded?
155
+
156
+ modified_row = []
157
+ modified_row << (type_in_table ? "" : type)
158
+ modified_row << result.dependency_string
159
+ modified_row << result.license_string
160
+ modified_row << result.reason_string
161
+
162
+ type_in_table = true
163
+ table.add_row(modified_row)
164
+ end
98
165
 
99
- if manifests.length != 1
100
- raise LicenseScout::Exceptions::InvalidOutputReport.new("Found multiple manifests '#{manifests.join(", ")}' under '#{output_directory}'.")
166
+ table.add_separator if type_in_table
101
167
  end
102
168
 
103
- manifests.first
169
+ puts table unless LicenseScout::Config.only_show_failures && !@did_fail
170
+
171
+ puts
172
+ puts "Additional steps are required in order to pass Open Source license compliance:"
173
+ puts " * Please add fallback licenses for the 'Missing' or 'Undetermined' dependencies" if @needs_fallback
174
+ puts " https://github.com/chef/license_scout#fallback-licenses" if @needs_fallback
175
+ puts " * Please add exceptions for the 'Flagged' or 'Not Allowed' dependencies" if @needs_exception
176
+ puts " https://github.com/chef/license_scout#dependency-exceptions" if @needs_exception
177
+
178
+ exit 1 if @did_fail
104
179
  end
105
180
 
106
- def full_path_for(license_file_info)
107
- File.join(output_directory, license_file_info)
181
+ def generate_dependency_license_manifest
182
+ @dependency_license_manifest = {
183
+ license_manifest_version: 2,
184
+ generated_on: DateTime.now.to_s,
185
+ name: LicenseScout::Config.name,
186
+ dependencies: []
187
+ }
188
+
189
+ all_dependencies.each do |dep|
190
+ dependency_license_manifest[:dependencies] << {
191
+ type: dep.type,
192
+ name: dep.name,
193
+ version: dep.version,
194
+ has_exception: dep.has_exception?,
195
+ exception_reason: dep.exception_reason,
196
+ licenses: dep.license.records.map(&:to_h),
197
+ }
198
+ end
108
199
  end
109
200
 
201
+ def license_manifest_path
202
+ File.join(LicenseScout::Config.output_directory, "#{LicenseScout::Config.name}-dependency-licenses.json")
203
+ end
110
204
  end
111
205
  end
@@ -0,0 +1,123 @@
1
+ #
2
+ # Copyright:: Copyright 2018 Chef Software, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ #     http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ # This library was inspired by (and pulls some logic from) librariesio/spdx
19
+
20
+ require "ffi_yajl"
21
+ require "fuzzy_match"
22
+
23
+ module LicenseScout
24
+ class SPDX
25
+ class << self
26
+
27
+ # Try to find the SPDX ID that most closely matches the given license ID
28
+ #
29
+ # @param license_id [String, nil] The license ID
30
+ # @return [String, nil, false] Returns either the SPDX ID, false if the
31
+ # license_id was nil, or nil if we could not find a valid SPDX ID
32
+ def find(license_id, force = false)
33
+ return license_id if force
34
+ return nil if license_id.nil?
35
+ lookup(license_id) || find_by_special_case(license_id) || closest(license_id) || license_id
36
+ end
37
+
38
+ # Right now this just returns the license keys that are present in the string.
39
+ # In the future, we should handle a proper compound structure like
40
+ # https://github.com/jslicense/spdx-expression-parse.js
41
+ def parse(license_string)
42
+ license_string.nil? ? [] : (license_string.tr("()", "").split("\s") - spdx_join_words)
43
+ end
44
+
45
+ # @return [Hash] The SPDX license data in Hash form
46
+ def licenses
47
+ @@license_data ||= FFI_Yajl::Parser.parse(File.read(File.expand_path("../data/licenses.json", __FILE__)))["licenses"]
48
+ end
49
+
50
+ # @return [Hash] The SPDX license data in Hash form
51
+ def exceptions
52
+ @@license_data ||= FFI_Yajl::Parser.parse(File.read(File.expand_path("../data/exceptions.json", __FILE__)))["exceptions"]
53
+ end
54
+
55
+ def known_ids
56
+ @@known_ids ||= licenses.map { |l| l["licenseId"] }
57
+ end
58
+
59
+ def known_names
60
+ @@known_names ||= licenses.map { |l| l["name"] }
61
+ end
62
+
63
+ private
64
+
65
+ def lookup(license_id)
66
+ return license_id if known_ids.include?(license_id)
67
+ return spdx_for(license_id) if (Array(license_id) & known_names).any?
68
+ return license_id if (parse(license_id) & known_ids).any?
69
+ end
70
+
71
+ def find_by_special_case(license_id)
72
+ gpl = gpl_match(license_id)
73
+ return gpl unless gpl.nil?
74
+ lookup(special_cases[license_id.downcase])
75
+ end
76
+
77
+ def closest(license_id)
78
+ spdx_for(FuzzyMatch.new(known_names).find(license_id)) || FuzzyMatch.new(known_ids).find(license_id)
79
+ end
80
+
81
+ def gpl_match(license_id)
82
+ match = license_id.match(/^(l|a)?gpl-?\s?_?v?(1|2|3)\.?(\d)?(\+)?$/i)
83
+ return unless match
84
+ lookup("#{match[1]}GPL-#{match[2]}.#{match[3] || 0}#{match[4]}".upcase)
85
+ end
86
+
87
+ def spdx_for(license_name)
88
+ licenses.find { |n| n["name"] == license_name }["licenseId"]
89
+ end
90
+
91
+ def spdx_join_words
92
+ %w{WITH AND OR}
93
+ end
94
+
95
+ def special_cases
96
+ {
97
+ # Pulled from http://search.cpan.org/~dagolden/CPAN-Meta-2.150010/lib/CPAN/Meta/Spec.pm#license
98
+ "agpl_3" => "AGPL-3.0",
99
+ "apache_1_1" => "Apache-1.1",
100
+ "apache_2_0" => "Apache-2.0",
101
+ "artistic_1" => "Artistic-1.0",
102
+ "artistic_2" => "Artistic-2.0",
103
+ "bsd" => "BSD-3-Clause",
104
+ "freebsd" => "BSD-2-Clause-FreeBSD",
105
+ "gfdl_1_2" => "GFDL-1.2-only",
106
+ "gfdl_1_3" => "GFDL-1.3-only",
107
+ "lgpl_2_1" => "LGPL-2.1-only",
108
+ "lgpl_3_0" => "LGPL-3.0-only",
109
+ "mit" => "MIT",
110
+ "mozilla_1_0" => "MPL-1.0",
111
+ "mozilla_1_1" => "MPL-1.1",
112
+ "openssl" => "OpenSSL",
113
+ "qpl_1_0" => "QPL-1.0",
114
+ "perl" => "Artistic-1.0-Perl",
115
+ "perl_5" => "Artistic-1.0-Perl",
116
+ "ssleay" => "OpenSSL",
117
+ "sun" => "SISSL",
118
+ "zlib" => "Zlib",
119
+ }
120
+ end
121
+ end
122
+ end
123
+ end
@@ -16,5 +16,5 @@
16
16
  #
17
17
 
18
18
  module LicenseScout
19
- VERSION = "1.3.17".freeze
19
+ VERSION = "2.0.2"
20
20
  end
data/lib/license_scout.rb CHANGED
@@ -17,3 +17,5 @@
17
17
 
18
18
  module LicenseScout
19
19
  end
20
+
21
+ require "license_scout/cli"
@@ -0,0 +1,21 @@
1
+ # MixLockJson
2
+
3
+ **TODO: Add description**
4
+
5
+ ## Installation
6
+
7
+ If [available in Hex](https://hex.pm/docs/publish), the package can be installed
8
+ by adding `mix_lock_json` to your list of dependencies in `mix.exs`:
9
+
10
+ ```elixir
11
+ def deps do
12
+ [
13
+ {:mix_lock_json, "~> 0.1.0"}
14
+ ]
15
+ end
16
+ ```
17
+
18
+ Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
19
+ and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
20
+ be found at [https://hexdocs.pm/mix_lock_json](https://hexdocs.pm/mix_lock_json).
21
+
@@ -0,0 +1,20 @@
1
+ defmodule MixLockJson.CLI do
2
+ def main(mix_lock_path \\ "") do
3
+ mix_lock_path
4
+ |> parse_mix_lock
5
+ |> IO.puts
6
+ end
7
+
8
+ defp parse_mix_lock(mix_lock_path) do
9
+ {:ok, lockfile} = File.read(mix_lock_path)
10
+ {lock_deps, _} = lockfile |> Code.eval_string
11
+
12
+ Poison.encode!(Enum.reduce(lock_deps, [], fn(i, acc) ->
13
+ case i do
14
+ {name, {_, _, version, _hash, _, _child_deps, _}} -> [%{name => version} | acc]
15
+ {name, {:git, _path, hash, _}} -> [%{name => hash} | acc]
16
+ _ -> acc
17
+ end
18
+ end))
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ defmodule MixLockJson.MixProject do
2
+ use Mix.Project
3
+
4
+ def project do
5
+ [
6
+ app: :mix_lock_json,
7
+ version: "0.1.0",
8
+ escript: escript(),
9
+ deps: deps()
10
+ ]
11
+ end
12
+
13
+ def application do
14
+ [applications: []]
15
+ end
16
+
17
+ defp escript do
18
+ [
19
+ main_module: MixLockJson.CLI,
20
+ path: "../../bin/mix_lock_json",
21
+ app: nil,
22
+ embed_elixir: true
23
+ ]
24
+ end
25
+
26
+ defp deps do
27
+ [
28
+ {:poison, "~> 3.1"}
29
+ ]
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ %{
2
+ "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
3
+ }
@@ -11,11 +11,11 @@
11
11
  {<<"providers">>,{pkg,<<"providers">>,<<"1.6.0">>},1},
12
12
  {<<"rebar">>,
13
13
  {git,"https://github.com/erlang/rebar3",
14
- {ref,"4725d363c5b5583c9910f078da38c5b3a1d97aab"}},
14
+ {ref,"86e883b8d8d1d16487e245fff02eba8c83da2cdd"}},
15
15
  0},
16
16
  {<<"rebar3">>,
17
17
  {git,"https://github.com/erlang/rebar3",
18
- {ref,"86e883b8d8d1d16487e245fff02eba8c83da2cdd"}},
18
+ {ref,"cb743f76cbc26ac780066d285329e8a6c8330605"}},
19
19
  0},
20
20
  {<<"relx">>,{pkg,<<"relx">>,<<"3.22.2">>},1},
21
21
  {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.1">>},1}]}.