papers 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +5 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +163 -0
- data/Rakefile +8 -0
- data/bin/papers +8 -0
- data/lib/papers.rb +25 -0
- data/lib/papers/cli.rb +41 -0
- data/lib/papers/configuration.rb +46 -0
- data/lib/papers/dependency_specification.rb +35 -0
- data/lib/papers/dependency_specification/gem.rb +32 -0
- data/lib/papers/dependency_specification/javascript.rb +24 -0
- data/lib/papers/license_validator.rb +62 -0
- data/lib/papers/manifest_generator.rb +92 -0
- data/lib/papers/version.rb +8 -0
- data/papers.gemspec +32 -0
- data/spec/papers_spec.rb +206 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MjJiMDlhOTlmYjAzNjcwNDE1N2QxN2IyOGU2MTllOGNhNjVlMDI3Yg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MDBlNGZjZTRmMGQ5NTQ2Mjg4YWNjYzM0Y2M1MzNlM2RiMWY2NTBiYw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NGFhMTE2ZDg5MTg4ZDQ4NThhMDZjZTE3MzVkNDUwMDE4YzA0YzhhNDY3NWJk
|
10
|
+
ZDYwNGQzM2ExZWM1ZGU3ZmJjODgzNGM2NzRlYzBjMjhlOWFkYjI5OGFmODI4
|
11
|
+
NzQzZjI0ZWYxMzcyZDM1M2QyMmE3ZDgyOWFkMDQ3ZWUyNzg5NTU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
OWRkODEwYmFmNTRkZjE5OTg3OGUwZjU0MTJiNTVhNWVkZTgxMGIwNDc1MTEw
|
14
|
+
YzU1ZGU0ZGIyODQ0ZDNjODllZjBkYWM2MjdhMDJlYmI5ZWNiNWU1MzQ5ZDZm
|
15
|
+
YWUzZDBlM2Q0ZjBlNzA1YjE4YjRmNWMxMzgxYTI1ZDg3ZmQ4ZDY=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 New Relic
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
# Papers
|
2
|
+
|
3
|
+
> "Papers, please."
|
4
|
+
|
5
|
+
Check that your Ruby/Rails project's dependencies are licensed with only the licenses you specify. **Papers** will validate that your gems and JavaScript files conform to a whitelist of software licenses. Don't get caught flat-footed by the GPL.
|
6
|
+
|
7
|
+
# Contents
|
8
|
+
* [Usage](#usage)
|
9
|
+
* [Validations](#validations)
|
10
|
+
* [Configuration](#configuration)
|
11
|
+
* [Structure of Dependency Manifest](#dependency-manifest-structure)
|
12
|
+
* [License](#license)
|
13
|
+
* [Contributing](#contributing)
|
14
|
+
|
15
|
+
|
16
|
+
# Usage
|
17
|
+
|
18
|
+
tl;dr -- add gem, generate dependency manifest, run spec
|
19
|
+
|
20
|
+
### 0. Add gem to Gemfile
|
21
|
+
|
22
|
+
```
|
23
|
+
gem 'papers'
|
24
|
+
```
|
25
|
+
### 1. Generate Dependency Manifest from your bundled gems and JS
|
26
|
+
|
27
|
+
```
|
28
|
+
$ papers
|
29
|
+
```
|
30
|
+
### 2. Create [Validation Spec](#testing-with-rspec)
|
31
|
+
|
32
|
+
### 3. Run the specs
|
33
|
+
|
34
|
+
```
|
35
|
+
$ rake spec spec/integration/papers_license_validation_spec.rb
|
36
|
+
...
|
37
|
+
Failures:
|
38
|
+
|
39
|
+
1) Papers License Validation finds no errors during license validation
|
40
|
+
Failure/Error: expect(validator.errors).to eq([])
|
41
|
+
|
42
|
+
expected: []
|
43
|
+
got: ["sass-3.2.12 is licensed under GPL, which is not whitelisted"]
|
44
|
+
|
45
|
+
(compared using ==)
|
46
|
+
# ./spec/integration/papers_license_validation_spec.rb:14:in `block (2 levels) in <top (required)>'
|
47
|
+
|
48
|
+
2) Papers License Validation knows and is satisfied by all dependency licenses
|
49
|
+
Failure/Error: expect(validator.valid?).to be_true
|
50
|
+
expected: true value
|
51
|
+
got: false
|
52
|
+
# ./spec/integration/papers_license_validation_spec.rb:9:in `block (2 levels) in <top (required)>'
|
53
|
+
|
54
|
+
Finished in 0.01043 seconds
|
55
|
+
2 examples, 2 failures
|
56
|
+
...
|
57
|
+
```
|
58
|
+
|
59
|
+
# Validations
|
60
|
+
|
61
|
+
## testing with RSpec
|
62
|
+
|
63
|
+
```
|
64
|
+
# => spec/integration/papers_license_validation_spec.rb
|
65
|
+
|
66
|
+
require 'spec_helper'
|
67
|
+
require 'papers'
|
68
|
+
|
69
|
+
describe 'Papers License Validation' do
|
70
|
+
|
71
|
+
let(:validator) { Papers::LicenseValidator.new }
|
72
|
+
|
73
|
+
it 'knows and is satisfied by all dependency licenses' do
|
74
|
+
expect(validator.valid?).to be_true
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'finds no errors during license validation' do
|
78
|
+
validator.valid?
|
79
|
+
expect(validator.errors).to eq([])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
## testing with MiniTest
|
85
|
+
|
86
|
+
```
|
87
|
+
# => test/integration/papers_license_validation_test.rb
|
88
|
+
|
89
|
+
require 'test_helper'
|
90
|
+
require 'papers'
|
91
|
+
|
92
|
+
class PapersLicenseValidationTest < ActiveSupport::TestCase
|
93
|
+
def test_know_and_be_satisfied_by_all_licenses
|
94
|
+
validator = Papers::LicenseValidator.new
|
95
|
+
|
96
|
+
assert validator.valid?, "License validator failed:\n#{validator.errors.join("\n")}"
|
97
|
+
|
98
|
+
assert_equal validator.errors, []
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
# Configuration
|
104
|
+
|
105
|
+
The default whitelist allows for permissive licensing for proprietary or commercial usage while avoiding strong copyleft licenses.
|
106
|
+
|
107
|
+
```
|
108
|
+
@license_whitelist = [
|
109
|
+
'MIT',
|
110
|
+
'BSD',
|
111
|
+
'Apache 2.0',
|
112
|
+
'Apache-2.0',
|
113
|
+
'LGPLv2.1',
|
114
|
+
'LGPLv3',
|
115
|
+
'Ruby',
|
116
|
+
'Manually Reviewed',
|
117
|
+
'Unlicensed'
|
118
|
+
]
|
119
|
+
```
|
120
|
+
|
121
|
+
## Available configuration options
|
122
|
+
|
123
|
+
To configure the Papers gem, pass options to ```Papers.configure``` before initialization of LicenseValidator:
|
124
|
+
|
125
|
+
```
|
126
|
+
Papers.configure do |c|
|
127
|
+
c.license_whitelist << 'New Relic'
|
128
|
+
c.manifest_file = File.join('some','other','dependency_manifest.yml')
|
129
|
+
c.validate_gems = true
|
130
|
+
c.validate_javascript = true
|
131
|
+
c.javascript_paths << File.join('some','other','javascripts')
|
132
|
+
end
|
133
|
+
|
134
|
+
validator = Papers::LicenseValidator.new
|
135
|
+
...
|
136
|
+
```
|
137
|
+
|
138
|
+
# Dependency Manifest structure
|
139
|
+
|
140
|
+
```
|
141
|
+
# => config/papers_manifest.yml
|
142
|
+
---
|
143
|
+
gems:
|
144
|
+
sqlite3-1.3.7:
|
145
|
+
license: MIT
|
146
|
+
license_url: https://github.com/luislavena/sqlite3-ruby
|
147
|
+
project_url: https://github.com/luislavena/sqlite3-ruby/blob/master/LICENSE
|
148
|
+
...
|
149
|
+
|
150
|
+
javascripts:
|
151
|
+
app/assets/javascripts/application.js:
|
152
|
+
license: New Relic
|
153
|
+
license_url: http://newrelic.com
|
154
|
+
project_url: http://newrelic.com
|
155
|
+
```
|
156
|
+
|
157
|
+
# License
|
158
|
+
|
159
|
+
The Papers Gem is licensed under the __MIT License__. See [MIT-LICENSE](https://github.com/newrelic/papers/blob/master/MIT-LICENSE) for full text.
|
160
|
+
|
161
|
+
# Contributing
|
162
|
+
|
163
|
+
You are welcome to send pull requests to us - however, by doing so you agree that you are granting New Relic a non-exclusive, non-revokable, no-cost license to use the code, algorithms, patents, and ideas in that code in our products if we so choose. You also agree the code is provided as-is and you provide no warranties as to its fitness or correctness for any purpose.
|
data/Rakefile
ADDED
data/bin/papers
ADDED
data/lib/papers.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'papers/configuration'
|
2
|
+
require 'papers/license_validator'
|
3
|
+
require 'papers/manifest_generator'
|
4
|
+
require 'papers/cli'
|
5
|
+
require 'papers/version'
|
6
|
+
|
7
|
+
require 'papers/dependency_specification'
|
8
|
+
require 'papers/dependency_specification/gem'
|
9
|
+
require 'papers/dependency_specification/javascript'
|
10
|
+
|
11
|
+
module Papers
|
12
|
+
def self.configure(&block)
|
13
|
+
yield configuration
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.configuration
|
17
|
+
@config ||= Configuration.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# alias
|
21
|
+
def self.config
|
22
|
+
configuration
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/papers/cli.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Papers
|
4
|
+
|
5
|
+
class CLI
|
6
|
+
|
7
|
+
def run
|
8
|
+
if parse_options[:generate]
|
9
|
+
begin
|
10
|
+
generator = Papers::ManifestGenerator.new
|
11
|
+
generator.generate!
|
12
|
+
rescue Papers::FileExistsError => e
|
13
|
+
warn "Error: 'papers_manifest.yml' already exists at '#{e.message}'. Aborting..."
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def parse_options
|
21
|
+
options = {}
|
22
|
+
OptionParser.new do |opts|
|
23
|
+
opts.banner = "Usage: papers [options]"
|
24
|
+
|
25
|
+
opts.on("-g", "--generate", "Generate papers_manifest.yml") do |v|
|
26
|
+
options[:generate] = v
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on_tail( '-h', '--help', 'Display this screen' ) do |v|
|
30
|
+
p opts
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
@avail_opts = opts
|
34
|
+
end.parse!
|
35
|
+
|
36
|
+
p @avail_opts if options.empty?
|
37
|
+
|
38
|
+
return options
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Papers
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :license_whitelist
|
4
|
+
|
5
|
+
attr_accessor :manifest_file
|
6
|
+
|
7
|
+
attr_accessor :validate_gems
|
8
|
+
|
9
|
+
attr_accessor :validate_javascript
|
10
|
+
|
11
|
+
attr_accessor :javascript_paths
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@license_whitelist = [
|
15
|
+
'MIT',
|
16
|
+
'BSD',
|
17
|
+
'Apache 2.0',
|
18
|
+
'Apache-2.0',
|
19
|
+
'LGPLv2.1',
|
20
|
+
'LGPLv3',
|
21
|
+
'Ruby',
|
22
|
+
'Manually Reviewed',
|
23
|
+
'Unlicensed'
|
24
|
+
]
|
25
|
+
|
26
|
+
@manifest_file = File.join(Dir.pwd, 'config', 'papers_manifest.yml')
|
27
|
+
|
28
|
+
@validate_gems = true
|
29
|
+
@validate_javascript = true
|
30
|
+
|
31
|
+
@javascript_paths = [
|
32
|
+
File.join(Dir.pwd, 'app', 'assets', 'javascripts'),
|
33
|
+
File.join(Dir.pwd, 'lib', 'assets', 'javascripts'),
|
34
|
+
File.join(Dir.pwd, 'vendor', 'assets', 'javascripts')
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate_gems?
|
39
|
+
!!@validate_gems
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate_javascript?
|
43
|
+
!!@validate_javascript
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Papers
|
2
|
+
class DependencySpecification
|
3
|
+
attr_accessor :name, :license, :license_url, :project_url
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@name = options[:name]
|
7
|
+
@license = options[:license]
|
8
|
+
@license_url = options[:license_url]
|
9
|
+
@project_url = options[:project_url]
|
10
|
+
end
|
11
|
+
|
12
|
+
def acceptable_license?
|
13
|
+
Papers.config.license_whitelist.include?(license)
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def self.all_from_manifest(manifest)
|
19
|
+
(manifest[manifest_key] || []).map do |name, info|
|
20
|
+
license_url = info['license_url']
|
21
|
+
license = info['license']
|
22
|
+
project_url = info['project_url']
|
23
|
+
self.new(name: name, license: license, license_url: license_url, project_url: project_url)
|
24
|
+
end.sort { |a, b| a.name.downcase <=> b.name.downcase }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.missing_from_manifest(manifest)
|
28
|
+
introspected.to_set - all_from_manifest(manifest).map(&:name).to_set
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.unknown_in_manifest(manifest)
|
32
|
+
all_from_manifest(manifest).map(&:name).to_set - introspected.to_set
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Papers
|
2
|
+
class Gem < DependencySpecification
|
3
|
+
def pretty_hash
|
4
|
+
{
|
5
|
+
name: name_without_version,
|
6
|
+
license: license,
|
7
|
+
license_url: @license_url,
|
8
|
+
project_url: @project_url
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def name_without_version
|
13
|
+
return @name unless @name.include?('-')
|
14
|
+
@name.split('-')[0..-2].join('-')
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.introspected
|
18
|
+
Bundler.load.specs.map do |spec|
|
19
|
+
# bundler versions aren't controlled by the Gemfile
|
20
|
+
if spec.name == "bundler"
|
21
|
+
spec.name
|
22
|
+
else
|
23
|
+
"#{spec.name}-#{spec.version}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.manifest_key
|
29
|
+
"gems"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Papers
|
2
|
+
class Javascript < DependencySpecification
|
3
|
+
def pretty_hash
|
4
|
+
{
|
5
|
+
name: @name,
|
6
|
+
license: license,
|
7
|
+
license_url: @license_url,
|
8
|
+
project_url: @project_url
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.introspected
|
13
|
+
dirs = Papers.config.javascript_paths
|
14
|
+
|
15
|
+
# TODO: add logic for determining rails. Is Rails.root better than Dir.pwd for such a case?
|
16
|
+
root_regexp = /^#{Regexp.escape Dir.pwd.to_s}\//
|
17
|
+
dirs.map { |dir| Dir["#{dir}/**/*.js"] }.flatten.map { |name| name.sub(root_regexp, '') }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.manifest_key
|
21
|
+
"javascripts"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
require 'papers/dependency_specification'
|
4
|
+
require 'papers/dependency_specification/gem'
|
5
|
+
require 'papers/dependency_specification/javascript'
|
6
|
+
|
7
|
+
module Papers
|
8
|
+
class LicenseValidator
|
9
|
+
attr_reader :errors
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@errors = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?
|
16
|
+
@errors = []
|
17
|
+
|
18
|
+
validate_gems if Papers.config.validate_gems?
|
19
|
+
validate_js if Papers.config.validate_javascript?
|
20
|
+
|
21
|
+
@errors.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
def manifest
|
25
|
+
@manifest ||= YAML.load_file(Papers.config.manifest_file)
|
26
|
+
end
|
27
|
+
|
28
|
+
def pretty_gem_list
|
29
|
+
Gem.all_from_manifest(manifest).map(&:pretty_hash)
|
30
|
+
end
|
31
|
+
|
32
|
+
def pretty_js_list
|
33
|
+
Javascript.all_from_manifest(manifest).map(&:pretty_hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def validate_spec_type(spec_type)
|
39
|
+
spec_type.missing_from_manifest(manifest).each do |name|
|
40
|
+
errors << "#{name} is included in the application, but not in the manifest"
|
41
|
+
end
|
42
|
+
|
43
|
+
spec_type.unknown_in_manifest(manifest).each do |name|
|
44
|
+
errors << "#{name} is included in the manifest, but not in the application"
|
45
|
+
end
|
46
|
+
|
47
|
+
spec_type.all_from_manifest(manifest).each do |spec|
|
48
|
+
unless spec.acceptable_license?
|
49
|
+
errors << "#{spec.name} is licensed under #{spec.license}, which is not whitelisted"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def validate_gems
|
55
|
+
validate_spec_type Gem
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate_js
|
59
|
+
validate_spec_type Javascript
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'yaml'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Papers
|
6
|
+
|
7
|
+
class FileExistsError < StandardError;
|
8
|
+
attr_reader :manifest_path
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
@manifest_path = path
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class ManifestGenerator
|
17
|
+
|
18
|
+
def generate!(args = ARGV)
|
19
|
+
@manifest_path = File.join('config','papers_manifest.yml')
|
20
|
+
|
21
|
+
raise Papers::FileExistsError.new(@manifest_path) if manifest_exists?
|
22
|
+
|
23
|
+
begin
|
24
|
+
if FileUtils.mkdir_p(File.dirname(@manifest_path))
|
25
|
+
File.open(@manifest_path, 'w') do |file|
|
26
|
+
file.write(build_header)
|
27
|
+
file.write(YAML.dump(build_manifest))
|
28
|
+
end
|
29
|
+
puts "Created #{@manifest_path}!"
|
30
|
+
end
|
31
|
+
rescue RuntimeError => e
|
32
|
+
warn "Failure! #{e}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def build_manifest
|
39
|
+
manifest = {
|
40
|
+
"gems" => get_installed_gems,
|
41
|
+
"javascripts" => get_installed_javascripts
|
42
|
+
}
|
43
|
+
return manifest
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_installed_gems
|
47
|
+
gems = {}
|
48
|
+
Bundler.load.specs.each do |spec|
|
49
|
+
if spec.name == 'bundler'
|
50
|
+
name_and_version = spec.name
|
51
|
+
else
|
52
|
+
name_and_version = "#{spec.name}-#{spec.version}"
|
53
|
+
end
|
54
|
+
|
55
|
+
gems[name_and_version] = {
|
56
|
+
'license' => spec.license || 'Unknown',
|
57
|
+
'license_url' => nil,
|
58
|
+
'project_url' => spec.homepage || nil
|
59
|
+
# TODO: add support for multiple licenses? some gemspecs have dual licensing
|
60
|
+
}
|
61
|
+
end
|
62
|
+
return gems
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_installed_javascripts
|
66
|
+
js = {}
|
67
|
+
Javascript.introspected.each do |entry|
|
68
|
+
js[entry] = {
|
69
|
+
'license' => 'Unknown',
|
70
|
+
'license_url' => nil,
|
71
|
+
'project_url' => nil
|
72
|
+
}
|
73
|
+
end
|
74
|
+
js.empty? ? nil : js
|
75
|
+
end
|
76
|
+
|
77
|
+
def manifest_exists?
|
78
|
+
!!File.exist?(@manifest_path)
|
79
|
+
end
|
80
|
+
|
81
|
+
def build_header
|
82
|
+
[
|
83
|
+
"# Dependency Manifest for the Papers gem",
|
84
|
+
"# Used to test your gems and javascript against license whitelist",
|
85
|
+
"#",
|
86
|
+
"# http://github.com/newrelic/papers\n"
|
87
|
+
].join("\n")
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/papers.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
4
|
+
|
5
|
+
require 'papers/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = 'papers'
|
9
|
+
s.version = Papers::VERSION
|
10
|
+
s.summary = 'Validate the licenses of software dependencies you use'
|
11
|
+
|
12
|
+
s.description = <<-DESCRIPTION
|
13
|
+
Validate that the licenses used by your Ruby project's dependencies (both gems
|
14
|
+
and javascript libraries) conform to a software license whitelist. Don't get
|
15
|
+
caught flat-footed by the GPL.
|
16
|
+
DESCRIPTION
|
17
|
+
|
18
|
+
s.authors = ['Ralph Bodenner', 'Jade Rubick', 'Andrew Bloomgarden', 'Lucas Charles']
|
19
|
+
s.email = 'support@newrelic.com'
|
20
|
+
s.license = 'MIT'
|
21
|
+
s.homepage = 'http://github.com/newrelic/papers'
|
22
|
+
|
23
|
+
s.files = `git ls-files`.split($/)
|
24
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split($/)
|
25
|
+
s.executables = s.files.grep(/^bin\//) { |f| File.basename(f) }
|
26
|
+
|
27
|
+
s.require_paths = ['lib']
|
28
|
+
|
29
|
+
# dependencies
|
30
|
+
s.add_dependency 'rake', '~> 10.1'
|
31
|
+
s.add_development_dependency 'rspec', '~> 2.14'
|
32
|
+
end
|
data/spec/papers_spec.rb
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'rspec'
|
3
|
+
require_relative '../lib/papers'
|
4
|
+
|
5
|
+
describe 'Papers' do
|
6
|
+
|
7
|
+
let(:validator) { Papers::LicenseValidator.new }
|
8
|
+
|
9
|
+
it 'validates a manifest with empty values and set of dependencies' do
|
10
|
+
Papers::LicenseValidator.any_instance.stub(:manifest).and_return({
|
11
|
+
"javascripts" => {},
|
12
|
+
"gems" => {}
|
13
|
+
})
|
14
|
+
Papers::Gem.stub(:introspected).and_return([])
|
15
|
+
|
16
|
+
expect(validator.valid?).to be_true
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'detects mismatched gems' do
|
20
|
+
Papers::LicenseValidator.any_instance.stub(:manifest).and_return({
|
21
|
+
"javascripts" => {},
|
22
|
+
"gems" => {
|
23
|
+
"foo-1.2" => {
|
24
|
+
'license' => "MIT",
|
25
|
+
'license_url' => nil,
|
26
|
+
'project_url' => nil
|
27
|
+
},
|
28
|
+
"baz-1.3" => {
|
29
|
+
'license' => "BSD",
|
30
|
+
'license_url' => nil,
|
31
|
+
'project_url' => nil
|
32
|
+
}
|
33
|
+
}
|
34
|
+
})
|
35
|
+
Papers::Gem.stub(:introspected).and_return(["bar-1.2", "baz-1.3"])
|
36
|
+
|
37
|
+
expect(validator.valid?).to be_false
|
38
|
+
|
39
|
+
expect(validator.errors).to eq([
|
40
|
+
"bar-1.2 is included in the application, but not in the manifest",
|
41
|
+
"foo-1.2 is included in the manifest, but not in the application"
|
42
|
+
])
|
43
|
+
|
44
|
+
validator.valid?
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'detects mismatched gem versions' do
|
48
|
+
Papers::Configuration.any_instance.stub(:validate_javascript?).and_return(true)
|
49
|
+
|
50
|
+
expect(validator).to receive(:validate_js).at_least(:once)
|
51
|
+
|
52
|
+
Papers::LicenseValidator.any_instance.stub(:manifest).and_return({
|
53
|
+
"javascripts" => {},
|
54
|
+
"gems" => {
|
55
|
+
"foo-1.2" => {
|
56
|
+
'license' => "MIT",
|
57
|
+
'license_url' => nil,
|
58
|
+
'project_url' => nil
|
59
|
+
},
|
60
|
+
"baz-1.3" => {
|
61
|
+
'license' => "BSD",
|
62
|
+
'license_url' => nil,
|
63
|
+
'project_url' => nil
|
64
|
+
}
|
65
|
+
}
|
66
|
+
})
|
67
|
+
Papers::Gem.stub(:introspected).and_return(["foo-1.2", "baz-1.2"])
|
68
|
+
|
69
|
+
expect(validator.valid?).to be_false
|
70
|
+
|
71
|
+
expect(validator.errors).to eq([
|
72
|
+
"baz-1.2 is included in the application, but not in the manifest",
|
73
|
+
"baz-1.3 is included in the manifest, but not in the application"
|
74
|
+
])
|
75
|
+
validator.valid?
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'is OK with matching gem sets' do
|
79
|
+
Papers::LicenseValidator.any_instance.stub(:manifest).and_return({
|
80
|
+
"javascripts" => {},
|
81
|
+
"gems" => {
|
82
|
+
"foo-1.2" => {
|
83
|
+
'license' => "MIT",
|
84
|
+
'license_url' => nil,
|
85
|
+
'project_url' => nil
|
86
|
+
},
|
87
|
+
"baz-1.3" => {
|
88
|
+
'license' => "BSD",
|
89
|
+
'license_url' => nil,
|
90
|
+
'project_url' => nil
|
91
|
+
}
|
92
|
+
},
|
93
|
+
})
|
94
|
+
Papers::Gem.stub(:introspected).and_return(["foo-1.2", "baz-1.3"])
|
95
|
+
|
96
|
+
expect(validator.valid?).to be_true
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'is OK with matching gem sets but complain about a license issue' do
|
100
|
+
Papers::LicenseValidator.any_instance.stub(:manifest).and_return({
|
101
|
+
"javascripts" => {},
|
102
|
+
"gems" => {
|
103
|
+
"foo-1.2" => {
|
104
|
+
'license' => "MIT",
|
105
|
+
'license_url' => nil,
|
106
|
+
'project_url' => nil
|
107
|
+
},
|
108
|
+
"baz-1.3" => {
|
109
|
+
'license' => "GPL",
|
110
|
+
'license_url' => nil,
|
111
|
+
'project_url' => nil
|
112
|
+
}
|
113
|
+
},
|
114
|
+
})
|
115
|
+
Papers::Gem.stub(:introspected).and_return(["foo-1.2", "baz-1.3"])
|
116
|
+
|
117
|
+
expect(validator.valid?).to be_false
|
118
|
+
|
119
|
+
expect(validator.errors).to eq([
|
120
|
+
"baz-1.3 is licensed under GPL, which is not whitelisted"
|
121
|
+
])
|
122
|
+
|
123
|
+
validator.valid?
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'displays gem licenses in a pretty format without versions' do
|
127
|
+
Papers::LicenseValidator.any_instance.stub(:manifest).and_return({
|
128
|
+
"javascripts" => {},
|
129
|
+
"gems" => {
|
130
|
+
"foo-1.2" => {
|
131
|
+
'license' => "MIT",
|
132
|
+
'license_url' => nil,
|
133
|
+
'project_url' => nil
|
134
|
+
},
|
135
|
+
"baz-1.3" => {
|
136
|
+
'license' => "BSD",
|
137
|
+
'license_url' => nil,
|
138
|
+
'project_url' => nil
|
139
|
+
},
|
140
|
+
"with-hyphens-1.4" => {
|
141
|
+
'license' => "MIT",
|
142
|
+
'license_url' => nil,
|
143
|
+
'project_url' => nil
|
144
|
+
}
|
145
|
+
},
|
146
|
+
})
|
147
|
+
expect(validator.pretty_gem_list).to eq([
|
148
|
+
{
|
149
|
+
:name=>"baz",
|
150
|
+
:license=>"BSD",
|
151
|
+
:license_url => nil,
|
152
|
+
:project_url => nil
|
153
|
+
},
|
154
|
+
{
|
155
|
+
:name=>"foo",
|
156
|
+
:license=>"MIT",
|
157
|
+
:license_url => nil,
|
158
|
+
:project_url => nil
|
159
|
+
},
|
160
|
+
{
|
161
|
+
:name=>"with-hyphens",
|
162
|
+
:license=>"MIT",
|
163
|
+
:license_url => nil,
|
164
|
+
:project_url => nil
|
165
|
+
}
|
166
|
+
])
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'displays JS libraries in a pretty format without versions' do
|
170
|
+
Papers::LicenseValidator.any_instance.stub(:manifest).and_return({
|
171
|
+
"javascripts" => {
|
172
|
+
"/path/to/foo.js" => {
|
173
|
+
'license' => "MIT",
|
174
|
+
'license_url' => nil,
|
175
|
+
'project_url' => nil
|
176
|
+
},
|
177
|
+
"/path/to/newrelic.js" => {
|
178
|
+
'license' => "New Relic",
|
179
|
+
'license_url' => nil,
|
180
|
+
'project_url' => nil
|
181
|
+
}
|
182
|
+
},
|
183
|
+
"gems" => {}
|
184
|
+
})
|
185
|
+
expect(validator.pretty_js_list).to eq([
|
186
|
+
{
|
187
|
+
:name =>"/path/to/foo.js",
|
188
|
+
:license =>"MIT",
|
189
|
+
:license_url => nil,
|
190
|
+
:project_url => nil
|
191
|
+
},
|
192
|
+
{
|
193
|
+
:name =>"/path/to/newrelic.js",
|
194
|
+
:license =>"New Relic",
|
195
|
+
:license_url => nil,
|
196
|
+
:project_url => nil
|
197
|
+
}
|
198
|
+
])
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'displays the gem name when the gemspec does not specify a version' do
|
202
|
+
gemspec = Papers::Gem.new(name: 'foo')
|
203
|
+
expect('foo').to eq(gemspec.name_without_version)
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: papers
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ralph Bodenner
|
8
|
+
- Jade Rubick
|
9
|
+
- Andrew Bloomgarden
|
10
|
+
- Lucas Charles
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2013-12-10 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rake
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '10.1'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '10.1'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ~>
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '2.14'
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '2.14'
|
44
|
+
description: ! 'Validate that the licenses used by your Ruby project''s dependencies
|
45
|
+
(both gems
|
46
|
+
|
47
|
+
and javascript libraries) conform to a software license whitelist. Don''t get
|
48
|
+
|
49
|
+
caught flat-footed by the GPL.
|
50
|
+
|
51
|
+
'
|
52
|
+
email: support@newrelic.com
|
53
|
+
executables:
|
54
|
+
- papers
|
55
|
+
extensions: []
|
56
|
+
extra_rdoc_files: []
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- Gemfile
|
60
|
+
- MIT-LICENSE
|
61
|
+
- README.md
|
62
|
+
- Rakefile
|
63
|
+
- bin/papers
|
64
|
+
- lib/papers.rb
|
65
|
+
- lib/papers/cli.rb
|
66
|
+
- lib/papers/configuration.rb
|
67
|
+
- lib/papers/dependency_specification.rb
|
68
|
+
- lib/papers/dependency_specification/gem.rb
|
69
|
+
- lib/papers/dependency_specification/javascript.rb
|
70
|
+
- lib/papers/license_validator.rb
|
71
|
+
- lib/papers/manifest_generator.rb
|
72
|
+
- lib/papers/version.rb
|
73
|
+
- papers.gemspec
|
74
|
+
- spec/papers_spec.rb
|
75
|
+
homepage: http://github.com/newrelic/papers
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.1.5
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Validate the licenses of software dependencies you use
|
99
|
+
test_files:
|
100
|
+
- spec/papers_spec.rb
|
101
|
+
has_rdoc:
|