difftreelog
chore update flake
in: trunk
16 files changed
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,6 +2,8 @@
members = ["crates/*", "cmds/*"]
resolver = "2"
package.version = "0.1.0"
+package.edition = "2021"
+package.rust-version = "1.82.0"
[workspace.dependencies]
nixlike = { path = "./crates/nixlike" }
cmds/fleet/Cargo.tomldiffbeforeafterboth--- a/cmds/fleet/Cargo.toml
+++ b/cmds/fleet/Cargo.toml
@@ -3,7 +3,8 @@
description = "NixOS configuration management"
version = "0.2.0"
authors = ["Yaroslav Bolyukin <iam@lach.pw>"]
-edition = "2021"
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
nixlike.workspace = true
cmds/generator-helper/Cargo.tomldiffbeforeafterboth--- a/cmds/generator-helper/Cargo.toml
+++ b/cmds/generator-helper/Cargo.toml
@@ -1,7 +1,8 @@
[package]
name = "fleet-generator-helper"
-edition = "2021"
version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
age.workspace = true
cmds/generator-helper/src/main.rsdiffbeforeafterboth1use std::{2 env,3 fs::{File, OpenOptions},4 io::{self, copy, stdin, stdout, Read, Write},5 str::FromStr,6};78use age::{9 ssh::{ParseRecipientKeyError, Recipient as SshRecipient},10 Encryptor, Recipient,11};12use anyhow::{anyhow, bail, ensure, Context, Result};13use clap::{Parser, ValueEnum};14use fleet_shared::SecretData;15use rand::{16 distributions::{Alphanumeric, DistString, Distribution, Uniform},17 thread_rng, RngCore,18};1920fn write_output_file(out: &str) -> Result<File> {21 let file = OpenOptions::new()22 .create_new(true)23 .write(true)24 .open(out)25 .with_context(|| format!("failed to open output {out:?}"))?;26 Ok(file)27}28fn write_public(out: &str, mut input: impl Read, encoding: OutputEncoding) -> Result<()> {29 let mut output = write_output_file(out)?;3031 let mut data = Vec::new();32 copy(&mut input, &mut wrap_encoder(&mut data, encoding))?;3334 output.write_all(35 SecretData {36 data,37 encrypted: false,38 }39 .to_string()40 .as_bytes(),41 )?;42 Ok(())43}44fn write_private(45 identities: &Identities,46 out: &str,47 mut input: impl Read,48 encoding: OutputEncoding,49) -> Result<()> {50 let mut output = write_output_file(out)?;51 let encryptor = make_encryptor(identities)?;5253 let mut data = Vec::new();54 {55 let mut encrypted_writer = encryptor.wrap_output(&mut data)?;56 copy(57 &mut input,58 &mut wrap_encoder(&mut encrypted_writer, encoding),59 )?;60 encrypted_writer.finish()?;61 };6263 output.write_all(64 SecretData {65 data,66 encrypted: true,67 }68 .to_string()69 .as_bytes(),70 )?;71 Ok(())72}7374type Identities = Vec<SshRecipient>;75fn load_identities() -> Result<Identities> {76 let list = env::var("GENERATOR_HELPER_IDENTITIES");77 let list = match list {78 Ok(v) => v,79 Err(env::VarError::NotPresent) => {80 bail!("gh is only intended to be used from secret generator scripts, but if you really want to use it somewhere else - set GENERATOR_HELPER_IDENTITIES to list of newline-delimited ssh identities");81 }82 Err(e) => bail!("somehow, identities list is not utf-8: {e}"),83 };84 let list = list.trim();85 ensure!(!list.is_empty(), "no identities passed, can't encrypt data");86 list.lines()87 .map(age::ssh::Recipient::from_str)88 .collect::<Result<Identities, ParseRecipientKeyError>>()89 .map_err(|e| anyhow!("parse recipients: {e:?}"))90}91fn make_encryptor(r: &Identities) -> Result<Encryptor> {92 Ok(93 Encryptor::with_recipients(r.iter().map(|v| v as &dyn Recipient))94 .expect("list is not empty"),95 )96}97fn wrap_encoder<'t>(w: impl Write + 't, encoding: OutputEncoding) -> impl Write + 't {98 fn coerce<'t>(w: impl Write + 't) -> Box<dyn Write + 't> {99 Box::new(w)100 }101 match encoding {102 OutputEncoding::Raw => coerce(w),103 OutputEncoding::Base64 => {104 use base64::{engine::general_purpose::STANDARD, write::EncoderWriter};105106 let writer = EncoderWriter::new(w, &STANDARD);107 coerce(writer)108 }109 OutputEncoding::Hex => {110 struct HexWriter<W>(W);111 impl<W> Write for HexWriter<W>112 where113 W: Write,114 {115 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {116 let encoded = hex::encode(buf);117 self.0.write_all(encoded.as_bytes())?;118 Ok(buf.len())119 }120121 fn flush(&mut self) -> io::Result<()> {122 self.0.flush()123 }124 }125 coerce(HexWriter(w))126 }127 }128}129130#[derive(Clone, Copy, ValueEnum, Default)]131enum OutputEncoding {132 /// Do not encode data, store as is.133 #[default]134 Raw,135 /// Encode as base64 (with padding).136 Base64,137 /// Encode as hex (without leading 0x)138 Hex,139}140141#[derive(Parser)]142enum Generate {143 /// Generate public, private keys without wrapping, in standard ed25519 schema144 /// (64 bytes private (due to merge with private), 32 bytes public)145 Ed25519 {146 #[arg(long, short = 'p')]147 public: String,148 #[arg(long, short = 's')]149 private: String,150 /// Private key should be just the private key (32 bytes), not standard private+public.151 #[arg(long)]152 no_embed_public: bool,153 #[arg(long, short = 'e', value_enum, default_value_t)]154 encoding: OutputEncoding,155 },156 /// Generate public, private keys without wrapping, in standard x25519 schema157 /// (32 bytes private, 32 bytes public)158 X25519 {159 #[arg(long, short = 'p')]160 public: String,161 #[arg(long, short = 's')]162 private: String,163 #[arg(long, short = 'e', value_enum, default_value_t)]164 encoding: OutputEncoding,165 },166 Password {167 #[arg(long, short = 'o')]168 output: String,169 #[arg(long)]170 size: usize,171 #[arg(long, short = 'n')]172 no_symbols: bool,173 #[arg(long, short = 'e', value_enum, default_value_t)]174 encoding: OutputEncoding,175 },176 Bytes {177 #[arg(long, short = 'o')]178 output: String,179 #[arg(long, short = 'c')]180 count: usize,181 /// Ensure there is no NULs in bytestring.182 #[arg(long)]183 no_nuls: bool,184 #[arg(long, short = 'e', value_enum, default_value_t)]185 encoding: OutputEncoding,186 },187}188189#[derive(Parser)]190enum Opts {191 /// Encode public part from stdin.192 Public {193 #[arg(long, short = 'o')]194 output: String,195 #[arg(long, short = 'e', value_enum, default_value_t)]196 encoding: OutputEncoding,197 },198 /// Encrypt private part from stdin.199 Private {200 #[arg(long, short = 'o')]201 output: String,202 #[arg(long, short = 'e', value_enum, default_value_t)]203 encoding: OutputEncoding,204 },205 /// Sometimes you also need to reencode secret, this command allows you to get raw data from206 /// secret encoded using `gh public`... I would like if I knew a better design for some sort of207 /// such thing. Ideally there should be no need to decode secrets back, but garage wants both208 /// raw pubkey and raw secret key, yet also requires node id which is hex-reencoded public key.209 Decode {210 #[arg(long, short = 'i')]211 input: String,212 },213 /// Generate keys in well-known schemas.214 ///215 /// Note that this command is only intended to be used in fleet secret generator,216 /// otherwise you should ensure noone is able to read generated files, they don't have any mode set by default.217 ///218 /// Fleet also doesn't zeroize memory/assumes good OsRng/makes other assumptions, which makes it only suitable to219 /// be used in nix sandbox.220 #[command(subcommand)]221 Generate(Generate),222}223224fn main() -> Result<()> {225 let opts = Opts::parse();226 // Assumed to be secure, seeded from secure OsRng+reseeded.227 let mut rng = thread_rng();228229 match opts {230 Opts::Public { output, encoding } => {231 write_public(&output, stdin(), encoding)?;232 }233 Opts::Private { output, encoding } => {234 let recipients = load_identities()?;235 write_private(&recipients, &output, stdin(), encoding)?;236 }237 Opts::Generate(gen) => {238 match gen {239 Generate::Ed25519 {240 public,241 private,242 no_embed_public,243 encoding,244 } => {245 use ed25519_dalek::SigningKey;246247 let recipients = load_identities()?;248 let key = SigningKey::generate(&mut rng).to_keypair_bytes();249 write_public(&public, &key[32..], encoding)?;250 write_private(251 &recipients,252 &private,253 &key[..{254 if no_embed_public {255 32256 } else {257 64258 }259 }],260 encoding,261 )?;262 }263 Generate::X25519 {264 public,265 private,266 encoding,267 } => {268 use x25519_dalek::{PublicKey, StaticSecret};269270 let recipients = load_identities()?;271 let key = StaticSecret::random_from_rng(rng);272 let public_key: PublicKey = (&key).into();273 write_public(&public, public_key.as_bytes().as_slice(), encoding)?;274 write_private(&recipients, &private, key.as_bytes().as_slice(), encoding)?;275 }276 Generate::Password {277 size,278 no_symbols,279 output,280 encoding,281 } => {282 ensure!(283 size >= 6,284 "misconfiguration? password is shorter than 6 chars"285 );286 let recipients = load_identities()?;287 let out = if no_symbols {288 Alphanumeric.sample_string(&mut rng, size)289 } else {290 // Alphabet of Alphanumberic + symbols291 const GEN_ASCII_SYMBOLS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";292 let uniform = Uniform::new(0, GEN_ASCII_SYMBOLS.len());293 (0..size)294 .map(|_| uniform.sample(&mut rng))295 .map(|i| GEN_ASCII_SYMBOLS[i] as char)296 .collect::<String>()297 };298 write_private(&recipients, &output, out.as_bytes(), encoding)?;299 }300 Generate::Bytes {301 output,302 count,303 no_nuls,304 encoding,305 } => {306 ensure!(307 count >= 6,308 "misconfiguration? bytestring is shorter than 6 chars"309 );310 let recipients = load_identities()?;311 let mut bytes = vec![0u8; count];312 if no_nuls {313 let rand = Uniform::new_inclusive(0x1u8, 0xffu8).sample_iter(&mut rng);314 for (byte, rand) in bytes.iter_mut().zip(rand) {315 *byte = rand;316 }317 } else {318 rng.fill_bytes(&mut bytes);319 };320 write_private(&recipients, &output, bytes.as_slice(), encoding)?;321 }322 }323 }324 Opts::Decode { input } => {325 let mut data = Vec::new();326 File::open(input)?.read_to_end(&mut data)?;327 let data = String::from_utf8(data).context(328 "encoded data is always utf-8, you are trying to use decode the wrong way.",329 )?;330 let data =331 SecretData::from_str(&data).map_err(|e| anyhow!("failed to decode data: {e}"))?;332 ensure!(333 !data.encrypted,334 "you can not decrypt secret data, only decode public."335 );336 stdout().write_all(&data.data)?;337 }338 }339 Ok(())340}1use std::{2 env,3 fs::{File, OpenOptions},4 io::{self, copy, stdin, stdout, Read, Write},5 str::FromStr,6};78use age::{9 ssh::{ParseRecipientKeyError, Recipient as SshRecipient},10 Encryptor, Recipient,11};12use anyhow::{anyhow, bail, ensure, Context, Result};13use clap::{Parser, ValueEnum};14use fleet_shared::SecretData;15use rand::{16 distributions::{Alphanumeric, DistString, Distribution, Uniform},17 thread_rng, RngCore,18};1920fn write_output_file(out: &str) -> Result<File> {21 let file = OpenOptions::new()22 .create_new(true)23 .write(true)24 .open(out)25 .with_context(|| format!("failed to open output {out:?}"))?;26 Ok(file)27}28fn write_public(out: &str, mut input: impl Read, encoding: OutputEncoding) -> Result<()> {29 let mut output = write_output_file(out)?;3031 let mut data = Vec::new();32 copy(&mut input, &mut wrap_encoder(&mut data, encoding))?;3334 output.write_all(35 SecretData {36 data,37 encrypted: false,38 }39 .to_string()40 .as_bytes(),41 )?;42 Ok(())43}44fn write_private(45 identities: &Identities,46 out: &str,47 mut input: impl Read,48 encoding: OutputEncoding,49) -> Result<()> {50 let mut output = write_output_file(out)?;51 let encryptor = make_encryptor(identities)?;5253 let mut data = Vec::new();54 {55 let mut encrypted_writer = encryptor.wrap_output(&mut data)?;56 copy(57 &mut input,58 &mut wrap_encoder(&mut encrypted_writer, encoding),59 )?;60 encrypted_writer.finish()?;61 };6263 output.write_all(64 SecretData {65 data,66 encrypted: true,67 }68 .to_string()69 .as_bytes(),70 )?;71 Ok(())72}7374type Identities = Vec<SshRecipient>;75fn load_identities() -> Result<Identities> {76 let list = env::var("GENERATOR_HELPER_IDENTITIES");77 let list = match list {78 Ok(v) => v,79 Err(env::VarError::NotPresent) => {80 bail!("gh is only intended to be used from secret generator scripts, but if you really want to use it somewhere else - set GENERATOR_HELPER_IDENTITIES to list of newline-delimited ssh identities");81 }82 Err(e) => bail!("somehow, identities list is not utf-8: {e}"),83 };84 let list = list.trim();85 ensure!(!list.is_empty(), "no identities passed, can't encrypt data");86 list.lines()87 .map(age::ssh::Recipient::from_str)88 .collect::<Result<Identities, ParseRecipientKeyError>>()89 .map_err(|e| anyhow!("parse recipients: {e:?}"))90}91fn make_encryptor(r: &Identities) -> Result<Encryptor> {92 Ok(93 Encryptor::with_recipients(r.iter().map(|v| v as &dyn Recipient))94 .expect("list is not empty"),95 )96}97fn wrap_encoder<'t>(w: impl Write + 't, encoding: OutputEncoding) -> impl Write + 't {98 fn coerce<'t>(w: impl Write + 't) -> Box<dyn Write + 't> {99 Box::new(w)100 }101 match encoding {102 OutputEncoding::Raw => coerce(w),103 OutputEncoding::Base64 => {104 use base64::{engine::general_purpose::STANDARD, write::EncoderWriter};105106 let writer = EncoderWriter::new(w, &STANDARD);107 coerce(writer)108 }109 OutputEncoding::Hex => {110 struct HexWriter<W>(W);111 impl<W> Write for HexWriter<W>112 where113 W: Write,114 {115 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {116 let encoded = hex::encode(buf);117 self.0.write_all(encoded.as_bytes())?;118 Ok(buf.len())119 }120121 fn flush(&mut self) -> io::Result<()> {122 self.0.flush()123 }124 }125 coerce(HexWriter(w))126 }127 }128}129130#[derive(Clone, Copy, ValueEnum, Default)]131enum OutputEncoding {132 /// Do not encode data, store as is.133 #[default]134 Raw,135 /// Encode as base64 (with padding).136 Base64,137 /// Encode as hex (without leading 0x)138 Hex,139}140141#[derive(Parser)]142enum Generate {143 /// Generate public, private keys without wrapping, in standard ed25519 schema144 /// (64 bytes private (due to merge with private), 32 bytes public)145 Ed25519 {146 #[arg(long, short = 'p')]147 public: String,148 #[arg(long, short = 's')]149 private: String,150 /// Private key should be just the private key (32 bytes), not standard private+public.151 #[arg(long)]152 no_embed_public: bool,153 #[arg(long, short = 'e', value_enum, default_value_t)]154 encoding: OutputEncoding,155 },156 /// Generate public, private keys without wrapping, in standard x25519 schema157 /// (32 bytes private, 32 bytes public)158 X25519 {159 #[arg(long, short = 'p')]160 public: String,161 #[arg(long, short = 's')]162 private: String,163 #[arg(long, short = 'e', value_enum, default_value_t)]164 encoding: OutputEncoding,165 },166 Password {167 #[arg(long, short = 'o')]168 output: String,169 #[arg(long)]170 size: usize,171 #[arg(long, short = 'n')]172 no_symbols: bool,173 #[arg(long, short = 'e', value_enum, default_value_t)]174 encoding: OutputEncoding,175 },176 Bytes {177 #[arg(long, short = 'o')]178 output: String,179 #[arg(long, short = 'c')]180 count: usize,181 /// Ensure there is no NULs in bytestring.182 #[arg(long)]183 no_nuls: bool,184 #[arg(long, short = 'e', value_enum, default_value_t)]185 encoding: OutputEncoding,186 },187}188189#[derive(Parser)]190enum Opts {191 /// Encode public part from stdin.192 Public {193 #[arg(long, short = 'o')]194 output: String,195 #[arg(long, short = 'e', value_enum, default_value_t)]196 encoding: OutputEncoding,197 },198 /// Encrypt private part from stdin.199 Private {200 #[arg(long, short = 'o')]201 output: String,202 #[arg(long, short = 'e', value_enum, default_value_t)]203 encoding: OutputEncoding,204 },205 /// Sometimes you also need to reencode secret, this command allows you to get raw data from206 /// secret encoded using `gh public`... I would like if I knew a better design for some sort of207 /// such thing. Ideally there should be no need to decode secrets back, but garage wants both208 /// raw pubkey and raw secret key, yet also requires node id which is hex-reencoded public key.209 Decode {210 #[arg(long, short = 'i')]211 input: String,212 },213 /// Generate keys in well-known schemas.214 ///215 /// Note that this command is only intended to be used in fleet secret generator,216 /// otherwise you should ensure noone is able to read generated files, they don't have any mode set by default.217 ///218 /// Fleet also doesn't zeroize memory/assumes good OsRng/makes other assumptions, which makes it only suitable to219 /// be used in nix sandbox.220 #[command(subcommand)]221 Generate(Generate),222}223224fn main() -> Result<()> {225 let opts = Opts::parse();226 // Assumed to be secure, seeded from secure OsRng+reseeded.227 let mut rng = thread_rng();228229 match opts {230 Opts::Public { output, encoding } => {231 write_public(&output, stdin(), encoding)?;232 }233 Opts::Private { output, encoding } => {234 let recipients = load_identities()?;235 write_private(&recipients, &output, stdin(), encoding)?;236 }237 Opts::Generate(generate) => {238 match generate {239 Generate::Ed25519 {240 public,241 private,242 no_embed_public,243 encoding,244 } => {245 use ed25519_dalek::SigningKey;246247 let recipients = load_identities()?;248 let key = SigningKey::generate(&mut rng).to_keypair_bytes();249 write_public(&public, &key[32..], encoding)?;250 write_private(251 &recipients,252 &private,253 &key[..{254 if no_embed_public {255 32256 } else {257 64258 }259 }],260 encoding,261 )?;262 }263 Generate::X25519 {264 public,265 private,266 encoding,267 } => {268 use x25519_dalek::{PublicKey, StaticSecret};269270 let recipients = load_identities()?;271 let key = StaticSecret::random_from_rng(rng);272 let public_key: PublicKey = (&key).into();273 write_public(&public, public_key.as_bytes().as_slice(), encoding)?;274 write_private(&recipients, &private, key.as_bytes().as_slice(), encoding)?;275 }276 Generate::Password {277 size,278 no_symbols,279 output,280 encoding,281 } => {282 ensure!(283 size >= 6,284 "misconfiguration? password is shorter than 6 chars"285 );286 let recipients = load_identities()?;287 let out = if no_symbols {288 Alphanumeric.sample_string(&mut rng, size)289 } else {290 // Alphabet of Alphanumberic + symbols291 const GEN_ASCII_SYMBOLS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";292 let uniform = Uniform::new(0, GEN_ASCII_SYMBOLS.len());293 (0..size)294 .map(|_| uniform.sample(&mut rng))295 .map(|i| GEN_ASCII_SYMBOLS[i] as char)296 .collect::<String>()297 };298 write_private(&recipients, &output, out.as_bytes(), encoding)?;299 }300 Generate::Bytes {301 output,302 count,303 no_nuls,304 encoding,305 } => {306 ensure!(307 count >= 6,308 "misconfiguration? bytestring is shorter than 6 chars"309 );310 let recipients = load_identities()?;311 let mut bytes = vec![0u8; count];312 if no_nuls {313 let rand = Uniform::new_inclusive(0x1u8, 0xffu8).sample_iter(&mut rng);314 for (byte, rand) in bytes.iter_mut().zip(rand) {315 *byte = rand;316 }317 } else {318 rng.fill_bytes(&mut bytes);319 };320 write_private(&recipients, &output, bytes.as_slice(), encoding)?;321 }322 }323 }324 Opts::Decode { input } => {325 let mut data = Vec::new();326 File::open(input)?.read_to_end(&mut data)?;327 let data = String::from_utf8(data).context(328 "encoded data is always utf-8, you are trying to use decode the wrong way.",329 )?;330 let data =331 SecretData::from_str(&data).map_err(|e| anyhow!("failed to decode data: {e}"))?;332 ensure!(333 !data.encrypted,334 "you can not decrypt secret data, only decode public."335 );336 stdout().write_all(&data.data)?;337 }338 }339 Ok(())340}cmds/install-secrets/Cargo.tomldiffbeforeafterboth--- a/cmds/install-secrets/Cargo.toml
+++ b/cmds/install-secrets/Cargo.toml
@@ -1,8 +1,8 @@
[package]
name = "fleet-install-secrets"
version = "0.1.0"
-edition = "2021"
-rust-version = "1.77.2"
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
clap.workspace = true
cmds/terraform-provider-fleet/Cargo.tomldiffbeforeafterboth--- a/cmds/terraform-provider-fleet/Cargo.toml
+++ b/cmds/terraform-provider-fleet/Cargo.toml
@@ -1,7 +1,8 @@
[package]
name = "terraform-provider-fleet"
-edition = "2021"
version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
anyhow.workspace = true
crates/better-command/Cargo.tomldiffbeforeafterboth--- a/crates/better-command/Cargo.toml
+++ b/crates/better-command/Cargo.toml
@@ -1,7 +1,8 @@
[package]
name = "better-command"
version = "0.1.0"
-edition = "2021"
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
regex = "1.10"
crates/fleet-base/Cargo.tomldiffbeforeafterboth--- a/crates/fleet-base/Cargo.toml
+++ b/crates/fleet-base/Cargo.toml
@@ -1,7 +1,8 @@
[package]
name = "fleet-base"
-edition = "2021"
version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
age.workspace = true
crates/fleet-shared/Cargo.tomldiffbeforeafterboth--- a/crates/fleet-shared/Cargo.toml
+++ b/crates/fleet-shared/Cargo.toml
@@ -1,7 +1,8 @@
[package]
name = "fleet-shared"
-edition = "2021"
version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
base64 = "0.22.1"
crates/nix-eval/Cargo.tomldiffbeforeafterboth--- a/crates/nix-eval/Cargo.toml
+++ b/crates/nix-eval/Cargo.toml
@@ -1,8 +1,9 @@
[package]
name = "nix-eval"
-edition = "2021"
version.workspace = true
build = "build.rs"
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
anyhow.workspace = true
crates/nix-native-eval/Cargo.tomldiffbeforeafterboth--- a/crates/nix-native-eval/Cargo.toml
+++ b/crates/nix-native-eval/Cargo.toml
@@ -1,7 +1,8 @@
[package]
name = "nix-native-eval"
-edition = "2021"
version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
anyhow.workspace = true
crates/nixlike/Cargo.tomldiffbeforeafterboth--- a/crates/nixlike/Cargo.toml
+++ b/crates/nixlike/Cargo.toml
@@ -1,7 +1,8 @@
[package]
name = "nixlike"
version = "0.1.0"
-edition = "2021"
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
thiserror.workspace = true
flake.lockdiffbeforeafterboth--- a/flake.lock
+++ b/flake.lock
@@ -2,11 +2,11 @@
"nodes": {
"crane": {
"locked": {
- "lastModified": 1731098351,
- "narHash": "sha256-HQkYvKvaLQqNa10KEFGgWHfMAbWBfFp+4cAgkut+NNE=",
+ "lastModified": 1739936662,
+ "narHash": "sha256-x4syUjNUuRblR07nDPeLDP7DpphaBVbUaSoeZkFbGSk=",
"owner": "ipetkov",
"repo": "crane",
- "rev": "ef80ead953c1b28316cc3f8613904edc2eb90c28",
+ "rev": "19de14aaeb869287647d9461cbd389187d8ecdb7",
"type": "github"
},
"original": {
@@ -22,11 +22,11 @@
]
},
"locked": {
- "lastModified": 1730504689,
- "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=",
+ "lastModified": 1738453229,
+ "narHash": "sha256-7H9XgNiGLKN1G1CgRh0vUL4AheZSYzPm+zmZ7vxbJdo=",
"owner": "hercules-ci",
"repo": "flake-parts",
- "rev": "506278e768c2a08bec68eb62932193e341f55c90",
+ "rev": "32ea77a06711b758da0ad9bd6a844c5740a87abd",
"type": "github"
},
"original": {
@@ -37,16 +37,16 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1731873344,
- "narHash": "sha256-bKfFggwcvvh9gmOsaMCXKVAGBfXCZZ6QrxLq9Nb1/vw=",
+ "lastModified": 1740339700,
+ "narHash": "sha256-cbrw7EgQhcdFnu6iS3vane53bEagZQy/xyIkDWpCgVE=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "39e98fadd66c2564ac85b1f65bab89e044302c62",
+ "rev": "04ef94c4c1582fd485bbfdb8c4a8ba250e359195",
"type": "github"
},
"original": {
"owner": "nixos",
- "ref": "master",
+ "ref": "release-24.11",
"repo": "nixpkgs",
"type": "github"
}
@@ -56,7 +56,8 @@
"crane": "crane",
"flake-parts": "flake-parts",
"nixpkgs": "nixpkgs",
- "rust-overlay": "rust-overlay"
+ "rust-overlay": "rust-overlay",
+ "shelly": "shelly"
}
},
"rust-overlay": {
@@ -66,11 +67,11 @@
]
},
"locked": {
- "lastModified": 1731820690,
- "narHash": "sha256-/hHFMTD+FGURXZ4JtfXoIgpy87zL505pVi6AL76Wc+U=",
+ "lastModified": 1740277845,
+ "narHash": "sha256-NNU0CdiaSbAeZ8tpDG4aFi9qtcdlItRvk8Xns9oBrVU=",
"owner": "oxalica",
"repo": "rust-overlay",
- "rev": "bbab2ab9e1932133b1996baa1dc00fefe924ca81",
+ "rev": "f933070c29f9c1c5457447a51903f27f76ebb519",
"type": "github"
},
"original": {
@@ -78,6 +79,21 @@
"repo": "rust-overlay",
"type": "github"
}
+ },
+ "shelly": {
+ "locked": {
+ "lastModified": 1737089050,
+ "narHash": "sha256-SQ22z9L7fSC8FWNIlImpKeBGBUPoWpsTy9uc75o7uK0=",
+ "owner": "CertainLach",
+ "repo": "shelly",
+ "rev": "b5fa6bb56dcd1541ec399ceab1e95a74872ecd34",
+ "type": "github"
+ },
+ "original": {
+ "owner": "CertainLach",
+ "repo": "shelly",
+ "type": "github"
+ }
}
},
"root": "root",
flake.nixdiffbeforeafterboth--- a/flake.nix
+++ b/flake.nix
@@ -2,7 +2,7 @@
description = "NixOS configuration management";
inputs = {
- nixpkgs.url = "github:nixos/nixpkgs/master";
+ nixpkgs.url = "github:nixos/nixpkgs/release-24.11";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
@@ -12,126 +12,146 @@
inputs.nixpkgs-lib.follows = "nixpkgs";
};
crane.url = "github:ipetkov/crane";
+ shelly.url = "github:CertainLach/shelly";
};
- outputs = inputs:
- inputs.flake-parts.lib.mkFlake {
- inherit inputs;
- } {
- flake = rec {
- lib =
- (import ./lib {
- inherit (inputs.nixpkgs) lib;
- })
- // {
- fleetConfiguration = throw "function-based interface is deprecated, use flake-parts syntax instead";
+ outputs =
+ inputs:
+ inputs.flake-parts.lib.mkFlake
+ {
+ inherit inputs;
+ }
+ {
+ imports = [ inputs.shelly.flakeModule ];
+ flake = rec {
+ lib =
+ (import ./lib {
+ inherit (inputs.nixpkgs) lib;
+ })
+ // {
+ fleetConfiguration = throw "function-based interface is deprecated, use flake-parts syntax instead";
+ };
+ flakeModules.default = import ./lib/flakePart.nix {
+ inherit (inputs) crane;
};
- flakeModules.default = import ./lib/flakePart.nix {
- inherit (inputs) crane;
- };
- flakeModule = flakeModules.default;
+ flakeModule = flakeModules.default;
- fleetModules.tf = ./modules/extras/tf.nix;
+ fleetModules.tf = ./modules/extras/tf.nix;
- # To be used with https://github.com/NixOS/nix/pull/8892
- schemas = let
- inherit (inputs.nixpkgs.lib) mapAttrs;
- in {
- fleetConfigurations = {
- version = 1;
- doc = ''
- The `fleetConfigurations` flake output defines fleet cluster configurations.
- '';
- inventory = output: {
- children =
- mapAttrs (configName: cluster: {
- what = "fleet cluster configuration";
+ # To be used with https://github.com/NixOS/nix/pull/8892
+ schemas =
+ let
+ inherit (inputs.nixpkgs.lib) mapAttrs;
+ in
+ {
+ fleetConfigurations = {
+ version = 1;
+ doc = ''
+ The `fleetConfigurations` flake output defines fleet cluster configurations.
+ '';
+ inventory = output: {
+ children = mapAttrs (configName: cluster: {
+ what = "fleet cluster configuration";
- children =
- mapAttrs (hostName: host: {
+ children = mapAttrs (hostName: host: {
what = "host [${host.system}]";
- })
- cluster.config.hosts;
- # It is possible to implement this inventory right now, but I want to
- # get rid of `fleet.nix` file in the future.
- # children.secrets = { };
- })
- output;
+ }) cluster.config.hosts;
+ # It is possible to implement this inventory right now, but I want to
+ # get rid of `fleet.nix` file in the future.
+ # children.secrets = { };
+ }) output;
+ };
+ };
};
- };
};
- };
- # Supported and tested list of deployment targets.
- systems = ["x86_64-linux" "aarch64-linux" "armv7l-linux" "armv6l-linux"];
- perSystem = {
- config,
- system,
- pkgs,
- ...
- }: let
- inherit (lib.attrsets) mapAttrs';
- inherit (lib.lists) elem;
- # Can also be built for darwin, through it is not usual to deploy nixos systems from macos machines.
- # I have no hardware for such testing, thus only adding machines I actually have and use.
- #
- # It is not possible to deploy any host from armv6/armv7 hardware, and I don't think it even makes sense.
- deployerSystems = ["aarch64-linux" "x86_64-linux"];
- deployerSystem = elem system deployerSystems;
- lib = pkgs.lib;
- rust = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
- craneLib = (inputs.crane.mkLib pkgs).overrideToolchain rust;
- in {
- _module.args.pkgs = import inputs.nixpkgs {
- inherit system;
- overlays = [(inputs.rust-overlay.overlays.default)];
- };
- # Reference fleet package should be built with nightly rust, specified in rust-toolchain.toml.
- packages = lib.mkIf deployerSystem (let
- packages = pkgs.callPackages ./pkgs {
- inherit craneLib;
- };
- in
- packages // {default = packages.fleet;});
- # fleet-install-secrets will not be built normally, because they are not ran directly by user most of the time.
- # checks there build packages for default nixpkgs rustPlatform packages.
- checks = let
- packages = pkgs.callPackages ./pkgs {
- inherit craneLib;
- };
- prefixAttrs = prefix: attrs:
- mapAttrs' (name: value: {
- name = "${prefix}${name}";
- value = value.overrideAttrs (prev: {
- pname = "${prefix}${prev.pname}";
+ # Supported and tested list of deployment targets.
+ systems = [
+ "x86_64-linux"
+ "aarch64-linux"
+ "armv7l-linux"
+ "armv6l-linux"
+ ];
+ perSystem =
+ {
+ config,
+ system,
+ pkgs,
+ ...
+ }:
+ let
+ inherit (lib.attrsets) mapAttrs';
+ inherit (lib.lists) elem;
+ # Can also be built for darwin, through it is not usual to deploy nixos systems from macos machines.
+ # I have no hardware for such testing, thus only adding machines I actually have and use.
+ #
+ # It is not possible to deploy any host from armv6/armv7 hardware, and I don't think it even makes sense.
+ deployerSystems = [
+ "aarch64-linux"
+ "x86_64-linux"
+ ];
+ deployerSystem = elem system deployerSystems;
+ lib = pkgs.lib;
+ rust = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
+ craneLib = (inputs.crane.mkLib pkgs).overrideToolchain rust;
+ in
+ {
+ _module.args.pkgs = import inputs.nixpkgs {
+ inherit system;
+ overlays = [ (inputs.rust-overlay.overlays.default) ];
+ };
+ # Reference fleet package should be built with nightly rust, specified in rust-toolchain.toml.
+ packages = lib.mkIf deployerSystem (
+ let
+ packages = pkgs.callPackages ./pkgs {
+ inherit craneLib;
+ };
+ in
+ packages // { default = packages.fleet; }
+ );
+ # fleet-install-secrets will not be built normally, because they are not ran directly by user most of the time.
+ # checks there build packages for default nixpkgs rustPlatform packages.
+ checks =
+ let
+ nixpkgsCraneLib = inputs.crane.mkLib pkgs;
+ packages = pkgs.callPackages ./pkgs {
+ craneLib = nixpkgsCraneLib;
+ };
+ prefixAttrs =
+ prefix: attrs:
+ mapAttrs' (name: value: {
+ name = "${prefix}${name}";
+ value = value.overrideAttrs (prev: {
+ pname = "${prefix}${prev.pname}";
+ });
+ }) attrs;
+ in
+ # fleet-install-secrets is installed to remote systems, thus needs to work
+ # with rust in nixpkgs.
+ (prefixAttrs "nixpkgs-" {
+ inherit (packages) fleet-install-secrets;
});
- })
- attrs;
- in
- # `fleet` crate wants nightly rust, also little sense of supporting it on stable nixpkgs.
- (prefixAttrs "nixpkgs-" (removeAttrs packages ["fleet"]));
- # TODO: It should be possible to move lib.mkIf to default attribute, instead of disabling the whole
- # devShells block, yet nix flake check fails here, due to no default shell found. It is nix or flake-parts bug?
- devShells = lib.mkIf deployerSystem {
- default = craneLib.devShell {
- packages = with pkgs; [
- rust
- alejandra
- cargo-edit
- cargo-udeps
- cargo-fuzz
- cargo-watch
- cargo-outdated
+ # TODO: It should be possible to move lib.mkIf to default attribute, instead of disabling the whole
+ # devShells block, yet nix flake check fails here, due to no default shell found. It is nix or flake-parts bug?
+ shelly.shells.default = lib.mkIf deployerSystem {
+ factory = craneLib.devShell;
+ packages = with pkgs; [
+ rust
+ alejandra
+ cargo-edit
+ cargo-udeps
+ cargo-fuzz
+ cargo-watch
+ cargo-outdated
- pkg-config
- openssl
- bacon
- nil
- rustPlatform.bindgenHook
- nixVersions.nix_2_22
- ];
- env.PROTOC = "${pkgs.protobuf}/bin/protoc";
+ pkg-config
+ openssl
+ bacon
+ nil
+ rustPlatform.bindgenHook
+ nixVersions.nix_2_22
+ ];
+ environment.PROTOC = "${pkgs.protobuf}/bin/protoc";
+ };
+ formatter = pkgs.alejandra;
};
- };
- formatter = pkgs.alejandra;
};
- };
}
lib/flakePart.nixdiffbeforeafterboth--- a/lib/flakePart.nix
+++ b/lib/flakePart.nix
@@ -65,11 +65,12 @@
else data;
nixpkgs.buildUsing = mkOptionDefault bootstrapNixpkgs;
nixpkgs.overlays = [
- (final: prev:
- import ../pkgs {
+ (final: prev: {
+ inherit (import ../pkgs {
inherit (prev) callPackage;
craneLib = crane.mkLib prev;
- })
+ }) fleet-install-secrets;
+ })
];
};
}
rust-toolchain.tomldiffbeforeafterboth--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2024-11-12"
+channel = "1.85.0"
components = ["rustfmt", "clippy", "rust-analyzer", "rust-src"]