Ports license auditing infrastructure
Table of Contents
Project description
This project is about adding a license framework to the ports system (i.e. bsd.licenses.mk), allowing it to be aware of the license used by each port. Another part of this project is to find an automated solution (so maintainers don't have to specify each port's license). With this information the infrastructure will be able to automate many tasks such as: restrict licenses, redistribution of files, identifying GPLv3 ports, etc.
See Project Ideas entry.
Project goals
Concrete features of the framework:
- Each port will have notion of the license type it has, and the permissions/restrictions it has (specially about redistribution).
- Users will be able to restrict certain licenses (either by default permit or default deny policies).
- If license is not allowed/denied by the user, an agreement will be presented (there will be framework-default and user preferences).
- Automated in any way possible (considering available resources): common licenses' permissions already defined (BSD, GPL, etc), and integration with FOSSology (after considering; it may be useful for determining the license, but only to assist the maintainer).
See below for a more detailed description.
Other (partial) implementations
The following partial implementations, and their TODO list are useful for the design.
NetBSD
The framework provides LICENSE, ACCEPTABLE_LICENSES, and DEFAULT_ACCEPTABLE_LICENSES. The first one is defined by the port, second optionally by users and the third by the framework.
Ports must define a license type, and if it's not in the accepted list the port will refuse to build.
There is a target show-license that displays LICENSE_FILE to the user.
See Handling licences, license.mk and TODO (section "Licenses of packages").
OpenBSD
The framework provides 4 variables PERMIT_{PACKAGE|DISTFILES}_{CDROM|FTP} (but no LICENSE like?) to control the redistribution. There is a policy to install license files under /usr/local/share/doc/<name>/
See Porting checklist and bsd.port.mk (see license-check and PERMIT_*).
Gentoo
Currently only supports attaching a license name to an ebuild, but there is a draft for adding more functionality.
See GLEP 23 (PRs at the end).
Design
As for other implementations the following considerations seem important:
Defining restrictions
Mainly there are 4 types of restrictions, depending on the distribution type and what is to be redistributed.
Item |
Type |
Description |
Distfile |
FTP |
Mirroring |
Distfile |
CDROM |
Selling |
Package |
FTP |
Mirroring |
Package |
CDROM |
Selling |
There are also licenses that restrict distribution of binaries created from modified source code, but generally these ones aren't friendly at all for redistributing binaries.
In addition, some applications can't be linked with incompatible licensed code, but our dependencies don't track this directly (a port in BUILD_DEPENDS may be used to process a file, or to link an archive file with code).
License grouping
Grouping licenses under tags like GPL, FSF and OSI is useful for the user to be able to accept or reject a particular group.
Other groups can be created having nothing to do with the mentioned ones, like CDROM_FRIENDLY or RESTRICTED_REDISTRIBUTION.
See:
http://en.wikipedia.org/wiki/Comparison_of_free_software_licences
http://fossology.org/interpret_the_license_group_analysis_report (and link to Fedora licenses)
http://developer.kde.org/documentation/licensing/licenses_summary.html
Multiple licenses
Another important consideration is when an application has more than one license, which could happen in the following cases:
- Dual licenses (OR - allows accepting one of them; the package can have any license).
Perl, with the license choice being GPL or the Artistic license.
Open Sound System, allowing to choose GPL, BSD, or CDDL`.
- Multiple licenses (AND - needs accepting all of them; the package will have all the restrictions).
- Optional code (i.e. OpenSSL when patented algorithms are enabled).
- Licensed artwork but open source application (i.e. some open sourced games with licensed demo data).
Status
Description of actual progress made up to now, current items and plans for the near future.
Features
- Defining license name, permissions and groups.
User variables to accept or reject individual licenses (see LICENSES_{ACCEPTED,REJECTED}).
Group tags, with global accept/reject policy via user variables (see LICENSES_GROUPS_{ACCEPTED,REJECTED}).
Simple database in bsd.licenses.db.mk for common licenses (with their permissions and groups).
- Verbose output and identification of port license status (accepted/rejected/ask).
User variable to disable automatic agreement, for better control (see LICENSES_ASK).
Menu interface based on dialog (GUI), or text interface if desired (see NO_LICENSES_DIALOGS).
Replace current variables NO_PACKAGE, NO_CDROM, RESTRICTED and RESTRICTED_FILES with more convenient (and automatic) ones. Leaving NO_PACKAGE for corresponding cases, and the rest unused.
Replace ports/LEGAL as licenses can be attached to certain distfiles only.
Multiple licenses support: dual (OR) and multi (AND). See LICENSE_COMB. But they can't be mixed for now.
Having all needed information to process/identify licenses both in the ports tree and installed applications (Makefiles and license reports). With this it's trivial to search by license for example, and support for it could even be added to pkg_add and present the agreement before installing packages).
Incomplete features and additional ideas
- Maybe permission handling should be backwards (specifying the restrictions instead of the allowed items).
FOSSology integration: currently the port is in the tree as devel/fossology but doesn't work on FreeBSD/amd64 8, and is relatively slow (it will improve in the next release). Later it may be used to automatically classify ports.
- Showing license permissions and groups from the current menu/text interface.
- Improve targets for deleting restricted files, with better control (now some distfiles/packages are deleted for FTP when they are only restricted for CDROM; this is how it has been done until now).
Consider licenses that need manual agreement/manual fetching. Provide framework help for manual distfile placing, and maybe also add pkg-fetch-message or some variables to avoid manual IGNORE/printf.
- Bring back configuration saving and checksum of licenses to the new dialog menus.
Maybe using more is better than dialog --textbox for displaying licenses (the main menu still can be done with dialog --menu).
Implementation notes
Integration with bsd.port.mk is done as follows:
Includes bsd.licenses.mk which checks for LICENSE definition (and includes bsd.licenses.db.mk if required).
check-license target added at the end of _SANITY_SEQ to check for incorrect or missing variables, and to stop if the license is rejected (if that is known at that point).
ask-license target added at start of _PATCH_SEQ to prepare license files for installation and ask the user if necessary (presents an agreement with a GUI or text menu).
install-license target added to _INSTALL_SUSEQ before post-install, for installing required files.
Replace clean-restricted and clean-for-cdrom targets if LICENSE is defined (replaces RESTRICTED, NO_CDROM and RESTRICTED_FILES functionality).
New files to be installed (can be disabled with NO_LICENSE_INSTALL):
A catalog for internal use (stores variables defined by the port or incorporated from bsd.licenses.db.mk for use in scripts, statistics, etc), in form of make code. It is installed under ${PREFIX}/share/licenses/${PKGNAME}/catalog.mk.
A main license file for the package (constructed from license definitions), installed under ${PREFIX}/share/licenses/${PKGNAME}/LICENSE. Note that pkg_add does not have support for this now, but could be added with the present information.
One file for each license used, installed under the same directory. For now if there is no license file it is automatically created from the value of LICENSE_TEXT, or a placeholder if the license is in the database (we don't have a license pool, so it is just a pointer).
Interface
For the user
The following variables can be set wither from command-line or in /etc/make.conf.
Variable |
Description |
LICENSES_ACCEPTED |
Accepted licenses |
LICENSES_GROUPS_ACCEPTED |
Accepted groups |
LICENSES_REJECTED |
Rejected licenses |
LICENSES_GROUPS_REJECTED |
Rejected groups |
LICENSES_ASK |
Require explicit user agreement for licenses accepted by default, for example most common licenses in bsd.licenses.db.mk |
NO_LICENSES_DIALOGS |
Disable dialog menus (GUI), and use the text interface |
NO_LICENSES_INSTALL |
Disable installation of (all) license files. These will possibly be required for future features (specially scripts or tools outside the ports systems). |
For the port
The following variables can be defined by the port (this is for a single license, for more than one see next section).
Variable |
Description |
LICENSE |
Code of license (short name; only letters, numbers and underscore) |
LICENSE_PERMS |
Permissions (see below) |
LICENSE_GROUPS |
Groups the license belongs to |
LICENSE_NAME |
Full license name (for the reports) |
LICENSE_FILE |
Full path to license (or use LICENSE_TEXT) |
LICENSE_TEXT |
Text to use as a license, for referencing when not available |
LICENSE_DISTFILES |
Name of licensed files (defaults to ${_DISTFILES}) |
The LICENSE variable can be set to either a license from bsd.licenses.db.mk (see make -V _LICENSE_LIST) or a new name, falling in "known" and "unknown" categories respectively.
If the license is "known" then only LICENSE_FILE and LICENSE_DISTFILES can be defined (not mandatory). The second one defaults to ${_DISTFILES} and the first one to a correspondig text file (for now there isn't a license pool, so it will only contain a reference to it).
If the license is "unknown", then both LICENSE_{NAME,PERMS} and one of LICENSE_{FILE,TEXT} are mandatory.
Available components for LICENSE_PERMS:
Variable |
Description |
dist-mirror |
Free redistribution of distfile (like FTP mirroring; opposite of RESTRICTED) |
dist-sell |
Selling of distfile (like in CD-ROM; opposite of NO_CDROM) |
pkg-mirror |
Free redistribution of package (like FTP upload; opposite of NO_PACKAGE) |
pkg-sell |
Selling of package (like in CD-ROM; opposite of NO_CDROM) |
auto-accept |
If present the license is accepted by default, without agreement (at least LICENSES_ASK is defined by the user) |
Note that permissions can be denied by prefixing no-, for example no-dist-sell. If both are present, then it will be excluded. However this functionality not useful for now.
Currently two multiple licenses modes are supported: dual and multi. The first is for optional licenses, where the package/distfiles can use any of them. The second is for packages that combine distfiles with different licenses and accumulate restrictions (like an open source code, with restricted artwork).
To use set LICENSE_COMB to dual or multi. Note that when not defined it defaults to single (that is the code used internally). After defining it, you can add more than one entries to LICENSE. Then similar rules apply to each license present (see "known" and "unknown" above), but variables are prefixed with LICENSE_ and suffixed with _<license> where <license> is an entry of LICENSES.
Examples
Note that some license and port names may be invented for the purpose of the example.
If you type make in a port whoose license is accepted by default (which means to have the auto-accept permission in its definition), the following happens.
% make ===> Vulnerability check disabled, database not found ===> License accepted by the user ===> Extracting for test-license-1.0 ===> Patching for test-license-1.0 ===> Configuring for test-license-1.0
In this case the port could have contained something like this (assuming GPLv2 is defined in bsd.licenses.db.mk):
LICENSE=GPLv2 LICENSE_FILE=${WRKSRC}/LICENSE
If the license is not accepted by default, or you define LICENSES_ASK (which disables the auto-accept permission), it would look like this (with the text interface):
% make -DLICENSES_ASK -DNO_LICENSES_DIALOGS ===> Vulnerability check disabled, database not found ===> License needs confirmation, will ask later ===> Extracting for test-license-1.0 To install the port you must agree to the license: GPLv2 (GNU General Public License version 2). You can view the license at work/GPLv2. If you agree with the corresponding license/s, add them to LICENSES_ACCEPTED either in make arguments or /etc/make.conf. *** Error code 1
Then you can read the license and decide if you agree or not. Note that for now we don't have a license pool so if the port does not define LICENSE_FILE (which is unusual), the file will contain some text like this:
% cat work/GPLv2 The license: GPLv2 (GNU General Public License version 2) is standard, please read from the web.
If you agree with the license add it to LICENSES_ACCEPTED either in make arguments or /etc/make.conf, like this:
% echo "LICENSES_ACCEPTED+=GPLv2" >> /etc/make.conf % make -DLICENSES_ASK -DNO_LICENSES_DIALOGS ===> Patching for test-license-1.0 ===> Configuring for test-license-1.0
If the GUI menus are used, it would look like licenses-single-dialog.png.
Now suppose you have a port with the following license definitions:
LICENSE=GPLv2 BSD CDDL LICENSE_COMB=dual
Then if any of them have the auto-accept permission and LICENSES_ASK is undefined, that one will be selected (in order of appereance in LICENSES). If you define LICENSES_ASK this happens:
% make -DNO_LICENSES_DIALOGS -DLICENSES_ASK To install the port you must agree to any of the following licenses: - GPLv2 (GNU General Public License version 2), available at work/BSD - BSD (BSD license), available at work/BSD - CDDL (Common Development and Distribution License), available at work/CDDL If you agree with the corresponding license(s), add them to LICENSES_ACCEPTED either in make arguments or /etc/make.conf. *** Error code 1
Then for example if you choose BSD, you can run the following:
% make -DNO_LICENSES_DIALOGS LICENSES_ACCEPTED=BSD ===> Patching for test-license-1.0 ===> Configuring for test-license-1.0
If the GUI menus are used, it would look like licenses-dual-dialog.png.
Now suppose the port defines this multiple licenses (a GPLv2 source code for the program, but copyrighted data needed):
LICENSE=GPLv2 EULA LICENSE_COMB=multi LICENSE_DISTFILES_GPLv2=engine-src-1.2.tar.gz LICENSE_NAME_EULA=End User License Agreement for copyrighted data LICENSE_PERMS_EULA=pkg-mirror dist-mirror LICENSE_TEXT_EULA=Commercial redistribution is not allowed LICENSE_DISTFILES_EULA=demo-data.run
Then if GPLv2 is accepted by default, it will not appear in the message, but as LICENSE_PERMS_EULA does not contain auto-accept it will. Notice that EULA is an "unknown" license, so it has to be defined in contrast to GPLv2, BSD, CDDL, etc.
% make -DNO_LICENSES_DIALOGS ===> Vulnerability check disabled, database not found ===> License needs confirmation, will ask later ===> Extracting for test-license-1.0 To install the port you must agree to all of the following licenses: - EULA (End User License Agreement for copyrighted data), available at work/EULA If you agree with the corresponding license(s), add them to LICENSES_ACCEPTED either in make arguments or /etc/make.conf. *** Error code 1
Then as before, you can check the license:
% cat work/EULA Commercial redistribution is not allowed
And finally you must agree to all of them, but as GPLv2 was accepted by default, only EULA has to be added:
% make LICENSES_ACCEPTED="EULA" ===> Patching for test-license-1.0 ===> Configuring for test-license-1.0
If the GUI menus are used and LICENSES_ASK is defined, it would look like licenses-multi-dialog.png.
Please do not add unknown (per-port) licenses to /etc/make.conf because names can collide, so you may unexpectedly agree to a completely different license in another port.
-- AlejandroPulver 2008-04-24T18:51:35+0000