Appearance
Licence policy
The rules CI enforces, and the reasoning behind them.
1. Allowed without review
| SPDX | Notes |
|---|---|
MIT | Retain copyright and licence text |
Apache-2.0 | Retain licence, NOTICE contents, and state changes if modified |
BSD-2-Clause, BSD-3-Clause | Retain copyright, conditions, disclaimer. BSD-3 additionally forbids using contributor names to endorse the product |
ISC | Retain copyright and permission notice |
PostgreSQL | Retain copyright and permission notice |
Unlicense, 0BSD, CC0-1.0 | Public-domain-equivalent. See §4 on CC0 and patents |
Zlib, BSL-1.0 (Boost) | Permissive |
Unicode-3.0, Unicode-DFS-2016 | Unicode data terms; retain the notice |
OFL-1.1 | Unmodified font redistribution only. Retain the copyright and full OFL text; do not sell the font by itself or relicense it |
EPL-2.0, EPL-1.0, MPL-2.0, MPL-1.1 | Unmodified redistribution only. File-level copyleft: the obligation attaches to the licensed files and their modifications, not to a work that links them. Retain the notice and make those files' source available |
EDL-1.0 is not listed separately because it is BSD-3-Clause - the same text with the Eclipse Foundation as the named entity. A scanner reports it as unknown, and §2 then treats it as forbidden, which is a parsing gap presenting as a licence decision.
None of these is obligation-free. Every one requires that the copyright and licence text travel with any redistribution. The phrase "no requirements" never appears in this project's documentation, and CI rejects a pull request that introduces it into a licence field.
2. Forbidden in the distributed product
| SPDX / family | Why |
|---|---|
GPL-2.0, GPL-3.0, LGPL-*, AGPL-* | Copyleft. Linking would impose source-disclosure obligations on a proprietary product. LGPL is forbidden too because static linking - which Rust does by default - triggers the same obligations |
SSPL-1.0 | Requires publishing the entire service stack |
BUSL-1.1 | Source-available, not open source; use restrictions |
Elastic-2.0 | Restricts managed-service use |
Commons-Clause (any base) | Forbids selling |
CC-BY-NC-*, any non-commercial term | Forbids commercial use |
NOASSERTION, UNKNOWN, missing | Unknown terms are treated as forbidden, not as permissive |
A forbidden licence anywhere in the tree fails the build. There is no "temporarily allow" list.
Both halves of the tree are held to the same standard. deny.toml's allow-list governs the Rust crates through cargo deny and the dashboard's npm packages through tools/licence_policy.py, which reads the same file. It did not always: the npm half was gated by a denylist of licence families, so a package under MPL-2.0 or CC-BY-SA-4.0 passed there and failed on the Rust side. A denylist can only refuse what someone thought to write down, and it cannot implement §2's rule that unknown terms are forbidden at all.
tests/licence_gate.sh proves the gates refuse what they claim to, by introducing each violation on purpose.
3. Requires manual review
- Dual or multi-licensed dependencies. Which option is elected must be recorded, not left implicit. See the
notifydecision in Open-source inventory §4.1. - Models, datasets, rule packs and language packs. The code licence of a library says nothing about the licence of a model it downloads. This is not hypothetical: spaCy's
en_core_web_lgis MIT while its OntoNotes 5 training data is LDC-licensed under commercial terms. - Anything reached at runtime rather than linked - a downloaded rule pack, a language pack, a container base image.
- Any dependency whose repository has moved between organisations, because the future relicensing authority has changed.
4. Elections we have made
The weak-copyleft admissions carry a condition, and it is not decorative.EPL and MPL are admitted for unmodified redistribution only. If we ever patch a file under one of them, the election stops being valid and the obligation changes - modifications to those files must be published. The Modified column in Open-source inventory exists for exactly this, and a change from "no" to "yes" in it is a licence decision, not a housekeeping edit.
Explicitly not admitted, and staying forbidden: CDDL, LGPL, GPL, AGPL. The artefacts carrying them are excluded instead - see SPIKE-003 for what that meant in practice.
OFL-1.1 is admitted for the unmodified IBM Plex Sans files bundled by the dashboard. A modified font requires a new licence review, including the OFL's reserved-name and same-licence conditions. The generated third-party notices record the redistribution obligation.
| Dependency | Options | Elected | Why |
|---|---|---|---|
| Most Rust crates | MIT OR Apache-2.0 | Apache-2.0 | Express patent grant; one consistent choice across the tree |
aho-corasick | Unlicense OR MIT | MIT | A recognised licence is easier to account for than a public-domain dedication |
rustls | Apache-2.0 OR ISC OR MIT | Apache-2.0 | Consistency and the patent grant |
blake3 | CC0-1.0 OR Apache-2.0 OR Apache-2.0-with-LLVM-exception | Apache-2.0 | CC0 explicitly disclaims any patent licence |
notify | CC0-1.0 OR Artistic-2.0 | Artistic-2.0 | Same patent reasoning; Artistic-2.0 §1 and §8 are clear on aggregate redistribution |
CC0 is listed as allowed in §1 but is never elected where an alternative exists, because it grants no patent rights.
5. What CI does
yaml
# .github/workflows/ci.yml → licence job
- cargo deny check licenses # allow-list from deny.toml; fails on anything else
- cargo deny check bans # duplicate and banned crates
- cargo deny check advisories # RUSTSEC vulnerabilities
- cargo audit # second opinion on advisories
- syft . -o cyclonedx-json # SBOM, direct and transitive, with hashes
- license-checker --production # dashboard dependencies
- tools/check_notices.py # every distributed dependency has a NOTICE entryConfiguration lives in deny.toml. The allow-list there is the machine-readable form of §1 and is the file to change when adding a licence, so the change is reviewable in a diff.
6. Adding a dependency
- Read the actual
LICENSEandNOTICEin the repository at the tag being adopted. Not a summary site, not the package-manager metadata field - those are frequently wrong, and Hyperscan'sNOASSERTIONon GitHub versus its plainly BSD-3-ClauseLICENSEfile is a live example. - Record the exact version or commit.
- Enumerate transitive licences.
- Assess any bundled model, dataset or rule pack separately.
- Check repository activity, latest release, open advisories, and whether the project has changed hands.
- Record the integration form - linked, embedded, separate process, separate service - and whether it is redistributed.
- Record the exact notice obligation in Third-party notices.
- Add a row to Open-source inventory with the decision and the reviewer.
A dependency that cannot complete every step is not adopted. "The repository is public" is not an approval.
7. Release gate
A release is blocked if any of the following is true:
- A forbidden licence appears anywhere in the tree
- Any dependency has an unknown or ambiguous licence
- A dual-licensed dependency has no recorded election
- A model, dataset or rule pack has no separate assessment
THIRD_PARTY_NOTICES.mdis missing an entry for a distributed dependency- The SBOM is older than the lockfile
- A
RUSTSECadvisory of high or critical severity is unresolved and unwaivered
Waivers are recorded in deny.toml with an expiry date and a ticket. A waiver without an expiry is not a waiver.