format nix with rfc style

This commit is contained in:
Ryan Mulligan 2025-08-04 09:26:41 -07:00
parent 856df6f692
commit 0814fdc0de
13 changed files with 500 additions and 453 deletions

View file

@ -14,7 +14,7 @@ jobs:
extra-experimental-features = recursive-nix nix-command flakes
- run: nix build
- run: nix build .#doc
- run: nix fmt . -- --check
- run: nix fmt . -- --ci
- run: nix flake check
tests-darwin:
runs-on: macos-latest
@ -27,7 +27,7 @@ jobs:
extra-experimental-features = recursive-nix nix-command flakes
- run: nix build
- run: nix build .#doc
- run: nix fmt . -- --check
- run: nix fmt . -- --ci
- run: nix flake check
- name: "Install nix-darwin module"
run: |

View file

@ -1,3 +1,6 @@
{pkgs ? import <nixpkgs> {}}: {
{
pkgs ? import <nixpkgs> { },
}:
{
agenix = pkgs.callPackage ./pkgs/agenix.nix { };
}

View file

@ -1,11 +1,21 @@
let
user1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0idNvgGiucWgup/mP78zyC23uFjYq0evcWdjGQUaBH";
system1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPJDyIr/FSz1cJdcoW69R+NrWzwGK/+3gJpqD1t8L2zE";
in {
"secret1.age".publicKeys = [user1 system1];
in
{
"secret1.age".publicKeys = [
user1
system1
];
"secret2.age".publicKeys = [ user1 ];
"passwordfile-user1.age".publicKeys = [user1 system1];
"-leading-hyphen-filename.age".publicKeys = [user1 system1];
"passwordfile-user1.age".publicKeys = [
user1
system1
];
"-leading-hyphen-filename.age".publicKeys = [
user1
system1
];
"armored-secret.age" = {
publicKeys = [ user1 ];
armor = true;

View file

@ -14,15 +14,18 @@
systems.url = "github:nix-systems/default";
};
outputs = {
outputs =
{
self,
nixpkgs,
darwin,
home-manager,
systems,
}: let
}:
let
eachSystem = nixpkgs.lib.genAttrs (import systems);
in {
in
{
nixosModules.age = ./modules/age.nix;
nixosModules.default = self.nixosModules.age;
@ -34,7 +37,7 @@
overlays.default = import ./overlay.nix;
formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.nixfmt-tree);
packages = eachSystem (system: {
agenix = nixpkgs.legacyPackages.${system}.callPackage ./pkgs/agenix.nix { };
@ -64,8 +67,7 @@
};
}
];
})
.system;
}).system;
})
// {
x86_64-linux.integration = import ./test/integration.nix {

View file

@ -5,7 +5,8 @@
pkgs,
...
}:
with lib; let
with lib;
let
cfg = config.age;
ageBin = lib.getExe config.age.package;
@ -22,11 +23,12 @@ with lib; let
setTruePath = secretType: ''
${
if secretType.symlink
then ''
if secretType.symlink then
''
_truePath="${cfg.secretsMountPoint}/$_agenix_generation/${secretType.name}"
''
else ''
else
''
_truePath="${secretType.path}"
''
}
@ -54,7 +56,9 @@ with lib; let
umask u=r,g=,o=
test -f "${secretType.file}" || echo '[agenix] WARNING: encrypted file ${secretType.file} does not exist!'
test -d "$(dirname "$TMP_FILE")" || echo "[agenix] WARNING: $(dirname "$TMP_FILE") does not exist!"
LANG=${config.i18n.defaultLocale or "C"} ${ageBin} --decrypt "''${IDENTITIES[@]}" -o "$TMP_FILE" "${secretType.file}"
LANG=${
config.i18n.defaultLocale or "C"
} ${ageBin} --decrypt "''${IDENTITIES[@]}" -o "$TMP_FILE" "${secretType.file}"
)
chmod ${secretType.mode} "$TMP_FILE"
mv -f "$TMP_FILE" "$_truePath"
@ -65,12 +69,9 @@ with lib; let
''}
'';
testIdentities =
map
(path: ''
testIdentities = map (path: ''
test -f ${path} || echo '[agenix] WARNING: config.age.identityPaths entry ${path} not present!'
'')
cfg.identityPaths;
'') cfg.identityPaths;
cleanupAndLink = ''
_agenix_generation="$(basename "$(readlink "${cfg.secretsDir}")" || echo 0)"
@ -91,11 +92,13 @@ with lib; let
++ [ cleanupAndLink ]
);
secretType = types.submodule ({
secretType = types.submodule (
{
config,
name,
...
}: {
}:
{
options = {
name = mkOption {
type = types.str;
@ -124,11 +127,15 @@ with lib; let
Permissions mode of the decrypted secret in a format understood by chmod.
'';
};
symlink = mkEnableOption "symlinking secrets to their destination" // {default = true;};
symlink = mkEnableOption "symlinking secrets to their destination" // {
default = true;
};
});
};
}
);
mountingScript = let
mountingScript =
let
app = pkgs.writeShellApplication {
name = "agenix-home-manager-mount-secrets";
runtimeInputs = with pkgs; [ coreutils ];
@ -141,19 +148,21 @@ with lib; let
in
lib.getExe app;
userDirectory = dir: let
userDirectory =
dir:
let
inherit (pkgs.stdenv.hostPlatform) isDarwin;
baseDir =
if isDarwin
then "$(getconf DARWIN_USER_TEMP_DIR)"
else "\${XDG_RUNTIME_DIR}";
in "${baseDir}/${dir}";
baseDir = if isDarwin then "$(getconf DARWIN_USER_TEMP_DIR)" else "\${XDG_RUNTIME_DIR}";
in
"${baseDir}/${dir}";
userDirectoryDescription = dir:
userDirectoryDescription =
dir:
literalExpression ''
"''${XDG_RUNTIME_DIR}"/''${dir} on linux or "$(getconf DARWIN_USER_TEMP_DIR)"/''${dir} on darwin.
'';
in {
in
{
options.age = {
package = mkPackageOption pkgs "age" { };

View file

@ -5,7 +5,8 @@
pkgs,
...
}:
with lib; let
with lib;
let
cfg = config.age;
isDarwin = lib.attrsets.hasAttrByPath [ "environment" "darwinConfig" ] options;
@ -15,13 +16,14 @@ with lib; let
users = config.users.users;
sysusersEnabled =
if isDarwin
then false
else options.systemd ? sysusers && (config.systemd.sysusers.enable || config.services.userborn.enable);
if isDarwin then
false
else
options.systemd ? sysusers && (config.systemd.sysusers.enable || config.services.userborn.enable);
mountCommand =
if isDarwin
then ''
if isDarwin then
''
if ! diskutil info "${cfg.secretsMountPoint}" &> /dev/null; then
num_sectors=1048576
dev=$(hdiutil attach -nomount ram://"$num_sectors" | sed 's/[[:space:]]*$//')
@ -29,7 +31,8 @@ with lib; let
mount -t hfs -o nobrowse,nodev,nosuid,-m=0751 "$dev" "${cfg.secretsMountPoint}"
fi
''
else ''
else
''
grep -q "${cfg.secretsMountPoint} ramfs" /proc/mounts ||
mount -t ramfs none "${cfg.secretsMountPoint}" -o nodev,nosuid,mode=0751
'';
@ -44,10 +47,7 @@ with lib; let
chmod 0751 "${cfg.secretsMountPoint}/$_agenix_generation"
'';
chownGroup =
if isDarwin
then "admin"
else "keys";
chownGroup = if isDarwin then "admin" else "keys";
# chown the secrets mountpoint and the current generation to the keys group
# instead of leaving it root:root.
chownMountPoint = ''
@ -56,11 +56,12 @@ with lib; let
setTruePath = secretType: ''
${
if secretType.symlink
then ''
if secretType.symlink then
''
_truePath="${cfg.secretsMountPoint}/$_agenix_generation/${secretType.name}"
''
else ''
else
''
_truePath="${secretType.path}"
''
}
@ -87,7 +88,9 @@ with lib; let
umask u=r,g=,o=
test -f "${secretType.file}" || echo '[agenix] WARNING: encrypted file ${secretType.file} does not exist!'
test -d "$(dirname "$TMP_FILE")" || echo "[agenix] WARNING: $(dirname "$TMP_FILE") does not exist!"
LANG=${config.i18n.defaultLocale or "C"} ${ageBin} --decrypt "''${IDENTITIES[@]}" -o "$TMP_FILE" "${secretType.file}"
LANG=${
config.i18n.defaultLocale or "C"
} ${ageBin} --decrypt "''${IDENTITIES[@]}" -o "$TMP_FILE" "${secretType.file}"
)
chmod ${secretType.mode} "$TMP_FILE"
mv -f "$TMP_FILE" "$_truePath"
@ -97,12 +100,9 @@ with lib; let
''}
'';
testIdentities =
map
(path: ''
testIdentities = map (path: ''
test -f ${path} || echo '[agenix] WARNING: config.age.identityPaths entry ${path} not present!'
'')
cfg.identityPaths;
'') cfg.identityPaths;
cleanupAndLink = ''
_agenix_generation="$(basename "$(readlink ${cfg.secretsDir})" || echo 0)"
@ -134,7 +134,9 @@ with lib; let
++ (map chownSecret (builtins.attrValues cfg.secrets))
);
secretType = types.submodule ({config, ...}: {
secretType = types.submodule (
{ config, ... }:
{
options = {
name = mkOption {
type = types.str;
@ -184,10 +186,14 @@ with lib; let
Group of the decrypted secret.
'';
};
symlink = mkEnableOption "symlinking secrets to their destination" // {default = true;};
symlink = mkEnableOption "symlinking secrets to their destination" // {
default = true;
};
});
in {
};
}
);
in
{
imports = [
(mkRenamedOptionModule [ "age" "sshKeyPaths" ] [ "age" "identityPaths" ])
];
@ -219,12 +225,14 @@ in {
};
secretsMountPoint = mkOption {
type =
types.addCheck types.str
(s:
(builtins.match "[ \t\n]*" s)
== null # non-empty
&& (builtins.match ".+/" s) == null) # without trailing slash
// {description = "${types.str.description} (with check: non-empty without trailing slash)";};
types.addCheck types.str (
s:
(builtins.match "[ \t\n]*" s) == null # non-empty
&& (builtins.match ".+/" s) == null
) # without trailing slash
// {
description = "${types.str.description} (with check: non-empty without trailing slash)";
};
default = "/run/agenix.d";
description = ''
Where secrets are created before they are symlinked to {option}`age.secretsDir`
@ -233,14 +241,17 @@ in {
identityPaths = mkOption {
type = types.listOf types.path;
default =
if isDarwin
then [
if isDarwin then
[
"/etc/ssh/ssh_host_ed25519_key"
"/etc/ssh/ssh_host_rsa_key"
]
else if (config.services.openssh.enable or false)
then map (e: e.path) (lib.filter (e: e.type == "rsa" || e.type == "ed25519") config.services.openssh.hostKeys)
else [];
else if (config.services.openssh.enable or false) then
map (e: e.path) (
lib.filter (e: e.type == "rsa" || e.type == "ed25519") config.services.openssh.hostKeys
)
else
[ ];
defaultText = literalExpression ''
if isDarwin
then [
@ -277,13 +288,11 @@ in {
path = [ pkgs.mount ];
serviceConfig = {
Type = "oneshot";
ExecStart = pkgs.writeShellScript "agenix-install" (
concatLines [
ExecStart = pkgs.writeShellScript "agenix-install" (concatLines [
newGeneration
installSecrets
chownSecrets
]
);
]);
RemainAfterExit = true;
};
};

View file

@ -9,7 +9,8 @@
replaceVars,
ageBin ? "${age}/bin/age",
shellcheck,
}: let
}:
let
bin = "${placeholder "out"}/bin/agenix";
in
stdenv.mkDerivation rec {

View file

@ -1,5 +1,6 @@
# Do not copy this! It is insecure. This is only okay because we are testing.
{config, ...}: {
{ config, ... }:
{
system.activationScripts.agenixInstall.deps = [ "installSSHHostKeys" ];
system.activationScripts.installSSHHostKeys.text = ''

View file

@ -1,7 +1,6 @@
{
nixpkgs ? <nixpkgs>,
pkgs ?
import <nixpkgs> {
pkgs ? import <nixpkgs> {
inherit system;
config = { };
},
@ -10,12 +9,14 @@
}:
pkgs.nixosTest {
name = "agenix-integration";
nodes.system1 = {
nodes.system1 =
{
config,
pkgs,
options,
...
}: {
}:
{
imports = [
../modules/age.nix
./install_ssh_host_keys.nix
@ -47,7 +48,9 @@ pkgs.nixosTest {
};
};
home-manager.users.user1 = {options, ...}: {
home-manager.users.user1 =
{ options, ... }:
{
imports = [
../modules/age-home.nix
];
@ -71,13 +74,15 @@ pkgs.nixosTest {
};
};
testScript = let
testScript =
let
user = "user1";
password = "password1234";
secret2 = "world!";
hyphen-secret = "filename started with hyphen";
armored-secret = "Hello World!";
in ''
in
''
system1.wait_for_unit("multi-user.target")
system1.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
system1.sleep(2)

View file

@ -3,7 +3,8 @@
pkgs,
options,
...
}: let
}:
let
secret = "hello";
testScript = pkgs.writeShellApplication {
name = "agenix-integration";
@ -11,7 +12,8 @@
grep "${secret}" "${config.age.secrets.system-secret.path}"
'';
};
in {
in
{
imports = [
./install_ssh_host_keys_darwin.nix
../modules/age.nix

View file

@ -4,7 +4,8 @@
options,
lib,
...
}: {
}:
{
imports = [ ../modules/age-home.nix ];
age = {
@ -18,14 +19,18 @@
stateVersion = lib.trivial.release;
};
home.file = let
home.file =
let
name = "agenix-home-integration";
in {
in
{
${name}.source = pkgs.writeShellApplication {
inherit name;
text = let
text =
let
secret = "world!";
in ''
in
''
diff -q "${config.age.secrets.user-secret.path}" <(printf '${secret}\n')
'';
};