From 3106949fd710b35d3e89e3def45913f1441394a1 Mon Sep 17 00:00:00 2001 From: Felix Buehler Date: Wed, 1 Oct 2025 22:45:49 +0200 Subject: [PATCH] lib/types: add externalPath --- lib/tests/modules.sh | 9 +++++++++ lib/tests/modules/types.nix | 8 ++++++++ lib/types.nix | 5 +++++ .../manual/development/option-types.section.md | 15 +++++++++++++++ 4 files changed, 37 insertions(+) diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index 093196da16c5..505c1c5a5fe4 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -223,6 +223,15 @@ checkConfigError 'A definition for option .* is not of type .path in the Nix sto checkConfigError 'A definition for option .* is not of type .path in the Nix store.. Definition values:\n\s*- In .*: ".*/store/.links"' config.pathInStore.bad4 ./types.nix checkConfigError 'A definition for option .* is not of type .path in the Nix store.. Definition values:\n\s*- In .*: "/foo/bar"' config.pathInStore.bad5 ./types.nix +# types.externalPath +checkConfigOutput '".*/foo/bar"' config.externalPath.ok1 ./types.nix +checkConfigOutput '".*/"' config.externalPath.ok2 ./types.nix +checkConfigError 'A definition for option .* is not of type .absolute path not in the Nix store.' config.externalPath.bad1 ./types.nix +checkConfigError 'A definition for option .* is not of type .absolute path not in the Nix store.' config.externalPath.bad2 ./types.nix +checkConfigError 'A definition for option .* is not of type .absolute path not in the Nix store.' config.externalPath.bad3 ./types.nix +checkConfigError 'A definition for option .* is not of type .absolute path not in the Nix store.' config.externalPath.bad4 ./types.nix +checkConfigError 'A definition for option .* is not of type .absolute path not in the Nix store.' config.externalPath.bad5 ./types.nix + # types.fileset checkConfigOutput '^0$' config.filesetCardinal.ok1 ./fileset.nix checkConfigOutput '^1$' config.filesetCardinal.ok2 ./fileset.nix diff --git a/lib/tests/modules/types.nix b/lib/tests/modules/types.nix index 3127ece89e49..0a566ea960c4 100644 --- a/lib/tests/modules/types.nix +++ b/lib/tests/modules/types.nix @@ -15,6 +15,7 @@ in { options = { pathInStore = mkOption { type = types.lazyAttrsOf types.pathInStore; }; + externalPath = mkOption { type = types.lazyAttrsOf types.externalPath; }; assertions = mkOption { }; }; config = { @@ -26,6 +27,13 @@ in pathInStore.bad3 = "${storeDir}/"; pathInStore.bad4 = "${storeDir}/.links"; # technically true, but not reasonable pathInStore.bad5 = "/foo/bar"; + externalPath.bad1 = "${storeDir}/0lz9p8xhf89kb1c1kk6jxrzskaiygnlh-bash-5.2-p15.drv"; + externalPath.bad2 = "${storeDir}/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15"; + externalPath.bad3 = "${storeDir}/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15/bin/bash"; + externalPath.bad4 = ""; + externalPath.bad5 = "./foo/bar"; + externalPath.ok1 = "/foo/bar"; + externalPath.ok2 = "/"; assertions = with lib.types; diff --git a/lib/types.nix b/lib/types.nix index cb41fb5c85aa..e57ceafcbaa4 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -676,6 +676,11 @@ let inStore = true; }; + externalPath = pathWith { + absolute = true; + inStore = false; + }; + pathWith = { inStore ? null, diff --git a/nixos/doc/manual/development/option-types.section.md b/nixos/doc/manual/development/option-types.section.md index d2e0c7299415..707e2e3d1345 100644 --- a/nixos/doc/manual/development/option-types.section.md +++ b/nixos/doc/manual/development/option-types.section.md @@ -31,6 +31,21 @@ merging is handled. : A path that is contained in the Nix store. This can be a top-level store path like `pkgs.hello` or a descendant like `"${pkgs.hello}/bin/hello"`. +`types.externalPath` + +: A path that is not contained in the Nix store. Typical use cases are: + secrets, password or any other external file. + +::: {.warning} +This type only validates that the path is not *currently* in the Nix store. +It does NOT prevent the value from being copied to the store later when: +- Referenced in a derivation +- Used in certain path operations (e.g., `${path}` interpolation) +- Passed to functions that copy to the store + +Users must still be careful about how they reference these paths. +::: + `types.pathWith` { *`inStore`* ? `null`, *`absolute`* ? `null` } : A filesystem path. Either a string or something that can be coerced