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 nginx and 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 links glibc dynamically.
  • 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, and asyncapi-docs of 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.json files in the node_modules directories 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.toml files in the vendor directories (cargoDeps) of the Rust packages of the roots, with their declared license. The vendor directory has all the crates of Cargo.lock, also the crates for other platforms, thus the SBOM can give more crates than the build links.
  • Go: sbom-go-modules.py reads the modules that each program links from its build information (.go.buildinfo, the list of go 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 a replace directive changes to another module is in the directory of the path that the go.mod requires, thus the script gets that directory from modules.txt. A Go module declares no license, thus identify_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 the drvAttrs of 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 example grafana-loki and tempo, and the Go standard library.
  • The npm packages in the bundles of a front end, for example public/packs of Mastodon. A bundle has no package.json files.

Questions

  • Does a gemspec list of licenses (spec.licenses) mean AND or OR? The documentation of RubyGems does not say. Most gems with a list give a choice, for example diff-lcs and the gems with Ruby and BSD-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.