Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/client/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ pub struct Config {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub namespace_map_path: Option<PathBuf>,

/// List of creds availabe in keyring
/// List of creds available in keyring
#[serde(default, skip_serializing_if = "IndexSet::is_empty")]
pub keys: IndexSet<String>,

Expand Down
65 changes: 64 additions & 1 deletion crates/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::storage::PackageInfo;
use anyhow::{anyhow, Context, Result};
use bytes::Bytes;
use futures_util::{Stream, StreamExt, TryStreamExt};
use indexmap::IndexMap;
use indexmap::{IndexMap, IndexSet};
use reqwest::{Body, IntoUrl};
use secrecy::Secret;
use semver::{Version, VersionReq};
Expand Down Expand Up @@ -71,6 +71,8 @@ where
ignore_federation_hints: bool,
auto_accept_federation_hints: bool,
disable_interactive: bool,
keyring_backend: Option<String>,
keys: IndexSet<String>,
}

impl<R: RegistryStorage, C: ContentStorage, N: NamespaceMapStorage> Client<R, C, N> {
Expand All @@ -86,6 +88,8 @@ impl<R: RegistryStorage, C: ContentStorage, N: NamespaceMapStorage> Client<R, C,
ignore_federation_hints: bool,
auto_accept_federation_hints: bool,
disable_interactive: bool,
keyring_backend: Option<String>,
keys: IndexSet<String>,
) -> ClientResult<Self> {
let api = api::Client::new(url, auth_token)?;
Ok(Self {
Expand All @@ -96,6 +100,8 @@ impl<R: RegistryStorage, C: ContentStorage, N: NamespaceMapStorage> Client<R, C,
ignore_federation_hints,
auto_accept_federation_hints,
disable_interactive,
keyring_backend,
keys,
})
}

Expand Down Expand Up @@ -311,6 +317,47 @@ impl<R: RegistryStorage, C: ContentStorage, N: NamespaceMapStorage> Client<R, C,
res
}

/// Submits the provided publish information or, if not provided, loads from client
/// storage. Uses the keyring to retrieve a key and sign.
///
/// If there's no publishing information in client storage, an error is returned.
///
/// Returns the identifier of the record that was published.
///
/// Use `wait_for_publish` to wait for the record to transition to the `published` state.
#[cfg(feature = "keyring")]
pub async fn sign_with_keyring_and_publish(
&self,
publish_info: Option<PublishInfo>,
) -> ClientResult<RecordId> {
let publish_info = if let Some(publish_info) = publish_info {
publish_info
} else {
self.registry
.load_publish()
.await?
.ok_or(ClientError::NotPublishing)?
};

let registry_domain = self
.get_warg_registry(publish_info.name.namespace())
.await?;
let signing_key = keyring::Keyring::new(
self.keyring_backend
.as_deref()
.unwrap_or(keyring::Keyring::DEFAULT_BACKEND),
)?
.get_signing_key(
registry_domain.map(|domain| domain.to_string()).as_deref(),
&self.keys,
Some(&self.url().to_string()),
)?;

let res = self.publish_with_info(&signing_key, publish_info).await;
self.registry.store_publish(None).await?;
res
}

/// Submits the provided publish information.
///
/// Any publish information in client storage is ignored.
Expand Down Expand Up @@ -1344,6 +1391,12 @@ impl FileSystemClient {
let disable_interactive =
cfg!(not(feature = "cli-interactive")) || config.disable_interactive;

let (keyring_backend, keys) = if cfg!(feature = "keyring") {
(config.keyring_backend.clone(), config.keys.clone())
} else {
(None, IndexSet::new())
};

#[cfg(feature = "keyring")]
if auth_token.is_none() && config.keyring_auth {
auth_token = crate::keyring::Keyring::from_config(config)?.get_auth_token(&url)?
Expand All @@ -1358,6 +1411,8 @@ impl FileSystemClient {
config.ignore_federation_hints,
config.auto_accept_federation_hints,
disable_interactive,
keyring_backend,
keys,
)?))
}

Expand Down Expand Up @@ -1399,6 +1454,12 @@ impl FileSystemClient {
let disable_interactive =
cfg!(not(feature = "cli-interactive")) || config.disable_interactive;

let (keyring_backend, keys) = if cfg!(feature = "keyring") {
(config.keyring_backend.clone(), config.keys.clone())
} else {
(None, IndexSet::new())
};

#[cfg(feature = "keyring")]
if auth_token.is_none() && config.keyring_auth {
auth_token =
Expand All @@ -1414,6 +1475,8 @@ impl FileSystemClient {
config.ignore_federation_hints,
config.auto_accept_federation_hints,
disable_interactive,
keyring_backend,
keys,
)
}

Expand Down
15 changes: 15 additions & 0 deletions src/commands/publish.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::CommonOptions;
use anyhow::{anyhow, bail, Context, Result};
use clap::{Args, Subcommand};
use dialoguer::{theme::ColorfulTheme, Confirm};
use futures::TryStreamExt;
use itertools::Itertools;
use std::{future::Future, path::PathBuf, time::Duration};
Expand Down Expand Up @@ -275,6 +276,20 @@ pub struct PublishYankCommand {
impl PublishYankCommand {
/// Executes the command.
pub async fn exec(self) -> Result<()> {
if !Confirm::with_theme(&ColorfulTheme::default())
.with_prompt(format!(
"`Yank` revokes a version, making it unavailable. It is permanent and cannot be reversed.
Yank `{version}` of `{package}`?",
version = &self.version,
package = &self.name,
))
.default(false)
.interact()?
{
println!("Aborted and did not yank.");
return Ok(());
}

let config = self.common.read_config()?;
let client = self.common.create_client(&config)?;
let registry_domain = client.get_warg_registry(self.name.namespace()).await?;
Expand Down