`reqwest` was added to continuum-proxy so a gateway can download a job file from a presigned URL. Everything it brings is permissive and verified from `cargo metadata`; the entry lists each crate so the next person does not have to re-derive it. The useful half is the rejection. reqwest 0.13's `rustls` feature pulls `webpki-root-certs` under CDLA-Permissive-2.0 and `cargo deny` refuses it. That licence is in fact permissive and could reasonably be added to the table - but it is a *data* licence on a certificate bundle, which is a different question from a code licence, and waving it through to unblock a dependency bump is how a policy stops meaning anything. Recorded as a deliberate open question rather than silently allowed or silently forgotten. The other 0.13 route brings `aws-lc` and its OpenSSL-licensed C, which is simply out. Also noted: rustls here does not remove `openssl-sys` from the tree. It is still there via the `native-tls` that the Bambu MQTT and FTPS clients use, so nobody should read this entry as "the proxy no longer links OpenSSL".
11 KiB
Licence policy
Continuum is a closed-source commercial product. We intend to sell it, so
every dependency must permit distribution in proprietary software without
publishing our own source. This document is the policy; deny.toml in each
repo is the machine-enforced half of it.
The rule
Permissive only. A dependency is allowed if it is one of:
| Licence | Notes |
|---|---|
| MIT, ISC, 0BSD, BSD-2-Clause, BSD-3-Clause | The common case |
Apache-2.0 (incl. WITH LLVM-exception) |
Carries a patent grant, which is a plus |
| Unlicense, CC0-1.0 | Public-domain dedications |
| Zlib, BlueOak-1.0.0 | Permissive, OSI/Blue Oak approved |
| Unicode-3.0 | Unicode data tables |
| MPL-2.0 | File-level copyleft only; fine as long as we do not edit the dependency's own files |
Forbidden, no exceptions: GPL, LGPL (when statically linked), AGPL, SSPL, RSAL, Commons Clause, "source available", CC-BY-NC, and any licence with a field-of-use or non-commercial restriction.
Two rules that are easy to get wrong:
- Dual-licensed dependencies are fine - we elect the permissive option.
Record the election here so it is not re-litigated (see
node-forgebelow). - LGPL is conditionally fine but only via dynamic linking with the library replaceable by the user. Rust static linking does not qualify. Assume LGPL is forbidden unless someone writes down why a specific case is not.
How it is enforced
Rust, per repo:
cargo deny check licenses # proxy, ai-worker
cargo deny --manifest-path packages/rust-core/Cargo.toml check licenses # common, schemas
cargo deny --manifest-path apps/desktop/src-tauri/Cargo.toml check licenses # app
Our own crates declare license = "LicenseRef-Proprietary" with
publish = false. LicenseRef-Proprietary is deliberately not a real SPDX
identifier and must never be added to a deny.toml allow list - a
third-party crate claiming it would be a genuine finding, and publish = false is what marks ours as first-party. Our npm packages use
"license": "UNLICENSED" with "private": true, which is npm's equivalent
convention.
JavaScript has no cargo deny equivalent wired up yet; the audit below was
done by walking installed node_modules manifests.
What the tooling cannot see
cargo deny only reads the cargo graph. Three categories sit outside it and
have to be checked by hand:
- External binaries we spawn or ship. Invoking a GPL program as a separate process is not itself a derivative work, but shipping it in our installer means distributing it under its own terms.
- ML model weights. A model's licence is independent of the runtime that
loads it. This is the single biggest trap in this project (see
continuum-ai-workerbelow). - Managed/self-hosted services. The client library's licence is not the
server's licence.
ioredisbeing MIT says nothing about Redis.
Audit, 2026-09-17 (Redis resolved 2026-10-03)
All six repos audited. No copyleft code is currently compiled into any
Continuum binary. Every Rust crate across continuum-proxy,
continuum-ai-worker, continuum-app/apps/desktop, continuum-common and
continuum-schemas passes the policy above. The JS graphs are MIT/Apache/ISC/
BSD/BlueOak throughout.
Fixed in this pass: all six of our own crates and all nine of our npm
packages were missing a licence field (cargo deny reported them as
unlicensed errors), and no repo had a deny.toml.
Findings carried forward
Redis - RESOLVED 2026-10-03, we use Valkey. Redis 7.4+ is RSALv2/SSPLv1
and Redis 8.0+ added AGPLv3 as a third option. All three are non-permissive,
and SSPL §13 specifically targets offering the software's functionality as a
service - which is what a cloud control plane does. The clients were never
the problem (ioredis and the redis crate are both MIT); the server we
deploy was.
We now deploy Valkey (BSD-3-Clause, Linux Foundation, forked from Redis
7.2.4). What changed: REDIS_URL -> VALKEY_URL and
CONTINUUM_REDIS_URL -> CONTINUUM_VALKEY_URL, the exported redis client
in continuum-backend/src/queue/ renamed to valkey, Config.redis_url ->
Config.valkey_url in continuum-ai-worker, /health now reports a
valkey field, and continuum-backend/docker-compose.yml pins
valkey/valkey:8-alpine. Both tiers still typecheck/compile unchanged
otherwise, because Valkey speaks the same protocol.
Two things deliberately did not change, so nobody "fixes" them later:
the redis:// URL scheme (it names the RESP wire protocol, and no client
library understands a valkey:// scheme), and the client libraries
themselves (ioredis, the redis crate) - they are RESP clients, and their
names refer to the protocol's origin, not to the server we run.
AI model weights - blocks PLAN.md step 4. src/inference/mod.rs
currently stubs a "spaghetti" detection. The two obvious off-the-shelf
sources are both AGPL-3.0: Ultralytics YOLO (v5/v8/v11) and Obico / The
Spaghetti Detective's print-failure model. Neither can ship in a commercial
product without a paid enterprise licence. The ort crate itself is MIT and
fine. Permissive alternatives to evaluate when step 4 comes up: YOLOX
(Apache-2.0), RT-DETR (Apache-2.0), RF-DETR (Apache-2.0), or training our own
weights on a permissively-licensed architecture. Decide the architecture
before collecting training data - retraining because of a licence is the
expensive version of this mistake.
go2rtc and ffmpeg - currently fine, keep it that way.
continuum-proxy/src/go2rtc.rs spawns go2rtc (MIT) from PATH and expects
the operator to have installed it, so we distribute nothing. If that ever
changes: go2rtc shells out to ffmpeg, and ffmpeg is LGPL-2.1+ only when
built without --enable-gpl. Most distro and prebuilt ffmpeg binaries are
GPL builds (they bundle x264). Shipping one would be a GPL distribution.
node-forge - dual-licensed, we elect BSD-3-Clause. It appears in
continuum-app as (BSD-3-Clause OR GPL-2.0). The election is ours to make
and is recorded here so the GPL half does not trigger a false alarm later.
caniuse-lite - CC-BY-4.0, attribution required if redistributed. A
build-time browserslist dependency in continuum-app; its data is not
bundled into the Nuxt output, so no attribution obligation today. It would
acquire one if anything started shipping the dataset itself.
Infrastructure already clear. PostgreSQL and pgvector (PostgreSQL licence), PgBouncer (ISC), pgCat (MIT), Supabase (Apache-2.0), ONNX Runtime (MIT), Cloudflare R2 (a service, governed by contract not licence) all permit commercial use.
Not findings
A node_modules walk turns up packages named baz, browser_field,
invalid_main, false_main and nw-pre-gyp-module-test with no licence
field. These are test fixtures inside other packages, not dependencies.
Ignore them.
Audit, 2026-10-15 - continuum-proxy dual-licence elections
Found while adding a zip reader to continuum-proxy (see below). All three
were already in the tree, all three pass cargo deny check licenses, and
none had its election recorded - which rule one at the top of this document
says to do, so that a grep for "GPL" does not restart the argument.
Verified from cargo metadata, not from memory.
unescaper 0.1.10 - MIT OR GPL-3.0-only, we elect MIT. Reached via
tokio-serial -> serialport -> unescaper, so it is in the Linux build.
The MIT half is ours to take.
r-efi 6.0.0 - MIT OR Apache-2.0 OR LGPL-2.1-or-later, we elect MIT or
Apache-2.0. Reached via native-tls -> tempfile -> getrandom, but only
on UEFI targets: it is not compiled for any platform we ship. The LGPL option
would be the problem one if it ever were, and electing around it is free.
serialport 4.10.0 - MPL-2.0, allowed with a condition. The table above
permits MPL-2.0 because its copyleft is per-file, which holds only while we
do not edit the dependency's own files. We do not and should not: if
serialport ever needs a patch, vendor the change as a fork with its own
notice, or wrap it, rather than editing files in place.
An HTTP client in continuum-proxy, and the version we could not take.
Added 2026-10-15 so a gateway can download a job file from a presigned URL.
The choice is reqwest 0.12.28 with default-features = false and
rustls-tls-native-roots, and the version matters:
- reqwest 0.13 is out. Its
rustlsfeature pullsrustls-platform-verifier->webpki-root-certsunder CDLA-Permissive-2.0, which is not in the table above, andcargo denyrejects it outright (error[rejected]: license is not explicitly allowed). CDLA-Permissive-2.0 is in fact a permissive licence and could reasonably be added - but it is a data licence applied to a certificate bundle, which is a different question from a code licence and deserves a deliberate decision rather than being waved through to unblock a dependency bump. Left out until someone wants it. - The other 0.13 route brings
aws-lc, which contains OpenSSL-licensed C. Also out.
What 0.12 with that feature set brings, all verified from cargo metadata
rather than from memory, and all permissive: reqwest 0.12.28, hyper
1.12.0, hyper-util 0.1.21, http-body 1.1.0, tower 0.5.3,
tower-service 0.3.3 (all MIT); rustls 0.23.46, hyper-rustls 0.27.10,
rustls-native-certs 0.8.5 (Apache-2.0 OR ISC OR MIT); rustls-webpki
0.103.15 and untrusted 0.9.0 (ISC); ring 0.17.14
(Apache-2.0 AND ISC - note the AND: both apply, and both are fine);
sync_wrapper 1.0.2 (Apache-2.0); subtle 2.6.1 (BSD-3-Clause);
zerocopy 0.8.56 (BSD-2-Clause OR Apache-2.0 OR MIT); plus http,
httparse, base64, url, ipnet, rustls-pki-types and tokio-rustls
(MIT OR Apache-2.0).
openssl-probe 0.2.1 appears and is only a certificate-path lookup, no C.
Note that openssl-sys is still in the tree regardless, via the existing
native-tls the Bambu MQTT and FTPS clients use - rustls here does not
remove it.
New in continuum-proxy on 2026-10-15, all clear: zip 9.0.3 (MIT),
flate2 1.1.10, crc32fast 1.5.2, typed-path 0.12.3 (all
MIT OR Apache-2.0), miniz_oxide 0.9.1 (MIT OR Zlib OR Apache-2.0),
adler2 2.0.1 (0BSD OR MIT OR Apache-2.0), simd-adler32 0.3.10 (MIT),
zlib-rs 0.6.8 (Zlib). Added for reading .3mf project archives. The
feature set is deliberately deflate-flate2 only - zip's other codec
features pull in bzip2, lzma/xz and zstd bindings, none of which are needed
and each of which is another licence to check. Confirmed none of them entered
the graph.
When adding a dependency
- Check the licence against the table above before writing code against it. Replacing a library after it is load-bearing is the costly path.
- Run the repo's
cargo deny check licenses. - If it is an external binary, a model, or a service, none of the tooling will catch it - add it to the audit section above by hand.