Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nix_health: trusted_users check #62

Merged
merged 31 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d710a1e
get it working
shivaraj-bh Sep 1, 2023
eaaad1a
TrustedUsersView
shivaraj-bh Sep 1, 2023
5202670
add system_rs crate; add sys_info parameter to Check trait
shivaraj-bh Sep 12, 2023
364b01b
fmt
shivaraj-bh Sep 12, 2023
202e443
fix: system_rs doc
shivaraj-bh Sep 12, 2023
024ec67
gc
shivaraj-bh Sep 12, 2023
70332e8
fmt
shivaraj-bh Sep 13, 2023
27cdf63
remove system_rs crate
shivaraj-bh Sep 13, 2023
0450dab
move SysInfo to its own module
shivaraj-bh Sep 13, 2023
6a0cc19
revert info mod doc
shivaraj-bh Sep 13, 2023
c5992bd
change suggestion based on os
shivaraj-bh Sep 13, 2023
1f9c657
Merge branch 'main' into trusted-users
shivaraj-bh Sep 13, 2023
0e6330a
fmt
shivaraj-bh Sep 13, 2023
f6a9905
display instance for trusted_users; use ssr in system module
shivaraj-bh Sep 13, 2023
a9784d9
pass sys_info in nix_health's main
shivaraj-bh Sep 13, 2023
44448a0
remove shivaraj; use rust style string
shivaraj-bh Sep 13, 2023
90f2816
Adjust order of health checks
srid Sep 13, 2023
ddf108f
check nix_darwin
shivaraj-bh Sep 13, 2023
4f92dbf
fmt
shivaraj-bh Sep 13, 2023
f7d4f4e
Merge branch 'main' into trusted-users
srid Sep 13, 2023
5a7689e
Make symlink check actually work (tested on macOS)
srid Sep 13, 2023
e359f0c
refactor: simplify using ADT; hide boolean flags from leaking through…
srid Sep 13, 2023
37d71b1
cleanup/fixes
srid Sep 13, 2023
e9d9847
SysInfo -> NixEnv
srid Sep 13, 2023
dd74622
async is unnecessary; plus other changes
srid Sep 13, 2023
c5fbf91
import ordering, consistent
srid Sep 13, 2023
45800a4
sys_info -> nix_env
srid Sep 13, 2023
a50cdd7
refactor Report creation; enrich the msg/suggestion with details
srid Sep 13, 2023
42d0979
Fix warnings/errrs
srid Sep 13, 2023
2bca0d6
make symlink detection non-blocking using tokio::fs
srid Sep 13, 2023
d4295fb
Run os_info in non-blocking manner, https://docs.rs/tokio/1.32.0/toki…
srid Sep 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions crates/nix_health/src/check/caches.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt::Display;

use nix_rs::{config::ConfigVal, info};
use nix_rs::{config::ConfigVal, env, info};
use serde::{Deserialize, Serialize};
use url::Url;

Expand All @@ -14,8 +14,8 @@ use crate::{
pub struct Caches(pub ConfigVal<Vec<Url>>);

impl Check for Caches {
fn check(info: &info::NixInfo) -> Self {
Caches(info.nix_config.substituters.clone())
fn check(nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Self {
Caches(nix_info.nix_config.substituters.clone())
}
fn name(&self) -> &'static str {
"Nix Caches in use"
Expand Down
6 changes: 3 additions & 3 deletions crates/nix_health/src/check/flake_enabled.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt::Display;

use nix_rs::{config::ConfigVal, info};
use nix_rs::{config::ConfigVal, env, info};
use serde::{Deserialize, Serialize};

use crate::{
Expand All @@ -13,8 +13,8 @@ use crate::{
pub struct FlakeEnabled(pub ConfigVal<Vec<String>>);

impl Check for FlakeEnabled {
fn check(info: &info::NixInfo) -> Self {
FlakeEnabled(info.nix_config.experimental_features.clone())
fn check(nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Self {
FlakeEnabled(nix_info.nix_config.experimental_features.clone())
}
fn name(&self) -> &'static str {
"Flakes Enabled"
Expand Down
6 changes: 3 additions & 3 deletions crates/nix_health/src/check/max_jobs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt::Display;

use nix_rs::{config::ConfigVal, info};
use nix_rs::{config::ConfigVal, env, info};
use serde::{Deserialize, Serialize};

use crate::{
Expand All @@ -13,8 +13,8 @@ use crate::{
pub struct MaxJobs(pub ConfigVal<i32>);

impl Check for MaxJobs {
fn check(info: &info::NixInfo) -> Self {
MaxJobs(info.nix_config.max_jobs.clone())
fn check(nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Self {
MaxJobs(nix_info.nix_config.max_jobs.clone())
}
fn name(&self) -> &'static str {
"Max Jobs"
Expand Down
6 changes: 3 additions & 3 deletions crates/nix_health/src/check/min_nix_version.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt::Display;

use nix_rs::{info, version::NixVersion};
use nix_rs::{env, info, version::NixVersion};
use serde::{Deserialize, Serialize};

use crate::{
Expand All @@ -13,8 +13,8 @@ use crate::{
pub struct MinNixVersion(pub NixVersion);

impl Check for MinNixVersion {
fn check(info: &info::NixInfo) -> Self {
MinNixVersion(info.nix_version.clone())
fn check(nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Self {
MinNixVersion(nix_info.nix_version.clone())
}
fn name(&self) -> &'static str {
"Minimum Nix Version"
Expand Down
1 change: 1 addition & 0 deletions crates/nix_health/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pub mod caches;
pub mod flake_enabled;
pub mod max_jobs;
pub mod min_nix_version;
pub mod trusted_users;
54 changes: 54 additions & 0 deletions crates/nix_health/src/check/trusted_users.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use std::fmt::Display;

use nix_rs::{config::ConfigVal, env, info};
use serde::{Deserialize, Serialize};

use crate::{
report::{Report, WithDetails},
traits::Check,
};

/// Check that [crate::nix::config::NixConfig::trusted_users] is set to a good value.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TrustedUsers {
pub trusted_users: ConfigVal<Vec<String>>,
nix_env: env::NixEnv,
}

impl Check for TrustedUsers {
fn check(nix_info: &info::NixInfo, nix_env: &env::NixEnv) -> Self {
TrustedUsers {
trusted_users: nix_info.nix_config.trusted_users.clone(),
nix_env: nix_env.clone(),
}
}
fn name(&self) -> &'static str {
"Trusted users"
}
fn report(&self) -> Report<WithDetails> {
let current_user = &self.nix_env.current_user;
if self.trusted_users.value.contains(current_user) {
Report::Green
} else {
let msg = format!("User '{}' not present in trusted_users", current_user);
let suggestion = if self.nix_env.nix_system.has_configuration_nix() {
format!(
r#"Add `nix.trustedUsers = [ "root" "{}" ];` to your {} `configuration.nix`"#,
current_user, self.nix_env.nix_system,
)
} else {
format!(
r#"Run 'echo "trusted-users = root {}" | sudo tee -a /etc/nix/nix.conf && sudo pkill nix-daemon'"#,
current_user
)
};
Report::Red(WithDetails { msg, suggestion })
}
}
}

impl Display for TrustedUsers {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "trusted_users = {}", self.trusted_users.value.join(" "))
}
}
20 changes: 12 additions & 8 deletions crates/nix_health/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ pub mod traits;

use std::fmt::Display;

use nix_rs::info;
use nix_rs::{env, info};
use serde::{Deserialize, Serialize};

use self::check::{
caches::Caches, flake_enabled::FlakeEnabled, max_jobs::MaxJobs, min_nix_version::MinNixVersion,
trusted_users::TrustedUsers,
};
use self::report::{NoDetails, Report, WithDetails};
use self::traits::Check;
Expand All @@ -29,6 +30,7 @@ pub struct NixHealth {
pub caches: Caches,
pub flake_enabled: FlakeEnabled,
pub min_nix_version: MinNixVersion,
pub trusted_users: TrustedUsers,
}

impl<'a> IntoIterator for &'a NixHealth {
Expand All @@ -38,23 +40,25 @@ impl<'a> IntoIterator for &'a NixHealth {
/// Return an iterator to iterate on the fields of [NixHealth]
fn into_iter(self) -> Self::IntoIter {
let items: Vec<Self::Item> = vec![
&self.min_nix_version,
&self.flake_enabled,
&self.max_jobs,
&self.caches,
&self.flake_enabled,
&self.min_nix_version,
&self.trusted_users,
];
items.into_iter()
}
}

impl Check for NixHealth {
type Report = Report<NoDetails>;
fn check(info: &info::NixInfo) -> Self {
fn check(nix_info: &info::NixInfo, nix_env: &env::NixEnv) -> Self {
NixHealth {
max_jobs: MaxJobs::check(info),
caches: Caches::check(info),
flake_enabled: FlakeEnabled::check(info),
min_nix_version: MinNixVersion::check(info),
max_jobs: MaxJobs::check(nix_info, nix_env),
caches: Caches::check(nix_info, nix_env),
flake_enabled: FlakeEnabled::check(nix_info, nix_env),
min_nix_version: MinNixVersion::check(nix_info, nix_env),
trusted_users: TrustedUsers::check(nix_info, nix_env),
}
}
fn name(&self) -> &'static str {
Expand Down
9 changes: 6 additions & 3 deletions crates/nix_health/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use anyhow::Context;
use colored::Colorize;
use nix_health::{report::Report, traits::Check, NixHealth};
use nix_rs::{command::NixCmd, info::NixInfo};
use nix_rs::{command::NixCmd, env::NixEnv, info::NixInfo};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
human_panic::setup_panic!();
let info = NixInfo::from_nix(&NixCmd::default())
let nix_info = NixInfo::from_nix(&NixCmd::default())
.await
.with_context(|| "Unable to gather nix info")?;
let health = NixHealth::check(&info);
let nix_env = NixEnv::detect()
.await
.with_context(|| "Unable to gather system info")?;
let health = NixHealth::check(&nix_info, &nix_env);
println!("Checking the health of your Nix setup:\n");
for check in &health {
let report = check.report();
Expand Down
4 changes: 2 additions & 2 deletions crates/nix_health/src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt::Display;

use crate::report::{Report, WithDetails};
use nix_rs::info;
use nix_rs::{env, info};

/// Types that implement health check with reports
///
Expand All @@ -12,7 +12,7 @@ pub trait Check: Display {
type Report = Report<WithDetails>;

/// Run and create the health check
fn check(info: &info::NixInfo) -> Self
fn check(nix_info: &info::NixInfo, nix_env: &env::NixEnv) -> Self
where
Self: Sized;

Expand Down
1 change: 1 addition & 0 deletions crates/nix_rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
cfg-if.workspace = true
regex = "1.9.3"
os_info = "3.7.0"
thiserror.workspace = true
serde.workspace = true
serde_json.workspace = true
Expand Down
1 change: 1 addition & 0 deletions crates/nix_rs/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct NixConfig {
pub max_jobs: ConfigVal<i32>,
pub substituters: ConfigVal<Vec<Url>>,
pub system: ConfigVal<System>,
pub trusted_users: ConfigVal<Vec<String>>,
}

/// The value for each 'nix show-config --json' key.
Expand Down
82 changes: 82 additions & 0 deletions crates/nix_rs/src/env.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//! Information about the environment in which Nix will run
use std::fmt::Display;

use os_info;
use serde::{Deserialize, Serialize};

/// The environment in which Nix operates
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct NixEnv {
/// value of $USER
pub current_user: String,
/// Underlying nix system information
pub nix_system: NixSystem,
}

impl NixEnv {
/// Determine [NixEnv] on the user's system
#[cfg(feature = "ssr")]
pub async fn detect() -> Result<NixEnv, NixEnvError> {
let current_user = std::env::var("USER")?;
let nix_system = NixSystem::detect().await;
Ok(NixEnv {
current_user,
nix_system,
})
}
}

/// The system under which Nix is installed and operates
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum NixSystem {
/// https://github.com/LnL7/nix-darwin
NixDarwin,
/// https://nixos.org/
NixOS,
/// Nix is individually installed on Linux or macOS
Other(os_info::Type),
}

impl Display for NixSystem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NixSystem::NixDarwin => write!(f, "nix-darwin"),
NixSystem::NixOS => write!(f, "NixOS"),
NixSystem::Other(os_type) => write!(f, "{}", os_type),
}
}
}

impl NixSystem {
#[cfg(feature = "ssr")]
pub async fn detect() -> Self {
let os_info = tokio::task::spawn_blocking(os_info::get).await.unwrap();
let os_type = os_info.os_type();
async fn is_symlink(file_path: &str) -> std::io::Result<bool> {
let metadata = tokio::fs::symlink_metadata(file_path).await?;
Ok(metadata.file_type().is_symlink())
}
match os_type {
// To detect that we are on NixDarwin, we check if /etc/nix/nix.conf
// is a symlink (which nix-darwin manages like NixOS does)
os_info::Type::Macos if is_symlink("/etc/nix/nix.conf").await.unwrap_or(false) => {
NixSystem::NixDarwin
}
os_info::Type::NixOS => NixSystem::NixOS,
_ => NixSystem::Other(os_type),
}
}

/// The Nix for this [NixSystem] is configured automatically through a `configuration.nix`
pub fn has_configuration_nix(&self) -> bool {
self == &NixSystem::NixOS || self == &NixSystem::NixDarwin
}
}

/// Errors while trying to fetch [NixEnv]
#[cfg(feature = "ssr")]
#[derive(thiserror::Error, Debug)]
pub enum NixEnvError {
#[error("Failed to fetch ENV: {0}")]
EnvVarError(#[from] std::env::VarError),
}
1 change: 1 addition & 0 deletions crates/nix_rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//! along with a `from_nix` command to evaluate them.
pub mod command;
pub mod config;
pub mod env;
pub mod flake;
pub mod info;
pub mod refs;
Expand Down
Loading