From 03d71ded2ef38c3f3b499230794f93ca88eb79bf Mon Sep 17 00:00:00 2001 From: Calvin Prewitt Date: Wed, 4 Sep 2024 14:36:25 -0500 Subject: [PATCH 1/4] added `auto_package_init` option --- crates/client/src/config.rs | 6 ++++ crates/client/src/lib.rs | 67 +++++++++++++++++++++---------------- src/commands/config.rs | 8 ++++- tests/support/mod.rs | 1 + 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/crates/client/src/config.rs b/crates/client/src/config.rs index 729f01da..a6e18538 100644 --- a/crates/client/src/config.rs +++ b/crates/client/src/config.rs @@ -123,6 +123,11 @@ pub struct Config { #[serde(default)] pub auto_accept_federation_hints: bool, + /// Automatically attempt package initialize if does not exist + /// or ask the user to confirm first + #[serde(default)] + pub auto_package_init: bool, + /// Disable interactive prompts. #[serde(default)] pub disable_interactive: bool, @@ -210,6 +215,7 @@ impl Config { keyring_auth: self.keyring_auth, ignore_federation_hints: self.ignore_federation_hints, auto_accept_federation_hints: self.auto_accept_federation_hints, + auto_package_init: self.auto_package_init, disable_interactive: self.disable_interactive, keyring_backend: self.keyring_backend.clone(), }; diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs index 94b76297..40e1fcd7 100644 --- a/crates/client/src/lib.rs +++ b/crates/client/src/lib.rs @@ -74,6 +74,7 @@ where api: api::Client, ignore_federation_hints: bool, auto_accept_federation_hints: bool, + auto_package_init: bool, disable_interactive: bool, keyring_backend: Option, keys: IndexSet, @@ -91,6 +92,7 @@ impl Client>, ignore_federation_hints: bool, auto_accept_federation_hints: bool, + auto_package_init: bool, disable_interactive: bool, keyring_backend: Option, keys: IndexSet, @@ -103,6 +105,7 @@ impl Client Client { if !initializing { - if self.disable_interactive || cfg!(not(feature = "cli-interactive")) { - return Err(ClientError::MustInitializePackage { - name, - has_auth_token, - }); - } - - #[cfg(feature = "cli-interactive")] - { - use crate::storage::PublishEntry; - use dialoguer::{theme::ColorfulTheme, Confirm}; - - if accepted_prompt_to_initialize - || Confirm::with_theme(&ColorfulTheme::default()) - .with_prompt(format!( - "Package `{package_name}` was not found. -If it exists, you may not have access. -Attempt to create `{package_name}` and publish the release y/N\n", - package_name = &info.name, - )) - .default(false) - .interact() - .unwrap() - { - info.entries.insert(0, PublishEntry::Init); - initializing = true; - accepted_prompt_to_initialize = true; - } else { + if self.auto_package_init { + info.entries.insert(0, crate::storage::PublishEntry::Init); + initializing = true; + accepted_prompt_to_initialize = true; + } else { + if self.disable_interactive || cfg!(not(feature = "cli-interactive")) { return Err(ClientError::MustInitializePackage { name, has_auth_token, }); } + + #[cfg(feature = "cli-interactive")] + { + use crate::storage::PublishEntry; + use dialoguer::{theme::ColorfulTheme, Confirm}; + + if accepted_prompt_to_initialize + || Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt(format!( + "Package `{package_name}` was not found. + If it exists, you may not have access. + Attempt to create `{package_name}` and publish the release y/N\n", + package_name = &info.name, + )) + .default(false) + .interact() + .unwrap() + { + info.entries.insert(0, PublishEntry::Init); + initializing = true; + accepted_prompt_to_initialize = true; + } else { + return Err(ClientError::MustInitializePackage { + name, + has_auth_token, + }); + } + } } } PackageInfo::new(info.name.clone()) @@ -1447,6 +1456,7 @@ impl FileSystemClient { auth_token, config.ignore_federation_hints, config.auto_accept_federation_hints, + config.auto_package_init, disable_interactive, keyring_backend, keys, @@ -1511,6 +1521,7 @@ impl FileSystemClient { auth_token, config.ignore_federation_hints, config.auto_accept_federation_hints, + config.auto_package_init, disable_interactive, keyring_backend, keys, diff --git a/src/commands/config.rs b/src/commands/config.rs index f8f48765..13e45e79 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -27,6 +27,11 @@ pub struct ConfigCommand { #[clap(long)] pub auto_accept_federation_hints: Option, + /// Automatically attempt package initialize if does not exist + /// or ask the user to confirm first. + #[clap(long)] + pub auto_package_init: Option, + /// Overwrite the existing configuration file. #[clap(long)] pub overwrite: bool, @@ -86,7 +91,8 @@ impl ConfigCommand { keys: self.common.read_config()?.keys, keyring_auth: false, ignore_federation_hints: self.ignore_federation_hints.unwrap_or_default(), - auto_accept_federation_hints: self.auto_accept_federation_hints.unwrap_or_default(), + auto_accept_federation_hints: self.auto_accept_federation_hints.unwrap_or(true), + auto_package_init: self.auto_package_init.unwrap_or(true), disable_interactive: false, keyring_backend: self.keyring_backend, } diff --git a/tests/support/mod.rs b/tests/support/mod.rs index bab73be4..8afdea18 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -169,6 +169,7 @@ pub async fn spawn_server( keyring_auth: false, ignore_federation_hints: false, auto_accept_federation_hints: false, + auto_package_init: false, disable_interactive: true, keyring_backend: None, }; From 77ad13b48931b87e8cd32e28df845c2d182e9ac4 Mon Sep 17 00:00:00 2001 From: Calvin Prewitt Date: Wed, 4 Sep 2024 14:38:24 -0500 Subject: [PATCH 2/4] fixed clippy warning on doc comment --- crates/transparency/src/log/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/transparency/src/log/mod.rs b/crates/transparency/src/log/mod.rs index f22ce48e..12f9d18e 100644 --- a/crates/transparency/src/log/mod.rs +++ b/crates/transparency/src/log/mod.rs @@ -6,6 +6,7 @@ //! //! Implementations: //! * [`InOrderLog`] - +//! //! The only implementation in this module is , //! which is a [`VerifiableLog`] whose contents are structured //! using binary in-order interval numbering as described in From 73b0f7b433274d7cb2b50ac7e60a52ab48a3dc42 Mon Sep 17 00:00:00 2001 From: Calvin Prewitt Date: Wed, 4 Sep 2024 17:22:15 -0500 Subject: [PATCH 3/4] changed defaults --- crates/client/src/' | 262 ++++++++++++++++++++++++++++++++++++ crates/client/src/config.rs | 8 +- crates/client/src/lib.rs | 24 ++-- src/commands/config.rs | 21 ++- src/commands/login.rs | 12 +- tests/support/mod.rs | 4 +- 6 files changed, 303 insertions(+), 28 deletions(-) create mode 100644 crates/client/src/' diff --git a/crates/client/src/' b/crates/client/src/' new file mode 100644 index 00000000..6f99c0d0 --- /dev/null +++ b/crates/client/src/' @@ -0,0 +1,262 @@ +use anyhow::{bail, Context, Result}; +use indexmap::IndexSet; +use std::{ + env, + path::{Path, PathBuf}, + sync::atomic::{AtomicUsize, Ordering}, + time::Duration, +}; +use tokio::{fs, task::JoinHandle}; +use tokio_util::sync::CancellationToken; +use tracing::subscriber::DefaultGuard; +use url::Url; +use warg_client::{ + storage::{ContentStorage, PublishEntry, PublishInfo}, + FileSystemClient, StorageLockResult, +}; +use warg_crypto::{ + hash::AnyHash, + signing::{KeyID, PrivateKey}, +}; +use warg_protocol::{operator, registry::PackageName}; +use warg_server::{ + datastore::DataStore, + policy::{content::WasmContentPolicy, record::AuthorizedKeyPolicy}, + Config, Server, +}; +use wit_parser::{Resolve, UnresolvedPackage}; + +pub fn test_namespaces() -> Option> { + Some(vec![( + "test".to_string(), + operator::NamespaceState::Defined, + )]) +} + +pub fn test_operator_key() -> PrivateKey { + let key = "ecdsa-p256:I+UlDo0HxyBBFeelhPPWmD+LnklOpqZDkrFP5VduASk="; + PrivateKey::decode(key.to_string()).unwrap() +} + +pub fn test_signing_key() -> PrivateKey { + let key = "ecdsa-p256:2CV1EpLaSYEn4In4OAEDAj5O4Hzu8AFAxgHXuG310Ew="; + PrivateKey::decode(key.to_string()).unwrap() +} + +pub async fn create_client(config: &warg_client::Config) -> Result { + match FileSystemClient::try_new_with_config(None, config, None).await? { + StorageLockResult::Acquired(client) => Ok(client), + _ => bail!("failed to acquire storage lock"), + } +} + +pub struct ServerInstance { + task: Option>, + shutdown: CancellationToken, + _subscriber_guard: DefaultGuard, +} + +impl Drop for ServerInstance { + fn drop(&mut self) { + futures::executor::block_on(async move { + self.shutdown.cancel(); + self.task.take().unwrap().await.unwrap(); + }); + } +} + +pub async fn root() -> Result { + static NEXT_ID: AtomicUsize = AtomicUsize::new(0); + std::thread_local! { + static TEST_ID: usize = NEXT_ID.fetch_add(1, Ordering::SeqCst); + } + + let id = TEST_ID.with(|n| *n); + + let mut path = env::current_exe()?; + path.pop(); // remove test exe name + path.pop(); // remove `deps` + path.pop(); // remove `debug` or `release` + path.push("tests"); + path.push( + std::env::current_exe() + .context("failed to get process name")? + .file_name() + .context("failed to get process name")? + .to_str() + .context("failed to get process name")?, + ); + path.push(format!("{id}")); + + fs::remove_dir_all(&path).await.ok(); + + let server_content_dir = path.join("server"); + fs::create_dir_all(&server_content_dir).await?; + + let registries_dir = path.join("registries"); + fs::create_dir_all(®istries_dir).await?; + + let content_dir = path.join("content"); + fs::create_dir_all(&content_dir).await?; + + Ok(path) +} + +/// Sets up logging for the current thread, active until the returned guard is dropped. +fn thread_test_logging() -> DefaultGuard { + let subscriber = tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .with_test_writer() + .finish(); + tracing::subscriber::set_default(subscriber) +} + +/// Spawns a server as a background task. +pub async fn spawn_server( + root: &Path, + content_base_url: Option, + data_store: Option>, + authorized_keys: Option>, +) -> Result<(ServerInstance, warg_client::Config)> { + let _subscriber_guard = thread_test_logging(); + + let shutdown = CancellationToken::new(); + let mut config = Config::new(test_operator_key(), test_namespaces(), root.join("server")) + .with_addr(([127, 0, 0, 1], 0)) + .with_shutdown(shutdown.clone().cancelled_owned()) + .with_checkpoint_interval(Duration::from_millis(100)) + .with_content_policy(WasmContentPolicy::default()); // For the tests, we assume only wasm content is allowed. + + if let Some(content_url) = content_base_url { + config = config.with_content_base_url(content_url); + } + + if let Some(authorized_keys) = authorized_keys { + let mut policy = AuthorizedKeyPolicy::new(); + for (namespace, key) in authorized_keys { + policy = policy.with_namespace_key(namespace, key)?; + } + + config = config.with_record_policy(policy); + } + + if let Some(store) = data_store { + config = config.with_boxed_data_store(store); + } + + let server = Server::new(config).initialize().await?; + + let addr = server.local_addr()?; + tracing::debug!("Test server running at {addr}"); + + let task = tokio::spawn(async move { + let _subscriber_guard = thread_test_logging(); + server.serve().await.unwrap(); + }); + + let instance = ServerInstance { + task: Some(task), + shutdown, + _subscriber_guard, + }; + + let config = warg_client::Config { + home_url: Some(format!("http://{addr}")), + registries_dir: Some(root.join("registries")), + content_dir: Some(root.join("content")), + namespace_map_path: Some(root.join("namespaces")), + keys: IndexSet::new(), + keyring_auth: false, + ignore_federation_hints: false, + disable_auto_accept_federation_hints: false, + disable_auto_package_init: true, + disable_interactive: true, + keyring_backend: None, + }; + + Ok((instance, config)) +} + +pub async fn publish( + client: &FileSystemClient, + name: &PackageName, + version: &str, + content: Vec, + init: bool, + signing_key: &PrivateKey, +) -> Result { + let digest = client + .content() + .store_content( + Box::pin(futures::stream::once(async move { Ok(content.into()) })), + None, + ) + .await?; + + let mut entries = Vec::with_capacity(2); + if init { + entries.push(PublishEntry::Init); + } + entries.push(PublishEntry::Release { + version: version.parse().unwrap(), + content: digest.clone(), + }); + + let record_id = client + .publish_with_info( + signing_key, + PublishInfo { + name: name.clone(), + head: None, + entries, + }, + ) + .await?; + + client + .wait_for_publish(name, &record_id, Duration::from_millis(100)) + .await?; + + Ok(digest) +} + +pub async fn publish_component( + client: &FileSystemClient, + name: &PackageName, + version: &str, + wat: &str, + init: bool, + signing_key: &PrivateKey, +) -> Result { + publish( + client, + name, + version, + wat::parse_str(wat)?, + init, + signing_key, + ) + .await +} + +pub async fn publish_wit( + client: &FileSystemClient, + name: &PackageName, + version: &str, + wit: &str, + init: bool, + signing_key: &PrivateKey, +) -> Result { + let mut resolve = Resolve::new(); + let pkg = resolve.push(UnresolvedPackage::parse(Path::new("foo.wit"), wit)?)?; + + publish( + client, + name, + version, + wit_component::encode(Some(true), &resolve, pkg)?, + init, + signing_key, + ) + .await +} diff --git a/crates/client/src/config.rs b/crates/client/src/config.rs index a6e18538..336fc450 100644 --- a/crates/client/src/config.rs +++ b/crates/client/src/config.rs @@ -121,12 +121,12 @@ pub struct Config { /// Auto accept registry hint or ask the user to confirm #[serde(default)] - pub auto_accept_federation_hints: bool, + pub disable_auto_accept_federation_hints: bool, /// Automatically attempt package initialize if does not exist /// or ask the user to confirm first #[serde(default)] - pub auto_package_init: bool, + pub disable_auto_package_init: bool, /// Disable interactive prompts. #[serde(default)] @@ -214,8 +214,8 @@ impl Config { keys: self.keys.clone(), keyring_auth: self.keyring_auth, ignore_federation_hints: self.ignore_federation_hints, - auto_accept_federation_hints: self.auto_accept_federation_hints, - auto_package_init: self.auto_package_init, + disable_auto_accept_federation_hints: self.disable_auto_accept_federation_hints, + disable_auto_package_init: self.disable_auto_package_init, disable_interactive: self.disable_interactive, keyring_backend: self.keyring_backend.clone(), }; diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs index 40e1fcd7..68abd015 100644 --- a/crates/client/src/lib.rs +++ b/crates/client/src/lib.rs @@ -73,8 +73,8 @@ where namespace_map: N, api: api::Client, ignore_federation_hints: bool, - auto_accept_federation_hints: bool, - auto_package_init: bool, + disable_auto_accept_federation_hints: bool, + disable_auto_package_init: bool, disable_interactive: bool, keyring_backend: Option, keys: IndexSet, @@ -91,8 +91,8 @@ impl Client>, ignore_federation_hints: bool, - auto_accept_federation_hints: bool, - auto_package_init: bool, + disable_auto_accept_federation_hints: bool, + disable_auto_package_init: bool, disable_interactive: bool, keyring_backend: Option, keys: IndexSet, @@ -104,8 +104,8 @@ impl Client Client { if !initializing { - if self.auto_package_init { + if !self.disable_auto_package_init { info.entries.insert(0, crate::storage::PublishEntry::Init); initializing = true; accepted_prompt_to_initialize = true; @@ -945,7 +945,7 @@ impl Client, - /// Auto accept federation hints. + /// Disable auto accept federation hints. #[clap(long)] - pub auto_accept_federation_hints: Option, + pub disable_auto_accept_federation_hints: Option, /// Automatically attempt package initialize if does not exist /// or ask the user to confirm first. #[clap(long)] - pub auto_package_init: Option, + pub disable_auto_package_init: Option, /// Overwrite the existing configuration file. #[clap(long)] @@ -91,8 +91,10 @@ impl ConfigCommand { keys: self.common.read_config()?.keys, keyring_auth: false, ignore_federation_hints: self.ignore_federation_hints.unwrap_or_default(), - auto_accept_federation_hints: self.auto_accept_federation_hints.unwrap_or(true), - auto_package_init: self.auto_package_init.unwrap_or(true), + disable_auto_accept_federation_hints: self + .disable_auto_accept_federation_hints + .unwrap_or_default(), + disable_auto_package_init: self.disable_auto_package_init.unwrap_or_default(), disable_interactive: false, keyring_backend: self.keyring_backend, } @@ -126,8 +128,13 @@ impl ConfigCommand { if let Some(ignore_federation_hints) = self.ignore_federation_hints { config.ignore_federation_hints = ignore_federation_hints; } - if let Some(auto_accept_federation_hints) = self.auto_accept_federation_hints { - config.auto_accept_federation_hints = auto_accept_federation_hints; + if let Some(disable_auto_accept_federation_hints) = + self.disable_auto_accept_federation_hints + { + config.disable_auto_accept_federation_hints = disable_auto_accept_federation_hints; + } + if let Some(disable_auto_package_init) = self.disable_auto_package_init { + config.disable_auto_package_init = disable_auto_package_init; } if self.keyring_backend.is_some() { config.keyring_backend = self.keyring_backend; diff --git a/src/commands/login.rs b/src/commands/login.rs index 80425f9c..89a52186 100644 --- a/src/commands/login.rs +++ b/src/commands/login.rs @@ -25,9 +25,14 @@ pub struct LoginCommand { #[clap(long)] pub ignore_federation_hints: bool, - /// Auto accept federation hints. + /// Disable auto accept federation hints. #[clap(long)] - pub auto_accept_federation_hints: bool, + pub disable_auto_accept_federation_hints: bool, + + /// Automatically attempt package initialize if does not exist + /// or ask the user to confirm first. + #[clap(long)] + pub disable_auto_package_init: bool, /// The backend to use for keyring access #[clap(long, value_name = "KEYRING_BACKEND", value_parser = keyring_backend_parser, long_help = keyring_backend_help())] @@ -52,7 +57,8 @@ impl LoginCommand { .transpose()? .map(|u| u.to_string()); config.ignore_federation_hints = self.ignore_federation_hints; - config.auto_accept_federation_hints = self.auto_accept_federation_hints; + config.disable_auto_accept_federation_hints = self.disable_auto_accept_federation_hints; + config.disable_auto_package_init = self.disable_auto_package_init; // set keyring backend, if specified if self.keyring_backend.is_some() { diff --git a/tests/support/mod.rs b/tests/support/mod.rs index 8afdea18..6f99c0d0 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -168,8 +168,8 @@ pub async fn spawn_server( keys: IndexSet::new(), keyring_auth: false, ignore_federation_hints: false, - auto_accept_federation_hints: false, - auto_package_init: false, + disable_auto_accept_federation_hints: false, + disable_auto_package_init: true, disable_interactive: true, keyring_backend: None, }; From d6cf9c0980ba3e4adce4a3ff5fa6e2428e54f09e Mon Sep 17 00:00:00 2001 From: Calvin Prewitt Date: Wed, 4 Sep 2024 18:05:39 -0500 Subject: [PATCH 4/4] removed accidental file --- crates/client/src/' | 262 -------------------------------------------- 1 file changed, 262 deletions(-) delete mode 100644 crates/client/src/' diff --git a/crates/client/src/' b/crates/client/src/' deleted file mode 100644 index 6f99c0d0..00000000 --- a/crates/client/src/' +++ /dev/null @@ -1,262 +0,0 @@ -use anyhow::{bail, Context, Result}; -use indexmap::IndexSet; -use std::{ - env, - path::{Path, PathBuf}, - sync::atomic::{AtomicUsize, Ordering}, - time::Duration, -}; -use tokio::{fs, task::JoinHandle}; -use tokio_util::sync::CancellationToken; -use tracing::subscriber::DefaultGuard; -use url::Url; -use warg_client::{ - storage::{ContentStorage, PublishEntry, PublishInfo}, - FileSystemClient, StorageLockResult, -}; -use warg_crypto::{ - hash::AnyHash, - signing::{KeyID, PrivateKey}, -}; -use warg_protocol::{operator, registry::PackageName}; -use warg_server::{ - datastore::DataStore, - policy::{content::WasmContentPolicy, record::AuthorizedKeyPolicy}, - Config, Server, -}; -use wit_parser::{Resolve, UnresolvedPackage}; - -pub fn test_namespaces() -> Option> { - Some(vec![( - "test".to_string(), - operator::NamespaceState::Defined, - )]) -} - -pub fn test_operator_key() -> PrivateKey { - let key = "ecdsa-p256:I+UlDo0HxyBBFeelhPPWmD+LnklOpqZDkrFP5VduASk="; - PrivateKey::decode(key.to_string()).unwrap() -} - -pub fn test_signing_key() -> PrivateKey { - let key = "ecdsa-p256:2CV1EpLaSYEn4In4OAEDAj5O4Hzu8AFAxgHXuG310Ew="; - PrivateKey::decode(key.to_string()).unwrap() -} - -pub async fn create_client(config: &warg_client::Config) -> Result { - match FileSystemClient::try_new_with_config(None, config, None).await? { - StorageLockResult::Acquired(client) => Ok(client), - _ => bail!("failed to acquire storage lock"), - } -} - -pub struct ServerInstance { - task: Option>, - shutdown: CancellationToken, - _subscriber_guard: DefaultGuard, -} - -impl Drop for ServerInstance { - fn drop(&mut self) { - futures::executor::block_on(async move { - self.shutdown.cancel(); - self.task.take().unwrap().await.unwrap(); - }); - } -} - -pub async fn root() -> Result { - static NEXT_ID: AtomicUsize = AtomicUsize::new(0); - std::thread_local! { - static TEST_ID: usize = NEXT_ID.fetch_add(1, Ordering::SeqCst); - } - - let id = TEST_ID.with(|n| *n); - - let mut path = env::current_exe()?; - path.pop(); // remove test exe name - path.pop(); // remove `deps` - path.pop(); // remove `debug` or `release` - path.push("tests"); - path.push( - std::env::current_exe() - .context("failed to get process name")? - .file_name() - .context("failed to get process name")? - .to_str() - .context("failed to get process name")?, - ); - path.push(format!("{id}")); - - fs::remove_dir_all(&path).await.ok(); - - let server_content_dir = path.join("server"); - fs::create_dir_all(&server_content_dir).await?; - - let registries_dir = path.join("registries"); - fs::create_dir_all(®istries_dir).await?; - - let content_dir = path.join("content"); - fs::create_dir_all(&content_dir).await?; - - Ok(path) -} - -/// Sets up logging for the current thread, active until the returned guard is dropped. -fn thread_test_logging() -> DefaultGuard { - let subscriber = tracing_subscriber::fmt() - .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) - .with_test_writer() - .finish(); - tracing::subscriber::set_default(subscriber) -} - -/// Spawns a server as a background task. -pub async fn spawn_server( - root: &Path, - content_base_url: Option, - data_store: Option>, - authorized_keys: Option>, -) -> Result<(ServerInstance, warg_client::Config)> { - let _subscriber_guard = thread_test_logging(); - - let shutdown = CancellationToken::new(); - let mut config = Config::new(test_operator_key(), test_namespaces(), root.join("server")) - .with_addr(([127, 0, 0, 1], 0)) - .with_shutdown(shutdown.clone().cancelled_owned()) - .with_checkpoint_interval(Duration::from_millis(100)) - .with_content_policy(WasmContentPolicy::default()); // For the tests, we assume only wasm content is allowed. - - if let Some(content_url) = content_base_url { - config = config.with_content_base_url(content_url); - } - - if let Some(authorized_keys) = authorized_keys { - let mut policy = AuthorizedKeyPolicy::new(); - for (namespace, key) in authorized_keys { - policy = policy.with_namespace_key(namespace, key)?; - } - - config = config.with_record_policy(policy); - } - - if let Some(store) = data_store { - config = config.with_boxed_data_store(store); - } - - let server = Server::new(config).initialize().await?; - - let addr = server.local_addr()?; - tracing::debug!("Test server running at {addr}"); - - let task = tokio::spawn(async move { - let _subscriber_guard = thread_test_logging(); - server.serve().await.unwrap(); - }); - - let instance = ServerInstance { - task: Some(task), - shutdown, - _subscriber_guard, - }; - - let config = warg_client::Config { - home_url: Some(format!("http://{addr}")), - registries_dir: Some(root.join("registries")), - content_dir: Some(root.join("content")), - namespace_map_path: Some(root.join("namespaces")), - keys: IndexSet::new(), - keyring_auth: false, - ignore_federation_hints: false, - disable_auto_accept_federation_hints: false, - disable_auto_package_init: true, - disable_interactive: true, - keyring_backend: None, - }; - - Ok((instance, config)) -} - -pub async fn publish( - client: &FileSystemClient, - name: &PackageName, - version: &str, - content: Vec, - init: bool, - signing_key: &PrivateKey, -) -> Result { - let digest = client - .content() - .store_content( - Box::pin(futures::stream::once(async move { Ok(content.into()) })), - None, - ) - .await?; - - let mut entries = Vec::with_capacity(2); - if init { - entries.push(PublishEntry::Init); - } - entries.push(PublishEntry::Release { - version: version.parse().unwrap(), - content: digest.clone(), - }); - - let record_id = client - .publish_with_info( - signing_key, - PublishInfo { - name: name.clone(), - head: None, - entries, - }, - ) - .await?; - - client - .wait_for_publish(name, &record_id, Duration::from_millis(100)) - .await?; - - Ok(digest) -} - -pub async fn publish_component( - client: &FileSystemClient, - name: &PackageName, - version: &str, - wat: &str, - init: bool, - signing_key: &PrivateKey, -) -> Result { - publish( - client, - name, - version, - wat::parse_str(wat)?, - init, - signing_key, - ) - .await -} - -pub async fn publish_wit( - client: &FileSystemClient, - name: &PackageName, - version: &str, - wit: &str, - init: bool, - signing_key: &PrivateKey, -) -> Result { - let mut resolve = Resolve::new(); - let pkg = resolve.push(UnresolvedPackage::parse(Path::new("foo.wit"), wit)?)?; - - publish( - client, - name, - version, - wit_component::encode(Some(true), &resolve, pkg)?, - init, - signing_key, - ) - .await -}