How We Started Continuous OSS License Monitoring with License Finder

masutaka

Takashi Masuda

Posted on November 28, 2024

How We Started Continuous OSS License Monitoring with License Finder

Hey Devs!

Recently, some products in our company have started the process of becoming OSS (Open Source Software). In OSS projects, conflicts between the licenses of utilized packages and the project's license can pose a risk.

Today, I'd like to share how we began addressing this risk and monitoring it continuously by introducing a tool called License Finder.

Introduction to License Finder

License Finder is a Ruby-based CLI tool for license checking, developed by Pivotal (now VMware).

GitHub logo pivotal / LicenseFinder

Find licenses for your project's dependencies.

It integrates with package managers to discover dependencies and identify the licenses of each package. It supports bundler, npm, pnpm, and more.

The identified licenses are compared against a list of licenses approved by the user, and the results are outputted. It can also be integrated into CI pipelines.

Installation

Install License Finder with Ruby 2.6.0 or later:

$ gem install license_finder
Enter fullscreen mode Exit fullscreen mode

Usage

Install dependency packages using tools like bundle install or npm install.

Then simply run License Finder.

💡 The package manager is automatically detected. If you want to configure it manually, you can do so by editing the config/license_finder.yml file. For details, see Saving Configuration in the README.md.

When executed, all dependency packages are output with their license names. Initially, all packages are unapproved:

$ license_finder
LicenseFinder::Bundler: is active for '/Users/masutaka/work'

Dependencies that need approval:
actioncable, 7.2.1, MIT
actionmailbox, 7.2.1, MIT
(snip)
Enter fullscreen mode Exit fullscreen mode

Approving Dependencies

The goal is to have zero unapproved dependencies.

Typically, you approve licenses as a whole, and if needed, approve or ignore individual packages. Here are some examples:

# Permit MIT and Apache-2.0 licenses
$ license_finder permitted_licenses add "MIT" "Apache 2.0"

# Specify "who" and "why" when permitting a license
$ license_finder permitted_licenses add "Simplified BSD" --who CTO --why "Go ahead"

# Approve the package awesome_gpl_gem
$ license_finder approvals add awesome_gpl_gem

# Ignore the package awesome_ignore_gem
$ license_finder ignored_dependencies add awesome_ignore_gem
Enter fullscreen mode Exit fullscreen mode

By default, the decisions are saved in doc/dependency_decisions.yml.

Introducing License Finder to CI

When there are no unapproved packages, License Finder returns an exit code of 0. Using this feature, it can be incorporated into CI (GitHub Actions).

Example Integration with GitHub Actions

Here’s an example of integration in giselles-ai/giselle.

🔗 https://github.com/giselles-ai/giselle/blob/v0.3.1/.github/workflows/license.yml

The license_finder job (L18-L104) includes two main tasks:

  1. Execute License Finder (L80-L82). The CI fails if unapproved licenses are found, allowing us to detect licensing issues
  2. Update the license report docs/packages-license.md and commit it to the repository (L84-L104)

The license report is committed to the repository to meet requirements from licenses like CC BY 4.0 that mandate attribution. To reduce maintenance costs, the report is updated automatically using GitHub Actions.

Below are additional customizations:

  • The license_finder job takes about 3 minutes, so it only executes when necessary:
    • It runs only when files like package.json are updated (L48-L66)
    • Since this job is a required check before merging pull requests, no filtering is done in the on: section
  • For pull requests from forked repositories, the license report is not updated:
    • This is because GitHub Actions cannot access Repository variables/secrets needed to generate a GitHub App Token for committing changes
    • Although changing on: pull_request: to on: pull_request_target: would allow access, we avoided this due to security risks
  • The license report is not updated on the default branch

To update the license report, we created a GitHub App1 with the following permissions and installed it in the repository:

  • Contents: Read and write
  • Metadata: Read-only

Instead of the GITHUB_TOKEN environment variable, we used a GitHub App Token for the following reasons:

  • The license_finder job is a required check before merging pull requests
  • Even after committing via GitHub Actions, the license_finder job should still execute for the newly created commit
  • If GITHUB_TOKEN is used for commits, they are considered bot operations, and CI is not triggered
  • Personal Access Tokens have long lifetimes, so we avoid using them whenever possible

Conclusion

If you’re considering an in-house solution for monitoring OSS licenses, License Finder could be an option. However, without sufficient knowledge of licenses, there’s a risk of mistakenly approving dependencies (see appendix). Another concern is that development on License Finder is not very active.

For now, we plan to continue using License Finder while keeping SaaS options like FOSSA in mind.

Appendix: How ROUTE06, Inc. Handles It

Here's how we handle cases where License Finder fails in CI.

How to Handle License Finder Failures in CI

License Finder fails when a package with a license not permitted in the decisions file is added.

Below is an example of CI failing because the npm package mdn-data uses the CC0 1.0 Universal license, which is not permitted.

Example of a License Finder Failure

Please follow the response flow outlined below.

Response Flow

  1. Check the license of the relevant package
  2. Confirm that the identified license is compatible with the license of the OSS repository in question
  3. Take action based on the following cases:
    • Case 1: The licenses are compatible
      • Example: The repository is licensed under Apache-2.0, and the package uses the Zlib license
    • Case 2: The licenses are not compatible
      • Example: The repository is licensed under Apache-2.0, and the package uses GPL-3.0-only
    • Case 3: The license is unknown

Case 1: The licenses are compatible

If the licenses are compatible, allow the license in License Finder.

## Example of permitting the Zlib license
$ license_finder permitted_licenses add 'Zlib' \
 --why 'Compatible with Apache-2.0 license. See https://opensource.org/license/Zlib' \
 --who 'OSPO @masutaka'
Enter fullscreen mode Exit fullscreen mode
  • [Recommended] Use the --why option to specify the reason for permitting the license. Including the URL of the license can be helpful
  • [Optional] Use the --who option to specify who granted the permission

Case 2: The licenses are not compatible

Copyleft licenses such as GPL, LGPL, AGPL, or EPL may not be compatible with permissive licenses like MIT or Apache-2.0.

  • Compatible cases:
    • Using an Apache-2.0 package in a GPLv3 product
  • Incompatible cases:
    • Using a GPLv3 package in an Apache-2.0 product

When licenses are incompatible, you must take appropriate actions:

  • Exclude GPLv3 or other incompatible packages from the product
  • Change the entire product license to GPLv3 or similar
  • Separate the incompatible package and use it independently
  • Seek legal advice

Case 3: The license is unknown

If the package registry or Git repository does not specify the license, contact the provider.

Depending on the situation, if it seems acceptable, create an issue and approve the package temporarily.

$ license_finder approvals add '@vercel/flags' \
 --why 'The license is none. Check https://github.com/giselles-ai/giselle/issues/12 later'
Enter fullscreen mode Exit fullscreen mode

Once the license is identified, remove the approval and re-run License Finder. If it fails again, follow the previously mentioned response flow.

$ license_finder approvals remove '@vercel/flags' \
 --why 'It was released as OSS under the MIT license.'
Enter fullscreen mode Exit fullscreen mode

If the issue seems problematic, consider alternatives such as using a different package or temporarily holding off on merging into the main branch.

Supplement: License Finder Supports Composite Licenses with AND or OR

There are cases of composite licenses like (MIT AND Zlib) for the npm package pako.

License Finder supports AND and OR, so in such cases, you only need to permit MIT and Zlib individually. There is no need to permit (MIT AND Zlib) explicitly.


  1. Creating GitHub Apps - GitHub Docs ↩

💖 💪 🙅 🚩
masutaka
Takashi Masuda

Posted on November 28, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related