diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4861e724..397ca115 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,19 @@ env: CARGO_TERM_COLOR: always jobs: + dependency-advisories: + name: Dependency advisories + if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@stable + - name: Install advisory scanner + run: cargo install cargo-deny --version 0.20.2 --locked + - name: Check locked dependencies + run: cargo deny --locked check --warn unmaintained advisories bans sources + changes: name: Select checks runs-on: ubuntu-24.04 @@ -343,4 +356,4 @@ jobs: run: | . "$HOME/.cargo/env" export CRAFT_FONTS_DIR="$PWD/craft-fonts" - cargo check --all-targets --locked --target riscv64gc-unknown-linux-gnu \ No newline at end of file + cargo check --all-targets --locked --target riscv64gc-unknown-linux-gnu diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 26652e44..6270c57c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -100,6 +100,8 @@ The [README](README.md#architecture) has the layer table. The short version: not.) Permissive dependencies are fine. Note which one you're adding and why in the PR, and run `cargo xtask licences` so THIRD-PARTY-LICENSES.txt lists it (CI checks that it is current). + Nightly/manual CI also scans advisories, bans and sources with cargo-deny; see + [the local command and coverage limits](docs/book/src/dev/testing.md#dependency-advisories). 3. **Every asset is original or openly licensed and has a row in [ATTRIBUTION.md](ATTRIBUTION.md).** Icons are drawn in code (`crates/ui-egui/src/icons.rs`). `cargo xtask assets` enforces this. diff --git a/Cargo.lock b/Cargo.lock index a20cfac7..19820eed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2765,15 +2765,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" -[[package]] -name = "quick-xml" -version = "0.38.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" -dependencies = [ - "memchr", -] - [[package]] name = "quick-xml" version = "0.41.0" @@ -3297,7 +3288,7 @@ dependencies = [ "embed-resource", "hidapi", "log", - "quick-xml 0.38.4", + "quick-xml", "rfd", "serde_json", "solidcraft-engine", @@ -3358,7 +3349,7 @@ dependencies = [ name = "solidcraft-io" version = "0.7.0" dependencies = [ - "quick-xml 0.38.4", + "quick-xml", "serde", "serde_json", "sha2", @@ -4182,7 +4173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "338e30461b3a2b67d70eb30a6d89f8e0c93a833e07d2ae89085cd070c4a00ac0" dependencies = [ "proc-macro2", - "quick-xml 0.41.0", + "quick-xml", "quote", ] diff --git a/Cargo.toml b/Cargo.toml index 41f7c72d..b13211dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ truck-topology = "0.6" # packages (3MF) zip = { version = "3", default-features = false, features = ["deflate"] } -quick-xml = "0.38" +quick-xml = "0.41" # fonts (sketch text outlines; MIT OR Apache-2.0, pure Rust) ttf-parser = { version = "0.25", default-features = false, features = ["std"] } diff --git a/ROADMAP.md b/ROADMAP.md index bf81afb0..709880c2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -164,6 +164,11 @@ PCB / Package, Render, Animation, Simulation, Manufacture/CAM, Drawings. ## Known limitations +- Scheduled and manual CI scan locked dependency advisories, bans and sources with + cargo-deny. Vulnerabilities fail the scan; unmaintained crates warn. Local vendored + patches require separate upstream review because advisory databases cannot version-match + their path dependencies. Pull requests retain the existing licence checks. + - Associative shell-face sketches require a unique certified planar source. Nested shell attachments and ambiguous coincident sources remain unsupported. - Fillets and chamfers: constant, variable-radius and chord-length fillets; a radius per edge, diff --git a/THIRD-PARTY-LICENSES.txt b/THIRD-PARTY-LICENSES.txt index b6a2e4c5..263dd52c 100644 --- a/THIRD-PARTY-LICENSES.txt +++ b/THIRD-PARTY-LICENSES.txt @@ -1,6 +1,6 @@ Third-party software in SolidCraft -SolidCraft (the desktop app, solidcraft-cli and the web app) is built from the 454 crates below. +SolidCraft (the desktop app, solidcraft-cli and the web app) is built from the 453 crates below. Generated by `cargo xtask licences` from Cargo.lock and the crates' own licence files. SolidCraft's own licence is in LICENSE-MIT and LICENSE-APACHE, and NOTICE. @@ -262,7 +262,6 @@ proc-macro2 1.0.107 (MIT OR Apache-2.0) profiling 1.0.18 (MIT OR Apache-2.0) pxfm 0.1.30 (BSD-3-Clause OR Apache-2.0) quick-error 2.0.1 (MIT/Apache-2.0) -quick-xml 0.38.4 (MIT) quick-xml 0.41.0 (MIT) quote 1.0.47 (MIT OR Apache-2.0) r-efi 5.3.0 (MIT OR Apache-2.0 OR LGPL-2.1-or-later) @@ -8709,7 +8708,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================================================ -quick-xml 0.38.4, quick-xml 0.41.0 +quick-xml 0.41.0 ================================================================================ The MIT License (MIT) diff --git a/crates/io/src/svg.rs b/crates/io/src/svg.rs index 052935f0..e00d0574 100644 --- a/crates/io/src/svg.rs +++ b/crates/io/src/svg.rs @@ -114,7 +114,10 @@ fn attrs(e: &BytesStart) -> Vec<(String, String)> { .flatten() .map(|a| { let k = String::from_utf8_lossy(a.key.local_name().as_ref()).to_string(); - let v = a.unescape_value().map(|v| v.to_string()).unwrap_or_else(|_| String::from_utf8_lossy(&a.value).to_string()); + let v = a + .normalized_value(quick_xml::XmlVersion::Implicit1_0) + .map(|v| v.to_string()) + .unwrap_or_else(|_| String::from_utf8_lossy(&a.value).to_string()); (k, v) }) .collect() diff --git a/crates/io/src/threemf.rs b/crates/io/src/threemf.rs index 4a513a3d..fbb58922 100644 --- a/crates/io/src/threemf.rs +++ b/crates/io/src/threemf.rs @@ -319,7 +319,10 @@ fn attrs(e: &BytesStart) -> HashMap { let mut m = HashMap::new(); for a in e.attributes().flatten() { let k = String::from_utf8_lossy(a.key.local_name().as_ref()).to_string(); - let v = a.unescape_value().map(|v| v.to_string()).unwrap_or_else(|_| String::from_utf8_lossy(&a.value).to_string()); + let v = a + .normalized_value(quick_xml::XmlVersion::Implicit1_0) + .map(|v| v.to_string()) + .unwrap_or_else(|_| String::from_utf8_lossy(&a.value).to_string()); m.insert(k, v); } m diff --git a/deny.toml b/deny.toml new file mode 100644 index 00000000..c24dbb4c --- /dev/null +++ b/deny.toml @@ -0,0 +1,15 @@ +# Licences remain covered by `cargo xtask licences --check`. +[advisories] +# The nightly command downgrades only this diagnostic with --warn unmaintained. +unmaintained = "all" +yanked = "warn" + +[bans] +multiple-versions = "warn" +wildcards = "warn" +allow-wildcard-paths = true + +[sources] +unknown-registry = "deny" +unknown-git = "deny" +allow-registry = ["https://github.com/rust-lang/crates.io-index"] diff --git a/docs/book/src/dev/testing.md b/docs/book/src/dev/testing.md index 8df5ea16..bf4b0055 100644 --- a/docs/book/src/dev/testing.md +++ b/docs/book/src/dev/testing.md @@ -15,6 +15,28 @@ profile and the wasm build check. | Kill mid-save | `apps/solidcraft-cli/tests/kill_mid_save.rs` | a save killed at any moment leaves a readable file | | Reference tests | `cargo xtask oracle` → [docs/oracle.md](oracle.md) | parts rebuilt from `tests/oracle/*/recipe.json`, compared with analytic or FreeCAD expected values | +## Dependency advisories + +Scheduled and manually dispatched CI runs have a separate **Dependency advisories** job; +new advisories do not fail unrelated pull requests. To run the same scan locally: + +```sh +cargo install cargo-deny --version 0.20.2 --locked +cargo deny --locked check --warn unmaintained advisories bans sources +``` + +The checked-in `deny.toml` rejects vulnerabilities and unknown registries/git sources. +Unmaintained crates, yanked versions and duplicate versions warn; licences remain covered +by `cargo xtask licences --check`. Review advisory failures and update dependencies rather +than adding broad ignores. The first scan prompted an update to quick-xml 0.41.0 for +[RUSTSEC-2026-0194](https://rustsec.org/advisories/RUSTSEC-2026-0194) and +[RUSTSEC-2026-0195](https://rustsec.org/advisories/RUSTSEC-2026-0195). + +Coverage excludes the version matching of local path patches: `truck-shapeops`, +`truck-stepio`, `truck-meshalgo`, `matext4cgmath` and `egui-wgpu` in `vendor/`. Their checked-in +code and patches still need comparison with their permissively licensed upstreams; a green +scan does not establish their security or incorporate an upstream fix automatically. + ## UI scenarios A scenario is a JSON list of steps run against the real app with a headless egui context: