Skip to content

Commit

Permalink
Update Rust crate tough to 0.15 (#4477)
Browse files Browse the repository at this point in the history
Co-authored-by: Rain <[email protected]>
  • Loading branch information
oxide-renovate[bot] and sunshowers authored Nov 20, 2023
1 parent 74d3bf9 commit cd2d23b
Show file tree
Hide file tree
Showing 24 changed files with 434 additions and 217 deletions.
60 changes: 38 additions & 22 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -367,11 +367,11 @@ tokio = "1.33.0"
tokio-postgres = { version = "0.7", features = [ "with-chrono-0_4", "with-uuid-1" ] }
tokio-stream = "0.1.14"
tokio-tungstenite = "0.18"
tokio-util = "0.7.10"
tokio-util = { version = "0.7.10", features = ["io", "io-util"] }
toml = "0.8.8"
toml_edit = "0.21.0"
topological-sort = "0.2.2"
tough = { version = "0.14", features = [ "http" ] }
tough = { version = "0.15", features = [ "http" ] }
trust-dns-client = "0.22"
trust-dns-proto = "0.22"
trust-dns-resolver = "0.22"
Expand Down
1 change: 1 addition & 0 deletions nexus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ anyhow.workspace = true
assert_matches.workspace = true
async-trait.workspace = true
base64.workspace = true
buf-list.workspace = true
cancel-safe-futures.workspace = true
camino.workspace = true
clap.workspace = true
Expand Down
16 changes: 8 additions & 8 deletions nexus/src/app/update/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ impl super::Nexus {
),
})?;

let artifacts = tokio::task::spawn_blocking(move || {
crate::updates::read_artifacts(&trusted_root, base_url)
})
.await
.unwrap()
.map_err(|e| Error::InternalError {
internal_message: format!("error trying to refresh updates: {}", e),
})?;
let artifacts = crate::updates::read_artifacts(&trusted_root, base_url)
.await
.map_err(|e| Error::InternalError {
internal_message: format!(
"error trying to refresh updates: {}",
e
),
})?;

// FIXME: if we hit an error in any of these database calls, the
// available artifact table will be out of sync with the current
Expand Down
24 changes: 12 additions & 12 deletions nexus/src/updates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,38 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use buf_list::BufList;
use futures::TryStreamExt;
use nexus_db_queries::db;
use omicron_common::update::ArtifactsDocument;
use std::convert::TryInto;

// TODO(iliana): make async/.await. awslabs/tough#213
pub(crate) fn read_artifacts(
pub(crate) async fn read_artifacts(
trusted_root: &[u8],
mut base_url: String,
) -> Result<
Vec<db::model::UpdateArtifact>,
Box<dyn std::error::Error + Send + Sync>,
> {
use std::io::Read;

if !base_url.ends_with('/') {
base_url.push('/');
}

let repository = tough::RepositoryLoader::new(
trusted_root,
&trusted_root,
format!("{}metadata/", base_url).parse()?,
format!("{}targets/", base_url).parse()?,
)
.load()?;
.load()
.await?;

let mut artifact_document = Vec::new();
match repository.read_target(&"artifacts.json".parse()?)? {
Some(mut target) => target.read_to_end(&mut artifact_document)?,
None => return Err("artifacts.json missing".into()),
};
let artifact_document =
match repository.read_target(&"artifacts.json".parse()?).await? {
Some(target) => target.try_collect::<BufList>().await?,
None => return Err("artifacts.json missing".into()),
};
let artifacts: ArtifactsDocument =
serde_json::from_slice(&artifact_document)?;
serde_json::from_reader(buf_list::Cursor::new(&artifact_document))?;

let valid_until = repository
.root()
Expand Down
38 changes: 26 additions & 12 deletions nexus/tests/integration_tests/updates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// - test that an unknown artifact returns 404, not 500
// - tests around target names and artifact names that contain dangerous paths like `../`

use async_trait::async_trait;
use chrono::{Duration, Utc};
use dropshot::test_util::LogContext;
use dropshot::{
Expand Down Expand Up @@ -45,17 +46,22 @@ const UPDATE_COMPONENT: &'static str = "omicron-test-component";
#[tokio::test]
async fn test_update_end_to_end() {
let mut config = load_test_config();
let logctx = LogContext::new("test_update_end_to_end", &config.pkg.log);

// build the TUF repo
let rng = SystemRandom::new();
let tuf_repo = new_tuf_repo(&rng);
let tuf_repo = new_tuf_repo(&rng).await;
slog::info!(
logctx.log,
"TUF repo created at {}",
tuf_repo.path().display()
);

// 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 logctx = LogContext::new("test_update_end_to_end", &config.pkg.log);
let server =
HttpServerStarter::new(&dropshot_config, api, context, &logctx.log)
.unwrap()
Expand Down Expand Up @@ -122,17 +128,22 @@ async fn static_content(
for component in path.into_inner().path {
fs_path.push(component);
}
let body = tokio::fs::read(fs_path)
.await
.map_err(|e| HttpError::for_bad_request(None, e.to_string()))?;
let body = tokio::fs::read(fs_path).await.map_err(|e| {
// tough 0.15+ depend on ENOENT being translated into 404.
if e.kind() == std::io::ErrorKind::NotFound {
HttpError::for_not_found(None, e.to_string())
} else {
HttpError::for_bad_request(None, e.to_string())
}
})?;
Ok(Response::builder().status(StatusCode::OK).body(body.into())?)
}

// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^=

const TARGET_CONTENTS: &[u8] = b"hello world".as_slice();

fn new_tuf_repo(rng: &dyn SecureRandom) -> TempDir {
async fn new_tuf_repo(rng: &(dyn SecureRandom + Sync)) -> TempDir {
let version =
NonZeroU64::new(Utc::now().timestamp().try_into().unwrap()).unwrap();
let expires = Utc::now() + Duration::minutes(5);
Expand Down Expand Up @@ -180,13 +191,14 @@ fn new_tuf_repo(rng: &dyn SecureRandom) -> TempDir {
&signing_keys,
rng,
)
.await
.unwrap();

// TODO(iliana): there's no way to create a `RepositoryEditor` without having the root.json on
// disk. this is really unergonomic. write and upstream a fix
let mut root_tmp = NamedTempFile::new().unwrap();
root_tmp.as_file_mut().write_all(signed_root.buffer()).unwrap();
let mut editor = RepositoryEditor::new(&root_tmp).unwrap();
let mut editor = RepositoryEditor::new(&root_tmp).await.unwrap();
root_tmp.close().unwrap();

editor
Expand All @@ -200,19 +212,20 @@ fn new_tuf_repo(rng: &dyn SecureRandom) -> TempDir {
.timestamp_expires(expires);
let (targets_dir, target_names) = generate_targets();
for target in target_names {
editor.add_target_path(targets_dir.path().join(target)).unwrap();
editor.add_target_path(targets_dir.path().join(target)).await.unwrap();
}

let signed_repo = editor.sign(&signing_keys).unwrap();
let signed_repo = editor.sign(&signing_keys).await.unwrap();

let repo = TempDir::new().unwrap();
signed_repo.write(repo.path().join("metadata")).unwrap();
signed_repo.write(repo.path().join("metadata")).await.unwrap();
signed_repo
.copy_targets(
targets_dir,
repo.path().join("targets"),
PathExists::Fail,
)
.await
.unwrap();

repo
Expand Down Expand Up @@ -257,8 +270,9 @@ impl Debug for KeyKeySource {
}
}

#[async_trait]
impl KeySource for KeyKeySource {
fn as_sign(
async fn as_sign(
&self,
) -> Result<Box<dyn Sign>, Box<dyn std::error::Error + Send + Sync + 'static>>
{
Expand All @@ -267,7 +281,7 @@ impl KeySource for KeyKeySource {
Ok(Box::new(Ed25519KeyPair::from_pkcs8(self.0.as_ref()).unwrap()))
}

fn write(
async fn write(
&self,
_value: &str,
_key_id_hex: &str,
Expand Down
Loading

0 comments on commit cd2d23b

Please sign in to comment.