License Decisions
This file gives a recommendation for each license that the matrix does not give, the decision of a maintainer when there is one, and the causes of NOASSERTION. A license that [licenses] of core/setups/nixos/license-allowlist.toml does not have makes the report fail, except NOASSERTION. The data comes from the license reports of the 30 nodes of core.
This is not legal advice. The authors are not lawyers. A person with legal knowledge must approve a decision before it goes into [licenses].
Relations between components
The compatibility of two licenses is a question only when the two works become one work. The EUPL-1.2 leaves this to the law: "This Licence does not define the extent of modification or dependence on the Original Work required in order to classify a work as a Derivative Work" (Article 1). There are three relations:
- Aggregation: separate programs on one system, for example
nginxand the api. Each program keeps its own license. A node is mostly an aggregation. For aggregation, a license only has to permit the distribution of the component. The licenses of two components do not have to be compatible with each other. - Dynamic linking: a program loads a shared library when it runs, for example a C program and
libssl.so, or a Python program and a module that it imports. The European Commission says that this does not make a derivative work: "static and dynamic linking can be implemented with other programs without barriers or conditions. On this specific point, EUPL works like the LGPL" (EUPL FAQ), with recitals 10 and 15 of Directive 2009/24/EC as the reason. The FSF has a different opinion for the GPL. There is no case law. - Static linking and incorporation: the code of the library is copied into the program, for example a Go or Rust binary with its modules and crates, or a JavaScript bundle. This is the relation that most likely makes a derivative work.
nixpkgs links C and C++ programs dynamically: each program finds its libraries in the store through its RPATH. No node uses pkgsStatic, and no node has a Haskell program. Static linking occurs in these cases:
- Go programs include their modules (for example
openbao,forgejo,incus,spire,authelia,restic,rclone,grafana). cgo linksglibcdynamically. - Rust programs include their crates (for example
garage,lldap,windmill,uv). - JavaScript applications include bundles of npm packages (for example
mastodon,peertube,grafana,forgejo,garage-webui, andasyncapi-docsof this repository).
The SBOM gives each of these programs as one component. It also gives the npm packages from the package.json files in the node_modules directories of the closure, and the crates from the Cargo.toml files in the vendor directories (cargoDeps) of the Rust packages of the roots in sbom.nix. It does not give the Go modules or the npm packages in a bundle. See "The dependencies that Go, Rust and npm builds vendor". Except for asyncapi-docs, these programs do not include code of this repository: their upstream projects combined the code, and the node only aggregates the programs.
The EUPL compatibility matrix
The matrix of the European Commission ("Matrix of EUPL compatible open source licences", July 2011, updated 2013 and 2017) has the columns "Incorporation", "Static link" and "Dynamic link". It is about inbound compatibility: "it allows you to merge a work covered by another F/OSS license into a larger work that you may distribute under the EUPL". The "Dynamic link" column is "OK" for each license of the matrix. "NO" and "?" occur only in the other columns, for example for the GPL ("NO (exceptions exist)" for incorporation). The reason that the matrix gives: "linking two programs does not produce a single derivative of both (each program stay covered by its primary licence)".
The Appendix of the EUPL-1.2 is a different list: it gives the licenses under which a licensee can distribute a work that combines an EUPL work with a work under that license (Article 5). It is an outbound list, not a list of the licenses that a dependency can have, thus the allowlist does not use it as a source. For a license that is not in the matrix, the allowlist uses the EUPL FAQ of the European Commission: "the simple fact of "Using" a covered component as a dependency or as a tool, does not transform your work in a derivative". Such a license is acceptable when it permits the distribution of the component.
Thus no license in the report fails because of dynamic linking. For aggregation and dynamic linking, a license is acceptable when it permits the distribution of the component, also for a commercial service.
Recommendations
"Nodes" is the number of nodes (of 30) with the license. "Accept" means: add the license to [licenses]. "Accepted" means: a maintainer accepted the license, and it is in [licenses] with its source. "Refuse" means: remove the component from the nodes. "Refused" means: a maintainer refused the license, it is in no list, and no node has a component with it. The report fails when a node has such a component.
Permissive licenses
These licenses permit distribution with notice and attribution conditions. They are acceptable for aggregation and for dynamic linking.
| License | Nodes | Components (examples) | Recommendation | Reason |
|---|---|---|---|---|
0BSD |
30 | libressl, git-pages, sord |
accepted | permits all use, no conditions |
MIT-0 |
30 | systemd, cffi |
accepted | MIT without the notice condition |
MIT-open-group |
30 | libx11, libice, libxau |
accepted | MIT variant |
MIT-CMU |
1 | pillow |
accepted | MIT variant |
X11 |
30 | libx11, libxcb, libpciaccess |
accepted | MIT with a no-endorsement clause |
X11-no-permit-persons |
1 | libxinerama |
accepted | X11 variant |
HPND |
30 | libx11, pngquant |
accepted | permits use, copy and distribution with notice |
HPND-sell-variant |
30 | libx11, libxfixes |
accepted | HPND variant |
HPND-doc |
30 | libx11, libxext |
accepted | HPND variant for documentation |
HPND-doc-sell |
30 | libx11, libxext |
accepted | HPND variant for documentation |
HPND with different disclaimer |
1 | xorgproto |
accepted | HPND variant |
TekHVC |
30 | libx11 |
accepted | permissive, with naming conditions; it grants no patent license |
ICU |
1 | xorgproto |
accepted | MIT variant |
Unicode-3.0 |
30 | icu4c |
accepted | permissive data and code license |
SGI-B-2.0 |
1 | xorgproto |
accepted | permissive, with notice |
Cronyx |
1 | xkeyboard-config |
accepted | "may be used, modified, copied, distributed, and sold" |
hyphen-bulgarian |
1 | xkeyboard-config |
accepted | permissive, as Cronyx |
OpenSSL |
30 | libressl |
accepted | BSD-style, with an advertising clause (attribution only) |
LicenseRef-nixos-bsdAskToEndorse |
30 | sudo |
accepted | BSD with a no-endorsement clause |
BSD |
1 | sysexits |
accepted | "BSD (all versions)" is "OK" in the matrix |
2-clause BSDL |
1 | unf |
accepted | BSD-2-Clause, which is in the matrix |
BSD-2-Clause-Patent |
5 | libvmaf |
accepted | BSD-2-Clause with an express patent grant |
Boehm-GC |
30 | boehm-gc |
accepted | permissive, with notice |
bzip2-1.0.6 |
30 | bzip2 |
accepted | BSD-style |
curl |
30 | curl |
accepted | MIT variant |
libpng-2.0 |
30 | libpng-apng |
accepted | zlib-style; "Zlib/libpng" is in the matrix |
libtiff |
5 | libtiff |
accepted | permissive, with notice |
IJG |
5 | libjpeg-turbo |
accepted | permissive; the documentation must give credit |
TCL |
1 | tcl |
accepted | BSD-style |
OLDAP-2.8 |
5 | openldap |
accepted | BSD-style |
CNRI-Python |
1 | regex |
accepted | permissive, FSF free, as Python-2.0 in the matrix |
Beerware |
30 | libbsd, libmd |
accepted | permits all use, with notice |
WTFPL |
4 | libcaca, zimg |
accepted | permits all use |
blessing |
30 | sqlite |
accepted | a public domain dedication |
Unlicense |
1 | rdf, json-ld |
accepted | a public domain dedication |
CC0-1.0 |
30 | systemd, libargon2, libblake3 |
accepted | a public domain dedication |
Public Domain |
30 | systemd, libressl, tzdata, docutils |
accepted | no copyright license is necessary |
LicenseRef-nixos-publicDomain |
30 | util-linux, hdrhistogram_c |
accepted | as Public Domain |
Weak copyleft licenses
These licenses have conditions only for changes to the component itself. The node does not change these components.
| License | Nodes | Components (examples) | Recommendation | Reason |
|---|---|---|---|---|
LGPL-2.0 |
4 | aalib, gobject-introspection, lame, libiscsi |
accepted | section 3 permits the GPL-2.0 or later instead, which is in the matrix |
MPL-1.0 |
3 | cairo |
accepted | section 6.2 permits later versions; MPL-1.1 is in the matrix |
CECILL-C |
1 | openfec (hypervisor-incus) |
accepted | FSF free, "somewhat like the GNU Lesser General Public License"; not in the matrix, thus the acceptance rests on the EUPL FAQ of the EC |
PHP-3.01 |
1 | php-with-extensions (operator-pixelfed) |
accepted | clause 5 permits later versions; "PHP License 3.0" is in the matrix |
Licenses with a choice
| License | Nodes | Components (examples) | Recommendation | Reason |
|---|---|---|---|---|
Ruby |
1 | 40 gems of operator-mastodon |
accepted | the COPYING of Ruby permits the 2-clause BSDL instead |
Artistic-1.0 |
30 | perl |
accepted | alone only for perl, which has the Perl terms (Artistic-1.0 or GPL-1.0-or-later). The FSF says to avoid it "except as part of the disjunctive license of Perl". The matrix gives "Artistic license (Perl foundation)" only as version 2.0 |
Artistic-1.0-Perl |
1 | diff-lcs (operator-mastodon) |
accepted | the gem gives a choice of MIT, Artistic-1.0-Perl and GPL-2.0-or-later, but the report joins the gemspec list with AND; see the questions |
Documentation and content licenses
| License | Nodes | Components (examples) | Recommendation | Reason |
|---|---|---|---|---|
CC-BY-4.0 |
30 | libuv (documentation) |
accepted | permits distribution with attribution |
GFDL-1.3-or-later |
4 | flac (documentation) |
accepted | permits distribution of verbatim copies |
Licenses of vendored components
These licenses come from the npm packages, the crates and the Go modules that the SBOM gives as vendored components (FR-010). A license that is "accepted" is in [licenses], with its source. For a module that is in [components], the licenses that only the module has are in no list. The Go rows come from a scan of 19 Go packages of the pinned nixpkgs that the configuration uses (see below), not from the reports of the nodes.
| License | Components (examples) | Recommendation | Reason |
|---|---|---|---|
Unicode-DFS-2016 |
crates unicode-ident, unicode_names2 |
accepted | permissive data and code license, as Unicode-3.0 |
BlueOak-1.0.0 |
npm glob, lru-cache, isexe; crate minicbor |
accepted | permissive, with a patent license |
Libpng |
crate libpng-sys (pngquant) |
accepted | zlib-style; "Zlib/libpng" is in the matrix |
Artistic-2.0 |
npm npm; crates notify, file-id |
accepted (matrix) |
the matrix gives "Artistic license (Perl foundation)", version 2.0 |
CC-BY-3.0 |
npm spdx-exceptions (data) |
accepted | permits distribution with attribution, as CC-BY-4.0 |
CDLA-Permissive-2.0 |
crates webpki-roots, webpki-root-certs (CA certificates) |
accepted | a permissive license for data; the condition is to keep the license text |
Apache 2.0 |
npm qrcode-terminal (in npm) |
[components] gives the module |
a name, not the SPDX identifier Apache-2.0. The LICENSE of the package is Apache-2.0, and the code in vendor/QRCode has MIT |
UPL-1.0 |
Go github.com/oracle/oci-go-sdk (rclone), github.com/nrdcg/oci-go-sdk (lego) |
accepted (faq) |
permissive, with a patent license. The module gives a choice of UPL-1.0 or Apache-2.0, but the classifier joins them with AND |
X11-Lucent |
Go bazil.org/fuse (rclone), github.com/anacrolix/fuse (restic) |
accepted (faq) |
permissive; a notice for the code from Plan 9, next to BSD-3-Clause |
FSFAP |
Go github.com/apache/thrift (grafana, otelcol, otelcol-contrib) |
accepted (faq) |
all-permissive; only for some autoconf macros in the source, next to Apache-2.0 |
CC-BY-SA-4.0 |
Go github.com/opencontainers/go-digest (forgejo, forgejo-runner, incus, openbao, opentofu, otelcol, otelcol-contrib, spire) |
[components] gives the module |
only for the documentation (LICENSE.docs), which the programs do not include. The code has Apache-2.0 |
TPM-2 |
Go github.com/google/go-tpm-tools (spire) |
accepted (faq) |
permissive; the conditions are for the patents of the TCG members. Only for the TPM 2.0 simulator of Microsoft in the module (simulator/ms-tpm-20-ref), next to Apache-2.0 |
AFL-2.0, AFL-2.1, BSD-2-Clause-NetBSD, BSD-3-Clause-Clear, BSD-4-Clause-UC, BSD-Source-Code, CC-BY-SA-2.0, GPL-1.0, GPL-3.0-with-bison-exception, InnerNet, LicenseRef-C-Ares, LicenseRef-MIT-Lucent, LicenseRef-uthash, OSL-1.1, OpenLDAP, OpenVision, RSA, Rijndael-3.0, Spencer-86, SunPro |
Go github.com/hashicorp/vic (openbao) |
[components] gives the module |
only in the list of third-party licenses of the vSphere Integrated Containers product, in the LICENSE of the module. The list says that the product does not necessarily use all of them. The module has Apache-2.0 |
Licenses that need a person
| License | Nodes | Components (examples) | Recommendation | Reason |
|---|---|---|---|---|
Brakeman Public Use License |
1 | brakeman (operator-mastodon) |
refused | "Commercial Uses ... require a commercial, non-free license", and this includes a hosted service. brakeman is in the development group of the Gemfile of Mastodon. The bundlerEnv of mastodon in nixpkgs gives no groups and thus includes all groups. nix/overlays/mastodon.nix gives the groups without development and test, and sets BUNDLE_WITHOUT for the asset build. The node sets BUNDLE_WITHOUT for its units |
FDK-AAC |
1 | fdk-aac (hypervisor-incus, through qemu_kvm of the Incus module) |
refused | it grants no patent license; Debian gives it in non-free and Fedora does not allow it. It comes through the SDL display (sdl2-compat, sdl3, zenity, gtk4, gst-plugins-bad) and the PipeWire audio of qemu. Incus does not use these. core/components/hosting-provider/incus/qemu.nix loads the Incus module with a qemu_kvm that has sdlSupport, gtkSupport and pipewireSupport set to false |
Alliance for Open Media Patent License 1.0 |
4 | svt-av1 |
accepted (faq) |
a royalty-free patent grant in addition to the copyright license (BSD-3-Clause), with defensive termination |
LicenseRef-nixos-free |
8 | dejavu-fonts-minimal, gd, gfxstream |
[components] gives the packages |
nixpkgs does not name the license. The license files of the sources give the Bitstream Vera and Arev Fonts licenses (dejavu-fonts-minimal), GD (gd), and Apache-2.0, MIT, CC-BY-4.0 and the M+ Font License (gfxstream) |
NOASSERTION |
30 | 281 components | verdict unknown |
the SBOM has no license data; see below. A decision applies to each component, not to the identifier |
Components without license data
A component has NOASSERTION when bombon did not find its derivation. bombon finds the derivations only through derivation values (drvAttrs), and a NixOS system gets most packages through strings. sbom.nix gives bombon more roots (see FR-002 of spec.md). The scripts that the configuration generates, for example forgejo-runner-daemon-* and gitea-register-runner-*, get the license of this repository (FR-009 of spec.md). With these roots and this rule, the reports of the 30 nodes have 281 component names without license data and outside [components] (324 pairs of name and version). The causes that remain:
| Cause | Components (examples) | Fix |
|---|---|---|
PHP extensions, found only through the php.ini of php.buildEnv |
php-* of operator-pixelfed |
upstream (nixpkgs): give the extensions as a derivation value of the PHP package |
Perl modules of perl.withPackages |
perl5.42.3-* of hypervisor-incus and of the nodes with git |
upstream (nixpkgs): keep the module list as a derivation value |
Python modules of python3.withPackages |
python3.14-* of hosting-provider-netbox |
upstream (nixpkgs): keep the module list as a derivation value |
Providers of terraform.withPlugins |
terraform-provider-* |
upstream (nixpkgs): keep the provider list as a derivation value |
Grafana plugins in the linkFarm of grafana-plugins |
loki, tempo and prometheus datasource plugins |
upstream (nixpkgs): give the plugins as a derivation value |
Ruby gems of a bundlerEnv without a gemspec license |
webpush, validate_url, omniauth-cas, idn-ruby of operator-mastodon |
upstream: bundix and the gemsets of nixpkgs do not keep the licenses (NixOS/nixpkgs#576545, nix-community/bundix#124) |
The kernel and the initrd, which are not roots (see sbom.nix) |
linux, initrd-linux, linux-headers-static, make-initrd-ng |
upstream (bombon): a purl for each output, and keep a root without a version |
Packages that a unit or /etc gets through a string, and that have no attribute of the same name in pkgs |
kmod-blacklist, dns-root-data, hostname-debian, nix-nswrapper, column-util-linux, lldap-frontend |
in this repository: give the package as a derivation value, for example in environment.systemPackages, or a row in [components] |
Packages that a derivation other than a unit or /etc gets through a string |
switch-to-configuration (the package switch-to-configuration-ng, MIT) of the toplevel, system-sendmail (MIT) of the configure flags of php |
in this repository: give the package as a root in sbom.nix, or a row in [components] |
| Packages of this repository that a unit gets through a string | spire-tpm-plugin, openbao-plugin-secrets-ldap, fediversity-asyncapi-docs |
in this repository: give the package as a derivation value, or a row in [components] |
| Dependencies of a component without license data | vips (through ruby-vips), and the libraries of gst-plugins-bad on hypervisor-incus (through gtk4 and zenity) |
the fix of the component that depends on them |
| npm packages that a package of this repository includes | jose, oauth4webapi, openid-client of the PeerTube OIDC plugin (MIT) |
in this repository: rows in [components] (present), or a vendored SBOM (bombon.passthruVendoredSbom.npm) |
Unit files that the strings of the units and of /etc do not refer to directly |
unit-mastodon-streaming of operator-mastodon |
in this repository: apply the rule of FR-009 to the unit files |
The meta.license of nixpkgs gives only one of the licenses |
perl (artistic1, upstream Artistic-1.0 or GPL-1.0-or-later) |
upstream (nixpkgs): [ artistic1 gpl1Plus ]. Artistic-1.0 is in [licenses] |
The dependencies that Go, Rust and npm builds vendor
The report must check the modules, crates and npm packages that the Go, Rust and JavaScript programs include. These programs do not include code of this repository, thus they are an aggregation. But the node distributes them, thus their notice conditions apply. sbom-vendored.py adds them to the SBOM (FR-010), each one with its parent packages:
- npm: the
package.jsonfiles in thenode_modulesdirectories of the closure, with their declared license. These files are in the closure, thus the build of the SBOM does not get larger. - Rust: the
Cargo.tomlfiles in the vendor directories (cargoDeps) of the Rust packages of the roots, with their declared license. The vendor directory has all the crates ofCargo.lock, also the crates for other platforms, thus the SBOM can give more crates than the build links. - Go:
sbom-go-modules.pyreads the modules that each program links from its build information (.go.buildinfo, the list ofgo version -m), and the license files from the root directory of each module in the module directory (goModules) of the package. In a vendor directory, a module that areplacedirective changes to another module is in the directory of the path that thego.modrequires, thus the script gets that directory frommodules.txt. A Go module declares no license, thusidentify_license(licenseclassifier) finds the licenses in the text, and the SBOM gives them as concluded. The scan runs in one derivation for each Go package of the roots, thus the SBOM of a node gets only a small JSON file.
The source of the Go data
| Source | Result |
|---|---|
A scan of goModules (chosen) |
no compilation; goModules is a fixed-output derivation that the build of the package already needs, thus a binary cache has it |
A second build of the package, for example with go-licenses |
needs goModules too, and compiles the package again |
modules.txt of goModules for the module list |
has also the modules of other platforms and build tags, and the proxyVendor layout has no modules.txt; the build information of a program has only the modules that it links |
| Classifier | Result |
|---|---|
licenseclassifier (chosen) |
7.5 MB closure; finds each license in a file with several licenses, and a license notice (-headers) |
askalono |
57 MB closure; gives only one license for a file, and no result for a file with several licenses |
licensee, go-licenses, scancode-toolkit, trivy |
a Ruby, Go or Python program with a larger closure, or a scanner that does more than the classification |
The cost of the Go scan
The scan of 19 Go packages of the pinned nixpkgs (the Go packages that core/ uses) took 18 s together, with the module directories in the store. The scan of otelcol-contrib, the largest, takes 2 s and 250 MB of memory. A node needs the module directory of a Go package only to build the JSON file of that package. When a binary cache has that file, the node does not download the module directory. Else, it downloads it from the binary cache of nixpkgs:
| Package | Modules (with a license) | goModules download |
goModules size |
|---|---|---|---|
grafana |
521 (493) | 1153 MB | 1263 MB |
otelcol-contrib |
1037 (1035) | 676 MB | 733 MB |
openbao |
287 (286) | 252 MB | 268 MB |
spire |
306 (305) | 228 MB | 251 MB |
otelcol |
406 (406) | 20 MB | 178 MB |
niks3 |
44 (44) | 21 MB | 152 MB |
opentofu |
244 (244) | 15 MB | 116 MB |
forgejo |
225 (223) | 20 MB | 108 MB |
rclone |
245 (245) | 16 MB | 90 MB |
lego |
201 (201) | 11 MB | 79 MB |
incus |
164 (163) | 11 MB | 62 MB |
authelia |
86 (86) | 16 MB | 60 MB |
caddy |
146 (146) | 9 MB | 52 MB |
restic |
85 (85) | 7 MB | 47 MB |
minio-client |
98 (95) | 5 MB | 38 MB |
alertmanager |
118 (117) | 6 MB | 36 MB |
forgejo-runner |
72 (72) | 4 MB | 25 MB |
node_exporter |
46 (46) | 2 MB | 17 MB |
age |
6 (6) | 1 MB | 11 MB |
A module without a license is in the source of the package (for example the submodules github.com/grafana/grafana/apps/*, with the license in the root of the repository), or has no license file in its root directory.
These dependencies are not in the SBOM (see "Known Deviations" in spec.md):
- The crates of a Rust package and the Go modules of a Go package that is not a root, for example
librsvg. A walk through all of thedrvAttrsof the roots finds them, but also the packages that only the build of the toplevel uses. With their vendor directories, the build of the SBOM of a node needs 1 GB to 4 GB more. - The Go modules of a Go package without a module directory (
vendorHash = null), for examplegrafana-lokiandtempo, and the Go standard library. - The npm packages in the bundles of a front end, for example
public/packsof Mastodon. A bundle has nopackage.jsonfiles.
Questions
- Does a gemspec list of licenses (
spec.licenses) meanANDorOR? The documentation of RubyGems does not say. Most gems with a list give a choice, for examplediff-lcsand the gems withRubyandBSD-2-Clause. - Does a hosted service "distribute" in the sense of the licenses? The EUPL-1.2 says yes ("providing access to its essential functionalities"), and so does the AGPL. Most other licenses apply only to copies. The recommendations above take the strict position: each component is distributed.