aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-12 19:44:41 +0000
committertv <tv@krebsco.de>2026-11-13 03:24:12 +0100
commit470de08082a8d251c3854ceb6da9cef8bd43b74b (patch)
treec576ac7e5f8c55bf0eb9899c28726b81ab3cdad3 /README.md
parent333144080f4a03f1adc1eb7ded0a9d3ae1bfa9ee (diff)
populate: stay inside the target directory
Populate replaces what's at the target paths of sources, removes what sources don't deliver anymore, and prunes. Nothing of that may reach beyond the target directory, whatever names sources have and whatever the target directory contains: - Source names that aren't file names in the target directory don't evaluate: the empty name, ., .., .populate, and names with slashes or control characters. E.g. a git source named "" removes the target directory, and a file source named .. syncs into its parent. - Target paths that aren't absolute, that are the root directory, or that contain .. don't evaluate. - A symlink at the target path of a source gets replaced, not followed, and populate says so. rsync-based and flake sources do that already. git sources replace the link as well, and also a work tree whose .git is a symlink or a file naming a repository elsewhere, instead of fetching, resetting, and cleaning there. derivation sources replace a link that doesn't point into the store, instead of failing. - Populate refuses to use the sentinel, or a state directory therein, if it is a symlink, instead of changing and removing what it points to. - What populate removes recursively gets removed as a link if it is one: chmod -R follows a link named on the command line. - Flake and flake-input sources that get patched, get their lock file rewritten, or are materialized replace a symlink at their target path like every source does, and say so. - Nix rewrites lock files in place, which changes other hard links to them as well, e.g. in a backup or outside the target directory, and what a lock file that is a symlink points to. Populate replaces a lock file by a copy of its own before rewriting it. The target directory itself may be a symlink. Nix refuses path: URLs with symlinks on the way, so the flakes step resolves the paths it hands to Nix. Backups work on a sentinel that is still a file, which becomes a directory, like for everything else that keeps state. The tests create canaries outside the target directories: a file and a directory beside them, and a directory elsewhere with a read-only directory and a Git work tree with uncommitted changes. The check of every phase of every scenario fails if a canary changed, or if a store path that the target directory links to doesn't match its hash anymore. A new test, safety, points links at the canaries: at the target path of every source type, inside what sources replace, in place of populate's state, and among what it removes and prunes. It also covers the names and target paths that don't evaluate, a target directory that is a symlink, and a lock file with another hard link.
Diffstat (limited to 'README.md')
-rw-r--r--README.md29
1 files changed, 27 insertions, 2 deletions
diff --git a/README.md b/README.md
index 87d5e36..ae7eca2 100644
--- a/README.md
+++ b/README.md
@@ -290,6 +290,29 @@ pkgs.krops.writeCommand "deploy-with-swap" {
whether the ssh session should do a pseudo-terminal allocation.
sets `-t` on the ssh command.
+## The target directory
+
+Populate owns the target directory, `/var/src` by default: it replaces
+whatever is at the target path of a source, and with `prune` it removes
+everything else. It doesn't change or remove anything outside:
+
+* Target paths must be absolute, must not be the root directory, and must not
+ contain `..`. Source names must be file names other than `.`, `..`, and
+ `.populate`, without slashes and control characters. Anything else fails
+ when evaluating.
+
+* A symlink at the target path of a source gets replaced by what the source
+ delivers, not followed, and populate says so. To keep a source elsewhere,
+ e.g. on another disk or in memory, mount that place at the target path, or
+ make the target directory itself a symlink. A Git work tree whose `.git`
+ is a symlink, or a file naming a repository elsewhere, gets replaced by a
+ `git` source as well.
+
+* Populate keeps its state in the sentinel, `.populate`, which becomes a
+ directory once there is state to keep. Populating fails if the sentinel,
+ or a directory populate needs therein, is a symlink.
+
+
## Source Types
### `derivation`
@@ -658,8 +681,10 @@ flakes, as long as the inputs drawing from them are declared with
`tests/` contains NixOS VM tests for populate: one test per source type, one
for features spanning sources, such as flake inputs from sources, one for edge
-cases of flakes, such as unusual lock files, and one for the arguments
-`writeDeploy` passes to `nixos-rebuild`. The tests deploy every combination
+cases of flakes, such as unusual lock files, one for staying inside the target
+directory, whatever links it contains, and one for the arguments `writeDeploy`
+passes to `nixos-rebuild`. After every deploy, all tests check that nothing
+outside the target directory changed. The tests deploy every combination
of a source type's options, except for patches, which the features test
covers, to the deploying machine itself, to a remote target
as `root`, and to a remote target using `sudo`, and check the result after