Skip to content

chore(license): fixes from license hygiene audit - #3627

Merged
dr-bonez merged 11 commits into
masterfrom
chore/license-hygiene
Aug 6, 2026
Merged

chore(license): fixes from license hygiene audit#3627
dr-bonez merged 11 commits into
masterfrom
chore/license-hygiene

Conversation

@helix-nine

Copy link
Copy Markdown
Contributor

Audit of what's actually in the tree, then fixes. Scoped per drbonez: code committed to this repo should be MIT; third-party pulled in at build time is out of scope as long as it's compliant.

Short version of the audit: the claim wasn't true, and nothing in the repo said what it excluded. The only SPDX-License-Identifier headers anywhere said GPL-2.0-only; zero files declared MIT in-band.

Not MIT, now handled

projects/start-wrt/openwrt-overlay/ + openwrt-patches/ — 16 files carry an explicit SPDX-License-Identifier: GPL-2.0-only header naming SpaceMiT Ltd. or OpenWrt.org, plus patches against GPL-2.0 kernel/U-Boot/OpenWrt sources. projects/start-wrt/LICENSE claimed MIT over all of it, which offers rights we don't hold. Added COPYING (GPL-2.0) + a provenance README to each, scoped the MIT grant to exclude them, and noted the §3 source obligation.

Proxima Nova (7 weights + a second undeclared copy under start-wrt) — Copyright (c) Mark Simonson, 2005. All rights reserved., a retail EULA font, copied by angular.json into the ui, setup-wizard, start-tunnel, start-wrt and marketplace bundles. MBF Minimal CustomCopyright (c) 2020 by MoonBandit. All rights reserved., no license file. Replaced with Hanken Grotesk (OFL-1.1); one variable face covers the full 100–900 range the seven static weights served, 54 KB vs 460 KB. MBF was declared in start-tunnel but no rule ever applied the family, so it's dropped, not replaced.

⚠️ This is the piece to review — you said we'd likely need to rip the family out and pick something open for now. Hanken Grotesk is a geometric-humanist sans with the full 100–900 axis (Figtree, the other close candidate, starts at 300 and can't do the thin face). Swapping it is a two-file change if you'd rather something else.

extract-ikconfig — the Linux kernel's GPL script, installed to /usr/bin in every RPi image. Nothing referenced it; deleted.

Intel BIOS capsule — 16 MB, Copyright (C) 2000-2015 Intel Corp. All Rights Reserved. / DECOMPILATION OR DISASSEMBLY PROHIBITED, mirrored because Intel withdrew it when the 2023 Server One was discontinued. Kept (users need it) but attributed on the page that serves it and carved out in NOTICE.

MIT, but not ours alone

imbl-value is largely copied from serde_json and said so nowhere. I diffed it: de.rs is 84% line-identical to serde_json/src/value/de.rs with a 107-line contiguous run, ser.rs 80%, index.rs 74%, and macros.rs is the json! muncher with upstream's comments intact. LICENSE named only Start9, and AGENTS.md asserted the opposite — "(De)serialization is custom … not serde_json's". It's MIT-compatible, so this is notice compliance, not relicensing: credited Tryzelaar/Tolnay, recorded the derivation, fixed the AGENTS.md bullet. Per your call, no patch release — the crates.io tarball for 0.4.4 still lacks the notice; it'll ride the next publish.

Also attributed: json-patch (fork of idubrov, was shipping no license text despite declaring dual terms — added LICENSE-MIT + verbatim LICENSE-APACHE), jsonpath (MIT template placeholders [2019] [Changseok Han] never filled in), init_resize.sh (derived from RPi-Distro/raspi-config).

json-patch and jsonpath_lib are now publish = false — both sit at crates.io names owned by their upstreams. I left json-ptr alone since it's your own crate and the name situation is ambiguous.

Making the claim checkable

NOTICE.md is the complete list of exceptions — if a file isn't named there, it's MIT — linked from the root LICENSE, README and the StartOS architecture doc.

  • license declared on 5 Cargo manifests and 11 package.json that had none (no [workspace.package] to inherit from, so tooling reported them unlicensed)
  • exver and rpc-toolkit are on crates.io but shipped no license text — added
  • copyright holder normalized (Start9 / Start9 Labs / Start9 Labs, Inc.); yasi/LICENSE.md renamed so cargo packages it
  • CONTRIBUTING gains an inbound-licensing statement + a rule that vendored code keeps its notice and lands in NOTICE.md in the same PR
  • .debs now get usr/share/doc/<pkg>/copyright (Debian policy requires it)
  • the upload-each ncc bundle inlined 97 deps with notices stripped — now built with --license, notices committed alongside; bundle is byte-identical
  • deny.toml moved to the workspace root and migrated off copyleft/unlicensed/allow-osi-fsf-free, removed from cargo-deny's schema in 0.14

Verification

make test (0 failures), make manpages-check, make start-core-ts-bindings-check, repo-wide prettier --check, cargo fmt --check, cargo metadata — all green. All four changed stylesheets compile under sass; font URLs verified against on-disk paths and the asset globs of all five apps. Lockfiles re-synced (5 license lines, zero dependency churn) and npm ci re-verified.

One thing I could not verify: ng build fails on this repo. I checked out pristine origin/master (d7e657b6c) in a separate worktree and it fails there too, so it's not from this PR — CI never runs an Angular build, so it's gone unnoticed. That means the font swap is verified by SCSS compilation and path checks, not by a rendered UI. Worth a look independently of this PR.

Not done, deliberately

  • Nothing runs cargo deny in CI, so it's still documentation rather than a gate. Adding the job is a separate call since deps are out of scope here.
  • The Intel capsule stays in git history; excising it means a rewrite.
  • 35 third-party brand SVGs are noted in NOTICE as trademarks rather than relicensed.

Proxima Nova (Copyright (c) Mark Simonson, all rights reserved) and MBF Minimal
Custom (Copyright (c) MoonBandit, all rights reserved) were tracked in-tree and
copied into the ui, setup-wizard, start-tunnel, start-wrt and marketplace
bundles by angular.json, under a repository that grants recipients MIT rights to
distribute and sublicense.

Replace them with Hanken Grotesk (SIL OFL 1.1). One variable face covers the
whole 100-900 range the seven static Proxima weights were serving, so the two
woff2 subsets are 54 KB against the 460 KB they replace. The MBF face was
declared in start-tunnel but no rule ever applied the family, so it is dropped
rather than replaced.
… MIT grant

projects/start-wrt/LICENSE claimed MIT over the whole project, but sixteen files
under openwrt-overlay/ carry an explicit SPDX-License-Identifier: GPL-2.0-only
header naming SpaceMiT Ltd. or OpenWrt.org, and openwrt-patches/ are derivative
works of GPL-2.0 OpenWrt sources. GPL-2.0 cannot be relicensed downstream, so
the MIT grant was offering rights Start9 does not hold.

Add COPYING (GPL-2.0) plus a README to each directory recording provenance and
the GPL-2.0 §3 source obligation, and scope the MIT grant in the LICENSE and
README to exclude them. CONTRIBUTING described openwrt-overlay/ as "the Start9
additions"; it is mostly SpaceMiT's BSP, so say so.
imbl-value's src/de.rs is 84% line-identical to serde_json's src/value/de.rs
(longest identical run 107 lines), ser.rs 80% and index.rs 74%, and macros.rs is
serde_json's json! muncher with its comments intact — yet LICENSE named only
Start9 and AGENTS.md asserted the impls were not serde_json's. All the upstreams
here are MIT or MIT-compatible, so this is notice compliance, not relicensing.

- imbl-value: credit Erick Tryzelaar and David Tolnay in LICENSE, record the
  derivation in README, and correct the AGENTS.md bullet.
- patch-db/json-patch: a fork of idubrov/json-patch with serde_json swapped for
  imbl-value + json-ptr, shipping no license text despite declaring dual terms.
  Add LICENSE-MIT and the verbatim LICENSE-APACHE, a README recording the fork,
  and normalize the SPDX expression to "MIT OR Apache-2.0".
- jsonpath: fill in the MIT template placeholders left as "[2019] [Changseok
  Han]" and credit the upstream in the README.
- init_resize.sh: name RPi-Distro/raspi-config, which it derives from.

json-patch and jsonpath_lib are also set publish = false: both sit at crates.io
names owned by their upstreams, so publishing a diverged fork from here would be
wrong even if it were possible.
… crates

Five Cargo manifests (backup-fs, patch-db-util, the three start-wrt crates) and
eleven package.json files declared no license at all, and the workspace root has
no [workspace.package] table to inherit one from, so tooling reported them as
unlicensed. Declare MIT on each.

exver and rpc-toolkit are published to crates.io but carried no license text in
their tarballs; give them a LICENSE. Normalize the copyright holder across the
existing files, which variously read "Start9", "Start9 Labs" and "Start9 Labs,
Inc.", and rename yasi's LICENSE.md so cargo packages it by convention.

The upload-each action's committed ncc bundle inlined 97 dependencies with their
notices stripped; build it with --license so the per-dependency notices are
generated and committed alongside. The bundle itself is byte-identical.
Nothing in the repo said what "everything is MIT" excludes, so the claim could
not be checked. NOTICE.md is now the complete list of files under other terms —
if something is not named there, it is MIT — and the root LICENSE, README and
the StartOS architecture doc point at it.

Also:
- CONTRIBUTING gains an inbound-licensing statement and a rule that vendored
  code keeps its notice and lands in NOTICE.md in the same PR.
- .deb packages are built with a usr/share/doc/<pkg>/copyright file, which
  Debian policy requires and which the hand-written control block omitted.
- deny.toml moves to the workspace root and drops copyleft/unlicensed/
  allow-osi-fsf-free, removed from cargo-deny's schema in 0.14. Note nothing in
  CI runs it yet, so it remains documentation rather than a gate.
- The Intel BIOS capsule mirrored for the discontinued 2023 Server One is
  attributed to Intel on the page that serves it. It is Intel's, not ours, and
  the architecture doc no longer implies the shipped image is MIT end to end.
npm records the root package's license in package-lock.json, so declaring it in
package.json leaves the lockfile out of sync — which is exactly what CI's
`npm ci` drift gate rejects. Five lockfiles, one line each, no dependency churn.
The relocated file landed at the repo root without going through taplo, whose
reorder_keys sorts each [[licenses.clarify]] table's keys. Caught by CI's
format-check, which I hadn't run locally because it needs the fmt container.
Nothing had ever run this policy, so it had drifted from reality in both
directions. Ran cargo-deny against the real dependency graph:

- LGPL-3.0, OpenSSL and Unicode-DFS-2016 were allowed but appear nowhere. LGPL
  is the one that mattered: allowing it invited a copyleft dependency that would
  have been incompatible with shipping start-core as MIT.
- The webpki and ring clarifications are dead — webpki is gone (rustls-webpki
  now) and ring declares "Apache-2.0 AND ISC" itself.
- Four permissive licenses genuinely in the tree were missing, so 25 crates were
  rejected for no good reason: Unicode-3.0 (the ICU stack), CDLA-Permissive-2.0
  (webpki-roots), BSL-1.0 (xxhash-rust, lazy-bytes-cast) and 0BSD
  (quoted_printable).

MPL-2.0 stays allowed and is now explained: its copyleft is per-file, so linking
imbl and friends into an MIT binary is fine as long as we don't modify them.

This leaves two genuine GPL-3.0-or-later rejections, which need code changes
rather than a policy change, so the CI gate lands with that fix.
Review of my own decisions found several that were wrong or went further than
the evidence supported. Reverting them.

- Restore "LGPL-3.0" to deny.toml. My commit message claimed allowing it was
  "incompatible with shipping start-core as MIT". That is wrong: LGPL-3.0 §4
  expressly permits combining the library with a work conveyed under other
  terms, subject to notice and relink conditions. Worse, the entry was not
  drift — 5b22d0a (Aiden McClelland, 2021-06-17) added it in the commit that
  created the file, as a deliberate carve-out. An unmatched allowance is only a
  warning, so removing it bought nothing and would have hard-rejected a future
  LGPL dependency that is in fact perfectly usable.
- Restore the root LICENSE to byte-canonical MIT. Editing the license body to
  add a carve-out risks breaking automated license detection, and the carve-out
  already lives in README.md and NOTICE.md. Same for start-wrt's LICENSE.
- Restore extract-ikconfig. Deleting a working debugging tool from the image was
  a functional change made for a licensing reason that a NOTICE entry solves.
- Restore jsonpath's LICENSE verbatim. Filling in a third party's copyright
  placeholders is not ours to do; the clarification belongs in the README.
- CONTRIBUTING lumped LGPL in with GPL/AGPL as forbidden. Corrected: GPL/AGPL
  can't be linked into our binaries, LGPL and MPL-2.0 can, with obligations.
- NOTICE claimed to be "the complete list" and that anything unlisted is MIT.
  Softened — I can't guarantee completeness.
- Moved brand marks out of "Not MIT" into their own Trademarks section.
  Trademark is not copyright and is not granted or withheld by a copyright
  license, so listing logos as a licensing exception was a category error.
- The MPL note said obligations attach only if we modify the sources. They
  attach on distribution (§3.2), modified or not.
- The overlay README asserted every unheadered file was GPL "including the
  Start9-authored ones, which are derivative works". A new file in an OpenWrt
  tree is not automatically derivative; that gave away Start9's own copyright by
  assertion. Now stated as a deliberate contribution choice. Also dropped "the
  one exception" (NOTICE lists several) and softened GPL-2.0-only to
  GPL-licensed, since the tree mixes -only and -or-later.
- Restore the start-wrt font-weight design comment, reworded for the variable
  face rather than deleted.
socks5-impl is GPL-3.0-or-later, and it was a direct dependency of start-core,
so every product binary linking start-core would have to be conveyed under
GPL-3.0. No permissive version exists upstream — the current 0.9.6 is still
GPL-3.0-or-later — so this is a swap rather than a bump.

fast-socks5 (MIT) covers the same ground: read_command() hands back the target
before connecting, which is what lets us keep intercepting .onion (tunnel via
the tor service's SOCKS proxy) and .local (resolve over mDNS), and get_socket()
unwraps the client tunnel to a plain TcpStream so the keepalive still applies.
BIND and UDP ASSOCIATE are still answered CommandNotSupported.

The proxy had no test coverage, so this adds three: a round trip through the
proxy to an echo server, an unreachable target refused rather than hung, and
BIND/UDP rejected.
…te licenses in CI

tracing-rfc-5424 is GPL-3.0-or-later — the last crate in the tree whose terms we
can't meet while conveying our binaries under MIT. syslog-tracing (MIT) writes
through libc's syslog(), which lands in the same /dev/log that the old
UnixSocket transport targeted, so logread still sees the entries. Its MakeWriter
maps tracing levels to syslog severities via make_writer_for.

init_logging took a name it then ignored; syslog-tracing can use it as the
openlog identity, so startwrt-cli and startwrt-ctrld are now distinguishable in
logread instead of sharing one tag. The startwrt-activity marker activity.rs
greps for is in the message body, so it is unaffected. Timestamps and tag are
dropped from the formatter because syslogd adds its own.

With that, `cargo deny check licenses` passes, so it becomes a CI job. LGPL-3.0
stays allowed and simply reports as an unmatched allowance.
@dr-bonez dr-bonez changed the title chore(license): make it true, and checkable, that the repo is MIT chore(license): fixes from license hygiene audit Aug 6, 2026
@dr-bonez
dr-bonez merged commit 33a532c into master Aug 6, 2026
42 checks passed
@dr-bonez
dr-bonez deleted the chore/license-hygiene branch August 6, 2026 16:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants