From 9f7b7eb8ecffc9a5867046a2602bbe635ad72b14 Mon Sep 17 00:00:00 2001 From: Christoph Herzog Date: Tue, 31 Oct 2023 17:30:13 +0100 Subject: [PATCH 1/4] feat(cli): Add package build/download/unpack commands Adds a new CLI command for working with packages: * package download: download a package from a registry * build: build a package from a wasmer.toml manifest * unpack: extract package contents --- Cargo.lock | 2 + Cargo.toml | 2 +- lib/cli/Cargo.toml | 60 ++------ lib/cli/src/cli.rs | 13 +- lib/cli/src/commands/container/mod.rs | 12 ++ lib/cli/src/commands/container/unpack.rs | 90 +++++++++++ lib/cli/src/commands/mod.rs | 11 +- lib/cli/src/commands/package/build.rs | 135 +++++++++++++++++ lib/cli/src/commands/package/download.rs | 181 +++++++++++++++++++++++ lib/cli/src/commands/package/mod.rs | 14 ++ lib/registry/src/queries.rs | 0 lib/registry/src/wasmer_env.rs | 24 +++ 12 files changed, 487 insertions(+), 57 deletions(-) create mode 100644 lib/cli/src/commands/container/mod.rs create mode 100644 lib/cli/src/commands/container/unpack.rs create mode 100644 lib/cli/src/commands/package/build.rs create mode 100644 lib/cli/src/commands/package/download.rs create mode 100644 lib/cli/src/commands/package/mod.rs delete mode 100644 lib/registry/src/queries.rs diff --git a/Cargo.lock b/Cargo.lock index cb1a8594715..ac2bbb33fe6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5685,7 +5685,9 @@ dependencies = [ "dirs", "distance", "flate2", + "futures", "hex", + "http", "hyper", "indexmap 1.9.3", "indicatif", diff --git a/Cargo.toml b/Cargo.toml index 0508e5de946..fc9e5d7b73b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,7 +86,7 @@ version = "4.2.3" [workspace.dependencies] memoffset = "0.9.0" wasmer-toml = "0.9.2" -webc = { version = "5.6.0", default-features = false, features = ["package"] } +webc = { version = "5.8.0", default-features = false, features = ["package"] } [build-dependencies] test-generator = { path = "tests/lib/test-generator" } diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml index ead0d793f85..f000e756315 100644 --- a/lib/cli/Cargo.toml +++ b/lib/cli/Cargo.toml @@ -113,6 +113,8 @@ once_cell = "1.17.1" indicatif = "0.17.5" opener = "0.6.1" hyper = { version = "0.14.27", features = ["server"] } +http = "0.2.9" +futures = "0.3.29" # NOTE: Must use different features for clap because the "color" feature does not # work on wasi due to the anstream dependency not compiling. @@ -155,14 +157,7 @@ unix_mode = "0.1.3" [features] # Don't add the compiler features in default, please add them on the Makefile # since we might want to autoconfigure them depending on the availability on the host. -default = [ - "sys", - "wat", - "wast", - "compiler", - "wasmer-artifact-create", - "static-artifact-create", -] +default = ["sys", "wat", "wast", "compiler", "wasmer-artifact-create", "static-artifact-create"] backend = [] coredump = ["wasm-coredump-builder"] sys = ["compiler", "wasmer-vm"] @@ -170,56 +165,21 @@ jsc = ["backend", "wasmer/jsc", "wasmer/std"] wast = ["wasmer-wast"] host-net = ["virtual-net/host-net"] wat = ["wasmer/wat"] -compiler = [ - "backend", - "wasmer/compiler", - "wasmer-compiler/translator", - "wasmer-compiler/compiler", -] -wasmer-artifact-create = [ - "compiler", - "wasmer/wasmer-artifact-load", - "wasmer/wasmer-artifact-create", - "wasmer-compiler/wasmer-artifact-load", - "wasmer-compiler/wasmer-artifact-create", - "wasmer-object", -] -static-artifact-create = [ - "compiler", - "wasmer/static-artifact-load", - "wasmer/static-artifact-create", - "wasmer-compiler/static-artifact-load", - "wasmer-compiler/static-artifact-create", - "wasmer-object", -] -wasmer-artifact-load = [ - "compiler", - "wasmer/wasmer-artifact-load", - "wasmer-compiler/wasmer-artifact-load", -] -static-artifact-load = [ - "compiler", - "wasmer/static-artifact-load", - "wasmer-compiler/static-artifact-load", -] +compiler = ["backend", "wasmer/compiler", "wasmer-compiler/translator", "wasmer-compiler/compiler"] +wasmer-artifact-create = ["compiler", "wasmer/wasmer-artifact-load", "wasmer/wasmer-artifact-create", "wasmer-compiler/wasmer-artifact-load", "wasmer-compiler/wasmer-artifact-create", "wasmer-object"] +static-artifact-create = ["compiler", "wasmer/static-artifact-load", "wasmer/static-artifact-create", "wasmer-compiler/static-artifact-load", "wasmer-compiler/static-artifact-create", "wasmer-object"] +wasmer-artifact-load = ["compiler", "wasmer/wasmer-artifact-load", "wasmer-compiler/wasmer-artifact-load"] +static-artifact-load = ["compiler", "wasmer/static-artifact-load", "wasmer-compiler/static-artifact-load"] experimental-io-devices = ["wasmer-wasix-experimental-io-devices"] singlepass = ["wasmer-compiler-singlepass", "compiler"] cranelift = ["wasmer-compiler-cranelift", "compiler"] llvm = ["wasmer-compiler-llvm", "compiler"] -disable-all-logging = [ - "wasmer-wasix/disable-all-logging", - "log/release_max_level_off", -] +disable-all-logging = ["wasmer-wasix/disable-all-logging", "log/release_max_level_off"] headless = [] headless-minimal = ["headless", "disable-all-logging"] # Optional -enable-serde = [ - "wasmer/enable-serde", - "wasmer-vm/enable-serde", - "wasmer-compiler/enable-serde", - "wasmer-wasix/enable-serde", -] +enable-serde = ["wasmer/enable-serde", "wasmer-vm/enable-serde", "wasmer-compiler/enable-serde", "wasmer-wasix/enable-serde"] [dev-dependencies] assert_cmd = "2.0.11" diff --git a/lib/cli/src/cli.rs b/lib/cli/src/cli.rs index 8b343f4587c..1575ee140dd 100644 --- a/lib/cli/src/cli.rs +++ b/lib/cli/src/cli.rs @@ -9,7 +9,8 @@ use crate::commands::CreateExe; #[cfg(feature = "wast")] use crate::commands::Wast; use crate::commands::{ - Add, Cache, Config, Init, Inspect, Login, Publish, Run, SelfUpdate, Validate, Whoami, + Add, Cache, CmdPackage, Config, Init, Inspect, Login, Publish, Run, SelfUpdate, Validate, + Whoami, }; #[cfg(feature = "static-artifact-create")] use crate::commands::{CreateObj, GenCHeader}; @@ -108,6 +109,11 @@ impl Args { Some(Cmd::Init(init)) => init.execute(), Some(Cmd::Login(login)) => login.execute(), Some(Cmd::Publish(publish)) => publish.execute(), + Some(Cmd::Package(cmd)) => match cmd { + CmdPackage::Download(cmd) => cmd.execute(), + CmdPackage::Unpack(cmd) => cmd.execute(), + CmdPackage::Build(cmd) => cmd.execute(), + }, /* Some(Cmd::Connect(connect)) => connect.execute(), */ @@ -258,7 +264,10 @@ enum Cmd { #[clap(alias = "run-unstable")] Run(Run), - // DEPLOY commands + #[clap(subcommand)] + Package(crate::commands::CmdPackage), + + // Edge commands /// Deploy apps to the Wasmer Edge. Deploy(wasmer_deploy_cli::cmd::deploy::CmdDeploy), diff --git a/lib/cli/src/commands/container/mod.rs b/lib/cli/src/commands/container/mod.rs new file mode 100644 index 00000000000..533d1ad0d89 --- /dev/null +++ b/lib/cli/src/commands/container/mod.rs @@ -0,0 +1,12 @@ +mod unpack; + +pub use unpack::PackageUnpack; + +/// Container related commands. (inspecting, unpacking, ...) +#[derive(clap::Subcommand, Debug)] +// Allowing missing_docs because the comment would override the doc comment on +// the command struct. +#[allow(missing_docs)] +pub enum Container { + Unpack(PackageUnpack), +} diff --git a/lib/cli/src/commands/container/unpack.rs b/lib/cli/src/commands/container/unpack.rs new file mode 100644 index 00000000000..e71c1405f7d --- /dev/null +++ b/lib/cli/src/commands/container/unpack.rs @@ -0,0 +1,90 @@ +use std::path::PathBuf; + +use anyhow::Context; + +/// Extract contents of a container to a directory. +#[derive(clap::Parser, Debug)] +pub struct PackageUnpack { + /// The output directory. + #[clap(short = 'o', long)] + out_dir: PathBuf, + + /// Overwrite existing directories/files. + #[clap(long)] + overwrite: bool, + + /// Path to the package. + package_path: PathBuf, +} + +impl PackageUnpack { + pub(crate) fn execute(&self) -> Result<(), anyhow::Error> { + eprintln!("Unpacking..."); + + let pkg = webc::compat::Container::from_disk(&self.package_path).with_context(|| { + format!( + "could not open package at '{}'", + self.package_path.display() + ) + })?; + + let outdir = &self.out_dir; + std::fs::create_dir_all(outdir) + .with_context(|| format!("could not create output directory '{}'", outdir.display()))?; + + pkg.unpack(outdir, self.overwrite) + .with_context(|| "could not extract package".to_string())?; + + eprintln!("Extracted package contents to '{}'", self.out_dir.display()); + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Download a package from the dev registry. + #[test] + fn test_cmd_package_extract() { + let dir = tempfile::tempdir().unwrap(); + + let package_path = std::env::var("CARGO_MANIFEST_DIR").map(PathBuf::from).unwrap() + .parent().unwrap() + .parent().unwrap() + .join("tests/integration/cli/tests/webc/hello-0.1.0-665d2ddc-80e6-4845-85d3-4587b1693bb7.webc"); + + assert!(package_path.is_file()); + + let cmd = PackageUnpack { + out_dir: dir.path().to_owned(), + overwrite: false, + package_path, + }; + + cmd.execute().unwrap(); + + let mut items = std::fs::read_dir(dir.path()) + .unwrap() + .map(|x| { + x.unwrap() + .path() + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_string() + }) + .collect::>(); + items.sort(); + assert_eq!( + items, + vec![ + "atom".to_string(), + "manifest.json".to_string(), + "metadata".to_string(), + ] + ); + } +} diff --git a/lib/cli/src/commands/mod.rs b/lib/cli/src/commands/mod.rs index 9f2365837cd..337faa19c8c 100644 --- a/lib/cli/src/commands/mod.rs +++ b/lib/cli/src/commands/mod.rs @@ -6,6 +6,7 @@ mod cache; #[cfg(feature = "compiler")] mod compile; mod config; +mod container; #[cfg(any(feature = "static-artifact-create", feature = "wasmer-artifact-create"))] mod create_exe; #[cfg(feature = "static-artifact-create")] @@ -15,6 +16,7 @@ mod gen_c_header; mod init; mod inspect; mod login; +mod package; mod publish; mod run; mod self_update; @@ -23,6 +25,11 @@ mod validate; mod wast; mod whoami; +pub use self::{ + add::*, cache::*, config::*, container::*, init::*, inspect::*, login::*, package::*, + publish::*, run::Run, self_update::*, validate::*, whoami::*, +}; + #[cfg(target_os = "linux")] pub use binfmt::*; #[cfg(feature = "compiler")] @@ -31,9 +38,5 @@ pub use compile::*; pub use create_exe::*; #[cfg(feature = "wast")] pub use wast::*; -pub use { - add::*, cache::*, config::*, init::*, inspect::*, login::*, publish::*, run::Run, - self_update::*, validate::*, whoami::*, -}; #[cfg(feature = "static-artifact-create")] pub use {create_obj::*, gen_c_header::*}; diff --git a/lib/cli/src/commands/package/build.rs b/lib/cli/src/commands/package/build.rs new file mode 100644 index 00000000000..9ff4f21cc4e --- /dev/null +++ b/lib/cli/src/commands/package/build.rs @@ -0,0 +1,135 @@ +use std::path::PathBuf; + +use anyhow::Context; + +/// Build a container from a package manifest. +#[derive(clap::Parser, Debug)] +pub struct PackageBuild { + /// Output path for the package file. + /// Defaults to current directory + [name]-[version].webc. + #[clap(short = 'o', long)] + out: Option, + + /// Path of the package or wasmer.toml manifest. + /// + /// Defaults to current directory. + package: Option, +} + +impl PackageBuild { + pub(crate) fn execute(&self) -> Result<(), anyhow::Error> { + let manifest_path = self.manifest_path()?; + let pkg = webc::wasmer_package::Package::from_manifest(manifest_path)?; + + let manifest = pkg + .manifest() + .wapm() + .context("could not load package manifest")? + .context("package does not contain a Wasmer manifest")?; + + let pkgname = manifest.name.replace('/', "-"); + let name = format!("{}-{}.webc", pkgname, manifest.version,); + let out_path = if let Some(p) = &self.out { + if p.is_dir() { + p.join(name) + } else { + if let Some(parent) = p.parent() { + std::fs::create_dir_all(parent).context("could not create output directory")?; + } + + p.to_owned() + } + } else { + std::env::current_dir() + .context("could not determine current directory")? + .join(name) + }; + + if out_path.exists() { + anyhow::bail!( + "Output path '{}' already exists - specify a different path with -o/--out", + out_path.display() + ); + } + + let data = pkg.serialize()?; + std::fs::write(&out_path, &data) + .with_context(|| format!("could not write contents to '{}'", out_path.display()))?; + + eprintln!("Package written to '{}'", out_path.display()); + + Ok(()) + } + + fn manifest_path(&self) -> Result { + let path = if let Some(p) = &self.package { + if p.is_dir() { + let manifest_path = p.join("wasmer.toml"); + if !manifest_path.is_file() { + anyhow::bail!( + "Specified directory '{}' does not contain a wasmer.toml manifest", + p.display() + ); + } + manifest_path + } else if p.is_file() { + p.clone() + } else { + anyhow::bail!( + "Specified path '{}' is not a file or directory", + p.display() + ); + } + } else { + let dir = std::env::current_dir().context("could not get current directory")?; + let manifest_path = dir.join("wasmer.toml"); + if !manifest_path.is_file() { + anyhow::bail!( + "Current directory '{}' does not contain a wasmer.toml manifest - specify a path with --package-dir", + dir.display() + ); + } + manifest_path + }; + + Ok(path) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Download a package from the dev registry. + #[test] + fn test_cmd_package_build() { + let dir = tempfile::tempdir().unwrap(); + let path = dir.path(); + + std::fs::write( + path.join("wasmer.toml"), + r#" +[package] +name = "wasmer/hello" +version = "0.1.0" +description = "hello" + +[fs] +"data" = "data" +"#, + ) + .unwrap(); + + std::fs::create_dir(path.join("data")).unwrap(); + std::fs::write(path.join("data").join("hello.txt"), "Hello, world!").unwrap(); + + let cmd = PackageBuild { + package: Some(path.to_owned()), + out: Some(path.to_owned()), + }; + + cmd.execute().unwrap(); + + webc::Container::from_disk(path.join("wasmer-hello-0.1.0.webc")).unwrap(); + } +} diff --git a/lib/cli/src/commands/package/download.rs b/lib/cli/src/commands/package/download.rs new file mode 100644 index 00000000000..096aa0245ac --- /dev/null +++ b/lib/cli/src/commands/package/download.rs @@ -0,0 +1,181 @@ +use std::{io::Write, path::PathBuf}; + +use anyhow::Context; +use futures::StreamExt; +use wasmer_registry::wasmer_env::WasmerEnv; +use wasmer_wasix::runtime::resolver::PackageSpecifier; + +/// Download a package from the registry. +#[derive(clap::Parser, Debug)] +pub struct PackageDownload { + #[clap(flatten)] + env: WasmerEnv, + + /// Verify that the downloaded file is a valid package. + #[clap(long)] + validate: bool, + + /// Path where the package file should be written to. + /// If not specified, the data will be written to stdout. + #[clap(short = 'o', long)] + out_path: PathBuf, + + /// The package to download. + /// Can be: + /// * a pakage specifier: `namespace/package[@vesion]` + /// * a URL + package: PackageSpecifier, +} + +impl PackageDownload { + pub(crate) fn execute(&self) -> Result<(), anyhow::Error> { + let rt = tokio::runtime::Runtime::new()?; + rt.block_on(self.run()) + } + + async fn run(&self) -> Result<(), anyhow::Error> { + if let Some(parent) = self.out_path.parent() { + match parent.metadata() { + Ok(m) => { + if !m.is_dir() { + anyhow::bail!( + "parent of output file is not a directory: '{}'", + parent.display() + ); + } + } + Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + std::fs::create_dir_all(parent) + .context("could not create parent directory of output file")?; + } + Err(err) => return Err(err.into()), + } + }; + + let (full_name, version, api_endpoint, token) = match &self.package { + PackageSpecifier::Registry { full_name, version } => { + let endpoint = self.env.registry_endpoint()?; + let version = version.to_string(); + let version = if version == "*" { None } else { Some(version) }; + + ( + full_name, + version, + endpoint, + self.env.get_token_opt().map(|x| x.to_string()), + ) + } + PackageSpecifier::Url(url) => { + bail!("cannot download a package from a URL: '{}'", url); + } + PackageSpecifier::Path(_) => { + anyhow::bail!("cannot download a package from a local path"); + } + }; + + let package = wasmer_registry::query_package_from_registry( + api_endpoint.as_str(), + full_name, + version.as_deref(), + token.as_deref(), + ) + .with_context(|| { + format!( + "could not retrieve package information for package '{}' from registry '{}'", + full_name, api_endpoint, + ) + })?; + + let download_url = package + .pirita_url + .context("registry does provide a container download container download URL")?; + + let client = reqwest::Client::new(); + let mut b = client + .get(&download_url) + .header(http::header::ACCEPT, "application/webc"); + if let Some(token) = token { + b = b.header(http::header::AUTHORIZATION, format!("Bearer {token}")); + }; + + eprintln!("Downloading package..."); + + let res = b + .send() + .await + .context("http request failed")? + .error_for_status() + .context("http request failed with non-success status code")?; + + let mut tmpfile = tempfile::NamedTempFile::new()?; + + let ty = res + .headers() + .get(http::header::CONTENT_TYPE) + .and_then(|t| t.to_str().ok()) + .unwrap_or_default(); + if !(ty == "application/webc" || ty == "application/octet-stream") { + eprintln!( + "Warning: response has invalid content type - expected \ + 'application/webc' or 'application/octet-stream', got {ty}" + ); + } + + let mut body = res.bytes_stream(); + + while let Some(res) = body.next().await { + let chunk = res.context("could not read response body")?; + // Yes, we are mixing async and sync code here, but since this is + // a top-level command, this can't interfere with other tasks. + tmpfile + .write_all(&chunk) + .context("could not write to temporary file")?; + } + + tmpfile.as_file_mut().sync_all()?; + + if self.validate { + eprintln!("Validating package..."); + webc::compat::Container::from_disk(tmpfile.path()) + .context("could not parse downloaded file as a package - invalid download?")?; + eprintln!("Downloaded package is valid!"); + } + + tmpfile.persist(&self.out_path).with_context(|| { + format!( + "could not persist temporary file to '{}'", + self.out_path.display() + ) + })?; + + eprintln!("Package downloaded to '{}'", self.out_path.display()); + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use wasmer_registry::wasmer_env::WASMER_DIR; + + use super::*; + + /// Download a package from the dev registry. + #[test] + fn test_cmd_package_download() { + let dir = tempfile::tempdir().unwrap(); + + let out_path = dir.path().join("hello.webc"); + + let cmd = PackageDownload { + env: WasmerEnv::new(WASMER_DIR.clone(), Some("wasmer.wtf".into()), None, None), + validate: true, + out_path: out_path.clone(), + package: "wasmer/hello@0.1.0".parse().unwrap(), + }; + + cmd.execute().unwrap(); + + webc::compat::Container::from_disk(out_path).unwrap(); + } +} diff --git a/lib/cli/src/commands/package/mod.rs b/lib/cli/src/commands/package/mod.rs new file mode 100644 index 00000000000..aec1d4931a1 --- /dev/null +++ b/lib/cli/src/commands/package/mod.rs @@ -0,0 +1,14 @@ +mod build; +mod download; + +pub use {build::PackageBuild, download::PackageDownload}; + +/// Package related commands. +#[derive(clap::Subcommand, Debug)] +// Allowing missing_docs because the comment would override the doc comment on +// the command struct. +#[allow(missing_docs)] +pub enum Package { + Download(PackageDownload), + Build(build::PackageBuild), +} diff --git a/lib/registry/src/queries.rs b/lib/registry/src/queries.rs deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/registry/src/wasmer_env.rs b/lib/registry/src/wasmer_env.rs index 110d434fdee..5ba71834693 100644 --- a/lib/registry/src/wasmer_env.rs +++ b/lib/registry/src/wasmer_env.rs @@ -42,6 +42,22 @@ impl WasmerEnv { } } + pub fn registry_public_url(&self) -> Result { + let mut url = self.registry_endpoint()?; + url.set_path(""); + + let domain = url + .host_str() + .context("url has no host")? + .strip_prefix("registry.") + .context("could not derive registry public url")? + .to_string(); + url.set_host(Some(&domain)) + .context("could not derive registry public url")?; + + Ok(url) + } + /// Get the GraphQL endpoint used to query the registry. pub fn registry_endpoint(&self) -> Result { if let Some(registry) = &self.registry { @@ -79,6 +95,14 @@ impl WasmerEnv { } } + /// Retrieve the specified token. + /// + /// NOTE: In contrast to [`Self::token`], this will not fall back to loading + /// the token from the confg file. + pub fn get_token_opt(&self) -> Option<&str> { + self.token.as_deref() + } + /// The API token for the active registry. pub fn token(&self) -> Option { if let Some(token) = &self.token { From 2de48f4ab9c2d3a7ea866a8aa3d0638ecc2b2398 Mon Sep 17 00:00:00 2001 From: Christoph Herzog Date: Mon, 13 Nov 2023 12:27:47 +0100 Subject: [PATCH 2/4] fix(cli): Pass auth token when querying packages Need to pass an auth token to the package query, otherwise it would fail due to not being able to query the private package. --- lib/cli/src/cli.rs | 16 ++++++++++------ lib/cli/src/commands/publish.rs | 8 +++++++- lib/registry/src/lib.rs | 5 +++-- lib/registry/src/package/builder.rs | 26 +++++++++++++++++++------- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/lib/cli/src/cli.rs b/lib/cli/src/cli.rs index 1575ee140dd..22d1dad04ff 100644 --- a/lib/cli/src/cli.rs +++ b/lib/cli/src/cli.rs @@ -9,8 +9,7 @@ use crate::commands::CreateExe; #[cfg(feature = "wast")] use crate::commands::Wast; use crate::commands::{ - Add, Cache, CmdPackage, Config, Init, Inspect, Login, Publish, Run, SelfUpdate, Validate, - Whoami, + Add, Cache, Config, Init, Inspect, Login, Package, Publish, Run, SelfUpdate, Validate, Whoami, }; #[cfg(feature = "static-artifact-create")] use crate::commands::{CreateObj, GenCHeader}; @@ -110,9 +109,11 @@ impl Args { Some(Cmd::Login(login)) => login.execute(), Some(Cmd::Publish(publish)) => publish.execute(), Some(Cmd::Package(cmd)) => match cmd { - CmdPackage::Download(cmd) => cmd.execute(), - CmdPackage::Unpack(cmd) => cmd.execute(), - CmdPackage::Build(cmd) => cmd.execute(), + Package::Download(cmd) => cmd.execute(), + Package::Build(cmd) => cmd.execute(), + }, + Some(Cmd::Container(cmd)) => match cmd { + crate::commands::Container::Unpack(cmd) => cmd.execute(), }, /* Some(Cmd::Connect(connect)) => connect.execute(), @@ -265,7 +266,10 @@ enum Cmd { Run(Run), #[clap(subcommand)] - Package(crate::commands::CmdPackage), + Package(crate::commands::Package), + + #[clap(subcommand)] + Container(crate::commands::Container), // Edge commands /// Deploy apps to the Wasmer Edge. diff --git a/lib/cli/src/commands/publish.rs b/lib/cli/src/commands/publish.rs index 055bc9bc196..b141cece830 100644 --- a/lib/cli/src/commands/publish.rs +++ b/lib/cli/src/commands/publish.rs @@ -1,3 +1,4 @@ +use anyhow::Context as _; use clap::Parser; use wasmer_registry::wasmer_env::WasmerEnv; @@ -31,13 +32,18 @@ pub struct Publish { impl Publish { /// Executes `wasmer publish` pub fn execute(&self) -> Result<(), anyhow::Error> { + let token = self + .env + .token() + .context("could not determine auth token for registry - runer 'wasmer login'")?; + let publish = wasmer_registry::package::builder::Publish { registry: self.env.registry_endpoint().map(|u| u.to_string()).ok(), dry_run: self.dry_run, quiet: self.quiet, package_name: self.package_name.clone(), version: self.version.clone(), - token: self.env.token(), + token, no_validate: self.no_validate, package_path: self.package_path.clone(), }; diff --git a/lib/registry/src/lib.rs b/lib/registry/src/lib.rs index 18cae5825e3..3fbc5422dd4 100644 --- a/lib/registry/src/lib.rs +++ b/lib/registry/src/lib.rs @@ -153,6 +153,7 @@ pub fn query_package_from_registry( registry_url: &str, name: &str, version: Option<&str>, + auth_token: Option<&str>, ) -> Result { use crate::graphql::{ execute_query, @@ -164,8 +165,8 @@ pub fn query_package_from_registry( version: version.map(|s| s.to_string()), }); - let response: get_package_version_query::ResponseData = execute_query(registry_url, "", &q) - .map_err(|e| { + let response: get_package_version_query::ResponseData = + execute_query(registry_url, auth_token.unwrap_or_default(), &q).map_err(|e| { QueryPackageError::ErrorSendingQuery(format!("Error sending GetPackagesQuery: {e}")) })?; diff --git a/lib/registry/src/package/builder.rs b/lib/registry/src/package/builder.rs index d381a8c87c7..544b403e2e6 100644 --- a/lib/registry/src/package/builder.rs +++ b/lib/registry/src/package/builder.rs @@ -32,8 +32,8 @@ pub struct Publish { pub package_name: Option, /// Override the package version of the uploaded package in the wasmer.toml pub version: Option, - /// Override the token (by default, it will use the current logged in user) - pub token: Option, + /// The auth token to use. + pub token: String, /// Skip validation of the uploaded package pub no_validate: bool, /// Directory containing the `wasmer.toml` (defaults to current root dir) @@ -132,7 +132,13 @@ impl Publish { let mut policy = self.validation_policy(); if !policy.skip_validation() { - validate::validate_directory(&manifest, ®istry, manifest_dir, &mut *policy)?; + validate::validate_directory( + &manifest, + ®istry, + manifest_dir, + &mut *policy, + &self.token, + )?; } let archive_path = &archive_meta.archive_path; @@ -164,7 +170,7 @@ impl Publish { crate::publish::try_chunked_uploading( Some(registry), - self.token.clone(), + Some(self.token.clone()), &manifest.package, &archive_meta.manifest_toml, &archive_meta.license, @@ -602,6 +608,7 @@ mod validate { registry: &str, pkg_path: PathBuf, callbacks: &mut dyn ValidationPolicy, + auth_token: &str, ) -> anyhow::Result<()> { // validate as dir for module in manifest.modules.iter() { @@ -612,7 +619,7 @@ mod validate { } } - if would_change_package_privacy(manifest, registry)? + if would_change_package_privacy(manifest, registry, auth_token)? && callbacks.on_package_privacy_changed(manifest).is_break() { if manifest.package.private { @@ -631,9 +638,14 @@ mod validate { fn would_change_package_privacy( manifest: &wasmer_toml::Manifest, registry: &str, + auth_token: &str, ) -> Result { - let package_version = - crate::query_package_from_registry(registry, &manifest.package.name, None)?; + let package_version = crate::query_package_from_registry( + registry, + &manifest.package.name, + None, + Some(auth_token), + )?; Ok(package_version.is_private != manifest.package.private) } From f4ffcb843e34185c452c06a8252be38327aa5c5a Mon Sep 17 00:00:00 2001 From: Christoph Herzog Date: Mon, 13 Nov 2023 13:07:50 +0100 Subject: [PATCH 3/4] deps: Upgrade self_cell due to a vulnerability Fixed in self_cell version 1.02 See https://rustsec.org/advisories/RUSTSEC-2023-0070.html --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac2bbb33fe6..863abecadff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3903,9 +3903,9 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6" +checksum = "e388332cd64eb80cd595a00941baf513caffae8dce9cfd0467fc9c66397dade6" [[package]] name = "semver" From 8d87a58f3d6e14fb6eff0bc3760f4dabe8b1dc61 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Mon, 13 Nov 2023 20:28:56 +0800 Subject: [PATCH 4/4] Fixed a typo --- lib/cli/src/commands/publish.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cli/src/commands/publish.rs b/lib/cli/src/commands/publish.rs index b141cece830..46de87fb12f 100644 --- a/lib/cli/src/commands/publish.rs +++ b/lib/cli/src/commands/publish.rs @@ -35,7 +35,7 @@ impl Publish { let token = self .env .token() - .context("could not determine auth token for registry - runer 'wasmer login'")?; + .context("could not determine auth token for registry - run 'wasmer login'")?; let publish = wasmer_registry::package::builder::Publish { registry: self.env.registry_endpoint().map(|u| u.to_string()).ok(),