license_scout 1.3.7 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
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 -1120
  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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 821efe0b7cbe4c23507fd59f9ff95d1f581e31a5de758f99274ace3b201dc759
4
- data.tar.gz: 2a8237eb322b64cdd18203d9e971916a032faac03107f683238af38716dd5390
3
+ metadata.gz: 9b68d1311c50cda672da2ff036a9933a38d45e7a79e8a9c40352d839ba818186
4
+ data.tar.gz: 5efda8ed1041680fb943017f5f6015765ef33a77fffb428e0c402fb685778446
5
5
  SHA512:
6
- metadata.gz: 3ecf357fa8c9b1f2926b406a45b729a056fedf4365abb1208c8725521001f3f43164c8210d163cc94f670971e8bb61340f5da7fd5ce1aa2cd10931b89dbdd9e3
7
- data.tar.gz: 4dd72ce9855374853248b7fa80090a292474d058033537706a7819d5a5a6e22c8e440558fe4794c95059c263ed7737685df6fa34b6a177917c618d9f79120b1c
6
+ metadata.gz: 0cfac147a17d18bba538ce8152015c9fea05c7b8956d3a9db6beb0bcea990951bd19d7fb855fef4f4a03a02f2ea71e09608192c6ea882a0b92045f8967da702e
7
+ data.tar.gz: c337a0bd8b8aa6906a5ed992012df0de3a42fe190dc63fce545c6a1407a4f818f5dccc6abd69304aec334c1ecb3749057605d31404720986b30169ba4ec6042c
data/README.md ADDED
@@ -0,0 +1,195 @@
1
+ # License Scout
2
+
3
+ License Scout is a utility that discovers and aggregates the licenses for your software project's transitive dependencies.
4
+
5
+ Currently supported Dependency Types and Dependency Managers are:
6
+
7
+ Dependency Type | Supported Dependency Managers
8
+ --- | ---
9
+ chef_cookbook | berkshelf
10
+ erlang | rebar
11
+ elixir | mix
12
+ golang | dep, godep, glide
13
+ habitat | habitat
14
+ nodejs | npm
15
+ perl | cpan
16
+ ruby | bundler
17
+
18
+ ## Dependencies
19
+
20
+ * If you wish to scan for `berkshelf` dependencies, you'll need to manually install the Berkshelf gem in the same Ruby as License Scout
21
+ * If you wish to scan for `mix` or `rebar` dependencies, you'll need to install Erlang OTP 18.3 or greater.
22
+
23
+ ## Usage
24
+
25
+ License Scout's default behavior is to scan the current directory and return a breakdown of all the licenses it can find.
26
+
27
+ ```bash
28
+ my_project $ license_scout
29
+
30
+ +------+------------+------------+---------+
31
+ | Type | Dependency | License(s) | Results |
32
+ +------+------------+------------+---------+
33
+ ...
34
+ ```
35
+
36
+ LicenseScout will exit `0` if it was able to find licenses for all your dependencies. Otherwise, it will exit `1`.
37
+
38
+ Under the covers, License Scout leverages [Licensee](http://ben.balter.com/licensee/) (the same Ruby Gem [GitHub](https://developer.github.com/v3/licenses/) uses to detect [OSS licenses](https://spdx.org/licenses/)). In addition to using Licensee to scan your source code for licenses, License Scout will go a step further and attempt to determine if the metadata provided by the Dependency Manager specifies which license each dependency uses. At the end of the process, License Scout will provide you a Dependency Manifest following information:
39
+
40
+ 1. The name of the license(s) (the SPDX ID if the a recognized open source license).
41
+ 2. The name of the file where the License Scout found the license.
42
+ 3. The contents of the license file (if available).
43
+
44
+ In addition to the printout provided to STDOUT, License Scout will also save a JSON manifest of all your dependencies to disk.
45
+
46
+ ```json
47
+ {
48
+ "license_manifest_version": 2,
49
+ "generated_on": "<DATE>",
50
+ "name": "<YOUR_PROJECT>",
51
+ "dependencies": [...]
52
+ }
53
+ ```
54
+
55
+ For more information about the structure of JSON manifest, please check out the full [JSON Schema](lib/license_scout/data/dependency_manifest_v2_schema.json).
56
+
57
+ ### Result Types
58
+
59
+ License Scout will provide a summary of the licenses it finds to STDOUT. These results are intended to provide direction as to which actions may or may not be necessary to generate a Dependency Manifest that meets all of your compliance requirements. To do this it categorizes its findings into the following results.
60
+
61
+ Result | Description
62
+ --- | ---
63
+ Flagged | License Scout was able to determine the license for this software dependency, and it is one of the licenses you have explicitly flagged. You should either remove the dependency or [add an Exception](#dependency-exceptions).
64
+ Missing | License Scout could not find any license files or license metadata associated with this dependency. You should contact the maintainer and/or specify a [Fallback License](#fallback-licenses).
65
+ Not Allowed | License Scout was able to determine the license for this software dependency, but it is not one of the licenses you have explicitly allowed. You should either remove the dependency or [add an Exception](#dependency-exceptions).
66
+ OK | There were no issues.
67
+ Undetermined | License Scout found a license file but was unable to determine (with sufficient confidence) what license that file represents. License Scout was also unable to determine the license using Dependency Manager metadata. You should contact the maintainer and/or specify a [Fallback License](#fallback-licenses).
68
+
69
+ ## Advanced Usage
70
+
71
+ ### Configuration File(s)
72
+
73
+ You can control License Scout's behavior by providing one or more YAML configuration files, available either locally or via HTTP, to the `--config-files` option of the CLI.
74
+
75
+ ```bash
76
+ $ license_scout --config-files http://example.com/license_scout/common.yml,./.license_scout.yml
77
+ ```
78
+
79
+ License Scout evalutes these files in the order they are provided, allowing you to hydrate configuration by composing multiple files together. For example, you can have a single organization-wide configuration file that specifies what licenses are allowed and project-specific configuration file that specifies exceptions and which directories to scan.
80
+
81
+ #### How multiple configuration files are handled
82
+
83
+ License Scout uses [mixlib-config](https://github.com/chef/mixlib-config) to handle it's configuration. When loading multiple configuration files, mixlib-config (and thus License Scout) will not perform deep merges of Arrays. That means that License Scout will not merge (for example) `allowed_licenses` (or `flagged_licenses`) from two different configuration files; it will only take the `allowed_licenses` value from the configuration that is loaded last. This logic does not apply to the `fallbacks` or `exceptions`, because those are defined as [`config_contexts`](lib/license_scout/config.rb). It **does** apply to the individuals types specified within the `fallbacks` or `exceptions` however.
84
+
85
+ ### Allowed and Flagged Licenses
86
+
87
+ License Scout provides you with the ability to provide a list of licenses that are explicitly allowed, or a list of licenses that should be flagged for further scrutiny.
88
+
89
+ - When you specify a list of `allowed_licenses`, License Scout will exit `1` if it detects a dependency with a license other than one on the list.
90
+ - When you specify a list of `flagged_licenses`, License Scout will exit `1` if it finds a dependency with that license.
91
+
92
+ To add a license to the list of allowed or flagged licenses, you need only provide the array of licenses as a string in your configuration file. A configuration may have a list of allowed licenses _or_ flagged licenses, it cannot have both. _License Scout does not support regular expressions or glob-patterms for `allowed_licenses` or `flagged_licenses`._
93
+
94
+ ```yaml
95
+ allowed_licenses:
96
+ - Apache-2.0
97
+
98
+ # OR
99
+
100
+ flagged_licenses:
101
+ - Apache-2.0
102
+ ```
103
+
104
+ License Scout will compare these string values to the licenses it finds within the dependencies. License Scout does its best to resolve everything down to valid [SPDX IDs](https://spdx.org/licenses/), so you should specify licenses using their SDPX ID.
105
+
106
+ > _Warning: Because we cannot control how maintainers specify licenses in their metadata, there may be a situation where License Scout cannot correctly detect the intended SPDX ID. In this case, you may need to temporarily provide a temporary Fallback License in your configuration. If you encounter this situation, we encourage you to [open an Issue](https://github.com/chef/license_scout) with us._
107
+
108
+ ### Dependency Exceptions
109
+
110
+ If you specify a list of allowed or flagged licenses, there may be a dependency that does not adhere to the specified license(s) for which you wish to make an exception. License Scout allows you to specify Exceptions to these lsits as part of your Configuration File.
111
+
112
+ ```yaml
113
+ ---
114
+ allowed_licenses:
115
+ - Apache-2.0
116
+
117
+ exceptions:
118
+ ruby:
119
+ - name: bundler
120
+ reason: Used only during .gem creation
121
+ - name: json (1.8.3)
122
+ ```
123
+
124
+ Exceptions are organized by `type` (e.g. `ruby` - see Table above). There are two elements to each exception: a `name` and a `reason`.
125
+
126
+ Property | Description
127
+ --- | ---
128
+ `name` | Can be specified by `dep-name` or `dep-name (dep-version)` where `dep-name` is the name of the dependency as it exists in the Dependency Manifest and `dep-version` can be a traditional version, git reference, or type-specific version specification such as `$pkg_version-$pkg_release` for Habitat.
129
+ `reason` | An optional string that will be included in the Dependency Manifest for documentation purposes.
130
+
131
+ Simple glob-style pattern matching _is_ supported for Exceptions, so you can have an Exception for a large collection of dependencies without enumerating them all.
132
+
133
+ ```yaml
134
+ ---
135
+ exceptions:
136
+ chef_cookbook:
137
+ - name: apache2 (5.*)
138
+ reason: Allowed by TICKET-001
139
+ habitat:
140
+ - name: core/bundler (1.15.1-*)
141
+ reason: Only used for .gem creation
142
+ ruby:
143
+ - name: aws-sdk-*
144
+ reason: Exception granted by Bobo T. Clown on 2018/02/31
145
+ ```
146
+
147
+ ### Fallback Licenses
148
+
149
+ In situations where License Scout is unable to determine the license for a particular dependency, either because Licensee was not able to identify any of the license files or the Dependency Manager did not provide any metadata that incidated how the dependency was licensed, you'll need to provide a Fallback License in your configuration. Like Exceptions, Fallback Licenses are grouped by `type`.
150
+
151
+ ```yaml
152
+ fallbacks:
153
+ golang:
154
+ - name: github.com/dchest/siphash
155
+ license_id: CC0-1.0
156
+ license_content: https://raw.githubusercontent.com/dchest/siphash/master/README.md
157
+ ```
158
+
159
+ Property | Description
160
+ --- | ---
161
+ name | The name of the dependency as it appears in the JSON manifest.
162
+ license_id | The ID of the license as it appears in the JSON manifest.
163
+ license_content | A URL to a file where the raw text of the license can be downloaded.
164
+
165
+ In addition to including any files Licensee identified as potential license files (but couldn't identify), License Scout will also include the Fallback License you specified in the Dependency Manifest.
166
+
167
+ ## Configuration
168
+
169
+ Value | Description | Default
170
+ --- | --- | ---
171
+ directories | The fully-qualified local paths to the directories you wish to scan | _The current working directory._ |
172
+ name | The name you want to give to the scan result. | _The basename of the first directory to be scanned._ |
173
+ output_directory | The path to the directory where the output JSON file should be saved. | _The current working directory._ |
174
+ log_level | What log information should be included in STDOUT | `info` |
175
+ allowed_licenses | Only allow dependencies to have these licenses. | `[]` |
176
+ flagged_licenses | An array of licenses that should be flagged for removal or exception. | `[]` |
177
+ exceptions | An array of Exceptions. | `[]` |
178
+ environment | A hash of additional Environment Variables to pass to [mixlib-shellout](https://github.com/chef/mixlib-shellout) | `{}` |
179
+ escript_bin | The path to the `escript` binary you wish to use when shelling out to Erlang. | `escript` |
180
+ ruby_bin | The path to the `ruby` binary you wish to use when shelling out to Ruby. | `ruby` |
181
+ cpanm_root | The path to where the cpanminus install cache is located. | `~/.cpanm` |
182
+
183
+ ## Contributing
184
+
185
+ This project is maintained by the contribution guidelines identified for [chef](https://github.com/chef/chef) project. You can find the guidelines here:
186
+
187
+ https://github.com/chef/chef/blob/master/CONTRIBUTING.md
188
+
189
+ Pull requests in this project are merged when they have two :+1:s from maintainers.
190
+
191
+ ## Maintainers
192
+
193
+ - [Dan DeLeo](https://github.com/danielsdeleo)
194
+ - [Tom Duffield](https://github.com/tduffield)
195
+
data/bin/license_scout CHANGED
@@ -16,64 +16,8 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- $:.unshift File.expand_path("../lib", __dir__)
19
+ $:.unshift File.expand_path("../../lib", __FILE__)
20
20
 
21
- require "license_scout/collector"
22
- require "license_scout/overrides"
23
- require "license_scout/options"
21
+ require "license_scout"
24
22
 
25
- project_dir = ARGV[0] || File.expand_path(Dir.pwd)
26
- project_name = File.basename(project_dir)
27
-
28
- # Create the output files under a specific directory in order not to pollute the
29
- # project_dir too much.
30
- output_dir = File.join(project_dir, "license-cache")
31
-
32
- overrides = LicenseScout::Overrides.new
33
-
34
- opts = LicenseScout::Options.new(overrides: overrides)
35
-
36
- collector = LicenseScout::Collector.new(project_name, project_dir, output_dir, opts)
37
-
38
- collector.run
39
- report = collector.issue_report
40
-
41
- unless report.empty?
42
- puts report
43
-
44
- puts <<~EXPLANATION
45
-
46
- How to fix this depends on what information license_scout was unable to
47
- determine:
48
-
49
- * If the package is missing license information, that means license_scout was
50
- unable to determine which license the package was released under. Depending
51
- on the package manager, this is usually specified in the package's metadata,
52
- for example, in the gemspec file for rubygems or in the package.json for npm.
53
- If you know which license a package was released under, MIT for example, you
54
- can add an override in license_scout's overrides.rb file in the section for
55
- the appropriate package manager like this:
56
- ["package-name", "MIT", nil]
57
-
58
- * If the package is missing the license file, that means license_scout could not
59
- find the license text in any of the places the license is typically found, for
60
- example, in a file named LICENSE in the root of the package. If the package
61
- includes the license text in a non standard location or in its source repo,
62
- you can indicate this by adding an override in license_scout's overrides.rb
63
- file in the section for the appropriate package manager like this:
64
- ["package-name", nil, ["https://example.com/foocorp/package-name/master/LICENSE"]],
65
-
66
- If you know that the package was released under one of the common software
67
- licenses, MIT for example, but does not include the license text in packaged
68
- releases or in its source repo, you can add an override in license_scout's
69
- overrides.rb file in the section for the appropriate package manager like
70
- this:
71
- ["package-name", nil, [canonical("MIT")]]
72
-
73
- See the closed pull requests on the license_scout repo for examples of how to
74
- do this:
75
- https://github.com/chef/license_scout/pulls?q=is%3Apr+is%3Aclosed
76
- EXPLANATION
77
-
78
- exit 2
79
- end
23
+ LicenseScout::CLI.new.run
data/bin/mix_lock_json ADDED
Binary file
data/bin/rebar_lock_json CHANGED
Binary file
@@ -0,0 +1,99 @@
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
+ require "mixlib/cli"
19
+ require "license_scout/config"
20
+ require "license_scout/collector"
21
+ require "license_scout/reporter"
22
+
23
+ module LicenseScout
24
+ class CLI
25
+ include Mixlib::CLI
26
+
27
+ #
28
+ # These config values should match values available in LicenseScout::Config
29
+ #
30
+ option :config_files,
31
+ short: "-c CONFIG_FILES",
32
+ long: "--config-files CONFIG_FILES",
33
+ description: "Comma-separated list of local (or remote) YAML configuration file(s) evaluated in order specified (priority goes to last file)",
34
+ proc: Proc.new { |c| c.split(",") }
35
+
36
+ option :directories,
37
+ short: "-d DIRECTORIES",
38
+ long: "--directories DIRECTORIES",
39
+ description: "Comma-separated list of directories to scan",
40
+ proc: Proc.new { |d| d.split(",") }
41
+
42
+ option :log_level,
43
+ short: "-l LEVEL",
44
+ long: "--log-level LEVEL",
45
+ description: "Set the log level (debug, info, warn, error, fatal)",
46
+ proc: Proc.new { |l| l.to_sym }
47
+
48
+ option :only_show_failures,
49
+ long: "--only-show-failures",
50
+ description: "Only print results for dependencies with licenses that failed checks",
51
+ boolean: true
52
+
53
+ option :help,
54
+ short: "-h",
55
+ long: "--help",
56
+ description: "Show this message",
57
+ on: :tail,
58
+ boolean: true,
59
+ show_options: true,
60
+ exit: 0
61
+
62
+ def run(argv = ARGV)
63
+ parse_options(argv)
64
+
65
+ LicenseScout::Config.merge!(config)
66
+
67
+ LicenseScout::Log.level = LicenseScout::Config.log_level
68
+ LicenseScout::Log.formatter = proc do |sev, datetime, progname, msg|
69
+ "#{sev.ljust(5)} #{msg}\n"
70
+ end
71
+
72
+ LicenseScout::Config.config_files.each do |config_file|
73
+ if config_file =~ /^http/
74
+ require "open-uri"
75
+
76
+ LicenseScout::Log.info("[cli] Loading config from #{config_file}")
77
+
78
+ Dir.mktmpdir do |dir|
79
+ local_tmp_file = File.join(dir, File.basename(config_file))
80
+ IO.copy_stream(open(config_file), local_tmp_file)
81
+ LicenseScout::Config.from_file(local_tmp_file)
82
+ end
83
+ else
84
+ full_config_file = File.expand_path(config_file)
85
+ LicenseScout::Log.info("[cli] Loading config from #{full_config_file}")
86
+ LicenseScout::Config.from_file(full_config_file)
87
+ end
88
+ end
89
+
90
+ LicenseScout::Config.validate!
91
+
92
+ collector = LicenseScout::Collector.new
93
+ collector.collect
94
+
95
+ reporter = LicenseScout::Reporter.new(collector.dependencies)
96
+ reporter.report
97
+ end
98
+ end
99
+ end
@@ -15,103 +15,51 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
+ require "license_scout/log"
18
19
  require "license_scout/exceptions"
19
20
  require "license_scout/dependency_manager"
20
- require "license_scout/reporter"
21
-
22
- require "ffi_yajl" unless defined?(FFI_Yajl)
21
+ require "license_scout/license"
23
22
 
24
23
  module LicenseScout
25
24
  class Collector
26
25
 
27
- attr_reader :project_name
28
- attr_reader :project_dir
29
- attr_reader :output_dir
30
- attr_reader :license_manifest_data
31
- attr_reader :options
26
+ attr_reader :dependencies
32
27
 
33
- def initialize(project_name, project_dir, output_dir, options)
34
- @project_name = project_name
35
- @project_dir = project_dir
36
- @output_dir = output_dir
37
- @options = options
38
- end
39
-
40
- def dependency_managers
41
- @dependency_managers ||= all_dependency_managers.select(&:detected?)
42
- end
43
-
44
- def run
45
- reset_license_manifest
46
-
47
- unless File.exist?(project_dir)
48
- raise LicenseScout::Exceptions::ProjectDirectoryMissing.new(project_dir)
49
- end
50
-
51
- FileUtils.mkdir_p(output_dir) unless File.exist?(output_dir)
28
+ def collect
29
+ @dependencies = Set.new
52
30
 
53
31
  if dependency_managers.empty?
54
- raise LicenseScout::Exceptions::UnsupportedProjectType.new(project_dir)
32
+ raise LicenseScout::Exceptions::Error.new("Failed to find any files associated with known dependency managers in the following directories:\n#{LicenseScout::Config.directories.map { |dir| "\t• #{dir}" }.join("\n")}\n")
55
33
  end
56
34
 
57
35
  dependency_managers.each { |d| collect_licenses_from(d) }
58
36
 
59
- File.open(license_manifest_path, "w+") do |file|
60
- file.print(FFI_Yajl::Encoder.encode(license_manifest_data, pretty: true))
61
- end
62
- end
63
-
64
- def issue_report
65
- Reporter.new(output_dir).report
37
+ LicenseScout::Log.info("[collector] All licenses successfully collected")
66
38
  end
67
39
 
68
40
  private
69
41
 
70
- def reset_license_manifest
71
- @license_manifest_data = {
72
- license_manifest_version: 1,
73
- project_name: project_name,
74
- dependency_managers: {},
75
- }
76
- end
77
-
78
- def license_manifest_path
79
- File.join(output_dir, "#{project_name}-dependency-licenses.json")
80
- end
81
-
82
- def collect_licenses_from(dependency_manager)
83
- dependency_manager.dependencies.each do |dep|
84
- license_manifest_data[:dependency_managers][dep.dep_mgr_name] ||= []
85
-
86
- license_data = {
87
- name: dep.name,
88
- version: dep.version,
89
- license: dep.license,
90
- license_files: [],
91
- }
92
-
93
- dep.license_files.each do |license_file|
94
- output_license_filename = [
95
- dependency_manager.name,
96
- dep.name,
97
- dep.version,
98
- File.basename(license_file),
99
- ].join("-")
100
- output_license_path = File.join(output_dir, output_license_filename)
101
- FileUtils.cp(license_file, output_license_path)
102
-
103
- license_data[:license_files] << output_license_filename
104
- end
105
-
106
- license_manifest_data[:dependency_managers][dep.dep_mgr_name] << license_data
107
-
42
+ def collect_licenses_from(dep_mgr)
43
+ LicenseScout::Log.info("[collector] Collecting licenses for #{dep_mgr.type} dependencies found in #{dep_mgr.directory}/#{dep_mgr.signature}")
44
+ dep_mgr.dependencies.each do |dep|
45
+ @dependencies << dep
108
46
  end
47
+ rescue LicenseScout::Exceptions::MissingSourceDirectory => e
48
+ raise LicenseScout::Exceptions::Error.new("#{e.message}\n\n\tPlease try running `#{dep_mgr.install_command}` to download the dependency.\n")
109
49
  end
110
50
 
111
- def all_dependency_managers
112
- LicenseScout::DependencyManager.implementations.map do |implementation|
113
- implementation.new(project_dir, options)
114
- end
51
+ def dependency_managers
52
+ @dependency_managers ||= LicenseScout::Config.directories.map do |dir|
53
+ LicenseScout::DependencyManager.implementations.map do |implementation|
54
+ dep_mgr = implementation.new(File.expand_path(dir))
55
+ if dep_mgr.detected?
56
+ LicenseScout::Log.info("[collector] Found #{dep_mgr.signature} in #{dir}")
57
+ dep_mgr
58
+ else
59
+ nil
60
+ end
61
+ end
62
+ end.flatten.compact
115
63
  end
116
64
  end
117
65
  end
@@ -0,0 +1,94 @@
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
+ require "mixlib/config"
19
+ require "tmpdir"
20
+
21
+ require "license_scout/exceptions"
22
+ require "license_scout/log"
23
+ require "license_scout/license"
24
+
25
+ module LicenseScout
26
+ module Config
27
+ extend Mixlib::Config
28
+
29
+ # Inputs
30
+ default :directories, [File.expand_path(Dir.pwd)]
31
+ default :name, File.basename(directories.first)
32
+ default :config_files, [File.join(File.expand_path(Dir.pwd), ".license_scout.yml")]
33
+
34
+ # Output
35
+ default :log_level, :info
36
+ default :output_directory, Dir.pwd
37
+ default :only_show_failures, false
38
+
39
+ # Compliance Specifications
40
+ default :allowed_licenses, []
41
+ default :flagged_licenses, []
42
+
43
+ config_context :exceptions do
44
+ default :chef_cookbook, []
45
+ default :elixir, []
46
+ default :erlang, []
47
+ default :golang, []
48
+ default :habitat, []
49
+ default :nodejs, []
50
+ default :perl, []
51
+ default :ruby, []
52
+ end
53
+
54
+ config_context :fallbacks do
55
+ default :chef_cookbook, []
56
+ default :elixir, []
57
+ default :erlang, []
58
+ default :golang, []
59
+ default :habitat, []
60
+ default :nodejs, []
61
+ default :perl, []
62
+ default :ruby, []
63
+ end
64
+
65
+ # Runtime Parameters
66
+ default :environment, {}
67
+ default :ruby_bin, "ruby"
68
+ default :escript_bin, "escript"
69
+ default :cpanm_root, "#{ENV["HOME"]}/.cpanm"
70
+
71
+ #
72
+ # Helpers
73
+ #
74
+
75
+ class << self
76
+
77
+ def validate!
78
+ if !allowed_licenses.empty? && !flagged_licenses.empty?
79
+ raise LicenseScout::Exceptions::ConfigError.new("You may specify a list of licenses to allow or flag. You may not specify both.")
80
+ end
81
+
82
+ if (allowed_licenses.empty? && flagged_licenses.empty?) && dependency_exceptions?
83
+ LicenseScout::Log.warn("You have specified one or more dependency exceptions, but no allowed or flagged licenses. License Scout will ignore the depdendency exceptions.")
84
+ end
85
+
86
+ directories.each do |dir|
87
+ unless File.directory?(File.expand_path(dir))
88
+ raise LicenseScout::Exceptions::ConfigError.new("The '#{dir}' directory could not be found.")
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,62 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-06/schema#",
3
+ "title": "LicenseScout Manifest v2",
4
+ "description": "A breakdown of all the dependencies (and their licenses) for a software project",
5
+ "type": "object",
6
+ "properties": {
7
+ "license_manifest_version": {
8
+ "description": "The schema version for this document",
9
+ "type": "integer"
10
+ },
11
+ "generated_on": {
12
+ "description": "The timestamp corresponding with when the manifest was generated.",
13
+ "type": "string"
14
+ },
15
+ "name": {
16
+ "description": "The name to associate with the manifest. This is useful for configurations that include multiple directories.",
17
+ "type": "string"
18
+ },
19
+ "dependencies": {
20
+ "type": "object",
21
+ "properties": {
22
+ "type": {
23
+ "description": "The Depedency Type",
24
+ "type": "string"
25
+ },
26
+ "name": {
27
+ "description": "The name of the dependency",
28
+ "type": "string"
29
+ },
30
+ "version": {
31
+ "description": "The version of the dependendency. Can be a traditional version, git reference, or type-specific version specification such as `$pkg_version-$pkg_release` for Habitat",
32
+ "type": "string"
33
+ },
34
+ "has_exception": {
35
+ "description": "Whether or not an exception was specified for this dependency",
36
+ "type": "boolean"
37
+ },
38
+ "exception_reason": {
39
+ "description": "The user-provided reason for the exception",
40
+ "type": "string"
41
+ },
42
+ "licenses": {
43
+ "type": "object",
44
+ "properties": {
45
+ "id": {
46
+ "description": "The license ID. This can either be the null (if no license was determeind), the SPDX ID, or some other license name provided by the dependency maintainer.",
47
+ "type": ["string", "null"]
48
+ },
49
+ "source": {
50
+ "description": "From when the license ID was determined",
51
+ "type": "string"
52
+ },
53
+ "content": {
54
+ "description": "The actual content of the license (if available)",
55
+ "type": ["string", "null"]
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+ }