From a58abeee7d44cadac4ff8f2d83218b8d08e6c70c Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Tue, 29 Sep 2026 10:23:57 +0200 Subject: [PATCH] docs: add the LICENSE file the README's badge has always pointed at The badge linked to LICENSE at the root and no such file existed. The only licence statement anywhere was the SPDX string in the manifests, which tells a tool which licence applies but not a human the terms or who holds the copyright -- and distribution channels and corporate review processes look for the file. Each published crate carries a symlink to it, the same shape CLAUDE.md already uses. Cargo resolves the link when packaging, so the .crate ships the text rather than a dangling link: verified by unpacking rustmotion-core-0.7.1.crate. The holder was the one thing the repository did not contain and could not be guessed; it is the name every commit is signed with. --- LICENSE | 21 ++++++++++++ README.md | 2 +- crates/rustmotion-components/LICENSE | 1 + crates/rustmotion-core/LICENSE | 1 + crates/rustmotion-core/tests/audit_ws_k.rs | 37 ++++++++++++++++++++++ crates/rustmotion-html/LICENSE | 1 + crates/rustmotion/LICENSE | 1 + 7 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 LICENSE create mode 120000 crates/rustmotion-components/LICENSE create mode 120000 crates/rustmotion-core/LICENSE create mode 120000 crates/rustmotion-html/LICENSE create mode 120000 crates/rustmotion/LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a66122f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Baptiste Parmantier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 45546d1..fd29a7f 100644 --- a/README.md +++ b/README.md @@ -2181,4 +2181,4 @@ The `rustmotion` crate is where both binaries live — a crate with only a `[lib ## License -MIT +MIT — see [LICENSE](LICENSE). diff --git a/crates/rustmotion-components/LICENSE b/crates/rustmotion-components/LICENSE new file mode 120000 index 0000000..30cff74 --- /dev/null +++ b/crates/rustmotion-components/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/crates/rustmotion-core/LICENSE b/crates/rustmotion-core/LICENSE new file mode 120000 index 0000000..30cff74 --- /dev/null +++ b/crates/rustmotion-core/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/crates/rustmotion-core/tests/audit_ws_k.rs b/crates/rustmotion-core/tests/audit_ws_k.rs index d5526c4..405a7f3 100644 --- a/crates/rustmotion-core/tests/audit_ws_k.rs +++ b/crates/rustmotion-core/tests/audit_ws_k.rs @@ -236,3 +236,40 @@ fn every_public_schema_field_is_read_somewhere_or_allowlisted() { KNOWN_INERT_FIELDS above with a reason and the finding that tracks closing it." ); } + +#[test] +fn the_license_badge_points_at_a_file_that_exists_and_names_a_holder() { + let root = workspace_root(); + let license = std::fs::read_to_string(root.join("LICENSE")) + .expect("README's MIT badge links to LICENSE at the root, so the file has to be there"); + + assert!( + license.starts_with("MIT License"), + "the manifests declare license = \"MIT\", so the file has to be the MIT text" + ); + let holder = license + .lines() + .find_map(|l| l.strip_prefix("Copyright (c) ")) + .expect("a licence with no copyright holder tells a human nothing"); + assert!( + holder.split_whitespace().count() >= 2, + "the holder line must name someone, got {holder:?}" + ); + + for crate_name in [ + "rustmotion", + "rustmotion-core", + "rustmotion-components", + "rustmotion-html", + ] { + let packaged = root.join("crates").join(crate_name).join("LICENSE"); + assert_eq!( + std::fs::read_to_string(&packaged).ok().as_deref(), + Some(license.as_str()), + "{crate_name} is published to crates.io, and a .crate with no LICENSE file is the \ + gap the SPDX string in the manifest does not close — {} must resolve to the same \ + text as the root one", + packaged.display() + ); + } +} diff --git a/crates/rustmotion-html/LICENSE b/crates/rustmotion-html/LICENSE new file mode 120000 index 0000000..30cff74 --- /dev/null +++ b/crates/rustmotion-html/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/crates/rustmotion/LICENSE b/crates/rustmotion/LICENSE new file mode 120000 index 0000000..30cff74 --- /dev/null +++ b/crates/rustmotion/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file