From a84259d58c6fd8def618616de44dd62fa048ed4a Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Tue, 10 Nov 2026 18:04:49 -0500 Subject: [PATCH] ui-egui: embed craft-fonts files only from inside the checkout (#3281) * ui-egui: embed craft-fonts files only from inside the checkout The build hook canonicalised each manifest row's file and embedded it with include_bytes! wherever it led, so an absolute path, a .. path or a symlink in a craft-fonts checkout could put any readable file of the build machine into the binary. Manifests and font files must now resolve inside the canonical checkout directory. * address review: register the manifest path before validation and keep the Chinese manifest fallback optional --- crates/ui-egui/build.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/crates/ui-egui/build.rs b/crates/ui-egui/build.rs index 0c5dbf3e8..2551abf2c 100644 --- a/crates/ui-egui/build.rs +++ b/crates/ui-egui/build.rs @@ -76,7 +76,21 @@ fn emit_craft_fonts() { /// One `CraftFont { .. }` initialiser per manifest row GridCraft may embed. fn craft_fonts(dir: &std::path::Path, wasm: bool, required: bool) -> Result { - let manifest = dir.join("fonts/manifest.txt"); + // Every file embedded comes from inside the checkout: a manifest row (or a symlink) naming a + // path outside it would put that file of the build machine into the binary. + let root = dir.canonicalize().map_err(|e| format!("{}: {e}", dir.display()))?; + let inside = |path: std::path::PathBuf| -> Result { + let real = path.canonicalize().map_err(|e| format!("{}: {e}", path.display()))?; + if real.starts_with(&root) { Ok(real) } else { Err(format!("{} is outside the craft-fonts checkout {}", path.display(), root.display())) } + }; + // Registered before validation, by the path as given (and its folder, to see the manifest appear + // or a symlink replaced): a build that skipped the fonts must rebuild once they are there. + let manifest_path = dir.join("fonts/manifest.txt"); + println!("cargo::rerun-if-changed={}", manifest_path.display()); + if let Some(parent) = manifest_path.parent() { + println!("cargo::rerun-if-changed={}", parent.display()); + } + let manifest = inside(manifest_path)?; println!("cargo::rerun-if-changed={}", manifest.display()); let text = std::fs::read_to_string(&manifest).map_err(|e| format!("{}: {e}", manifest.display()))?; let rows = craft_fonts_policy::parse_manifest(&text)?; @@ -84,7 +98,7 @@ fn craft_fonts(dir: &std::path::Path, wasm: bool, required: bool) -> Result Result = row.scripts.iter().map(|s| format!("{s:?}")).collect(); let family = &row.family; @@ -120,6 +134,10 @@ fn chinese_font_rows(dir: &std::path::Path, required: bool) -> Result match craft_fonts_policy::parse_manifest(&text).and_then(|rows| { craft_fonts_policy::check_declared_scripts(&rows)?;