feat: detect and warn if running as root
This commit is contained in:
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -1453,6 +1453,15 @@ version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
||||
|
||||
[[package]]
|
||||
name = "is_elevated"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5299060ff5db63e788015dcb9525ad9b84f4fd9717ed2cbdeba5018cbf42f9b5"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.0"
|
||||
@@ -2883,6 +2892,7 @@ dependencies = [
|
||||
"glob",
|
||||
"home",
|
||||
"indexmap 2.9.0",
|
||||
"is_elevated",
|
||||
"jetbrains-toolbox-updater",
|
||||
"merge",
|
||||
"nix 0.29.0",
|
||||
|
||||
@@ -78,9 +78,10 @@ rust-ini = "~0.21"
|
||||
self_update_crate = { version = "~0.40", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
is_elevated = "~0.1"
|
||||
parselnk = "~0.1"
|
||||
self_update_crate = { version = "~0.40", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] }
|
||||
winapi = { version = "~0.3", features = ["consoleapi", "wincon"] }
|
||||
parselnk = "~0.1"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
@@ -6,6 +6,13 @@
|
||||
|
||||
|
||||
[misc]
|
||||
# On Unix systems, Topgrade should not be run as root, it
|
||||
# will run commands with sudo or equivalent where needed.
|
||||
# Set this to true to suppress the warning and confirmation
|
||||
# prompt if Topgrade detects it is being run as root.
|
||||
# (default: false)
|
||||
# allow_root = false
|
||||
|
||||
# Run `sudo -v` to cache credentials at the start of the run
|
||||
# This avoids a blocking password prompt in the middle of an unattended run
|
||||
# (default: false)
|
||||
|
||||
@@ -1120,6 +1120,24 @@ _version: 2
|
||||
zh_CN: "\n(R)重启\n(S)Shell\n(Q)退出"
|
||||
zh_TW: "\n(R)重新啟動\n(S)殼層\n(Q)退出"
|
||||
de: "\n(R) Neustarten\n(S)hell\n(Q)uit beenden"
|
||||
|
||||
"Continue?":
|
||||
en: "Continue?"
|
||||
lt: "Tęsti?"
|
||||
es: "¿Continuar?"
|
||||
fr: "Continuer ?"
|
||||
zh_CN: "继续?"
|
||||
zh_TW: "繼續?"
|
||||
de: "Fortfahren?"
|
||||
|
||||
"Topgrade should not be run as root, it will run commands with sudo or equivalent where needed.":
|
||||
en: "Topgrade should not be run as root, it will run commands with sudo or equivalent where needed."
|
||||
lt: "Topgrade neturėtų būti paleistas kaip root, jis vykdys komandas su sudo ar atitikmeniu, kai to reikės."
|
||||
es: "Topgrade no debe ejecutarse como root, ejecutará comandos con sudo o equivalente cuando sea necesario."
|
||||
fr: "Topgrade ne doit pas être exécuté en tant que root, il exécutera les commandes avec sudo ou équivalent si nécessaire."
|
||||
zh_CN: "Topgrade 不应以 root 身份运行,它会在需要时使用 sudo 或等效工具执行命令。"
|
||||
zh_TW: "Topgrade 不應以 root 身份執行,它會在需要時使用 sudo 或等效工具執行命令。"
|
||||
de: "Topgrade sollte nicht als Root ausgeführt werden, es führt Befehle mit sudo oder einem Äquivalent aus, wenn erforderlich."
|
||||
"Require sudo or counterpart but not found, skip":
|
||||
en: "Require sudo or counterpart but not found, skip"
|
||||
lt: "Reikalingas sudo arba atitikmuo, bet nerasta, praleidžiama"
|
||||
|
||||
@@ -295,6 +295,8 @@ pub struct Vim {
|
||||
#[derive(Deserialize, Default, Debug, Merge)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Misc {
|
||||
allow_root: Option<bool>,
|
||||
|
||||
pre_sudo: Option<bool>,
|
||||
|
||||
sudo_command: Option<SudoKind>,
|
||||
@@ -767,6 +769,10 @@ pub struct CommandLineArgs {
|
||||
#[arg(long = "show-skipped")]
|
||||
show_skipped: bool,
|
||||
|
||||
/// Suppress warning and confirmation prompt if running as root
|
||||
#[arg(long = "allow-root")]
|
||||
allow_root: bool,
|
||||
|
||||
/// Tracing filter directives.
|
||||
///
|
||||
/// See: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives
|
||||
@@ -1535,6 +1541,16 @@ impl Config {
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
pub fn allow_root(&self) -> bool {
|
||||
self.opt.allow_root
|
||||
|| self
|
||||
.config_file
|
||||
.misc
|
||||
.as_ref()
|
||||
.and_then(|misc| misc.allow_root)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn sudo_command(&self) -> Option<SudoKind> {
|
||||
self.config_file.misc.as_ref().and_then(|misc| misc.sudo_command)
|
||||
}
|
||||
|
||||
16
src/main.rs
16
src/main.rs
@@ -29,7 +29,7 @@ use self::error::Upgraded;
|
||||
use self::steps::{remote::*, *};
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use self::terminal::*;
|
||||
use self::utils::{install_color_eyre, install_tracing, update_tracing};
|
||||
use self::utils::{install_color_eyre, install_tracing, is_elevated, update_tracing};
|
||||
|
||||
mod breaking_changes;
|
||||
mod command;
|
||||
@@ -134,6 +134,18 @@ fn run() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
let elevated = is_elevated();
|
||||
|
||||
#[cfg(unix)]
|
||||
if !config.allow_root() && elevated {
|
||||
print_warning(t!(
|
||||
"Topgrade should not be run as root, it will run commands with sudo or equivalent where needed."
|
||||
));
|
||||
if !prompt_yesno(&t!("Continue?"))? {
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
let distribution = linux::Distribution::detect();
|
||||
|
||||
@@ -157,7 +169,7 @@ fn run() -> Result<()> {
|
||||
if !should_skip() && first_run_of_major_release()? {
|
||||
print_breaking_changes();
|
||||
|
||||
if prompt_yesno("Confirmed?")? {
|
||||
if prompt_yesno(&t!("Continue?"))? {
|
||||
write_keep_file()?;
|
||||
} else {
|
||||
exit(1);
|
||||
|
||||
16
src/utils.rs
16
src/utils.rs
@@ -169,6 +169,22 @@ pub fn hostname() -> Result<String> {
|
||||
.map(|output| output.stdout.trim().to_owned())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn is_elevated() -> bool {
|
||||
let euid = nix::unistd::Uid::effective();
|
||||
debug!("Running with euid: {euid}");
|
||||
euid.is_root()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn is_elevated() -> bool {
|
||||
let elevated = is_elevated::is_elevated();
|
||||
if elevated {
|
||||
debug!("Detected elevated process");
|
||||
}
|
||||
elevated
|
||||
}
|
||||
|
||||
pub mod merge_strategies {
|
||||
use merge::Merge;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user