Sudo in harmonic (#109)
* Perform sudo in harmonic * Remove sudo in scripts * A bit more tweaking... * Yay unix * Preserve environments we require * Preserve GITHUB_PATH too * Correct trace * Remove unused vars * Only pass --preserve-env if required
This commit is contained in:
parent
72792372ee
commit
148625c85f
24
.github/workflows/ci.yml
vendored
24
.github/workflows/ci.yml
vendored
|
@ -72,11 +72,11 @@ jobs:
|
||||||
- name: Set executable
|
- name: Set executable
|
||||||
run: chmod +x ./harmonic
|
run: chmod +x ./harmonic
|
||||||
- name: Initial install
|
- name: Initial install
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install linux-multi --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install linux-multi --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
||||||
- name: Initial uninstall (without a `nix run` first)
|
- name: Initial uninstall (without a `nix run` first)
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic uninstall --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic uninstall --no-confirm
|
||||||
- name: Repeated install
|
- name: Repeated install
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install linux-multi --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install linux-multi --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
||||||
- name: echo $PATH
|
- name: echo $PATH
|
||||||
run: echo $PATH
|
run: echo $PATH
|
||||||
- name: Test `nix`
|
- name: Test `nix`
|
||||||
|
@ -99,7 +99,7 @@ jobs:
|
||||||
if: success() || failure()
|
if: success() || failure()
|
||||||
shell: fish --login {0}
|
shell: fish --login {0}
|
||||||
- name: Repeated uninstall
|
- name: Repeated uninstall
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic uninstall --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic uninstall --no-confirm
|
||||||
|
|
||||||
run-steam-deck:
|
run-steam-deck:
|
||||||
name: Run Steam Deck (mock)
|
name: Run Steam Deck (mock)
|
||||||
|
@ -119,11 +119,11 @@ jobs:
|
||||||
sudo chmod +x /bin/steamos-readonly
|
sudo chmod +x /bin/steamos-readonly
|
||||||
sudo useradd -m deck
|
sudo useradd -m deck
|
||||||
- name: Initial install
|
- name: Initial install
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install steam-deck --persistence `pwd`/ci-test-nix --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install steam-deck --persistence `pwd`/ci-test-nix --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
||||||
- name: Initial uninstall (without a `nix run` first)
|
- name: Initial uninstall (without a `nix run` first)
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm
|
||||||
- name: Repeated install
|
- name: Repeated install
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install steam-deck --persistence `pwd`/ci-test-nix --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install steam-deck --persistence `pwd`/ci-test-nix --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
||||||
- name: echo $PATH
|
- name: echo $PATH
|
||||||
run: echo $PATH
|
run: echo $PATH
|
||||||
- name: Test `nix`
|
- name: Test `nix`
|
||||||
|
@ -146,7 +146,7 @@ jobs:
|
||||||
if: success() || failure()
|
if: success() || failure()
|
||||||
shell: fish --login {0}
|
shell: fish --login {0}
|
||||||
- name: Repeated uninstall
|
- name: Repeated uninstall
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm
|
||||||
|
|
||||||
build-x86_64-darwin:
|
build-x86_64-darwin:
|
||||||
name: Build x86_64 Darwin
|
name: Build x86_64 Darwin
|
||||||
|
@ -179,11 +179,11 @@ jobs:
|
||||||
- name: Set executable
|
- name: Set executable
|
||||||
run: chmod +x ./harmonic
|
run: chmod +x ./harmonic
|
||||||
- name: Initial install
|
- name: Initial install
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install darwin-multi --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install darwin-multi --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
||||||
- name: Initial uninstall (without a `nix run` first)
|
- name: Initial uninstall (without a `nix run` first)
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm
|
||||||
- name: Repeated install
|
- name: Repeated install
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install darwin-multi --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install darwin-multi --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
|
||||||
- name: echo $PATH
|
- name: echo $PATH
|
||||||
run: echo $PATH
|
run: echo $PATH
|
||||||
- name: Test `nix`
|
- name: Test `nix`
|
||||||
|
@ -206,5 +206,5 @@ jobs:
|
||||||
if: success() || failure()
|
if: success() || failure()
|
||||||
shell: fish --login {0}
|
shell: fish --login {0}
|
||||||
- name: Repeated uninstall
|
- name: Repeated uninstall
|
||||||
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm
|
run: GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm
|
||||||
|
|
|
@ -93,11 +93,6 @@ main() {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local maybe_sudo=""
|
|
||||||
if [ "$(id -u)" -ne 0 ] && command -v sudo > /dev/null; then
|
|
||||||
maybe_sudo="sudo"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$need_tty" = "yes" ] && [ ! -t 0 ]; then
|
if [ "$need_tty" = "yes" ] && [ ! -t 0 ]; then
|
||||||
# The installer is going to want to ask for confirmation by
|
# The installer is going to want to ask for confirmation by
|
||||||
# reading stdin. This script was piped into `sh` though and
|
# reading stdin. This script was piped into `sh` though and
|
||||||
|
@ -107,9 +102,9 @@ main() {
|
||||||
err "Unable to run interactively. Run with -y to accept defaults, --help for additional options"
|
err "Unable to run interactively. Run with -y to accept defaults, --help for additional options"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ignore "$maybe_sudo" "$_file" "$@" < /dev/tty
|
ignore "$_file" "$@" < /dev/tty
|
||||||
else
|
else
|
||||||
ignore "$maybe_sudo" "$_file" "$@"
|
ignore "$_file" "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local _retval=$?
|
local _retval=$?
|
||||||
|
|
|
@ -7,7 +7,9 @@ mod interaction;
|
||||||
pub(crate) mod subcommand;
|
pub(crate) mod subcommand;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::process::ExitCode;
|
use eyre::WrapErr;
|
||||||
|
use owo_colors::OwoColorize;
|
||||||
|
use std::{ffi::CString, process::ExitCode};
|
||||||
use tokio::sync::broadcast::{Receiver, Sender};
|
use tokio::sync::broadcast::{Receiver, Sender};
|
||||||
|
|
||||||
use self::subcommand::HarmonicSubcommand;
|
use self::subcommand::HarmonicSubcommand;
|
||||||
|
@ -77,5 +79,55 @@ pub(crate) async fn signal_channel() -> eyre::Result<(Sender<()>, Receiver<()>)>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_root() -> bool {
|
pub fn is_root() -> bool {
|
||||||
nix::unistd::getuid() == nix::unistd::Uid::from_raw(0)
|
let euid = nix::unistd::Uid::effective();
|
||||||
|
tracing::trace!("Running as EUID {euid}");
|
||||||
|
euid.is_root()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ensure_root() -> eyre::Result<()> {
|
||||||
|
if !is_root() {
|
||||||
|
eprintln!(
|
||||||
|
"{}",
|
||||||
|
"Harmonic needs to run as `root`, attempting to escalate now via `sudo`..."
|
||||||
|
.yellow()
|
||||||
|
.dimmed()
|
||||||
|
);
|
||||||
|
let sudo_cstring = CString::new("sudo").wrap_err("Making C string of `sudo`")?;
|
||||||
|
|
||||||
|
let args = std::env::args();
|
||||||
|
let mut arg_vec_cstring = vec![];
|
||||||
|
arg_vec_cstring.push(sudo_cstring.clone());
|
||||||
|
|
||||||
|
let mut preserve_env_list = vec![];
|
||||||
|
for (key, _value) in std::env::vars() {
|
||||||
|
let preserve = match key.as_str() {
|
||||||
|
// Rust logging/backtrace bits we use
|
||||||
|
"RUST_LOG" | "RUST_BACKTRACE" => true,
|
||||||
|
// CI
|
||||||
|
"GITHUB_PATH" => true,
|
||||||
|
// Our own environments
|
||||||
|
key if key.starts_with("HARMONIC") => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if preserve {
|
||||||
|
preserve_env_list.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !preserve_env_list.is_empty() {
|
||||||
|
arg_vec_cstring.push(
|
||||||
|
CString::new(format!("--preserve-env={}", preserve_env_list.join(",")))
|
||||||
|
.wrap_err("Building a `--preserve-env` argument for `sudo`")?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for arg in args {
|
||||||
|
arg_vec_cstring.push(CString::new(arg).wrap_err("Making arg into C string")?);
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::trace!("Execvp'ing `{sudo_cstring:?}` with args `{arg_vec_cstring:?}`");
|
||||||
|
nix::unistd::execvp(&sudo_cstring, &arg_vec_cstring)
|
||||||
|
.wrap_err("Executing Harmonic as `root` via `sudo`")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
action::ActionState,
|
action::ActionState,
|
||||||
cli::{interaction, is_root, signal_channel, CommandExecute},
|
cli::{ensure_root, interaction, signal_channel, CommandExecute},
|
||||||
plan::RECEIPT_LOCATION,
|
plan::RECEIPT_LOCATION,
|
||||||
planner::Planner,
|
planner::Planner,
|
||||||
BuiltinPlanner, InstallPlan,
|
BuiltinPlanner, InstallPlan,
|
||||||
|
@ -53,11 +53,7 @@ impl CommandExecute for Install {
|
||||||
explain,
|
explain,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
if !is_root() {
|
ensure_root()?;
|
||||||
return Err(eyre!(
|
|
||||||
"`harmonic install` must be run as `root`, try `sudo harmonic install`"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let existing_receipt: Option<InstallPlan> = match Path::new(RECEIPT_LOCATION).exists() {
|
let existing_receipt: Option<InstallPlan> = match Path::new(RECEIPT_LOCATION).exists() {
|
||||||
true => {
|
true => {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{is_root, signal_channel},
|
cli::{ensure_root, signal_channel},
|
||||||
plan::RECEIPT_LOCATION,
|
plan::RECEIPT_LOCATION,
|
||||||
InstallPlan,
|
InstallPlan,
|
||||||
};
|
};
|
||||||
|
@ -47,11 +47,7 @@ impl CommandExecute for Uninstall {
|
||||||
explain,
|
explain,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
if !is_root() {
|
ensure_root()?;
|
||||||
return Err(eyre!(
|
|
||||||
"`harmonic install` must be run as `root`, try `sudo harmonic install`"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// During install, `harmonic` will store a copy of itself in `/nix/harmonic`
|
// During install, `harmonic` will store a copy of itself in `/nix/harmonic`
|
||||||
// If the user opted to run that particular copy of Harmonic to do this uninstall,
|
// If the user opted to run that particular copy of Harmonic to do this uninstall,
|
||||||
|
@ -89,6 +85,7 @@ impl CommandExecute for Uninstall {
|
||||||
let temp_exe_cstring = CString::new(temp_exe.to_string_lossy().into_owned())
|
let temp_exe_cstring = CString::new(temp_exe.to_string_lossy().into_owned())
|
||||||
.wrap_err("Making C string of executable path")?;
|
.wrap_err("Making C string of executable path")?;
|
||||||
|
|
||||||
|
tracing::trace!("Execv'ing `{temp_exe_cstring:?} {arg_vec_cstring:?}`");
|
||||||
nix::unistd::execv(&temp_exe_cstring, &arg_vec_cstring)
|
nix::unistd::execv(&temp_exe_cstring, &arg_vec_cstring)
|
||||||
.wrap_err("Executing copied Harmonic")?;
|
.wrap_err("Executing copied Harmonic")?;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue