//! Everything this binary embeds has to be inside what its image is built //! from. //! //! `services/api/Dockerfile` copies `Cargo.toml`, `Cargo.lock`, `services` //! and `crates` - and nothing else. An `include_bytes!` reaching outside //! those compiles in a checkout, where the whole repository is present, and //! fails in the container with "No such file or directory". That is a broken //! release found at deploy time rather than at desk time, which is what this //! is here to prevent. use std::path::{Path, PathBuf}; /// The directories `services/api/Dockerfile` copies into the build stage. const COPIED: [&str; 2] = ["services", "crates"]; #[test] fn every_embedded_path_is_inside_the_image_build_context() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../.."); let mut checked = 0; let mut outside = Vec::new(); for dir in COPIED { for source in rust_files(&root.join(dir)) { // This file names both macros in order to look for them, so it // would otherwise report itself. if source.ends_with("tests/embedded_assets.rs") { continue; } let Ok(text) = std::fs::read_to_string(&source) else { continue; }; for asked in embedded_paths(&text) { checked += 1; let target = source.parent().unwrap().join(&asked); let Ok(target) = target.canonicalize() else { outside.push(format!("{} -> {asked} (missing)", source.display())); continue; }; let inside = COPIED.iter().any(|dir| { root.join(dir) .canonicalize() .is_ok_and(|copied| target.starts_with(copied)) }); if !inside { outside.push(format!("{} -> {asked}", source.display())); } } } } assert!( outside.is_empty(), "embedded from outside the image build context ({COPIED:?}):\n {}", outside.join("\n ") ); // A walk that found nothing has passed without checking anything. assert!(checked > 0, "no embedded assets found - is the walk right?"); } fn rust_files(dir: &Path) -> Vec { let mut found = Vec::new(); let Ok(entries) = std::fs::read_dir(dir) else { return found; }; for entry in entries.flatten() { let path = entry.path(); if path.is_dir() { // Build output, not source, and enormous. if path.file_name().is_some_and(|name| name == "target") { continue; } found.extend(rust_files(&path)); } else if path.extension().is_some_and(|ext| ext == "rs") { found.push(path); } } found } /// The literal path out of every `include_bytes!("...")` and /// `include_str!("...")`. Text matching rather than parsing: a macro written /// across two lines or handed a constant is not something this repository /// does, and a test that misses one of those is better than a syn dependency /// to catch it. fn embedded_paths(text: &str) -> Vec { let mut found = Vec::new(); for macro_name in ["include_bytes!(\"", "include_str!(\""] { let mut rest = text; while let Some(at) = rest.find(macro_name) { rest = &rest[at + macro_name.len()..]; if let Some(end) = rest.find('"') { found.push(rest[..end].to_owned()); rest = &rest[end..]; } } } found }