Enable deleting users and groups on Mac (#253)
* Enable deleting users and groups on Mac * Scaffold user change * Add a warning if it doesn't work in situations we expect it to not work * Scaffold out doing group member ship -- maybe we need an AddGroup action * AddUserToGroup action * Update plans * Improve messaging * Nit in error message * Repair some review nits
This commit is contained in:
parent
7e951a5b6a
commit
689cf84bbf
|
@ -5,4 +5,5 @@ COPY binary-tarball /binary-tarball
|
|||
RUN mv /binary-tarball/nix-*.tar.xz nix.tar.xz
|
||||
RUN /nix-installer/bin/nix-installer install linux --nix-package-url file:///nix.tar.xz --init none --extra-conf "sandbox = false" --channel --no-confirm -vvv
|
||||
ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"
|
||||
RUN nix-build --no-substitute -E 'derivation { name = "foo"; system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > $out"]; }'
|
||||
RUN nix-build --no-substitute -E 'derivation { name = "foo"; system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > $out"]; }'
|
||||
RUN /nix/nix-installer uninstall --no-confirm
|
|
@ -236,6 +236,9 @@ let
|
|||
echo "Testing Nix installation..."
|
||||
$ssh "set -eux; $checkScript"
|
||||
|
||||
echo "Testing Nix installation..."
|
||||
$ssh "set -eux; /nix/nix-installer uninstall --no-confirm"
|
||||
|
||||
echo "Done!"
|
||||
touch $out
|
||||
'';
|
||||
|
|
283
src/action/base/add_user_to_group.rs
Normal file
283
src/action/base/add_user_to_group.rs
Normal file
|
@ -0,0 +1,283 @@
|
|||
use std::process::Stdio;
|
||||
|
||||
use nix::unistd::User;
|
||||
use target_lexicon::OperatingSystem;
|
||||
use tokio::process::Command;
|
||||
use tracing::{span, Span};
|
||||
|
||||
use crate::action::ActionError;
|
||||
use crate::execute_command;
|
||||
|
||||
use crate::action::{Action, ActionDescription, StatefulAction};
|
||||
|
||||
/**
|
||||
Create an operating system level user in the given group
|
||||
*/
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct AddUserToGroup {
|
||||
name: String,
|
||||
uid: u32,
|
||||
groupname: String,
|
||||
gid: u32,
|
||||
}
|
||||
|
||||
impl AddUserToGroup {
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
pub async fn plan(
|
||||
name: String,
|
||||
uid: u32,
|
||||
groupname: String,
|
||||
gid: u32,
|
||||
) -> Result<StatefulAction<Self>, ActionError> {
|
||||
let this = Self {
|
||||
name: name.clone(),
|
||||
uid,
|
||||
groupname,
|
||||
gid,
|
||||
};
|
||||
// Ensure user does not exists
|
||||
if let Some(user) = User::from_name(name.as_str())
|
||||
.map_err(|e| ActionError::GettingUserId(name.clone(), e))?
|
||||
{
|
||||
if user.uid.as_raw() != uid {
|
||||
return Err(ActionError::UserUidMismatch(
|
||||
name.clone(),
|
||||
user.uid.as_raw(),
|
||||
uid,
|
||||
));
|
||||
}
|
||||
|
||||
if user.gid.as_raw() != gid {
|
||||
return Err(ActionError::UserGidMismatch(
|
||||
name.clone(),
|
||||
user.gid.as_raw(),
|
||||
gid,
|
||||
));
|
||||
}
|
||||
|
||||
// See if group membership needs to be done
|
||||
match target_lexicon::OperatingSystem::host() {
|
||||
OperatingSystem::MacOSX {
|
||||
major: _,
|
||||
minor: _,
|
||||
patch: _,
|
||||
}
|
||||
| OperatingSystem::Darwin => {
|
||||
let mut command = Command::new("/usr/sbin/dseditgroup");
|
||||
command.process_group(0);
|
||||
command.args(["-o", "checkmember", "-m"]);
|
||||
command.arg(&this.name);
|
||||
command.arg(&this.groupname);
|
||||
command.stdout(Stdio::piped());
|
||||
command.stderr(Stdio::piped());
|
||||
let command_str = format!("{:?}", command.as_std());
|
||||
tracing::trace!("Executing `{command_str}`");
|
||||
let output = command.output().await.map_err(ActionError::Command)?;
|
||||
match output.status.code() {
|
||||
Some(0) => {
|
||||
// yes {user} is a member of {groupname}
|
||||
// Since the user exists, and is already a member of the group, we have truly nothing to do here
|
||||
tracing::debug!(
|
||||
"Adding user `{}` to group `{}` already complete",
|
||||
this.name,
|
||||
this.groupname
|
||||
);
|
||||
return Ok(StatefulAction::completed(this));
|
||||
},
|
||||
Some(64) => {
|
||||
// 64 is the exit code for "Group not found"
|
||||
tracing::trace!(
|
||||
"Will add user `{}` to newly created group `{}`",
|
||||
this.name,
|
||||
this.groupname
|
||||
);
|
||||
// The group will be created by the installer
|
||||
()
|
||||
},
|
||||
_ => {
|
||||
// Some other issue
|
||||
return Err(ActionError::Command(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"Command `{command_str}` failed{}, stderr:\n{}\n",
|
||||
if let Some(code) = output.status.code() {
|
||||
format!(" status {code}")
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
String::from_utf8_lossy(&output.stderr),
|
||||
),
|
||||
)));
|
||||
},
|
||||
};
|
||||
},
|
||||
_ => {
|
||||
let output = execute_command(
|
||||
Command::new("groups")
|
||||
.process_group(0)
|
||||
.arg(&this.name)
|
||||
.stdin(std::process::Stdio::null()),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
let output_str = String::from_utf8(output.stdout)?;
|
||||
let user_in_group = output_str.split(" ").any(|v| v == &this.groupname);
|
||||
|
||||
if user_in_group {
|
||||
tracing::debug!("Creating user `{}` already complete", this.name);
|
||||
return Ok(StatefulAction::completed(this));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(StatefulAction::uncompleted(this))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
#[typetag::serde(name = "add_user_to_group")]
|
||||
impl Action for AddUserToGroup {
|
||||
fn tracing_synopsis(&self) -> String {
|
||||
format!(
|
||||
"Add user `{}` (UID {}) to group `{}` (GID {})",
|
||||
self.name, self.uid, self.groupname, self.gid
|
||||
)
|
||||
}
|
||||
|
||||
fn tracing_span(&self) -> Span {
|
||||
span!(
|
||||
tracing::Level::DEBUG,
|
||||
"add_user_to_group",
|
||||
user = self.name,
|
||||
uid = self.uid,
|
||||
groupname = self.groupname,
|
||||
gid = self.gid,
|
||||
)
|
||||
}
|
||||
|
||||
fn execute_description(&self) -> Vec<ActionDescription> {
|
||||
vec![ActionDescription::new(
|
||||
self.tracing_synopsis(),
|
||||
vec![format!(
|
||||
"The Nix daemon requires the build users to be in a defined group"
|
||||
)],
|
||||
)]
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
async fn execute(&mut self) -> Result<(), ActionError> {
|
||||
let Self {
|
||||
name,
|
||||
uid: _,
|
||||
groupname,
|
||||
gid: _,
|
||||
} = self;
|
||||
|
||||
use target_lexicon::OperatingSystem;
|
||||
match OperatingSystem::host() {
|
||||
OperatingSystem::MacOSX {
|
||||
major: _,
|
||||
minor: _,
|
||||
patch: _,
|
||||
}
|
||||
| OperatingSystem::Darwin => {
|
||||
execute_command(
|
||||
Command::new("/usr/bin/dscl")
|
||||
.process_group(0)
|
||||
.args([
|
||||
".",
|
||||
"-append",
|
||||
&format!("/Groups/{groupname}"),
|
||||
"GroupMembership",
|
||||
])
|
||||
.arg(&name)
|
||||
.stdin(std::process::Stdio::null()),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
execute_command(
|
||||
Command::new("/usr/sbin/dseditgroup")
|
||||
.process_group(0)
|
||||
.args(["-o", "edit"])
|
||||
.arg("-a")
|
||||
.arg(&name)
|
||||
.arg("-t")
|
||||
.arg(&name)
|
||||
.arg(groupname)
|
||||
.stdin(std::process::Stdio::null()),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
},
|
||||
_ => {
|
||||
execute_command(
|
||||
Command::new("gpasswd")
|
||||
.process_group(0)
|
||||
.args(["-a"])
|
||||
.args([&name.to_string(), &groupname.to_string()])
|
||||
.stdin(std::process::Stdio::null()),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn revert_description(&self) -> Vec<ActionDescription> {
|
||||
vec![ActionDescription::new(
|
||||
format!(
|
||||
"Remove user `{}` (UID {}) from group {} (GID {})",
|
||||
self.name, self.uid, self.groupname, self.gid
|
||||
),
|
||||
vec![format!(
|
||||
"The Nix daemon requires system users it can act as in order to build"
|
||||
)],
|
||||
)]
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), ActionError> {
|
||||
let Self {
|
||||
name,
|
||||
uid: _,
|
||||
groupname,
|
||||
gid: _,
|
||||
} = self;
|
||||
|
||||
use target_lexicon::OperatingSystem;
|
||||
match target_lexicon::OperatingSystem::host() {
|
||||
OperatingSystem::MacOSX {
|
||||
major: _,
|
||||
minor: _,
|
||||
patch: _,
|
||||
}
|
||||
| OperatingSystem::Darwin => {
|
||||
execute_command(
|
||||
Command::new("/usr/bin/dscl")
|
||||
.process_group(0)
|
||||
.args([".", "-delete", &format!("/Groups/{groupname}"), "users"])
|
||||
.arg(&name)
|
||||
.stdin(std::process::Stdio::null()),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
},
|
||||
_ => {
|
||||
execute_command(
|
||||
Command::new("gpasswd")
|
||||
.process_group(0)
|
||||
.args(["-d"])
|
||||
.args([&name.to_string(), &groupname.to_string()])
|
||||
.stdin(std::process::Stdio::null()),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
},
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -133,16 +133,14 @@ impl Action for CreateGroup {
|
|||
patch: _,
|
||||
}
|
||||
| OperatingSystem::Darwin => {
|
||||
// TODO(@hoverbear): Make this actually work...
|
||||
// Right now, our test machines do not have a secure token and cannot delete users.
|
||||
tracing::warn!("`nix-installer` currently cannot delete groups on Mac due to https://github.com/DeterminateSystems/nix-installer/issues/33. This is a no-op, installing with `nix-installer` again will use the existing group.");
|
||||
// execute_command(Command::new("/usr/bin/dscl").args([
|
||||
// ".",
|
||||
// "-delete",
|
||||
// &format!("/Groups/{name}"),
|
||||
// ]).stdin(std::process::Stdio::null()))
|
||||
// .await
|
||||
// .map_err(|e| CreateGroupError::Command(e).boxed())?;
|
||||
let output = execute_command(
|
||||
Command::new("/usr/bin/dscl")
|
||||
.args([".", "-delete", &format!("/Groups/{name}")])
|
||||
.stdin(std::process::Stdio::null()),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
if !output.status.success() {}
|
||||
},
|
||||
_ => {
|
||||
execute_command(
|
||||
|
|
|
@ -20,7 +20,7 @@ pub struct CreateUser {
|
|||
|
||||
impl CreateUser {
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
pub fn plan(
|
||||
pub async fn plan(
|
||||
name: String,
|
||||
uid: u32,
|
||||
groupname: String,
|
||||
|
@ -51,9 +51,6 @@ impl CreateUser {
|
|||
gid,
|
||||
));
|
||||
}
|
||||
|
||||
tracing::debug!("Creating user `{}` already complete", this.name);
|
||||
return Ok(StatefulAction::completed(this));
|
||||
}
|
||||
|
||||
Ok(StatefulAction::uncompleted(this))
|
||||
|
@ -95,7 +92,7 @@ impl Action for CreateUser {
|
|||
let Self {
|
||||
name,
|
||||
uid,
|
||||
groupname,
|
||||
groupname: _,
|
||||
gid,
|
||||
} = self;
|
||||
|
||||
|
@ -171,20 +168,6 @@ impl Action for CreateUser {
|
|||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
execute_command(
|
||||
Command::new("/usr/bin/dscl")
|
||||
.process_group(0)
|
||||
.args([
|
||||
".",
|
||||
"-append",
|
||||
&format!("/Groups/{groupname}"),
|
||||
"GroupMembership",
|
||||
])
|
||||
.arg(&name)
|
||||
.stdin(std::process::Stdio::null()),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
execute_command(
|
||||
Command::new("/usr/bin/dscl")
|
||||
.process_group(0)
|
||||
|
@ -193,19 +176,6 @@ impl Action for CreateUser {
|
|||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
execute_command(
|
||||
Command::new("/usr/sbin/dseditgroup")
|
||||
.process_group(0)
|
||||
.args(["-o", "edit"])
|
||||
.arg("-a")
|
||||
.arg(&name)
|
||||
.arg("-t")
|
||||
.arg(&name)
|
||||
.arg(groupname)
|
||||
.stdin(std::process::Stdio::null()),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
},
|
||||
_ => {
|
||||
execute_command(
|
||||
|
@ -269,16 +239,44 @@ impl Action for CreateUser {
|
|||
patch: _,
|
||||
}
|
||||
| OperatingSystem::Darwin => {
|
||||
// TODO(@hoverbear): Make this actually work...
|
||||
// Right now, our test machines do not have a secure token and cannot delete users.
|
||||
tracing::warn!("`nix-installer` currently cannot delete groups on Mac due to https://github.com/DeterminateSystems/nix-installer/issues/33. This is a no-op, installing with `nix-installer` again will use the existing user.");
|
||||
// execute_command(Command::new("/usr/bin/dscl").args([
|
||||
// ".",
|
||||
// "-delete",
|
||||
// &format!("/Users/{name}"),
|
||||
// ]).stdin(std::process::Stdio::null()))
|
||||
// .await
|
||||
// .map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||
// MacOS is a "Special" case
|
||||
// It's only possible to delete users under certain conditions.
|
||||
// Documentation on https://it.megocollector.com/macos/cant-delete-a-macos-user-with-dscl-resolution/ and http://www.aixperts.co.uk/?p=214 suggested it was a secure token
|
||||
// That is correct, however it's a bit more nuanced. It appears to be that a user must be graphically logged in for some other user on the system to be deleted.
|
||||
let mut command = Command::new("/usr/bin/dscl");
|
||||
command.args([".", "-delete", &format!("/Users/{name}")]);
|
||||
command.process_group(0);
|
||||
command.stdin(std::process::Stdio::null());
|
||||
|
||||
let output = command
|
||||
.output()
|
||||
.await
|
||||
.map_err(|e| ActionError::Command(e))?;
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
match output.status.code() {
|
||||
Some(0) => (),
|
||||
Some(40) if stderr.contains("-14120") => {
|
||||
// The user is on an ephemeral Mac, like detsys uses
|
||||
// These Macs cannot always delete users, as sometimes there is no graphical login
|
||||
tracing::warn!("Encountered an exit code 40 with -14120 error while removing user, this is likely because the initial executing user did not have a secure token, or that there was no graphical login session. To delete the user, log in graphically, then run `/usr/bin/dscl . -delete /Users/{name}");
|
||||
},
|
||||
status => {
|
||||
let command_str = format!("{:?}", command.as_std());
|
||||
// Something went wrong
|
||||
return Err(ActionError::Command(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"Command `{command_str}` failed{}, stderr:\n{}\n",
|
||||
if let Some(status) = status {
|
||||
format!(" {status}")
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
stderr
|
||||
),
|
||||
)));
|
||||
},
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
execute_command(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! Base [`Action`](crate::action::Action)s that themselves have no other actions as dependencies
|
||||
|
||||
pub(crate) mod add_user_to_group;
|
||||
pub(crate) mod create_directory;
|
||||
pub(crate) mod create_file;
|
||||
pub(crate) mod create_group;
|
||||
|
@ -9,6 +10,7 @@ pub(crate) mod fetch_and_unpack_nix;
|
|||
pub(crate) mod move_unpacked_nix;
|
||||
pub(crate) mod setup_default_profile;
|
||||
|
||||
pub use add_user_to_group::AddUserToGroup;
|
||||
pub use create_directory::CreateDirectory;
|
||||
pub use create_file::CreateFile;
|
||||
pub use create_group::CreateGroup;
|
||||
|
|
|
@ -151,9 +151,13 @@ impl Action for SetupDefaultProfile {
|
|||
return Err(ActionError::Command(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"Command `{load_db_command_str}` failed status, stderr:\n{}\n",
|
||||
String::from_utf8(output.stderr)
|
||||
.unwrap_or_else(|_e| String::from("<Non-UTF-8>"))
|
||||
"Command `{load_db_command_str}` failed{}, stderr:\n{}\n",
|
||||
if let Some(code) = output.status.code() {
|
||||
format!(" status {code}")
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
),
|
||||
)));
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
action::{
|
||||
base::{CreateGroup, CreateUser},
|
||||
base::{AddUserToGroup, CreateGroup, CreateUser},
|
||||
Action, ActionDescription, ActionError, StatefulAction,
|
||||
},
|
||||
settings::CommonSettings,
|
||||
|
@ -17,6 +17,7 @@ pub struct CreateUsersAndGroups {
|
|||
nix_build_user_id_base: u32,
|
||||
create_group: StatefulAction<CreateGroup>,
|
||||
create_users: Vec<StatefulAction<CreateUser>>,
|
||||
add_users_to_groups: Vec<StatefulAction<AddUserToGroup>>,
|
||||
}
|
||||
|
||||
impl CreateUsersAndGroups {
|
||||
|
@ -26,16 +27,28 @@ impl CreateUsersAndGroups {
|
|||
settings.nix_build_group_name.clone(),
|
||||
settings.nix_build_group_id,
|
||||
)?;
|
||||
let create_users = (0..settings.nix_build_user_count)
|
||||
.map(|count| {
|
||||
let mut create_users = Vec::with_capacity(settings.nix_build_user_count as usize);
|
||||
let mut add_users_to_groups = Vec::with_capacity(settings.nix_build_user_count as usize);
|
||||
for index in 0..settings.nix_build_user_count {
|
||||
create_users.push(
|
||||
CreateUser::plan(
|
||||
format!("{}{count}", settings.nix_build_user_prefix),
|
||||
settings.nix_build_user_id_base + count,
|
||||
format!("{}{index}", settings.nix_build_user_prefix),
|
||||
settings.nix_build_user_id_base + index,
|
||||
settings.nix_build_group_name.clone(),
|
||||
settings.nix_build_group_id,
|
||||
)
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
.await?,
|
||||
);
|
||||
add_users_to_groups.push(
|
||||
AddUserToGroup::plan(
|
||||
format!("{}{index}", settings.nix_build_user_prefix),
|
||||
settings.nix_build_user_id_base + index,
|
||||
settings.nix_build_group_name.clone(),
|
||||
settings.nix_build_group_id,
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
}
|
||||
Ok(Self {
|
||||
nix_build_user_count: settings.nix_build_user_count,
|
||||
nix_build_group_name: settings.nix_build_group_name,
|
||||
|
@ -44,6 +57,7 @@ impl CreateUsersAndGroups {
|
|||
nix_build_user_id_base: settings.nix_build_user_id_base,
|
||||
create_group,
|
||||
create_users,
|
||||
add_users_to_groups,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
@ -82,6 +96,7 @@ impl Action for CreateUsersAndGroups {
|
|||
nix_build_user_id_base: _,
|
||||
create_group,
|
||||
create_users,
|
||||
add_users_to_groups,
|
||||
} = &self;
|
||||
|
||||
let mut create_users_descriptions = Vec::new();
|
||||
|
@ -91,6 +106,13 @@ impl Action for CreateUsersAndGroups {
|
|||
}
|
||||
}
|
||||
|
||||
let mut add_user_to_group_descriptions = Vec::new();
|
||||
for add_user_to_group in add_users_to_groups {
|
||||
if let Some(val) = add_user_to_group.describe_execute().iter().next() {
|
||||
add_user_to_group_descriptions.push(val.description.clone())
|
||||
}
|
||||
}
|
||||
|
||||
let mut explanation = vec![
|
||||
format!("The Nix daemon requires system users (and a group they share) which it can act as in order to build"),
|
||||
];
|
||||
|
@ -98,6 +120,7 @@ impl Action for CreateUsersAndGroups {
|
|||
explanation.push(val.description.clone())
|
||||
}
|
||||
explanation.append(&mut create_users_descriptions);
|
||||
explanation.append(&mut add_user_to_group_descriptions);
|
||||
|
||||
vec![ActionDescription::new(self.tracing_synopsis(), explanation)]
|
||||
}
|
||||
|
@ -107,6 +130,7 @@ impl Action for CreateUsersAndGroups {
|
|||
let Self {
|
||||
create_users,
|
||||
create_group,
|
||||
add_users_to_groups,
|
||||
nix_build_user_count: _,
|
||||
nix_build_group_name: _,
|
||||
nix_build_group_id: _,
|
||||
|
@ -169,6 +193,10 @@ impl Action for CreateUsersAndGroups {
|
|||
},
|
||||
};
|
||||
|
||||
for add_user_to_group in add_users_to_groups.iter_mut() {
|
||||
add_user_to_group.try_execute().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -181,6 +209,7 @@ impl Action for CreateUsersAndGroups {
|
|||
nix_build_user_id_base: _,
|
||||
create_group,
|
||||
create_users,
|
||||
add_users_to_groups,
|
||||
} = &self;
|
||||
let mut create_users_descriptions = Vec::new();
|
||||
for create_user in create_users {
|
||||
|
@ -189,6 +218,13 @@ impl Action for CreateUsersAndGroups {
|
|||
}
|
||||
}
|
||||
|
||||
let mut add_user_to_group_descriptions = Vec::new();
|
||||
for add_user_to_group in add_users_to_groups {
|
||||
if let Some(val) = add_user_to_group.describe_revert().iter().next() {
|
||||
add_user_to_group_descriptions.push(val.description.clone())
|
||||
}
|
||||
}
|
||||
|
||||
let mut explanation = vec![
|
||||
format!("The Nix daemon requires system users (and a group they share) which it can act as in order to build"),
|
||||
];
|
||||
|
@ -196,6 +232,7 @@ impl Action for CreateUsersAndGroups {
|
|||
explanation.push(val.description.clone())
|
||||
}
|
||||
explanation.append(&mut create_users_descriptions);
|
||||
explanation.append(&mut add_user_to_group_descriptions);
|
||||
|
||||
vec![ActionDescription::new(
|
||||
format!("Remove Nix users and group"),
|
||||
|
@ -208,6 +245,7 @@ impl Action for CreateUsersAndGroups {
|
|||
let Self {
|
||||
create_users,
|
||||
create_group,
|
||||
add_users_to_groups: _,
|
||||
nix_build_user_count: _,
|
||||
nix_build_group_name: _,
|
||||
nix_build_group_id: _,
|
||||
|
@ -243,6 +281,11 @@ impl Action for CreateUsersAndGroups {
|
|||
}
|
||||
}
|
||||
|
||||
// We don't actually need to do this, when a user is deleted they are removed from groups
|
||||
// for add_user_to_group in add_users_to_groups.iter_mut() {
|
||||
// add_user_to_group.try_revert().await?;
|
||||
// }
|
||||
|
||||
// Create group
|
||||
create_group.try_revert().await?;
|
||||
|
||||
|
|
|
@ -100,8 +100,13 @@ async fn execute_command(command: &mut Command) -> Result<Output, std::io::Error
|
|||
false => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"Command `{command_str}` failed status, stderr:\n{}\n",
|
||||
String::from_utf8(output.stderr).unwrap_or_else(|_e| String::from("<Non-UTF-8>"))
|
||||
"Command `{command_str}` failed{}, stderr:\n{}\n",
|
||||
if let Some(code) = output.status.code() {
|
||||
format!(" status {code}")
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
),
|
||||
)),
|
||||
}
|
||||
|
|
290
tests/fixtures/linux/linux.json
vendored
290
tests/fixtures/linux/linux.json
vendored
|
@ -325,6 +325,296 @@
|
|||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
],
|
||||
"add_users_to_groups": [
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld0",
|
||||
"uid": 3000,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld1",
|
||||
"uid": 3001,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld2",
|
||||
"uid": 3002,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld3",
|
||||
"uid": 3003,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld4",
|
||||
"uid": 3004,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld5",
|
||||
"uid": 3005,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld6",
|
||||
"uid": 3006,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld7",
|
||||
"uid": 3007,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld8",
|
||||
"uid": 3008,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld9",
|
||||
"uid": 3009,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld10",
|
||||
"uid": 3010,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld11",
|
||||
"uid": 3011,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld12",
|
||||
"uid": 3012,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld13",
|
||||
"uid": 3013,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld14",
|
||||
"uid": 3014,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld15",
|
||||
"uid": 3015,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld16",
|
||||
"uid": 3016,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld17",
|
||||
"uid": 3017,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld18",
|
||||
"uid": 3018,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld19",
|
||||
"uid": 3019,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld20",
|
||||
"uid": 3020,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld21",
|
||||
"uid": 3021,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld22",
|
||||
"uid": 3022,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld23",
|
||||
"uid": 3023,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld24",
|
||||
"uid": 3024,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld25",
|
||||
"uid": 3025,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld26",
|
||||
"uid": 3026,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld27",
|
||||
"uid": 3027,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld28",
|
||||
"uid": 3028,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld29",
|
||||
"uid": 3029,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld30",
|
||||
"uid": 3030,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "nixbld31",
|
||||
"uid": 3031,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
]
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
|
1549
tests/fixtures/linux/steam-deck.json
vendored
1549
tests/fixtures/linux/steam-deck.json
vendored
File diff suppressed because it is too large
Load diff
304
tests/fixtures/macos/macos.json
vendored
304
tests/fixtures/macos/macos.json
vendored
|
@ -13,7 +13,7 @@
|
|||
"path": "/etc/synthetic.conf",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 429,
|
||||
"mode": null,
|
||||
"buf": "nix\n",
|
||||
"position": "End"
|
||||
},
|
||||
|
@ -82,7 +82,7 @@
|
|||
"action": "provision_nix",
|
||||
"fetch_nix": {
|
||||
"action": {
|
||||
"url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-aarch64-darwin.tar.xz",
|
||||
"url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-aarch64-darwin.tar.xz",
|
||||
"dest": "/nix/temp-install-dir"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -390,6 +390,296 @@
|
|||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
],
|
||||
"add_users_to_groups": [
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld0",
|
||||
"uid": 300,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld1",
|
||||
"uid": 301,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld2",
|
||||
"uid": 302,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld3",
|
||||
"uid": 303,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld4",
|
||||
"uid": 304,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld5",
|
||||
"uid": 305,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld6",
|
||||
"uid": 306,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld7",
|
||||
"uid": 307,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld8",
|
||||
"uid": 308,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld9",
|
||||
"uid": 309,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld10",
|
||||
"uid": 310,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld11",
|
||||
"uid": 311,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld12",
|
||||
"uid": 312,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld13",
|
||||
"uid": 313,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld14",
|
||||
"uid": 314,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld15",
|
||||
"uid": 315,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld16",
|
||||
"uid": 316,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld17",
|
||||
"uid": 317,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld18",
|
||||
"uid": 318,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld19",
|
||||
"uid": 319,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld20",
|
||||
"uid": 320,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld21",
|
||||
"uid": 321,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld22",
|
||||
"uid": 322,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld23",
|
||||
"uid": 323,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld24",
|
||||
"uid": 324,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld25",
|
||||
"uid": 325,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld26",
|
||||
"uid": 326,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld27",
|
||||
"uid": 327,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld28",
|
||||
"uid": 328,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld29",
|
||||
"uid": 329,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld30",
|
||||
"uid": 330,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld31",
|
||||
"uid": 331,
|
||||
"groupname": "nixbld",
|
||||
"gid": 3000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
]
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -563,7 +853,7 @@
|
|||
"path": "/etc/bashrc",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"mode": 33060,
|
||||
"buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n",
|
||||
"position": "Beginning"
|
||||
},
|
||||
|
@ -574,7 +864,7 @@
|
|||
"path": "/etc/zshenv",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"mode": 33060,
|
||||
"buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n",
|
||||
"position": "Beginning"
|
||||
},
|
||||
|
@ -585,7 +875,7 @@
|
|||
"path": "/etc/bash.bashrc",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"mode": 33060,
|
||||
"buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n",
|
||||
"position": "Beginning"
|
||||
},
|
||||
|
@ -635,7 +925,7 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 436,
|
||||
"buf": "# Generated by https://github.com/DeterminateSystems/nix-installer, version 0.1.0-unreleased.\n\n\n\nbuild-users-group = nixbld\n\nexperimental-features = nix-command flakes\n\nauto-optimise-store = true\n\nbash-prompt-prefix = (nix:$name)\\040\n",
|
||||
"buf": "# Generated by https://github.com/DeterminateSystems/nix-installer, version 0.3.0.\n\n\n\nbuild-users-group = nixbld\n\nexperimental-features = nix-command flakes\n\nauto-optimise-store = true\n\nbash-prompt-prefix = (nix:$name)\\040\n",
|
||||
"force": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -670,7 +960,7 @@
|
|||
"nix_build_group_id": 3000,
|
||||
"nix_build_user_prefix": "_nixbld",
|
||||
"nix_build_user_id_base": 300,
|
||||
"nix_package_url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-aarch64-darwin.tar.xz",
|
||||
"nix_package_url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-aarch64-darwin.tar.xz",
|
||||
"extra_conf": [],
|
||||
"force": false
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue