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:
Ana Hobden 2023-02-22 07:46:52 -08:00 committed by GitHub
parent 7e951a5b6a
commit 689cf84bbf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 1899 additions and 711 deletions

View file

@ -6,3 +6,4 @@ 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/nix-installer uninstall --no-confirm

View file

@ -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
'';

View 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(())
}
}

View file

@ -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(

View file

@ -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(

View file

@ -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;

View file

@ -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)
),
)));
};

View file

@ -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?;

View file

@ -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)
),
)),
}

View file

@ -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"

View file

@ -4,7 +4,7 @@
{
"action": {
"action": "create_directory",
"path": "/home/nix",
"path": "/nix",
"user": null,
"group": null,
"mode": 493,
@ -12,56 +12,12 @@
},
"state": "Uncompleted"
},
{
"action": {
"action": "create_file",
"path": "/etc/systemd/system/nix-directory.service",
"user": null,
"group": null,
"mode": 420,
"buf": "[Unit]\nDescription=Create a `/nix` directory to be used for bind mounting\nPropagatesStopTo=nix-daemon.service\nPropagatesStopTo=nix.mount\nDefaultDependencies=no\nAfter=grub-recordfail.service\nAfter=steamos-finish-oobe-migration.service\n\n[Service]\nType=oneshot\nExecStart=steamos-readonly disable\nExecStart=mkdir -vp /nix\nExecStart=chmod -v 0755 /nix\nExecStart=chown -v root /nix\nExecStart=chgrp -v root /nix\nExecStart=steamos-readonly enable\nExecStop=steamos-readonly disable\nExecStop=rmdir /nix\nExecStop=steamos-readonly enable\nRemainAfterExit=true\n",
"force": false
},
"state": "Uncompleted"
},
{
"action": {
"action": "create_file",
"path": "/etc/systemd/system/nix.mount",
"user": null,
"group": null,
"mode": 420,
"buf": "[Unit]\nDescription=Mount `/home/nix` on `/nix`\nPropagatesStopTo=nix-daemon.service\nPropagatesStopTo=nix-directory.service\nAfter=nix-directory.service\nRequires=nix-directory.service\nConditionPathIsDirectory=/nix\nDefaultDependencies=no\n\n[Mount]\nWhat=/home/nix\nWhere=/nix\nType=none\nDirectoryMode=0755\nOptions=bind\n",
"force": false
},
"state": "Uncompleted"
},
{
"action": {
"action": "create_file",
"path": "/etc/systemd/system/ensure-symlinked-units-resolve.service",
"user": null,
"group": null,
"mode": 420,
"buf": "[Unit]\nDescription=Ensure Nix related units which are symlinked resolve\nAfter=nix.mount\nRequires=nix-directory.service\nRequires=nix.mount\nPropagatesStopTo=nix-directory.service\nPropagatesStopTo=nix.mount\nDefaultDependencies=no\n\n[Service]\nType=oneshot\nRemainAfterExit=yes\nExecStart=/usr/bin/systemctl daemon-reload\nExecStart=/usr/bin/systemctl restart --no-block sockets.target timers.target multi-user.target\n\n[Install]\nWantedBy=sysinit.target\n",
"force": false
},
"state": "Uncompleted"
},
{
"action": {
"action": "start_systemd_unit",
"unit": "ensure-symlinked-units-resolve.service",
"enable": true
},
"state": "Uncompleted"
},
{
"action": {
"action": "provision_nix",
"fetch_nix": {
"action": {
"url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz",
"url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-x86_64-linux.tar.xz",
"dest": "/nix/temp-install-dir"
},
"state": "Uncompleted"
@ -369,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"
@ -535,14 +781,25 @@
},
"configure_shell_profile": {
"action": {
"create_directories": [],
"create_directories": [
{
"action": {
"path": "/etc/fish/conf.d",
"user": null,
"group": null,
"mode": 420,
"force_prune_on_revert": false
},
"state": "Skipped"
}
],
"create_or_insert_into_files": [
{
"action": {
"path": "/etc/bashrc",
"user": null,
"group": null,
"mode": 493,
"mode": 33188,
"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"
},
@ -553,7 +810,7 @@
"path": "/etc/profile.d/nix.sh",
"user": null,
"group": null,
"mode": 493,
"mode": 33188,
"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"
},
@ -564,7 +821,7 @@
"path": "/etc/zshenv",
"user": null,
"group": null,
"mode": 493,
"mode": 33188,
"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"
},
@ -575,11 +832,22 @@
"path": "/etc/bash.bashrc",
"user": null,
"group": null,
"mode": 493,
"mode": 33188,
"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"
},
"state": "Uncompleted"
},
{
"action": {
"path": "/etc/fish/conf.d/nix.fish",
"user": null,
"group": null,
"mode": 33188,
"buf": "\n# Nix\nif test -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish'\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish'\nend\n# End Nix\n\n",
"position": "Beginning"
},
"state": "Uncompleted"
}
]
},
@ -595,7 +863,7 @@
],
"create_file": {
"action": {
"path": "/home/ana/.nix-channels",
"path": "/home/deck/.nix-channels",
"user": null,
"group": null,
"mode": 436,
@ -625,7 +893,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"
@ -646,8 +914,7 @@
}
],
"planner": {
"planner": "steam-deck",
"persistence": "/home/nix",
"planner": "linux",
"settings": {
"channels": [
[
@ -661,9 +928,13 @@
"nix_build_group_id": 3000,
"nix_build_user_prefix": "nixbld",
"nix_build_user_id_base": 3000,
"nix_package_url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz",
"nix_package_url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-x86_64-linux.tar.xz",
"extra_conf": [],
"force": false
},
"init": {
"init": "Systemd",
"start_daemon": true
}
}
}
}

View file

@ -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
},