Something went wrong. Try again.
Web frontend and supporting services for lance.blue
Something went wrong. Try again.
3.6 kB · 98 lines
Rust
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899//! 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<PathBuf> { 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<String> { 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}