mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
unstable_cli_options
This commit is contained in:
parent
5939ed0d4f
commit
d8df1425ea
@ -682,7 +682,7 @@ unstable_cli_options!(
|
|||||||
panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
|
panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
|
||||||
host_config: bool = ("Enable the [host] section in the .cargo/config.toml file"),
|
host_config: bool = ("Enable the [host] section in the .cargo/config.toml file"),
|
||||||
sparse_registry: bool = ("Support plain-HTTP-based crate registries"),
|
sparse_registry: bool = ("Support plain-HTTP-based crate registries"),
|
||||||
registry_auth: bool = ("Authentication for alternative registries"),
|
registry_auth: bool = ("Authentication for alternative registries, and generate registry authentication tokens using asymmetric cryptography"),
|
||||||
target_applies_to_host: bool = ("Enable the `target-applies-to-host` key in the .cargo/config.toml file"),
|
target_applies_to_host: bool = ("Enable the `target-applies-to-host` key in the .cargo/config.toml file"),
|
||||||
rustdoc_map: bool = ("Allow passing external documentation mappings to rustdoc"),
|
rustdoc_map: bool = ("Allow passing external documentation mappings to rustdoc"),
|
||||||
separate_nightlies: bool = (HIDDEN),
|
separate_nightlies: bool = (HIDDEN),
|
||||||
|
@ -44,6 +44,8 @@ pub enum RegistryCredentialConfig {
|
|||||||
Token(String),
|
Token(String),
|
||||||
/// Process used for fetching a token.
|
/// Process used for fetching a token.
|
||||||
Process((PathBuf, Vec<String>)),
|
Process((PathBuf, Vec<String>)),
|
||||||
|
/// Secret Key and subject for Asymmetric tokens.
|
||||||
|
AsymmetricKey((String, Option<String>)),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegistryCredentialConfig {
|
impl RegistryCredentialConfig {
|
||||||
@ -59,6 +61,12 @@ impl RegistryCredentialConfig {
|
|||||||
pub fn is_token(&self) -> bool {
|
pub fn is_token(&self) -> bool {
|
||||||
matches!(self, Self::Token(..))
|
matches!(self, Self::Token(..))
|
||||||
}
|
}
|
||||||
|
/// Returns `true` if the credential is [`Key`].
|
||||||
|
///
|
||||||
|
/// [`Key`]: Credential::Key
|
||||||
|
pub fn is_asymmetric_key(&self) -> bool {
|
||||||
|
matches!(self, Self::AsymmetricKey(..))
|
||||||
|
}
|
||||||
pub fn as_token(&self) -> Option<&str> {
|
pub fn as_token(&self) -> Option<&str> {
|
||||||
if let Self::Token(v) = self {
|
if let Self::Token(v) = self {
|
||||||
Some(&*v)
|
Some(&*v)
|
||||||
@ -73,6 +81,13 @@ impl RegistryCredentialConfig {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn as_asymmetric_key(&self) -> Option<&(String, Option<String>)> {
|
||||||
|
if let Self::AsymmetricKey(v) = self {
|
||||||
|
Some(v)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PublishOpts<'cfg> {
|
pub struct PublishOpts<'cfg> {
|
||||||
|
@ -26,6 +26,8 @@ pub fn registry_credential_config(
|
|||||||
index: Option<String>,
|
index: Option<String>,
|
||||||
token: Option<String>,
|
token: Option<String>,
|
||||||
credential_process: Option<config::PathAndArgs>,
|
credential_process: Option<config::PathAndArgs>,
|
||||||
|
secret_key: Option<String>,
|
||||||
|
secret_key_subject: Option<String>,
|
||||||
#[serde(rename = "default")]
|
#[serde(rename = "default")]
|
||||||
_default: Option<String>,
|
_default: Option<String>,
|
||||||
}
|
}
|
||||||
@ -46,26 +48,44 @@ pub fn registry_credential_config(
|
|||||||
let RegistryConfig {
|
let RegistryConfig {
|
||||||
token,
|
token,
|
||||||
credential_process,
|
credential_process,
|
||||||
|
secret_key,
|
||||||
|
secret_key_subject,
|
||||||
..
|
..
|
||||||
} = config.get::<RegistryConfig>("registry")?;
|
} = config.get::<RegistryConfig>("registry")?;
|
||||||
let credential_process =
|
let credential_process =
|
||||||
credential_process.filter(|_| config.cli_unstable().credential_process);
|
credential_process.filter(|_| config.cli_unstable().credential_process);
|
||||||
|
let secret_key = secret_key.filter(|_| config.cli_unstable().registry_auth);
|
||||||
|
let secret_key_subject = secret_key_subject.filter(|_| config.cli_unstable().registry_auth);
|
||||||
|
|
||||||
return Ok(match (token, credential_process) {
|
let err_both = |token_key: &str, proc_key: &str| {
|
||||||
(Some(_), Some(_)) => {
|
Err(format_err!(
|
||||||
return Err(format_err!(
|
"both `{token_key}` and `{proc_key}` \
|
||||||
"both `token` and `credential-process` \
|
were specified in the config`.\n\
|
||||||
were specified in the config`.\n\
|
Only one of these values may be set, remove one or the other to proceed.",
|
||||||
Only one of these values may be set, remove one or the other to proceed.",
|
))
|
||||||
))
|
};
|
||||||
}
|
return Ok(
|
||||||
(Some(token), _) => RegistryCredentialConfig::Token(token),
|
match (token, credential_process, secret_key, secret_key_subject) {
|
||||||
(_, Some(process)) => RegistryCredentialConfig::Process((
|
(Some(_), Some(_), _, _) => return err_both("token", "credential-process"),
|
||||||
process.path.resolve_program(config),
|
(Some(_), _, Some(_), _) => return err_both("token", "secret-key"),
|
||||||
process.args,
|
(_, Some(_), Some(_), _) => return err_both("credential-process", "secret-key"),
|
||||||
)),
|
(_, _, None, Some(_)) => {
|
||||||
(None, None) => RegistryCredentialConfig::None,
|
return Err(format_err!(
|
||||||
});
|
"`secret-key-subject` was set but `secret-key` was not in the config.\n\
|
||||||
|
Ether set the `secret-key` or remove the `secret-key-subject`."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
(Some(token), _, _, _) => RegistryCredentialConfig::Token(token),
|
||||||
|
(_, Some(process), _, _) => RegistryCredentialConfig::Process((
|
||||||
|
process.path.resolve_program(config),
|
||||||
|
process.args,
|
||||||
|
)),
|
||||||
|
(None, None, Some(key), subject) => {
|
||||||
|
RegistryCredentialConfig::AsymmetricKey((key, subject))
|
||||||
|
}
|
||||||
|
(None, None, None, _) => RegistryCredentialConfig::None,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the SourceId's name by its index URL. If environment variables
|
// Find the SourceId's name by its index URL. If environment variables
|
||||||
@ -133,52 +153,71 @@ pub fn registry_credential_config(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (token, credential_process) = if let Some(name) = &name {
|
let (token, credential_process, secret_key, secret_key_subject) = if let Some(name) = &name {
|
||||||
log::debug!("found alternative registry name `{name}` for {sid}");
|
log::debug!("found alternative registry name `{name}` for {sid}");
|
||||||
let RegistryConfig {
|
let RegistryConfig {
|
||||||
token,
|
token,
|
||||||
|
secret_key,
|
||||||
|
secret_key_subject,
|
||||||
credential_process,
|
credential_process,
|
||||||
..
|
..
|
||||||
} = config.get::<RegistryConfig>(&format!("registries.{name}"))?;
|
} = config.get::<RegistryConfig>(&format!("registries.{name}"))?;
|
||||||
let credential_process =
|
let credential_process =
|
||||||
credential_process.filter(|_| config.cli_unstable().credential_process);
|
credential_process.filter(|_| config.cli_unstable().credential_process);
|
||||||
(token, credential_process)
|
let secret_key = secret_key.filter(|_| config.cli_unstable().registry_auth);
|
||||||
|
let secret_key_subject = secret_key_subject.filter(|_| config.cli_unstable().registry_auth);
|
||||||
|
(token, credential_process, secret_key, secret_key_subject)
|
||||||
} else {
|
} else {
|
||||||
log::debug!("no registry name found for {sid}");
|
log::debug!("no registry name found for {sid}");
|
||||||
(None, None)
|
(None, None, None, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
let name = name.as_deref();
|
let name = name.as_deref();
|
||||||
Ok(match (token, credential_process) {
|
let err_both = |token_key: &str, proc_key: &str| {
|
||||||
(Some(_), Some(_)) => {
|
Err(format_err!(
|
||||||
return {
|
"both `{token_key}` and `{proc_key}` \
|
||||||
Err(format_err!(
|
were specified in the config for registry `{name}`.\n\
|
||||||
"both `token` and `credential-process` \
|
Only one of these values may be set, remove one or the other to proceed.",
|
||||||
were specified in the config for registry `{name}`.\n\
|
name = name.unwrap()
|
||||||
Only one of these values may be set, remove one or the other to proceed.",
|
))
|
||||||
name = name.unwrap()
|
};
|
||||||
))
|
Ok(
|
||||||
|
match (token, credential_process, secret_key, secret_key_subject) {
|
||||||
|
(Some(_), Some(_), _, _) => return err_both("token", "credential-process"),
|
||||||
|
(Some(_), _, Some(_), _) => return err_both("token", "secret-key"),
|
||||||
|
(_, Some(_), Some(_), _) => return err_both("credential-process", "secret-key"),
|
||||||
|
(_, _, None, Some(_)) => {
|
||||||
|
return Err(format_err!(
|
||||||
|
"`secret-key-subject` was set but `secret-key` was not in the config \
|
||||||
|
for registry `{}`.\n\
|
||||||
|
Ether set the `secret-key` or remove the `secret-key-subject`.",
|
||||||
|
name.unwrap()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
(Some(token), _, _, _) => RegistryCredentialConfig::Token(token),
|
||||||
(Some(token), _) => RegistryCredentialConfig::Token(token),
|
(_, Some(process), _, _) => RegistryCredentialConfig::Process((
|
||||||
(_, Some(process)) => {
|
process.path.resolve_program(config),
|
||||||
RegistryCredentialConfig::Process((process.path.resolve_program(config), process.args))
|
process.args,
|
||||||
}
|
)),
|
||||||
(None, None) => {
|
(None, None, Some(key), subject) => {
|
||||||
// If we couldn't find a registry-specific credential, try the global credential process.
|
RegistryCredentialConfig::AsymmetricKey((key, subject))
|
||||||
if let Some(process) = config
|
|
||||||
.get::<Option<config::PathAndArgs>>("registry.credential-process")?
|
|
||||||
.filter(|_| config.cli_unstable().credential_process)
|
|
||||||
{
|
|
||||||
RegistryCredentialConfig::Process((
|
|
||||||
process.path.resolve_program(config),
|
|
||||||
process.args,
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
RegistryCredentialConfig::None
|
|
||||||
}
|
}
|
||||||
}
|
(None, None, None, _) => {
|
||||||
})
|
// If we couldn't find a registry-specific credential, try the global credential process.
|
||||||
|
if let Some(process) = config
|
||||||
|
.get::<Option<config::PathAndArgs>>("registry.credential-process")?
|
||||||
|
.filter(|_| config.cli_unstable().credential_process)
|
||||||
|
{
|
||||||
|
RegistryCredentialConfig::Process((
|
||||||
|
process.path.resolve_program(config),
|
||||||
|
process.args,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
RegistryCredentialConfig::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -288,6 +327,9 @@ fn auth_token_optional(config: &Config, sid: &SourceId) -> CargoResult<Option<St
|
|||||||
RegistryCredentialConfig::Process(process) => {
|
RegistryCredentialConfig::Process(process) => {
|
||||||
run_command(config, &process, sid, Action::Get)?.unwrap()
|
run_command(config, &process, sid, Action::Get)?.unwrap()
|
||||||
}
|
}
|
||||||
|
RegistryCredentialConfig::AsymmetricKey((_secret_key, _secret_key_subject)) => {
|
||||||
|
todo!("sign the token")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
cache.insert(url.clone(), token.clone());
|
cache.insert(url.clone(), token.clone());
|
||||||
|
@ -1360,6 +1360,26 @@ impl Config {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if toml_v
|
||||||
|
.get("registry")
|
||||||
|
.and_then(|v| v.as_table())
|
||||||
|
.and_then(|t| t.get("secret-key"))
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
bail!(
|
||||||
|
"registry.secret-key cannot be set through --config for security reasons"
|
||||||
|
);
|
||||||
|
} else if let Some((k, _)) = toml_v
|
||||||
|
.get("registries")
|
||||||
|
.and_then(|v| v.as_table())
|
||||||
|
.and_then(|t| t.iter().find(|(_, v)| v.get("secret-key").is_some()))
|
||||||
|
{
|
||||||
|
bail!(
|
||||||
|
"registries.{}.secret-key cannot be set through --config for security reasons",
|
||||||
|
k
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
CV::from_toml(Definition::Cli(None), toml_v)
|
CV::from_toml(Definition::Cli(None), toml_v)
|
||||||
.with_context(|| format!("failed to convert --config argument `{arg}`"))?
|
.with_context(|| format!("failed to convert --config argument `{arg}`"))?
|
||||||
};
|
};
|
||||||
|
@ -435,6 +435,20 @@ fn no_disallowed_values() {
|
|||||||
config.unwrap_err(),
|
config.unwrap_err(),
|
||||||
"registries.crates-io.token cannot be set through --config for security reasons",
|
"registries.crates-io.token cannot be set through --config for security reasons",
|
||||||
);
|
);
|
||||||
|
let config = ConfigBuilder::new()
|
||||||
|
.config_arg("registry.secret-key=\"hello\"")
|
||||||
|
.build_err();
|
||||||
|
assert_error(
|
||||||
|
config.unwrap_err(),
|
||||||
|
"registry.secret-key cannot be set through --config for security reasons",
|
||||||
|
);
|
||||||
|
let config = ConfigBuilder::new()
|
||||||
|
.config_arg("registries.crates-io.secret-key=\"hello\"")
|
||||||
|
.build_err();
|
||||||
|
assert_error(
|
||||||
|
config.unwrap_err(),
|
||||||
|
"registries.crates-io.secret-key cannot be set through --config for security reasons",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user