"Open-source software (OSS) is great. Anyone can use virtually any open-source code in their projects."
Well, it depends. Licenses can make things difficult, especially when you are developing closed-source software. Since some OSS licenses even require the employing application to be open-sourced as well (looking at you, GPL), you cannot use such software in a closed-source project.
To be sure on this, we have developed a project-level integration of Pivotal's excellent license_finder Show archive.org snapshot that validates all dependencies during a regular test run. It will protect you from accidentally adding libraries with problematic licenses.
gem 'license_finder'
to the develoment dependencies of your project and run bundle install
spec/license_finder_spec.rb
with describe 'license_finder' do
describe 'action_items' do
before :all do # rubocop:disable RSpec/BeforeAfterAll
@stdout, @stderr, @status = Open3.capture3('license_finder action_items')
end
it 'activates all expected package managers' do
package_managers = @stdout.scan(/^LicenseFinder::(\w+).*is active/).flatten
expect(package_managers).to contain_exactly 'Bundler', 'Please list all expected package managers here'
end
it 'has no dependencies with unapproved licenses' do
expect(@status).to be_success, @stdout + @stderr
end
end
end
The first spec ensures no package manager is accidentally skipped (especially in the fragile Bower integration). Whenever a library with an unapproved (or restricted) license is added to the project, the second spec will fail.
Run the spec now and update its list of package managers.
Optional: Create an alias to simplify running LicenseFinder.
echo "alias lf='bundle exec license_finder'" >> ~/.bash_aliases # Store alias
source ~/.bash_aliases # Load stored aliases
For current versions of yarn (>=2) you will have to
install a plugin
Show archive.org snapshot
to have the yarn licenses
command available
LicenseFinder can exclude certain dependency groups from its report, for example development
and test
(add devDependencies
for yarn
). This only works with
certain package managers (among which Bundler and Yarn)
Show archive.org snapshot
. You can do so with:
bundle exec license_finder ignored_groups add $GROUP --why $REASON
LicenseFinder runs as part of the test suite. Run manually with
bundle exec license_finder
It will detect all known package managers Show archive.org snapshot automatically (among which Bundler and Yarn) and check the license of all dependencies.
This is how the output may look when all dependencies are approved:
This is how it may look when dependencies need approval (it is also the output of the failing licenses spec):
Read on to learn what to do about the output. All decisions are written to doc/dependency_decisions.yml. Please always state the reason for your decision with --why
.
When you are absolutely sure that a license can be used in any circumstances, you may permit it. Ask someone if you are not sure. Github license pages Show archive.org snapshot or tldrlegal.com Show archive.org snapshot give a good overview about a license's permissions, limitations and conditions.
Permit a license with
bundle exec license_finder permitted_licenses add $LICENSE --why $REASON
Dependencies with this license will automatically be considered approved, and will no more show up in the action items list. If you know there is a license that can never be used in your project, restrict it with
bundle exec license_finder restricted_licenses add AGPL --why 'Requires to open-source the whole application'
Some libraries will bring a license that has not been white listed. If your usage is valid with regard to that library's license, you can approve a single library without generally white-listing its license. GPL-licensed libraries are a candidate for this.
bundle exec license_finder approvals add $DEPENDENCY --why $REASON
When a license is reported as "unknown", you need to detect it manually. Check if current versions sport a license. Check package.json
, composer.json
, README
.
Once you know the license, tell LicenseFinder with
bundle exec license_finder licenses add $DEPENDENCY $LICENSE --why $LICENSE_FILE_URL
bundle exec license_finder licenses add ntlm-http ruby --why https://github.com/trampoline/ntlm-http/blob/9a61eaf20bd93ba035c17a79df0e9c814ffe6f2e/lib/net/ntlm_http.rb
Sometimes there may be a dependency the package manager does not know about, e.g. a copied tracking snippet or some nested dependency. Tell LicenseFinder with
bundle exec license_finder dependencies add $DEPENDENCY $LICENSE $VERSION --why $REASON
Use sparingly, as manually added dependencies are not updated automatically (obviously).
--who $NAME
to each decision to state who made the decision. However, Git logs will usually reveal that.license_finder help [command]
for help.Bower-rails is a Bower wrapper that simplifies Rails integration. Unfortunately, it makes it harder to integrate Bower with LicenseFinder. To get things running, follow these steps:
ln -s vendor/assets/bower.json
.bowerrc
file at the project root with
{
"comment": "Together with the bower.json symlink, this file integrates bower-rails with license_finder.",
"directory": "vendor/assets/bower_components"
}
Manually vendored libraries in vendor/asset-libs/ are not discovered by LicenseFinder. Convert each such library to a local Ruby gem by following these steps:
vendor/asset-libs/$library-$version
to a new sub-directory vendor/asset-libs/$library-$version/lib/assets/javascripts
. That's simply a path sprockets will consider, it is no problem if it contains non-JS files.$library-$version/local-$library.gemspec
with
Gem::Specification.new do |s|
s.name = 'local-$library'
s.summary = 'local copy of $library'
s.homepage = $homepage
s.version = $version
s.licenses = [$license]
s.authors = [$author]
s.files = Dir.chdir(__dir__) { Dir.glob('**/*') }
s.add_runtime_dependency 'rails', '< 100' # Silence warnings by adding version
end
This is a minimal gemspec.$library-$version/lib/local-$library.rb
with
module Local$Library
class Engine < ::Rails::Engine
end
end
Having the gem contain a Rails engine activates Sprockets, which will retrieve assets from the gem.$library-$version
to local-$library
gem 'local-$library', path: 'vendor/asset-libs/local-$library'
Finally, remove the asset path customization from config/initializers/assets.rb:
-# Load asset libs folders
-Rails.application.config.assets.paths += Dir[Rails.root.join('vendor/asset-libs/*')].sort_by { |dir| -dir.size }