unstable_cli_options

This commit is contained in:
Jacob Finkelman 2022-12-12 17:49:22 +00:00
parent 5939ed0d4f
commit d8df1425ea
5 changed files with 138 additions and 47 deletions

View File

@ -682,7 +682,7 @@ unstable_cli_options!(
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"),
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"),
rustdoc_map: bool = ("Allow passing external documentation mappings to rustdoc"),
separate_nightlies: bool = (HIDDEN),

View File

@ -44,6 +44,8 @@ pub enum RegistryCredentialConfig {
Token(String),
/// Process used for fetching a token.
Process((PathBuf, Vec<String>)),
/// Secret Key and subject for Asymmetric tokens.
AsymmetricKey((String, Option<String>)),
}
impl RegistryCredentialConfig {
@ -59,6 +61,12 @@ impl RegistryCredentialConfig {
pub fn is_token(&self) -> bool {
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> {
if let Self::Token(v) = self {
Some(&*v)
@ -73,6 +81,13 @@ impl RegistryCredentialConfig {
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> {

View File

@ -26,6 +26,8 @@ pub fn registry_credential_config(
index: Option<String>,
token: Option<String>,
credential_process: Option<config::PathAndArgs>,
secret_key: Option<String>,
secret_key_subject: Option<String>,
#[serde(rename = "default")]
_default: Option<String>,
}
@ -46,26 +48,44 @@ pub fn registry_credential_config(
let RegistryConfig {
token,
credential_process,
secret_key,
secret_key_subject,
..
} = config.get::<RegistryConfig>("registry")?;
let 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) {
(Some(_), Some(_)) => {
return Err(format_err!(
"both `token` and `credential-process` \
were specified in the config`.\n\
Only one of these values may be set, remove one or the other to proceed.",
))
}
(Some(token), _) => RegistryCredentialConfig::Token(token),
(_, Some(process)) => RegistryCredentialConfig::Process((
process.path.resolve_program(config),
process.args,
)),
(None, None) => RegistryCredentialConfig::None,
});
let err_both = |token_key: &str, proc_key: &str| {
Err(format_err!(
"both `{token_key}` and `{proc_key}` \
were specified in the config`.\n\
Only one of these values may be set, remove one or the other to proceed.",
))
};
return 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.\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
@ -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}");
let RegistryConfig {
token,
secret_key,
secret_key_subject,
credential_process,
..
} = config.get::<RegistryConfig>(&format!("registries.{name}"))?;
let 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 {
log::debug!("no registry name found for {sid}");
(None, None)
(None, None, None, None)
};
let name = name.as_deref();
Ok(match (token, credential_process) {
(Some(_), Some(_)) => {
return {
Err(format_err!(
"both `token` and `credential-process` \
were specified in the config for registry `{name}`.\n\
Only one of these values may be set, remove one or the other to proceed.",
name = name.unwrap()
))
let err_both = |token_key: &str, proc_key: &str| {
Err(format_err!(
"both `{token_key}` and `{proc_key}` \
were specified in the config for registry `{name}`.\n\
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(process)) => {
RegistryCredentialConfig::Process((process.path.resolve_program(config), process.args))
}
(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
(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, _) => {
// 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)]
@ -288,6 +327,9 @@ fn auth_token_optional(config: &Config, sid: &SourceId) -> CargoResult<Option<St
RegistryCredentialConfig::Process(process) => {
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());

View File

@ -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)
.with_context(|| format!("failed to convert --config argument `{arg}`"))?
};

View File

@ -435,6 +435,20 @@ fn no_disallowed_values() {
config.unwrap_err(),
"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]