diff options
Diffstat (limited to 'tvix/build/src/oci/spec.rs')
-rw-r--r-- | tvix/build/src/oci/spec.rs | 80 |
1 files changed, 34 insertions, 46 deletions
diff --git a/tvix/build/src/oci/spec.rs b/tvix/build/src/oci/spec.rs index e80e442f0350..e3b6172def8a 100644 --- a/tvix/build/src/oci/spec.rs +++ b/tvix/build/src/oci/spec.rs @@ -1,11 +1,10 @@ //! Module to create a OCI runtime spec for a given [BuildRequest]. -use crate::proto::BuildRequest; +use crate::buildservice::{BuildConstraints, BuildRequest}; use oci_spec::{ runtime::{Capability, LinuxNamespace, LinuxNamespaceBuilder, LinuxNamespaceType}, OciSpecError, }; use std::{collections::HashSet, path::Path}; -use tvix_castore::proto as castorepb; use super::scratch_name; @@ -35,33 +34,26 @@ pub(crate) fn make_spec( rootless: bool, sandbox_shell: &str, ) -> Result<oci_spec::runtime::Spec, oci_spec::OciSpecError> { - // TODO: add BuildRequest validations. BuildRequest must contain strings as inputs - let allow_network = request .constraints - .as_ref() - .is_some_and(|c| c.network_access); + .contains(&BuildConstraints::NetworkAccess); // Assemble ro_host_mounts. Start with constraints.available_ro_paths. - let mut ro_host_mounts = request + let mut ro_host_mounts: Vec<_> = request .constraints - .as_ref() - .map(|constraints| { - constraints - .available_ro_paths - .iter() - .map(|e| (e.as_str(), e.as_str())) - .collect::<Vec<_>>() + .iter() + .filter_map(|constraint| match constraint { + BuildConstraints::AvailableReadOnlyPath(path) => Some((path.as_path(), path.as_path())), + _ => None, }) - .unwrap_or_default(); + .collect(); // If provide_bin_sh is set, mount sandbox_shell to /bin/sh if request .constraints - .as_ref() - .is_some_and(|c| c.provide_bin_sh) + .contains(&BuildConstraints::ProvideBinSh) { - ro_host_mounts.push((sandbox_shell, "/bin/sh")) + ro_host_mounts.push((Path::new(sandbox_shell), Path::new("/bin/sh"))) } oci_spec::runtime::SpecBuilder::default() @@ -92,9 +84,9 @@ pub(crate) fn make_spec( .mounts(configure_mounts( rootless, allow_network, - request.scratch_paths.iter().map(|e| e.as_str()), + request.scratch_paths.iter().map(|e| e.as_path()), request.inputs.iter(), - &request.inputs_dir, // TODO: validate + &request.inputs_dir, ro_host_mounts, )?) .build() @@ -106,7 +98,7 @@ pub(crate) fn make_spec( /// Capabilities are a bit more complicated in case rootless building is requested. fn configure_process<'a>( command_args: &[String], - cwd: &String, + cwd: &Path, env: impl IntoIterator<Item = (&'a str, String)>, rootless: bool, ) -> Result<oci_spec::runtime::Process, oci_spec::OciSpecError> { @@ -232,10 +224,11 @@ fn configure_linux( fn configure_mounts<'a>( rootless: bool, allow_network: bool, - scratch_paths: impl IntoIterator<Item = &'a str>, - inputs: impl Iterator<Item = &'a castorepb::Node>, - inputs_dir: &str, - ro_host_mounts: impl IntoIterator<Item = (&'a str, &'a str)>, + scratch_paths: impl IntoIterator<Item = &'a Path>, + inputs: impl Iterator<Item = (&'a tvix_castore::PathComponent, &'a tvix_castore::Node)>, + + inputs_dir: &Path, + ro_host_mounts: impl IntoIterator<Item = (&'a Path, &'a Path)>, ) -> Result<Vec<oci_spec::runtime::Mount>, oci_spec::OciSpecError> { let mut mounts: Vec<_> = if rootless { oci_spec::runtime::get_rootless_mounts() @@ -244,8 +237,8 @@ fn configure_mounts<'a>( }; mounts.push(configure_mount( - "tmpfs", - "/tmp", + Path::new("tmpfs"), + Path::new("/tmp"), "tmpfs", &["nosuid", "noatime", "mode=700"], )?); @@ -255,28 +248,19 @@ fn configure_mounts<'a>( for scratch_path in scratch_paths.into_iter() { let src = scratch_root.join(scratch_name(scratch_path)); mounts.push(configure_mount( - src.to_str().unwrap(), - Path::new("/").join(scratch_path).to_str().unwrap(), + &src, + &Path::new("/").join(scratch_path), "none", &["rbind", "rw"], )?); } // For each input, create a bind mount from inputs/$name into $inputs_dir/$name. - for input in inputs { - let (input_name, _input) = input - .clone() - .try_into_name_and_node() - .expect("invalid input name"); - + for (input_name, _input) in inputs { let input_name = std::str::from_utf8(input_name.as_ref()).expect("invalid input name"); mounts.push(configure_mount( - Path::new("inputs").join(input_name).to_str().unwrap(), - Path::new("/") - .join(inputs_dir) - .join(input_name) - .to_str() - .unwrap(), + &Path::new("inputs").join(input_name), + &Path::new("/").join(inputs_dir).join(input_name), "none", &[ "rbind", "ro", @@ -295,7 +279,11 @@ fn configure_mounts<'a>( // In case network is enabled, also mount in /etc/{resolv.conf,services,hosts} if allow_network { - for p in ["/etc/resolv.conf", "/etc/services", "/etc/hosts"] { + for p in [ + Path::new("/etc/resolv.conf"), + Path::new("/etc/services"), + Path::new("/etc/hosts"), + ] { mounts.push(configure_mount(p, p, "none", &["rbind", "ro"])?); } } @@ -305,15 +293,15 @@ fn configure_mounts<'a>( /// Helper function to produce a mount. fn configure_mount( - source: &str, - destination: &str, + source: &Path, + destination: &Path, typ: &str, options: &[&str], ) -> Result<oci_spec::runtime::Mount, oci_spec::OciSpecError> { oci_spec::runtime::MountBuilder::default() - .destination(destination.to_string()) + .destination(destination) .typ(typ.to_string()) - .source(source.to_string()) + .source(source) .options(options.iter().map(|e| e.to_string()).collect::<Vec<_>>()) .build() } |