From ddcc692297878fc5d0855799b7a2b6e43b1eab4c Mon Sep 17 00:00:00 2001 From: Rain Date: Wed, 17 Jan 2024 15:07:27 -0800 Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?= =?UTF-8?q?l=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.5 --- Cargo.lock | 1 + common/src/nexus_config.rs | 53 +++++------ nexus/Cargo.toml | 1 + .../src/db/datastore/db_metadata.rs | 16 ++-- nexus/src/bin/nexus.rs | 4 +- nexus/src/bin/schema-updater.rs | 3 +- nexus/src/context.rs | 33 +++++-- nexus/src/external_api/console_api.rs | 88 +++++++++++-------- nexus/tests/integration_tests/console_api.rs | 6 +- nexus/tests/integration_tests/schema.rs | 3 +- nexus/tests/integration_tests/updates.rs | 13 ++- 11 files changed, 121 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b8f6ff1e7..5fd9103488 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4738,6 +4738,7 @@ dependencies = [ "base64", "buf-list", "camino", + "camino-tempfile", "cancel-safe-futures", "chrono", "clap 4.4.3", diff --git a/common/src/nexus_config.rs b/common/src/nexus_config.rs index 740823e755..7f26bd84b0 100644 --- a/common/src/nexus_config.rs +++ b/common/src/nexus_config.rs @@ -11,6 +11,7 @@ use crate::api::internal::shared::SwitchLocation; use super::address::{Ipv6Subnet, RACK_PREFIX}; use super::postgres_config::PostgresConfigWithUrl; use anyhow::anyhow; +use camino::{Utf8Path, Utf8PathBuf}; use dropshot::ConfigDropshot; use dropshot::ConfigLogging; use schemars::JsonSchema; @@ -24,13 +25,12 @@ use std::collections::HashMap; use std::fmt; use std::net::IpAddr; use std::net::SocketAddr; -use std::path::{Path, PathBuf}; use std::time::Duration; use uuid::Uuid; #[derive(Debug)] pub struct LoadError { - pub path: PathBuf, + pub path: Utf8PathBuf, pub kind: LoadErrorKind, } @@ -54,14 +54,14 @@ pub enum LoadErrorKind { InvalidTunable(InvalidTunable), } -impl From<(PathBuf, std::io::Error)> for LoadError { - fn from((path, err): (PathBuf, std::io::Error)) -> Self { +impl From<(Utf8PathBuf, std::io::Error)> for LoadError { + fn from((path, err): (Utf8PathBuf, std::io::Error)) -> Self { LoadError { path, kind: LoadErrorKind::Io(err) } } } -impl From<(PathBuf, toml::de::Error)> for LoadError { - fn from((path, err): (PathBuf, toml::de::Error)) -> Self { +impl From<(Utf8PathBuf, toml::de::Error)> for LoadError { + fn from((path, err): (Utf8PathBuf, toml::de::Error)) -> Self { LoadError { path, kind: LoadErrorKind::Parse(err) } } } @@ -72,18 +72,13 @@ impl fmt::Display for LoadError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.kind { LoadErrorKind::Io(e) => { - write!(f, "read \"{}\": {}", self.path.display(), e) + write!(f, "read \"{}\": {}", self.path, e) } LoadErrorKind::Parse(e) => { - write!(f, "parse \"{}\": {}", self.path.display(), e.message()) + write!(f, "parse \"{}\": {}", self.path, e.message()) } LoadErrorKind::InvalidTunable(inner) => { - write!( - f, - "invalid tunable \"{}\": {}", - self.path.display(), - inner, - ) + write!(f, "invalid tunable \"{}\": {}", self.path, inner) } } } @@ -170,7 +165,7 @@ impl DeploymentConfig { /// /// This config object can then be used to create a new `Nexus`. /// The format is described in the README. - pub fn from_file>(path: P) -> Result { + pub fn from_file>(path: P) -> Result { let path = path.as_ref(); let file_contents = std::fs::read_to_string(path) .map_err(|e| (path.to_path_buf(), e))?; @@ -207,7 +202,7 @@ pub struct AuthnConfig { #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct ConsoleConfig { - pub static_dir: PathBuf, + pub static_dir: Utf8PathBuf, /// how long a session can be idle before expiring pub session_idle_timeout_minutes: u32, /// how long a session can exist before expiring @@ -217,7 +212,7 @@ pub struct ConsoleConfig { #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct UpdatesConfig { /// Trusted root.json role for the TUF updates repository. - pub trusted_root: PathBuf, + pub trusted_root: Utf8PathBuf, /// Default base URL for the TUF repository. pub default_base_url: String, } @@ -225,7 +220,7 @@ pub struct UpdatesConfig { /// Options to tweak database schema changes. #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct SchemaConfig { - pub schema_dir: PathBuf, + pub schema_dir: Utf8PathBuf, } /// Optional configuration for the timeseries database. @@ -464,7 +459,7 @@ impl Config { /// /// This config object can then be used to create a new `Nexus`. /// The format is described in the README. - pub fn from_file>(path: P) -> Result { + pub fn from_file>(path: P) -> Result { let path = path.as_ref(); let file_contents = std::fs::read_to_string(path) .map_err(|e| (path.to_path_buf(), e))?; @@ -524,6 +519,7 @@ mod test { }; use crate::address::{Ipv6Subnet, RACK_PREFIX}; use crate::api::internal::shared::SwitchLocation; + use camino::{Utf8Path, Utf8PathBuf}; use dropshot::ConfigDropshot; use dropshot::ConfigLogging; use dropshot::ConfigLoggingIfExists; @@ -532,21 +528,18 @@ mod test { use std::collections::HashMap; use std::fs; use std::net::{Ipv6Addr, SocketAddr}; - use std::path::Path; - use std::path::PathBuf; use std::str::FromStr; use std::time::Duration; /// Generates a temporary filesystem path unique for the given label. - fn temp_path(label: &str) -> PathBuf { + fn temp_path(label: &str) -> Utf8PathBuf { let arg0str = std::env::args().next().expect("expected process arg0"); - let arg0 = Path::new(&arg0str) + let arg0 = Utf8Path::new(&arg0str) .file_name() - .expect("expected arg0 filename") - .to_str() - .expect("expected arg0 filename to be valid Unicode"); + .expect("expected arg0 filename"); let pid = std::process::id(); - let mut pathbuf = std::env::temp_dir(); + let mut pathbuf = Utf8PathBuf::try_from(std::env::temp_dir()) + .expect("expected temp dir to be valid UTF-8"); pathbuf.push(format!("{}.{}.{}", arg0, pid, label)); pathbuf } @@ -559,7 +552,7 @@ mod test { fn read_config(label: &str, contents: &str) -> Result { let pathbuf = temp_path(label); let path = pathbuf.as_path(); - eprintln!("writing test config {}", path.display()); + eprintln!("writing test config {}", path); fs::write(path, contents).expect("write to tempfile failed"); let result = Config::from_file(path); @@ -572,7 +565,7 @@ mod test { #[test] fn test_config_nonexistent() { - let error = Config::from_file(Path::new("/nonexistent")) + let error = Config::from_file(Utf8Path::new("/nonexistent")) .expect_err("expected config to fail from /nonexistent"); let expected = std::io::Error::from_raw_os_error(libc::ENOENT); assert_eq!(error, expected); @@ -734,7 +727,7 @@ mod test { address: Some("[::1]:8123".parse().unwrap()) }, updates: Some(UpdatesConfig { - trusted_root: PathBuf::from("/path/to/root.json"), + trusted_root: Utf8PathBuf::from("/path/to/root.json"), default_base_url: "http://example.invalid/".into(), }), schema: None, diff --git a/nexus/Cargo.toml b/nexus/Cargo.toml index 25833ec104..c50f482be4 100644 --- a/nexus/Cargo.toml +++ b/nexus/Cargo.toml @@ -88,6 +88,7 @@ omicron-workspace-hack.workspace = true [dev-dependencies] async-bb8-diesel.workspace = true +camino-tempfile.workspace = true criterion.workspace = true diesel.workspace = true dns-server.workspace = true diff --git a/nexus/db-queries/src/db/datastore/db_metadata.rs b/nexus/db-queries/src/db/datastore/db_metadata.rs index e579bb8476..1f9ec2c028 100644 --- a/nexus/db-queries/src/db/datastore/db_metadata.rs +++ b/nexus/db-queries/src/db/datastore/db_metadata.rs @@ -210,7 +210,7 @@ impl DataStore { // - Look in the schema directory for all the changes, in-order, to // migrate from our current version to the desired version. - info!(log, "Reading schemas from {}", config.schema_dir.display()); + info!(log, "Reading schemas from {}", config.schema_dir); let mut dir = tokio::fs::read_dir(&config.schema_dir) .await .map_err(|e| format!("Failed to read schema config dir: {e}"))?; @@ -239,14 +239,14 @@ impl DataStore { if !all_versions.contains(¤t_version) { return Err(format!( "Current DB version {current_version} was not found in {}", - config.schema_dir.display() + config.schema_dir )); } // TODO: Test this? if !all_versions.contains(&desired_version) { return Err(format!( "Target DB version {desired_version} was not found in {}", - config.schema_dir.display() + config.schema_dir )); } @@ -263,10 +263,7 @@ impl DataStore { "target_version" => target_version.to_string(), ); - let target_dir = Utf8PathBuf::from_path_buf( - config.schema_dir.join(target_version.to_string()), - ) - .map_err(|e| format!("Invalid schema path: {}", e.display()))?; + let target_dir = config.schema_dir.join(target_version.to_string()); let schema_change = all_sql_for_version_migration(&target_dir).await?; @@ -709,9 +706,8 @@ mod test { .await; // Show that the datastores can be created concurrently. - let config = SchemaConfig { - schema_dir: config_dir.path().to_path_buf().into_std_path_buf(), - }; + let config = + SchemaConfig { schema_dir: config_dir.path().to_path_buf() }; let _ = futures::future::join_all((0..10).map(|_| { let log = log.clone(); let pool = pool.clone(); diff --git a/nexus/src/bin/nexus.rs b/nexus/src/bin/nexus.rs index b67085db2c..59a77e7ca4 100644 --- a/nexus/src/bin/nexus.rs +++ b/nexus/src/bin/nexus.rs @@ -11,6 +11,7 @@ // omicron#2184, omicron#2414. use anyhow::anyhow; +use camino::Utf8PathBuf; use clap::Parser; use omicron_common::cmd::fatal; use omicron_common::cmd::CmdError; @@ -18,7 +19,6 @@ use omicron_nexus::run_openapi_external; use omicron_nexus::run_openapi_internal; use omicron_nexus::run_server; use omicron_nexus::Config; -use std::path::PathBuf; #[derive(Debug, Parser)] #[clap(name = "nexus", about = "See README.adoc for more information")] @@ -41,7 +41,7 @@ struct Args { openapi_internal: bool, #[clap(name = "CONFIG_FILE_PATH", action)] - config_file_path: Option, + config_file_path: Option, } #[tokio::main] diff --git a/nexus/src/bin/schema-updater.rs b/nexus/src/bin/schema-updater.rs index 944067a7df..db179dc7f6 100644 --- a/nexus/src/bin/schema-updater.rs +++ b/nexus/src/bin/schema-updater.rs @@ -72,8 +72,7 @@ async fn main() -> anyhow::Result<()> { let crdb_cfg = db::Config { url: args.url }; let pool = Arc::new(db::Pool::new(&log, &crdb_cfg)); - let schema_config = - SchemaConfig { schema_dir: args.schema_directory.into() }; + let schema_config = SchemaConfig { schema_dir: args.schema_directory }; // We use the unchecked constructor of the datastore because we // don't want to block on someone else applying an upgrade. diff --git a/nexus/src/context.rs b/nexus/src/context.rs index 7fd0a33c30..d34a04437f 100644 --- a/nexus/src/context.rs +++ b/nexus/src/context.rs @@ -10,6 +10,7 @@ use authn::external::session_cookie::HttpAuthnSessionCookie; use authn::external::spoof::HttpAuthnSpoof; use authn::external::token::HttpAuthnToken; use authn::external::HttpAuthnScheme; +use camino::Utf8PathBuf; use chrono::Duration; use internal_dns::ServiceName; use nexus_db_queries::authn::external::session_cookie::SessionStore; @@ -24,7 +25,6 @@ use oximeter::types::ProducerRegistry; use oximeter_instruments::http::{HttpService, LatencyTracker}; use slog::Logger; use std::env; -use std::path::PathBuf; use std::str::FromStr; use std::sync::Arc; use uuid::Uuid; @@ -60,7 +60,7 @@ pub(crate) struct ConsoleConfig { /// how long a session can exist before expiring pub session_absolute_timeout: Duration, /// directory containing static file to serve - pub static_dir: Option, + pub static_dir: Option, } impl ServerContext { @@ -119,14 +119,33 @@ impl ServerContext { let static_dir = if config.pkg.console.static_dir.is_absolute() { Some(config.pkg.console.static_dir.to_owned()) } else { - env::current_dir() - .map(|root| root.join(&config.pkg.console.static_dir)) - .ok() + match env::current_dir() { + Ok(root) => { + match Utf8PathBuf::try_from(root) { + Ok(root) => { + Some(root.join(&config.pkg.console.static_dir)) + } + Err(err) => { + error!(log, "Failed to convert current directory to UTF-8, \ + setting assets dir to None: {}", err); + None + } + } + } + Err(error) => { + error!( + log, + "Failed to get current directory, \ + setting assets dir to None: {}", + error + ); + None + } + } }; // We don't want to fail outright yet, but we do want to try to make - // problems slightly easier to debug. The only way it's None is if - // current_dir() fails. + // problems slightly easier to debug. if static_dir.is_none() { error!(log, "No assets directory configured. All console page and asset requests will 404."); } diff --git a/nexus/src/external_api/console_api.rs b/nexus/src/external_api/console_api.rs index 90450c3145..d369f57905 100644 --- a/nexus/src/external_api/console_api.rs +++ b/nexus/src/external_api/console_api.rs @@ -10,6 +10,7 @@ use crate::ServerContext; use anyhow::Context; +use camino::{Utf8Path, Utf8PathBuf}; use dropshot::{ endpoint, http_response_found, http_response_see_other, HttpError, HttpResponseFound, HttpResponseHeaders, HttpResponseSeeOther, @@ -42,7 +43,7 @@ use serde::{Deserialize, Serialize}; use serde_urlencoded; use std::num::NonZeroU32; use std::str::FromStr; -use std::{collections::HashSet, ffi::OsString, path::PathBuf, sync::Arc}; +use std::{collections::HashSet, sync::Arc}; // ----------------------------------------------------- // High-level overview of how login works in the console @@ -705,11 +706,11 @@ console_page!(console_silo_images, "/images"); console_page!(console_silo_utilization, "/utilization"); console_page!(console_silo_access, "/access"); -/// Make a new PathBuf with `.gz` on the end -fn with_gz_ext(path: &PathBuf) -> PathBuf { - let mut new_path = path.clone(); - let new_ext = match path.extension().map(|ext| ext.to_str()) { - Some(Some(curr_ext)) => format!("{curr_ext}.gz"), +/// Make a new Utf8PathBuf with `.gz` on the end +fn with_gz_ext(path: &Utf8Path) -> Utf8PathBuf { + let mut new_path = path.to_owned(); + let new_ext = match path.extension() { + Some(curr_ext) => format!("{curr_ext}.gz"), _ => "gz".to_string(), }; new_path.set_extension(new_ext); @@ -731,14 +732,20 @@ pub(crate) async fn asset( path_params: Path, ) -> Result, HttpError> { let apictx = rqctx.context(); - let path = PathBuf::from_iter(path_params.into_inner().path); + let path = Utf8PathBuf::from_iter(path_params.into_inner().path); // Bail unless the extension is allowed - let ext = path - .extension() - .map_or_else(|| OsString::from("disallowed"), |ext| ext.to_os_string()); - if !ALLOWED_EXTENSIONS.contains(&ext) { - return Err(not_found("file extension not allowed")); + match path.extension() { + Some(ext) => { + if !ALLOWED_EXTENSIONS.contains(&ext) { + return Err(not_found("file extension not allowed")); + } + } + None => { + return Err(not_found( + "requested file does not have extension, not allowed", + )); + } } // We only serve assets from assets/ within static_dir @@ -794,7 +801,7 @@ pub(crate) async fn serve_console_index( .static_dir .to_owned() .ok_or_else(|| not_found("static_dir undefined"))?; - let file = static_dir.join(PathBuf::from("index.html")); + let file = static_dir.join("index.html"); let file_contents = tokio::fs::read(&file) .await .map_err(|e| not_found(&format!("accessing {:?}: {:#}", file, e)))?; @@ -810,19 +817,19 @@ fn not_found(internal_msg: &str) -> HttpError { HttpError::for_not_found(None, internal_msg.to_string()) } -static ALLOWED_EXTENSIONS: Lazy> = Lazy::new(|| { - HashSet::from( - [ - "js", "css", "html", "ico", "map", "otf", "png", "svg", "ttf", - "txt", "webp", "woff", "woff2", - ] - .map(|s| OsString::from(s)), - ) +static ALLOWED_EXTENSIONS: Lazy> = Lazy::new(|| { + HashSet::from([ + "js", "css", "html", "ico", "map", "otf", "png", "svg", "ttf", "txt", + "webp", "woff", "woff2", + ]) }); /// Starting from `root_dir`, follow the segments of `path` down the file tree /// until we find a file (or not). Do not follow symlinks. -fn find_file(path: &PathBuf, root_dir: &PathBuf) -> Result { +fn find_file( + path: &Utf8Path, + root_dir: &Utf8Path, +) -> Result { let mut current = root_dir.to_owned(); // start from `root_dir` for segment in path.into_iter() { // If we hit a non-directory thing already and we still have segments @@ -855,24 +862,24 @@ fn find_file(path: &PathBuf, root_dir: &PathBuf) -> Result { #[cfg(test)] mod test { use super::{find_file, RelativeUri}; + use camino::{Utf8Path, Utf8PathBuf}; use http::StatusCode; - use std::{env::current_dir, path::PathBuf}; #[test] fn test_find_file_finds_file() { - let root = current_dir().unwrap(); + let root = current_dir(); let file = - find_file(&PathBuf::from("tests/static/assets/hello.txt"), &root); + find_file(Utf8Path::new("tests/static/assets/hello.txt"), &root); assert!(file.is_ok()); - let file = find_file(&PathBuf::from("tests/static/index.html"), &root); + let file = find_file(Utf8Path::new("tests/static/index.html"), &root); assert!(file.is_ok()); } #[test] fn test_find_file_404_on_nonexistent() { - let root = current_dir().unwrap(); + let root = current_dir(); let error = - find_file(&PathBuf::from("tests/static/nonexistent.svg"), &root) + find_file(Utf8Path::new("tests/static/nonexistent.svg"), &root) .unwrap_err(); assert_eq!(error.status_code, StatusCode::NOT_FOUND); assert_eq!(error.internal_message, "failed to get file metadata",); @@ -880,9 +887,9 @@ mod test { #[test] fn test_find_file_404_on_nonexistent_nested() { - let root = current_dir().unwrap(); + let root = current_dir(); let error = find_file( - &PathBuf::from("tests/static/a/b/c/nonexistent.svg"), + Utf8Path::new("tests/static/a/b/c/nonexistent.svg"), &root, ) .unwrap_err(); @@ -892,9 +899,9 @@ mod test { #[test] fn test_find_file_404_on_directory() { - let root = current_dir().unwrap(); + let root = current_dir(); let error = - find_file(&PathBuf::from("tests/static/assets/a_directory"), &root) + find_file(Utf8Path::new("tests/static/assets/a_directory"), &root) .unwrap_err(); assert_eq!(error.status_code, StatusCode::NOT_FOUND); assert_eq!(error.internal_message, "expected a non-directory"); @@ -902,33 +909,33 @@ mod test { #[test] fn test_find_file_404_on_symlink() { - let root = current_dir().unwrap(); + let root = current_dir(); let path_str = "tests/static/assets/a_symlink"; // the file in question does exist and is a symlink assert!(root - .join(PathBuf::from(path_str)) + .join(path_str) .symlink_metadata() .unwrap() .file_type() .is_symlink()); // so we 404 - let error = find_file(&PathBuf::from(path_str), &root).unwrap_err(); + let error = find_file(Utf8Path::new(path_str), &root).unwrap_err(); assert_eq!(error.status_code, StatusCode::NOT_FOUND); assert_eq!(error.internal_message, "attempted to follow a symlink"); } #[test] fn test_find_file_wont_follow_symlink() { - let root = current_dir().unwrap(); + let root = current_dir(); let path_str = "tests/static/assets/a_symlink/another_file.txt"; // the file in question does exist - assert!(root.join(PathBuf::from(path_str)).exists()); + assert!(root.join(path_str).exists()); // but it 404s because the path goes through a symlink - let error = find_file(&PathBuf::from(path_str), &root).unwrap_err(); + let error = find_file(Utf8Path::new(path_str), &root).unwrap_err(); assert_eq!(error.status_code, StatusCode::NOT_FOUND); assert_eq!(error.internal_message, "attempted to follow a symlink"); } @@ -945,4 +952,9 @@ mod test { assert!(RelativeUri::try_from(b.to_string()).is_err()); } } + + fn current_dir() -> Utf8PathBuf { + Utf8PathBuf::try_from(std::env::current_dir().unwrap()) + .expect("current dir is valid UTF-8") + } } diff --git a/nexus/tests/integration_tests/console_api.rs b/nexus/tests/integration_tests/console_api.rs index 55a23edfb9..d7918b01aa 100644 --- a/nexus/tests/integration_tests/console_api.rs +++ b/nexus/tests/integration_tests/console_api.rs @@ -3,6 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use anyhow::Context; +use camino::Utf8PathBuf; use dropshot::test_util::ClientTestContext; use dropshot::ResultsPage; use http::header::HeaderName; @@ -338,7 +339,10 @@ async fn test_assets(cptestctx: &ControlPlaneTestContext) { #[tokio::test] async fn test_absolute_static_dir() { let mut config = load_test_config(); - config.pkg.console.static_dir = current_dir().unwrap().join("tests/static"); + config.pkg.console.static_dir = + Utf8PathBuf::try_from(current_dir().unwrap()) + .unwrap() + .join("tests/static"); let cptestctx = test_setup_with_config::( "test_absolute_static_dir", &mut config, diff --git a/nexus/tests/integration_tests/schema.rs b/nexus/tests/integration_tests/schema.rs index f183b53282..f122bd8597 100644 --- a/nexus/tests/integration_tests/schema.rs +++ b/nexus/tests/integration_tests/schema.rs @@ -21,7 +21,6 @@ use similar_asserts; use slog::Logger; use std::collections::{BTreeMap, BTreeSet}; use std::net::IpAddr; -use std::path::PathBuf; use tokio::time::timeout; use tokio::time::Duration; use uuid::Uuid; @@ -54,7 +53,7 @@ async fn test_setup<'a>( ); let populate = false; builder.start_crdb(populate).await; - let schema_dir = PathBuf::from(SCHEMA_DIR); + let schema_dir = Utf8PathBuf::from(SCHEMA_DIR); builder.config.pkg.schema = Some(SchemaConfig { schema_dir }); builder.start_internal_dns().await; builder.start_external_dns().await; diff --git a/nexus/tests/integration_tests/updates.rs b/nexus/tests/integration_tests/updates.rs index 891166ed19..418e12e001 100644 --- a/nexus/tests/integration_tests/updates.rs +++ b/nexus/tests/integration_tests/updates.rs @@ -8,6 +8,7 @@ // - tests around target names and artifact names that contain dangerous paths like `../` use async_trait::async_trait; +use camino_tempfile::Utf8TempDir; use chrono::{Duration, Utc}; use dropshot::test_util::LogContext; use dropshot::{ @@ -51,17 +52,13 @@ async fn test_update_end_to_end() { // build the TUF repo let rng = SystemRandom::new(); let tuf_repo = new_tuf_repo(&rng).await; - slog::info!( - logctx.log, - "TUF repo created at {}", - tuf_repo.path().display() - ); + slog::info!(logctx.log, "TUF repo created at {}", tuf_repo.path()); // serve it over HTTP let dropshot_config = Default::default(); let mut api = ApiDescription::new(); api.register(static_content).unwrap(); - let context = FileServerContext { base: tuf_repo.path().to_owned() }; + let context = FileServerContext { base: tuf_repo.path().to_owned().into() }; let server = HttpServerStarter::new(&dropshot_config, api, context, &logctx.log) .unwrap() @@ -143,7 +140,7 @@ async fn static_content( const TARGET_CONTENTS: &[u8] = b"hello world".as_slice(); -async fn new_tuf_repo(rng: &(dyn SecureRandom + Sync)) -> TempDir { +async fn new_tuf_repo(rng: &(dyn SecureRandom + Sync)) -> Utf8TempDir { let version = NonZeroU64::new(Utc::now().timestamp().try_into().unwrap()).unwrap(); let expires = Utc::now() + Duration::minutes(5); @@ -217,7 +214,7 @@ async fn new_tuf_repo(rng: &(dyn SecureRandom + Sync)) -> TempDir { let signed_repo = editor.sign(&signing_keys).await.unwrap(); - let repo = TempDir::new().unwrap(); + let repo = Utf8TempDir::new().unwrap(); signed_repo.write(repo.path().join("metadata")).await.unwrap(); signed_repo .copy_targets(